第八部分 · 学习就是优化
反向传播:神经网络如何算梯度
梯度是训练的指南针,可几百万个偏导,照定义一个一个数值地算会慢到训练不动。深度学习真正的引擎,是一招把第 7 课的链式法则反着跑的算法——一次遍历,所有梯度全部到手。
留下的问题:指南针好,可怎么算得动?神经网络的损失是一长串函数套函数套函数(层叠层),参数上百万。若对每个参数都"扰动一下、看损失变化"去逼近偏导,要把整个网络前向跑上百万遍——根本不现实。
本课新增:反向传播。它的核心是第 7 课就埋下、却没充分使用的链式法则,加上一张计算图。先前向跑一遍算出每个中间值;再反向跑一遍,把每条边上的局部导数沿路相乘、在汇合处相加——一趟下来,所有参数的偏导同时算出。这就是深度网络之所以能被训练的根本原因。
链式法则:函数套函数怎么求导
神经网络说到底是函数的层层嵌套:输入经过第一层变成中间结果,再经过第二层、第三层……最后吐出一个损失。要对最里层的参数求导,绕不开第 7 课提过的链式法则。它讲的是一件很自然的事:若 a 影响 z、z 又影响 L,那么 a 对 L 的影响,等于一路上各段影响率相乘。
链条更长也一样,只是多乘几段:
问题是,网络里这样的"链条"有几百万条(每个参数到损失都有一条甚至多条路)。如果对每个参数都从头乘一遍,会有海量的重复计算。反向传播的聪明之处,正是把这些乘法组织得不重复——而组织它们的脚手架,叫计算图。
计算图:把算式画成一张图
任何复杂表达式都能拆成一连串最基本的运算(加、乘、平方、sigmoid……),画成一张图:节点是运算或变量,边表示"谁喂给谁"。拿一个小例子贯穿全课:
把它拆开,引入两个中间量:先算 u = a · b,再算 v = u + c,最后 L = v²。于是计算图是一条主干带一个分叉:
关键在于:每个基本运算的导数我们都背得出。乘法 u=a·b:∂u/∂a = b,∂u/∂b = a。加法 v=u+c:∂v/∂u = 1,∂v/∂c = 1。平方 L=v²:∂L/∂v = 2v。每条边上都贴着这样一个简单的局部导数。剩下要做的,只是把它们沿正确的路径乘起来——这就是反向传播。
前向传播:先把每个值算出来
第一趟是前向:从输入出发,顺着图把每个节点的数值算出来并记下(一会儿反向要用)。取一组具体数 a=2, b=3, c=1:
注意每条边上的局部导数现在也有了具体值:乘法节点处 ∂u/∂a = b = 3、∂u/∂b = a = 2;平方节点处 ∂L/∂v = 2v = 14。它们都依赖前向算出的值——这就是为什么必须先前向、再反向。
反向传播:从损失倒着乘回去
第二趟是反向。我们给每个节点配一个"它对损失的敏感度",记作 ∂L/∂(该节点),行话叫这个节点的"梯度"。从终点 L 出发,它对自己的敏感度当然是 1(∂L/∂L = 1),然后逆着每条边,把上游已经算好的敏感度乘上这条边的局部导数,传给下游:
三个答案 ∂L/∂a = 42, ∂L/∂b = 28, ∂L/∂c = 14 一次反向遍历就全有了。可以用前向定义验一下:L = (ab+c)² 对 a 求偏导是 2(ab+c)·b = 2×7×3 = 42,分毫不差。下面的小实验把这两趟画给你看——改 a、b、c,先看绿色的前向值,再点"反向传播"看红色的敏感度怎样从 L 一格一格倒着乘回去。
两条规则,就能让一趟反向覆盖整张图
上面的小图藏着反向传播的全部规则,再大的网络也只靠这两条:
- 沿边相乘。沿一条边回传时,把上游传来的敏感度乘以这条边的局部导数(这条边对应的基本运算的导数)。这就是链式法则在一条边上的样子。
- 分叉处相加。若一个变量同时喂给好几个下游(比如同一个参数在网络里被多处用到),它收到的敏感度是各条路回传的总和。这正是多元链式法则的内容:多条影响路径要叠加。
为什么一趟就够、不会重复?因为每个节点的敏感度只算一次、存下来,下游全都复用它。一个有 d 个参数的网络,前向一趟 + 反向一趟,总代价只跟网络规模成正比——而不是像数值逼近那样要 d 次前向。把"逐个参数 d 次"压成"两趟",这就是反向传播让百万参数训练成为可能的全部魔法。
这就是 gpt_mini 里发生的事
你在 gpt_mini 看到的训练循环,每一步底下跑的正是这套:先前向把一批文本喂进网络、算出预测和损失(损失用的是第 33 课的交叉熵);再反向传播,从损失沿计算图倒着乘回去,一次得到上亿个参数各自的梯度 ∇L;最后用这些梯度去更新参数(下一课)。框架里那行 loss.backward(),做的就是本课的反向遍历;它能自动完成,是因为框架替你记下了整张计算图和每条边的局部导数。强化学习(RL)、扩散模型(扩散)的训练,地基都是这同一招。
历史上,反向传播的现代形式在 1986 年由鲁梅尔哈特、辛顿、威廉斯一篇论文推广开来,让多层网络第一次能被有效训练——它没有发明新数学,只是把链式法则用对了顺序、且不重复。一个看似平凡的"算导数的技巧",撑起了整个深度学习时代。
常见误解
- "反向传播是一种特殊的求导公式。" 不是。它就是链式法则,只是沿计算图反向、且把中间结果存下来复用的高效组织方式。数学上没有任何新东西,新的只是计算的顺序。
- "反向才是重点,前向可以跳过。" 不行。反向用到的每条边的局部导数(如 ∂u/∂a = b、∂L/∂v = 2v)都依赖前向算出的值。必须先前向、缓存中间值,才能反向。
- "网络越深,反向就指数级变慢。" 恰恰相反。反向只是沿图走一遍,代价与网络规模成正比(线性)。指数级慢的是"对每个参数单独数值逼近"那条死路——反向传播正是用来避开它的。
- "反向传播是在做学习。" 它只负责算梯度,不负责更新参数。拿到梯度后怎么迈步、迈多大,是下一课梯度下降的事。算梯度和用梯度是两件事。