如果把 Transformer block 画成结构图,残差连接往往只是一根细细的旁路线:从输入绕过 attention 或 FFN,直接和子层输出相加。很多教程讲到这里会轻描淡写地说一句:"这样可以保留原始信息。"
这句话不能说错,但太轻了。残差连接真正解决的是深层网络的优化问题:它给梯度留了一条几乎不受参数影响的直路,让每一层都只需要学一个"小修正",而不是学一整个从零开始的大变换。没有这根直路,Transformer 很难从 6 层长到几十层、上百层。
这一篇我们就把这根线单独拎出来讲。你会看到:残差不仅是训练稳定性的关键,也是后来理解大模型内部机制时一个非常重要的观察窗口------所谓 residual stream,本质上就是整网持续累积和改写的那条主干表示。
一、什么叫残差:不是直接学 <math xmlns="http://www.w3.org/1998/Math/MathML"> H ( x ) H(x) </math>H(x),而是学 <math xmlns="http://www.w3.org/1998/Math/MathML"> F ( x ) F(x) </math>F(x)
ResNet 论文给出的原始动机很简单。假设我们想学一个目标映射 <math xmlns="http://www.w3.org/1998/Math/MathML"> H ( x ) H(x) </math>H(x)。普通堆叠层的写法是直接逼近它:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> y = H ( x ) y = H(x) </math>y=H(x)
残差写法把它改成:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> y = x + F ( x ) y = x + F(x) </math>y=x+F(x)
也就是说,不再直接学"应该输出什么",而是学"在输入基础上还需要补多少修正"。
1.1 为什么"修正"比"重来"更容易学
这背后有一个非常朴素的直觉:很多时候,理想变换离恒等映射并不远。
举个语言模型里的例子,一个 token 经过某一层 attention 后,往往不是"完全换个身份",而是:
- 多知道了一点和前文的关系;
- 某些维度被加强;
- 某些噪声被压低;
- 某些语义特征被显式化。
这些变化更像"在原向量上加一笔",而不是"把原向量推倒重算"。残差把这种结构偏好直接写进了网络。
1.2 Transformer 里的两条残差
每个 Transformer block 至少有两次残差相加:
- attention 子层外面一条;
- FFN 子层外面一条。
pre-LN 写法下,一层可以写成:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> h ′ = x + Attention ( LN ( x ) ) y = h ′ + FFN ( LN ( h ′ ) ) \begin{aligned} h' &= x + \operatorname{Attention}(\operatorname{LN}(x)) \\ y &= h' + \operatorname{FFN}(\operatorname{LN}(h')) \end{aligned} </math>h′y=x+Attention(LN(x))=h′+FFN(LN(h′))
从这个形式能直接看出残差的角色:主路径是 x -> h' -> y 这条直线,attention 和 FFN 更像两次可选的旁路修正。
二、真正关键的是梯度:残差给反向传播留了高速路
如果只从前向角度理解残差,容易把它当成"信息不丢失"的技巧;真正决定训练成败的是反向传播。
设一层输出是:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> y = x + F ( x ) y = x + F(x) </math>y=x+F(x)
对输入求导:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ∂ y ∂ x = I + ∂ F ( x ) ∂ x \frac{\partial y}{\partial x} = I + \frac{\partial F(x)}{\partial x} </math>∂x∂y=I+∂x∂F(x)
注意那个 <math xmlns="http://www.w3.org/1998/Math/MathML"> I I </math>I。它不等于"梯度一定没问题",但它确实改变了深层网络的默认处境:反向里不再只剩纯粹的 Jacobian 连乘,而是多了一个恒等项,使整体更容易靠近恒等映射附近训练。
2.1 没有残差时,深层梯度是连续矩阵乘
如果一串层都没有残差,梯度要穿过很多 Jacobian 连乘:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ∂ L ∂ x 0 = ∂ L ∂ x L ∏ ℓ = 1 L ∂ x ℓ ∂ x ℓ − 1 \frac{\partial \mathcal{L}}{\partial x_0} = \frac{\partial \mathcal{L}}{\partial x_L} \prod_{\ell=1}^{L} \frac{\partial x_\ell}{\partial x_{\ell-1}} </math>∂x0∂L=∂xL∂Lℓ=1∏L∂xℓ−1∂xℓ
这些矩阵的谱范数只要稍微偏大或偏小,层数一深就会爆炸或消失。RNN、早期深层 CNN 都被这个问题折磨过。
2.2 有了残差,最坏情况更接近恒等映射
残差不能从数学上彻底消灭梯度问题,但会显著改善最坏情况:就算子层暂时没学会什么,网络整体也更接近一堆恒等映射叠起来,而不是一堆随机矩阵叠起来。这里的关键词是"更接近",不是"自动稳定";稳定到什么程度,还取决于归一化、初始化和学习率配方。
这件事的工程意义非常大。因为训练开始时,attention、FFN 的权重几乎都是随机的。没有残差,网络最开始就像一串随机变换;有残差,它更像"以恒等映射为基底,慢慢往上叠修正"。
2.3 这就是为什么残差和归一化总是成对出现
残差解决的是"有直路";归一化解决的是"旁路修正别太野"。两者合起来,才把深层训练拉到一个稳定区间。
这也解释了为什么 24 和 25 两篇必须连着读:残差负责路径,LayerNorm 负责路径上的数值尺度。
三、把残差理解成"迭代 refinement"会更贴切
除了梯度视角,还有一个更适合直觉的解释:每一层不是重新编码,而是在前一层表示上做一次迭代修正。
3.1 每层只负责把表示往前推一小步
设第 <math xmlns="http://www.w3.org/1998/Math/MathML"> ℓ \ell </math>ℓ 层输入是 <math xmlns="http://www.w3.org/1998/Math/MathML"> x ( ℓ ) x^{(\ell)} </math>x(ℓ),输出是:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> x ( ℓ + 1 ) = x ( ℓ ) + Δ ( ℓ ) x^{(\ell+1)} = x^{(\ell)} + \Delta^{(\ell)} </math>x(ℓ+1)=x(ℓ)+Δ(ℓ)
其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ ( ℓ ) \Delta^{(\ell)} </math>Δ(ℓ) 就是这一层 attention 或 FFN 学到的修正。这样看,多层 Transformer 像是在一条主干表示上做很多次微小迭代:
- 某一层把指代关系补进去;
- 下一层把否定关系显式化;
- 再下一层把任务相关特征拉高。
把整网展开写,会更清楚:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> x ( L ) = x ( 0 ) + ∑ ℓ = 0 L − 1 Δ ( ℓ ) x^{(L)} = x^{(0)} + \sum_{\ell=0}^{L-1} \Delta^{(\ell)} </math>x(L)=x(0)+ℓ=0∑L−1Δ(ℓ)
在 pre-LN block 里,可以把每个增量进一步写成:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> Δ ( ℓ ) = F ℓ ( LN ( x ( ℓ ) ) ) \Delta^{(\ell)} = F_\ell(\operatorname{LN}(x^{(\ell)})) </math>Δ(ℓ)=Fℓ(LN(x(ℓ)))
这个式子把前面讲的三件事串到了一起:主路径负责把旧表示一路带下去,子层负责写入增量,深层能力则来自很多次可控的小步累积。
如果没有残差,这种"逐层增量改写"的语义会弱很多。
3.2 这也解释了为什么中间层表示经常已经很好用
很多 probing 研究会发现,Transformer 中间层往往已经学出了可分的句法或语义结构。更近一点的 logit lens、tuned lens 之类工作,也能看到中间层表征经常已经朝最终预测方向推进了一大截。更稳妥的说法不是"这单独证明了残差",而是:这类现象和 residual stream 的逐层累积视角高度一致。
这和纯前馈深网那种"越靠前越原始、越靠后越任务化"的感觉不完全一样。Transformer 的 residual stream 让不同层更像在共享一条不断变丰富的公共表示。
四、深层 Transformer 为什么格外依赖残差
ResNet 在视觉里已经证明了残差有用,但 Transformer 对残差的依赖更强,原因有三层。
4.1 每层本身就很"激进"
Transformer 子层里的 attention 和 FFN 都是大矩阵变换:
- attention 会把全序列的信息混进来;
- FFN 会把每个 token 拉到高维再压回来。
它们不像卷积那样只改一个局部感受野,而是每一层都有能力做大改写。没有残差,这种改写太容易把表示空间搞乱。
4.2 Transformer 没有 CNN 那种天然局部平滑偏置
CNN 的卷积、池化、局部连接天然带着"别一下子改太猛"的结构约束。Transformer 的全连接 attention 没这个保护,残差就成了最重要的结构性缓冲。
4.3 大模型需要很多层来积累能力
当模型从 6 层涨到 32 层、80 层时,单层学一点点修正是合理的;让每层都独立做大幅重写几乎不可能训练稳。残差正好支持这种"很多小步叠加成一个大能力"的扩展方式。
五、Pre-Norm 为什么比 Post-Norm 更容易训深
残差写法不只一种。对 Transformer 影响最大的区别,是 LayerNorm 放在加法前还是后。
5.1 Post-Norm:原论文的写法
原论文用的是:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> y = LN ( x + F ( x ) ) y = \operatorname{LN}(x + F(x)) </math>y=LN(x+F(x))
这时残差和旁路修正先相加,再一起归一化。问题在于:梯度沿主路径回传时,也会经过 LN 的 Jacobian。层数一深,这条"高速路"就不再那么直。
5.2 Pre-Norm:现代主流写法
现代更常见的是:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> y = x + F ( LN ( x ) ) y = x + F(\operatorname{LN}(x)) </math>y=x+F(LN(x))
这时主路径上的 x -> y 基本是直通,归一化只作用在旁路输入上。于是:
- 子层得到稳定输入;
- 主路径的恒等传递更完整;
- 深层训练明显更稳。
5.3 这不是"谁更先进",而是谁更适合大深度
在 6 层翻译模型里,post-norm 完全能用;在 48 层、80 层的大语言模型里,pre-norm 通常更省心。这不是品味问题,而是优化几何不同导致的现实选择。
现代还会进一步叠加:
- residual scaling;
- smaller init;
- DeepNorm、ReZero、NormFormer 一类改动;
- 更谨慎的学习率和 warmup。
这些方法的做法并不相同:DeepNorm 重点是深层稳定性,ReZero 重点是残差分支初始化,NormFormer 则继续细调 block 内的归一化与缩放。但它们都在围着同一个目标转:让 residual 主路径既稳定,又保留足够表达力。
六、Residual Stream:从优化问题走到表示流动
前面几节说的是优化;下面这一节换个角度,看表示是怎么在整网里流动的。近几年做机制可解释性的人,最爱盯的对象之一就是 residual stream。原因很简单:attention 和 FFN 的更新,最后都会以增量形式写回这条主干表示。
6.1 每个子层都像在往同一个共享总线上写入
如果把一个 block 抽象成:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> x ← x + Δ attn + Δ ffn x \leftarrow x + \Delta_{\text{attn}} + \Delta_{\text{ffn}} </math>x←x+Δattn+Δffn
那 residual stream 就像一条共享总线:
- 某个 attention head 把"把主语搬到当前位置"的信息写进去;
- 某个 FFN 把"这是首都问答模式"的特征写进去;
- 后续层再在这条总线上继续读取和追加。
这样看,Transformer 不像一串完全分离的层,更像很多模块在共同改写同一份活动内存。前面那条展开式
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> x ( L ) = x ( 0 ) + ∑ ℓ = 0 L − 1 Δ ( ℓ ) x^{(L)} = x^{(0)} + \sum_{\ell=0}^{L-1} \Delta^{(\ell)} </math>x(L)=x(0)+ℓ=0∑L−1Δ(ℓ)
也正好说明了为什么这条流值得盯:最终输出不是来自某一层"独占"的表示,而是来自一连串增量的累计结果。
6.2 模型编辑和可解释性常常落在这条流上
ROME、MEMIT、logit lens、tuned lens 这类工作,很多都会把分析对象落在这条流上。例如:
- 哪些层最明显地写入了事实相关更新;
- 中间层的当前表示离最终预测还有多远;
- 某些局部增量被改动后,最终输出会朝哪个方向偏移。
所以残差早就不只是训练技巧。到了大模型研究里,它也成了理解"模型内部状态到底如何流动"的核心切入点之一。
七、几个工程上很实际的细节
7.1 旁路并不是越大越好
残差的本意是学小修正。如果某层的 <math xmlns="http://www.w3.org/1998/Math/MathML"> F ( x ) F(x) </math>F(x) 数值幅度长期远大于 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x,那这层实际上就在强行覆盖主路径,训练会变得不稳。所以很多实现会:
- 调整初始化;
- 对 attention / FFN 输出加缩放;
- 在深层模型里显式控制 residual branch 的方差。
7.2 训练时更值得监控的是残差分支的尺度
工程上,一个常见做法不是只盯总 loss,而是顺手看 attention / FFN 输出范数,以及它们相对主干表示的比例。如果某几层的 residual branch 突然抬得很高,往往意味着:
- 学习率过激;
- 初始化或缩放不合适;
- 归一化配方没有把子层输入稳住。
这类监控本身不解决问题,但常常能比"等 loss 炸掉"更早暴露问题。
7.3 残差不能单独拯救坏配方
要注意,残差不是万能药。学习率太大、归一化放错、初始化离谱、mask 写错,模型照样会崩。残差只是把可训练区域大幅扩大,不是让所有坏设置都自动没事。
八、几个常见误解
8.1 "残差就是为了保留原始信息"
这句话太弱了。更准确的说法是:残差让每层学修正而不是重算,并给梯度留一条近似恒等的回传路径。
8.2 "有残差就不会梯度消失"
也不绝对。残差显著缓解问题,但不能从数学上保证任何深度下都绝对稳定。归一化、初始化、学习率同样重要。
8.3 "残差只在很深的模型里才重要"
6 层模型里它也重要,只是问题没那么显眼。到了几十层,重要性从"有帮助"升级为"几乎不可缺"。
8.4 "残差让模型变成线性的"
不会。虽然主路径是相加,但旁路里的 attention、FFN、归一化都还是高度非线性的。残差只是改变了函数的组织方式,不是拿掉了非线性。
8.5 "把更多模块都接到 residual 上一定更好"
也不一定。模块往 residual stream 里写得太多、太猛,会带来干扰、方差累积和优化困难。为什么现代架构会反复讨论门控、缩放和 norm,本质上都是在管这件事。
九、结语
残差连接真正让 Transformer 成立的地方,不在于它"看起来优雅",而在于它把深层网络最难的一件事------稳定优化------处理成了"在主路径上逐层叠加小修正"。一旦把这个视角建立起来,你再看 pre-norm、residual stream、模型编辑、深层扩展,就会发现它们其实都在围绕同一根主线展开:如何让这条主干既传得稳,又写得进新信息。
下一篇我们继续沿着这条主线走,不过把焦点从"有没有直路"换成"每层输出的数值尺度怎么稳住"------也就是 Layer Normalization 为什么会成为 Transformer 的标准配置。
十、参考文献
- He, K. et al. "Deep Residual Learning for Image Recognition." CVPR 2016. 残差学习的原始提出。
- Vaswani, A. et al. "Attention Is All You Need." NeurIPS 2017. Transformer 中 attention / FFN 子层外残差的标准写法。
- Xiong, R. et al. "On Layer Normalization in the Transformer Architecture." ICML 2020. 分析 pre-LN 与 post-LN 的训练稳定性差异。
- Wang, H. et al. "DeepNet: Scaling Transformers to 1,000 Layers." IEEE TPAMI 2024. 深层 Transformer 中 residual scaling 的代表工作。
- Bachlechner, T. et al. "ReZero is All You Need: Fast Convergence at Large Depth." UAI 2021. 通过控制残差分支初始化改善深层训练。
- Shleifer, S. et al. "NormFormer: Improved Transformer Pretraining with Extra Normalization." ICLR 2022. 通过额外归一化与缩放改进 Transformer 训练。
- Elhage, N. et al. "A Mathematical Framework for Transformer Circuits." Transformer Circuits Thread, 2021. 从 residual stream 视角分析 Transformer 内部计算。
- Tenney, I. et al. "BERT Rediscovers the Classical NLP Pipeline." ACL 2019. 早期 probing 工作,展示中间层逐步形成语言学结构。
- Belrose, N. et al. "Eliciting Latent Predictions from Transformers with the Tuned Lens." ICLR 2024. 用 tuned lens 观察中间层表征与最终预测的关系。
- Meng, K. et al. "Locating and Editing Factual Associations in GPT." NeurIPS 2022. ROME 方法,研究事实信息主要写入哪些层。
- Meng, K. et al. "Mass-Editing Memory in a Transformer." ICLR 2023. MEMIT 方法,研究大规模事实编辑与写入位置。
← 上一篇:23|Decoder 详解 | 下一篇:25|Layer Normalization →