看视频时对反向传播算法感到云里雾里,于是我想了一个例子来理解,可能不太严谨,在此分享给大家:
首先对梯度下降法作一个快速的回顾:我们已经知道了神经网络通过一个损失函数来衡量其工作是否有效
而所谓的训练神经网络,就是通过调整神经网络里的权重和偏置,设法降低损失函数值
而在读初中时,我们就知道找一个函数最小值的办法是求导,找导数为0的点,这些点也可能就是函数的最小值点,但当函数非常复杂时,不可能把每个可疑点都算出来一一比较,因此可以这样做:
先随便找一点,求其导数,导数为正时,说明在这里输入增大会导致输出上升,就应该减小输入值;而导数为负时,就应该增大输入值(当斜率趋于零、接近谷底时,调整的步长也要相应减小防止走过头错过了最小值)重复这一步骤,就会逼近函数的某个局部最小值
把这个过程类比到神经网络这样的极度复杂的多元函数上:多元函数的梯度,其指向就是对应输入下函数值增长最快的方向,所以只需要求某个输入下的负梯度,就能得到在此输入下函数值下降最快的方向,那么我们往这个方向“走一小步”,用新的输入再进行一次梯度计算,找此时函数值下降最快的方向,再“走一小步”……最终就会抵达一个局部最小值
上述这个不断寻找方向挪动到最小值的过程,“每一步”改变输入是神经网络的权重参数、要“抵达”的输出最小值是损失函数的最小值,所描述的也就是梯度下降法
在回顾完成后,我们进入重头戏,反向传播算法:
上述的过程中存在一个明显的问题:使用梯度确定“走一步”的方向,需要计算出“走这一步,对最终结果(即代价)的影响”
而对于有很多层,每层很多神经元的神经网络,从最后的损失函数值一路算回开头的输入,如果按我们学的链式求导法则,这显然需要非常庞大的计算量
为此,我们利用反向传播算法,“从输入到代价”这条长链拆成一层一层的小环节,每一环都只用到局部信息,先算好这些局部结果,再沿着网络从后往前一层层复用它们
这么说可能有点抽象,用一个极简的神经网络为例,我们手算一遍反向传播:
这个神经网络可以表示为 y = v (w1 · x1 + w2 · x2),为了方便,设置其初始权重全是1,偏置值全是0,给一个输入,得到输出值 y 为 3,如下:

1. 假设这个神经网络的目标 t 是 5,那么初始网络的损失函数值为:
loss = (y - t)^2 = (3 - 5)^2 = 2^2 = 4
2. 接着通过求导,可以看各个权重对损失值的影响。这里例子很简单,可以用链式法则一步步算:
∂loss/∂y = 2(y - t) = 2 × (3 - 5) = -4
这一步得到的意思是:在 y = 3 时,局部来看,输出值每增加 1,损失大约减小 4(注意,这里是在描述当前点的局部变化趋势,并不是的增加1会导致这种变化,后文同理)
3. 然后向前一层,因为 y = v · h,所以连接隐藏层与输出层的权重 v 对损失的影响是:
∂loss/∂v = 2(y - t) · ∂y/∂v
= 2(y - t) · h
= 2 × (3 - 5) × 3
= -12
意思是:在 v = 1 时,局部来看,权重 v 每增加 1,损失大约减小 12
4. 再向前一层,因为 h = w1x1 + w2x2,所以连接输入层与隐藏层的权重 w1、w2 对损失的影响是:
∂loss/∂w1 = 2(y - t) · ∂y/∂w1 = 2(y - t) · v · ∂h/∂w1 = ……
∂loss/∂w2 = 2(y - t) · ∂y/∂w2 = ……
5. 重点来了:可以看到,即便是这样简单的神经网络,随着层数与变量的增加,计算也会变得相当繁琐
这也就是反向传播算法“每一环都只用到局部信息”发挥作用的时候了,根据链式法则我们可以知道,以隐藏层到输出层这一步为例,计算过程实际上是:
∂loss/∂v = (∂loss/∂y) · (∂y/∂v)
∂loss/∂h = (∂loss/∂y) · (∂y/∂h)
可以发现,其中 ∂loss/∂y 已经在上游(从损失到输出的那一步)算出来了!根本没必要再次计算∂loss/∂y的部分!
6. 因此,只要把前一步算出的梯度保存下来,往前一层计算时直接调用,就能把一条长链的复杂计算变成两层之间的计算,省掉很多步骤
回到刚刚的步骤,算出隐藏层到输出层的 ∂loss/∂h = -4(∂y/∂h) = -4v = -4 后,再往前一层又可以用于计算输出层到隐藏层的:
∂loss/∂w1 = (∂loss/∂h) · (∂h/∂w1) = -4(x1) = -4
∂loss/∂w2 = (∂loss/∂h) · (∂h/∂w2) = -8(x2) = -8
7. 有了这些导数,就能拼出梯度(梯度的数学定义正是由函数对各个变量的偏导数拼成的向量),根据梯度下降法的原理,就知道该往哪里去找损失函数的最小值
但还有一个问题:应该以多大的步长去找?这个步长由“学习率”决定(学习率不是算出来的参数,而是人为规定的值,因此称为超参数)
简而言之,更新权重的方式是:
w_new = w - η · ∇
这个公式表示:新的权重值应该向着损失函数梯度的负方向,也就是当前局部区域内损失函数值下降最快的方向“走一步”,这“一步”的长度由学习率 η 控制
8. 例如,我们取学习率为0.025,代入计算好的导数,可得新的权重:
w1 = 1 - 0.025(-4) = 1+0.1 = 1.1
w2 = 1 - 0.025(-8) = 1+0.2 = 1.2
v = 1 - 0.025(-12) = 1+0.3 = 1.3
9. 在新权重下再进行一次前向传播,得到新结果,可见新结果的损失值大幅下降,说明梯度下降法训练很有效

10. 还需要补充一点:反向传播算法本质是“空间换时间”,在计算时虽然极大简化了繁琐重复的求导步骤,但必须把前向传播的中间结果(比如刚才的h)和前一步算出的梯度(比如刚才计算∂loss/∂h需要∂loss/∂y)存储起来,供后续逐层复用,对于动辄上百亿个参数的大模型来说是不小的开销,这也就是训练AI需要那么多内存(导致内存大涨价)的原因之一