文章:Sepp Hochreiter, Jürgen Schmidhuber; Long Short-Term Memory. Neural Comput 1997; 9 (8): 1735–1780. doi: https://doi.org/10.1162/neco.1997.9.8.1735
传统 反向传播算法(BPTT, Backpropagation Through Time) 的误差传播特性,Hochreiter(LSTM 的提出者之一)在 1991 年对其误差随时间衰减的数学分析,重点揭示 “误差消失(vanishing gradients)” 的根本原因。
3 CONSTANT ERROR BACKPROP(恒定误差反向传播)
3.1 EXPONENTIALLY DECAYING ERROR(指数衰减误差)
背景知识:为什么要强调“非输入单元 i”、“非输出神经元 j”?
这是因为在 反向传播(Backpropagation) 中,不同类型的神经元 —— 输入层、中间隐藏层、输出层 —— 处理方式是不同的。
🌟 一、输入单元(Input Units)
输入单元 不进行反向传播计算,因为:
-
它们只是接收外部输入数据(比如特征向量),
-
并不会有激活函数和误差信号可计算,
-
它们不需要被“更新”或“训练”——它们就是数据本身。
👉 所以反向传播过程不涉及输入单元。
🌟 二、输出单元(Output Units)
输出单元的误差是最容易计算的:
-
这里的
是目标输出,
是模型实际输出。
-
所以对于输出神经元来说,误差信号是已知的,直接从目标值与预测值计算而来。
🌟 三、非输出单元(Hidden Units,隐藏层)
这才是重点:
-
隐藏层没有目标值可比较,它的误差信号只能通过“传播回来”的方式计算。
-
它们通过从下一层的所有神经元接收到的误差信号,反向传播回来进行计算:
这就是后面在原文里看到的公式。
单元类型 | 是否参与误差计算 | 误差来源方式 |
---|---|---|
输入单元 | ❌ 不参与 | 没有误差,只是传递输入 |
输出单元 | ✅ 参与 | 从预测值和目标值直接算 |
非输出单元(隐藏层) | ✅ 参与 | 通过反向传播间接计算 |
所以原文才会特意说:
"is the activation of a non-input unit i…"
"some non-output unit j’s backpropagated error signal is…"
这是在告诉你 —— “这些公式是用于计算隐藏层的误差,不是输入层,也不是输出层。”
而原文开头特意提到输出神经元:
对于输出神经元 k,其在时间步 t 的目标值记为
,使用的是 mean squared error(均方误差,MSE)
原因:一、在反向传播中,误差的源头就是输出层
神经网络的训练目标是:
👉 让输出尽可能接近目标值,也就是最小化损失函数。
而损失函数(像 MSE)只能在输出层才能直接计算,因为:
-
只有输出层有“模型预测值”
-
只有它能和“目标值”
比较
比如均方误差公式:
这个公式就是在输出神经元那里才成立的。
二、输出层的误差是反向传播的“起点”
输出层误差信号的计算公式是:
你可以理解成:
-
差值部分:
是“你到底错了多少”
-
导数部分:
是这个误差对前面神经元影响有多大(灵敏度)
这个误差信号 是第一步计算出来的,然后才“传”回去给前面的隐藏层。
角色 | 为什么要特别提 | 原因 |
---|---|---|
输出神经元 | 起点 & 可对比目标 | 是误差的源头,是唯一能直接计算误差的地方 |
隐藏神经元 | 间接计算误差 | 要依赖从输出层回传下来的误差信号 |
💡 反向传播必须从输出层开始计算误差,然后才能传回隐藏层,所以它才是“第一步”,要特别提到!
传统 BPTT(例如 Williams 和 Zipser,1992)
对于输出神经元 k
,其在时间步 t
的目标值记为 dk(t)
,使用的是mean squared error 均方误差(MSE):
其中:
“is the activation of a non-input unit i with differentiable activation function fᵢ”
“是一个非输入单元 i 的激活值,该单元有一个可微分的的激活函数 fᵢ”
🔹 non-input unit i:
就是说这个单元不是输入层的神经元,而是在隐藏层或输出层的某个神经元,编号是 i。
🔹 activation function fᵢ:
激活函数就是决定神经元输出的函数,比如:
-
sigmoid
-
tanh
-
ReLU
这些函数通常是可微分的(differentiable),这样才能进行梯度下降。
"netᵢ(t) is unit i's current net input, and wᵢⱼ is the weight on the connection from unit j to i."
net input
的 net
不是 network,而是:
✅ net = 净的、总和之后的
比如英语里还有这种说法:
-
net profit(净利润)
-
net weight(净重)
-
这是说:unit i 当前的净输入是
-
通常计算方式是:
-
即:所有连接到它的上一个时间步的单元 j 的输出值
,乘以各自的权重
,加在一起。
-
:从单元 j 到单元 i 的连接权重。
Some non-output unit j's backpropagated error signal is
中文解释:
-
这里在讲:隐藏层中一个非输出神经元 j 的误差信号怎么计算。
🔹 拆解一下公式:
-
:表示在时间 t,神经元 j 的反向传播误差。
-
:是 j 神经元的激活函数的导数(在
处求导)。
-
:将当前单元 j 的误差,反向传播回来:
从 下一个时间步的所有目标神经元 i 处,获取误差信号,并乘以连接权重
。
🟡 换句话说:
“反向传播时,神经元 j 的误差信号是下一个时刻各目标神经元误差,乘以对应权重,加权后再乘以激活函数的导数。”
The corresponding contribution to wⱼₗ's total weight update is β δⱼ(t) · yₗ(t−1),
where β is the learning rate, and l stands for an arbitrary unit connected to unit j.
这一句在说:这个误差会怎样作用到权重更新上(也就是权重怎么学习)。
🔹 拆解:
-
:表示从单元 l 到单元 j 的连接权重
-
:是上一个时间点,单元 l 的输出
-
:当前时间点 j 单元的误差
-
β:学习率(控制每次权重调整的步长)
🔸 所以这一项是:
也就是说:
我们根据当前误差大小
和 上一个神经元输出
,来更新连接权重
。
这是标准的 反向传播权重更新公式,也称作梯度下降更新法则的一部分。
✅ 总结成一句话:
当前时刻某个非输出神经元的误差由下一时刻的误差反传回来,然后再用这个误差乘以上一时刻输入,乘以学习率,去更新连接到它的权重。
Hochreiter 的分析(1991)
分析重点:误差从某一单元 u 在时间 t,反向传播 q 步后到达另一个单元 v 时会经历怎样的“缩小”或“放大”?
假设:
-
网络为全连接;
-
考虑非输入单元的误差从
u
到v
的传播; -
传播
q
步的误差变化率为:
Outline of Hochreiter's analysis (1991, page 19–21). Suppose we have a fully connected net whose non-input unit indices range from 1 to n.
我们考虑一个完全连接的递归神经网络(RNN),它的非输入神经元编号是从 1 到 n,也就是说,每个神经元都可以连接到其他所有神经元。
Let us focus on local error flow from unit u to unit v (later we will see that the analysis immediately extends to global error flow).
我们先聚焦在“局部误差传播”上,也就是从一个神经元 u 到另一个神经元 v 的误差信号传播过程。之后,这个分析可以很自然地扩展到整网的“全局误差传播”(global error flow)。
The error occurring at an arbitrary unit u at time step t is propagated "back into time" for q time steps, to an arbitrary unit v.
假设在时间 t,神经元 u 上有一个误差信号,我们把这个误差向后传播 q 个时间步,追踪它传播到了另一个神经元 v 的路径和变化。这就是 RNN 中所谓的 “反向传播通过时间”(BPTT)。
🔸“The error occurring at an arbitrary unit u”
在任意一个神经元 u 上产生的误差,(arbitrary 是“任意的”的意思,也就是说不固定是哪个神经元)
🔸“at time step t”
在第 t 个时间步发生的,(比如 RNN 的输入是一个序列,第 t 步代表第 t 个输入)
🔸“is propagated 'back into time'”
会“沿时间向后”传播,(这是指 RNN 的反向传播过程 BPTT——Backpropagation Through Time)
🔸“for q time steps”往回传播 q 个时间步,(比如从时间点 t 向过去的 t-1, t-2, ..., t-q 传播误差信号)
🔸“to an arbitrary unit v”传播到了某个任意的神经元 v 上。
整句简洁翻译:
第 t 个时间步,在某个神经元 u 上产生的误差信号,会沿时间向后传播 q 个时间步,直到传播到某个神经元 v。
🧠 举个小例子帮助你理解:
比如你有一个 RNN,在时间步 t=5 的时候,你发现某个输出神经元(比如单元 u)有误差。你希望用 BPTT 把这个误差反向传播到网络前面几步,比如 t=4、3、2……,看看它是否是因为之前某个神经元 v 的输出影响了当前的误差。
所以这个过程就是在分析:
“t=5 的误差,是不是 t=2 的神经元 v 造成的?”
如果是,那就要把这个误差信号,反向传播 q=3 步,传回 t=2 时刻的神经元 v。
This will scale the error by the following factor:
在这个传播过程中,这个误差会被缩放(scale)——要么变小(衰减),要么变大(爆炸)——关键就在下面这个公式。
情况 1:q = 1
很简单,就是激活函数导数 × 连接权重。
情况 2:q > 1
误差经过多个中间单元传播,需要使用链式法则逐步累乘:
其中:
-
-
外部的求和符号(多个 Σ)表示:
-
枚举所有可能的中间神经元路径,比如从 u(
) → l₁ → l₂ → ... → v(
)。
-
对应的是网络中所有从 u 到 v 的不同路径。
-
内部的乘积符号(Π)表示:
-
每条路径上传播误差时,每经过一个神经元,误差都会乘上:
-
:激活函数的导数(如 sigmoid 的导数 ≤ 0.25)
-
:权重
-
-
-
-
这个公式的作用是什么?
它是为了描述:在时间步 t 上,单元 u 的误差是如何“通过时间”反向传播 q 步,传递到时间 ( t - q) 的某个单元 v 上的。 -
每一步发生了什么?
在一个 RNN 中,误差是一步一步往回传的:
🔁 每一步的传递:
每一次从 t回传到 t-1,都要乘两个东西:
-
激活函数的导数:
,通常 < 1
👉 表示当前神经元对误差的“响应程度”,如果小于 1,误差就会缩小 -
权重:
👉 当前连接的强度,也通常在 [−1,1] 范围 - 所以每传一步,误差就变成了
🧊 梯度消失是怎么来的?
(note that since the summation terms may have different signs, increasing the number of units n does not necessarily increase error flow)
解释:即使你网络中有很多神经元 n,这些误差路径相加起来也不一定会使误差总量变大,因为:
-
有些路径会让误差变成正数,有些变成负数,它们相加可能互相抵消
-
此外,如果每一步的激活函数导数都很小(比如 sigmoid 导数 < 1),这些连乘就会导致误差迅速衰减到接近 0
这段内容是 Hochreiter 对 RNN 梯度爆炸和梯度消失问题的直观解释。
Intuitive explanation of equation (2). If
for all m (as can happen, e.g., with linear) then the largest product increases exponentially with q.
如果每一层(或每一步)的导数乘权重的绝对值都 大于1,也就是说:
例如使用线性激活函数时,就可能出现这种情况。
那么,多步相乘时,这个乘积会指数级增长。也就是说:
📈 误差会不断放大(梯度爆炸)
That is, the error blows up, and conflicting error signals arriving at unit v can lead to oscillating weights and unstable learning(for error blow-ups or bifurcations see also Pineda 1988, Baldi and Pineda 1991, Doya 1992)
也就是说,误差会“爆炸”,最后导致:
-
在某个神经元 v 上,来自不同路径的误差会互相冲突(可能正负不同)
-
导致权重来回震荡(oscillate)
-
网络训练不稳定,根本学不好!
On the other hand, if
for all m, then the largest product decreases exponentially with q.
反过来,如果每一层导数乘权重的绝对值都小于 1,那么:
-
多次相乘后会指数级减小
-
误差会不断变小(📉梯度消失)
That is, the error vanishes, and nothing can be learned in acceptable time.
这叫梯度消失,网络无法学习长期依赖。你可能训练了一年,结果前面几个时间步的东西都没学会。
If
is the logistic sigmoid function, then the maximal value of
is 0.25.
如果你用的是经典 sigmoid 激活函数:
它的导数最大值是 0.25,也就是说:
If
is constant and not equal to zero, then
takes on maximal values where it goes to zero for
, and is less than 1.0 for
即使你想通过“增大权重”来让误差不消失,也行不通:
-
权重太大:
,sigmoid 饱和,导数
,乘积依然趋近于0
-
权重在 4 以内:导数本来就小,乘积依然 < 1,误差仍然会衰减
-
为什么是 4?来源是:
如果使用的是 sigmoid 激活函数(logistic sigmoid):
-
它的导数最大值是 0.25
-
所以,只要权重 ∣w∣<4|w| < 4,就会导致:
⇒ 梯度在传播过程中会 每一步都乘以一个 <1 的数 ⇒ 逐渐变小 ⇒ 梯度消失
-
Hence with conventional logistic sigmoid activation functions, the error flow tends to vanish as long as the weights have absolute values below 4.0...
即使你调整初始化权重大小、或者增大学习率,都解决不了这个根本问题:
-
学习率再大,也只是在传回误差后乘个系数,不会改变误差 自身的传递比例
-
大权重会让激活函数饱和 → 导数为0 → 传递彻底断掉
🚨 无论你怎么调学习率和权重,只要使用 sigmoid 激活函数,误差在反向传播时都会被不断压缩,最终导致梯度消失,模型学不到长期依赖。
总结:
1. Sigmoid 函数的特点决定了“梯度消失”几乎不可避免:
-
sigmoid 的导数最大是 0.25(出现在输入是0的时候)
-
输入一旦偏大或偏小,导数很快就趋近于 0(函数进入“饱和区”)
-
所以在反向传播时,链式法则中一堆导数连乘:
每个
,乘多了就会接近 0 ⟶ 梯度消失
-
即使你:
-
把权重初始化很大(但这样会让 sigmoid 饱和,反而导数变得更小)
-
学习率设置很大(只会加快训练,但不会解决梯度传不回来的问题)
-
2. 其他激活函数可能导致“梯度爆炸”:
-
比如 ReLU、tanh、线性激活函数,导数不一定小于1
-
如果再配合权重比较大,就可能出现:
-
-
连乘放大 ⟶ 梯度爆炸
-
-
例如 RNN 中的 tanh 激活配合长时间传播,很容易出现爆炸
只要使用的是 sigmoid 激活函数,反向传播过程中不管权重大小或学习率如何,最终都会出现梯度消失的问题。而使用其他激活函数时,如果导数和权重的乘积大于 1,就有可能引起梯度爆炸。