深层神经网络需要让信息与梯度经过许多计算模块。残差连接通过 y=x+F(x) 提供直接的加法路径,使模块能够学习输入的更新量。本文说明残差连接的计算结构、梯度传播、二维数值计算,以及它在 Transformer 中的应用。
一、深层网络为什么需要残差连接
普通神经网络模块写为 xl+1=Fl(xl)。随着网络加深,模型可能出现训练误差上升的退化问题(Degradation Problem)。即使新增加的网络层在理论上能够学习恒等映射,实际优化过程也未必容易得到相应参数。
残差模块将输出写成:
y=x+F(x)
这里,x 是输入,F(x) 是变换分支的结果。输入还会沿恒等路径直接传给加法节点。
二、残差的含义
如果目标映射为 H(x),可写为:
H(x)=x+F(x),F(x)=H(x)−x
例如:
x=253,H(x)=2.54.83.1
那么残差为:
F(x)=0.5−0.20.1
相加后得到目标输出。残差可以理解为相对于输入的调整量。残差数值较小,不代表这个函数一定容易学习。
2.1 交互演示:输入与残差
调整滑块,观察普通变换的结果与残差相加后的结果。
三、残差连接与梯度传播
3.1 普通网络的梯度
先考虑标量情况。普通网络中:
xl+1=Fl(xl)
由链式法则:
∂xl∂L=∂xl+1∂LFl′(xl)
经过 n 层:
∂x0∂L=∂xn∂Ll=0∏n−1Fl′(xl)
如果 20 层的局部导数均为 0.5,则乘积为:
0.520≈9.54×10−7
梯度可能因多次相乘而变得很小,导致靠近输入的网络层更新缓慢。
3.2 残差模块的梯度
残差模块为:
xl+1=xl+Fl(xl)
求导得到:
∂xl∂xl+1=1+Fl′(xl)
继续应用链式法则:
∂xl∂L=∂xl+1∂L(1+Fl′(xl))
公式中的 1 来自恒等路径。例如,当 Fl′(xl)=0.01 时,整个模块的导数是 1.01。变换分支的导数接近零时,模块的导数接近 1。
向量情况下,用 Jacobian(雅可比矩阵)表示:
Jy=I+JF
∇xL=(I+JF)T∇yL
I 是单位矩阵。上游梯度沿恒等路径直接传播,同时还经过变换分支,最后在输入位置相加。
3.3 多层残差网络
多个残差模块连续连接:
xl+1=xl+Fl(xl)
逐层展开:
xn=x0+l=0∑n−1Fl(xl)
对标量输入求导:
∂x0∂xn=1+∂x0∂l=0∑n−1Fl(xl)=l=0∏n−1(1+Fl′(xl))
这一结果揭示了恒等连接提供的直接梯度路径。
需要注意,残差连接并不能保证梯度始终稳定。当 Fl′=−1 时,局部导数 1+Fl′ 等于零。多个局部导数绝对值较大时,仍可能出现梯度爆炸。
3.4 交互实验:梯度倍率
假设每层变换分支的标量导数都等于 a,那么:
Gplain=∣a∣n,Gresidual=∣1+a∣n
拖动滑块改变层数与局部导数。特别可以观察 a=−1 时的结果。
四、二维数值计算
考虑线性残差模块:
y=x+Wx,x=[12],W=[0.1−0.10.20.3]
4.1 前向传播
先计算变换分支:
Wx=[0.1×1+0.2×2−0.1×1+0.3×2]=[0.50.5]
因此:
y=[1.52.5]
4.2 损失与输出梯度
令目标向量为 t=[1,1]T,采用平方误差:
L=21∥y−t∥2=21[(1.5−1)2+(2.5−1)2]=1.25
输出梯度为:
∇yL=y−t=[0.51.5]
4.3 输入梯度
因为 y=(I+W)x,根据向量链式法则:
∇xL=(I+W)T∇yL
代入:
∇xL=[1.10.2−0.11.3][0.51.5]=[0.42.05]
也可以分解为两条路径:
∇xL=恒等连接[0.51.5]+变换分支[−0.10.55]
梯度沿两条路径传播,并在共同输入位置相加。
五、为什么容易实现恒等映射
考虑 y=x+F(x;θ)。只要残差分支输出零,整个模块就实现恒等映射:
F(x;θ)=0⟹y=x
例如:
F(x)=W2σ(W1x+b1)+b2
当 W2=0 且 b2=0 时,残差为零。这使新增模块在结构上容易表示恒等映射。实际训练是否找到理想参数,仍取决于优化算法、参数初始化与数据。
Transformer 的 Attention(注意力机制)负责不同 Token 之间的信息交换,FFN(前馈神经网络)进一步变换每个 Token 的特征。二者通常分别具有残差连接。
输入形状一般是:
X∈RB×T×d
其中 B 是批量大小,T 是序列长度,d 是隐藏特征维度。
6.1 Pre-LN
Pre-LN(预归一化)在子模块之前执行 LayerNorm:
U=X+MHA(LN(X))
Y=U+FFN(LN(U))
6.2 Post-LN
Post-LN(后归一化)在残差相加之后执行 LayerNorm:
U=LN(X+MHA(X))
Y=LN(U+FFN(U))
对于抽象变换 F,对应的 Jacobian 为:
Pre-LN:J=I+JFJLN
Post-LN:J=JLN(I+JF)
Pre-LN 中显式存在单位矩阵项,因此常有利于深层模型的梯度传播。两种结构的训练表现还取决于其他设计和训练设置。
6.3 交互演示:归一化位置
选择 Pre-LN 或 Post-LN,查看 Attention、FFN 及两条残差连接的计算次序。
6.4 输入与输出维度
残差加法通常要求:
shape(X)=shape(F(X))
例如,输入形状为 32×128×768 时,Attention 的最终输出通常保持这一形状。FFN 可以使用 768→3072→768,中间扩大特征维度,最后恢复原来的维度。
如果维度变化,可以用投影连接:
y=P(x)+F(x),P(x)=Wsx
投影矩阵 Ws 带来额外的可训练参数,相应梯度需要经过投影变换。
七、训练稳定性与残差缩放
连续的残差相加可能使激活数值增大。深度模型通常结合归一化、参数初始化、学习率控制与残差缩放来改善训练稳定性。
残差缩放写成:
y=x+αF(x)
其 Jacobian 为:
J=I+αJF
系数 α 控制变换分支对结果的影响,可以是固定值,也可以通过训练学习。
残差结构提供直接利用输入的能力,但不能保证每个原始特征数值都会保留。例如,若 F(x)=−x,则输出为零。
八、PyTorch 实现
下面给出具有 Pre-LN 结构的 FFN 残差模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import torch import torch.nn as nn
class ResidualBlock(nn.Module): def __init__(self, hidden_dim): super().__init__() self.layer_norm = nn.LayerNorm(hidden_dim) self.linear1 = nn.Linear(hidden_dim, hidden_dim * 4) self.activation = nn.GELU() self.linear2 = nn.Linear(hidden_dim * 4, hidden_dim)
def forward(self, x): hidden = self.layer_norm(x) hidden = self.linear1(hidden) hidden = self.activation(hidden) hidden = self.linear2(hidden) return x + hidden
model = ResidualBlock(hidden_dim=4) x = torch.randn(2, 3, 4, requires_grad=True) y = model(x) assert y.shape == x.shape
loss = y.square().mean() loss.backward() assert x.grad.shape == x.shape
|
这里的 x+hidden 是逐元素相加。PyTorch 自动求导会计算两条路径的梯度。
下面使用第四节的数据核对结果:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import torch
x = torch.tensor([1.0, 2.0], requires_grad=True) weight = torch.tensor([[0.1, 0.2], [-0.1, 0.3]]) target = torch.tensor([1.0, 1.0])
y = x + weight @ x loss = 0.5 * ((y - target) ** 2).sum() loss.backward()
assert torch.allclose(y.detach(), torch.tensor([1.5, 2.5])) assert torch.allclose(x.grad, torch.tensor([0.4, 2.05])) assert abs(loss.item() - 1.25) < 1e-6
|
九、常见问题
9.1 残差连接会增加参数吗?
恒等连接本身不增加参数。使用 Wsx+F(x) 这样的投影连接时,矩阵 Ws 需要训练。
9.2 残差连接总能改善效果吗?
效果取决于模型深度、任务、数据和训练设置。残差连接在深层 ResNet 和 Transformer 中尤其常见。
9.3 残差连接与 LayerNorm 各有什么作用?
残差连接提供直接的加法与梯度传播路径,LayerNorm 调整特征的数值分布,两者共同影响训练稳定性。
9.4 为什么 Attention 和 FFN 都有残差连接?
Attention 更新 Token 间的信息,FFN 更新各 Token 的特征。分别设置残差连接后,两个模块都能在已有表示的基础上继续学习变化。
十、参考文献
评论由 GitHub Giscus 提供。若当前网络无法加载,可 前往 GitHub Discussions 查看或参与讨论。