Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

残差连接

我们用 4 章的篇幅完成了 GPT 模型最核心的部分:自注意力机制。

接下来,我们将聚焦 GPT 模型预训练的工程实现。

GPT 模型的一个显著特点就是“大力出奇迹”。这不仅表现在模型训练使用了海量的数据,还表现在巨大的参数规模,以及动则几十甚至上百层的深度网络结构。具体来说,GPT-3 模型里的 Transformer 模块已经达到 96 层,更深的模型层数更多。Transformer 模块堆得越多,训练越困难。梯度在反向传播时需要穿透几十、上百层,每经过一层就被“稀释”一点,到了最后几层几乎消失殆尽。这就是所谓的梯度消失(Vanishing Gradient)问题。

残差连接

2015 年,微软研究院的何恺明等人提出了残差连接(Residual Connection)的概念,极大缓解了深层神经网络的训练难题。这篇论文(ResNet)是深度学习历史上被引用最多的论文之一。

残差连接的核心思路极其简单:让每一层的输出 = 输入 + 变换。

output=x+f(x)\text{output} = x + f(x)

而不再是传统的:output=f(x)\text{output} = f(x)。

残差连接为什么有效

  • 前向传播:即使 f(x)f(x) 学得不好,输出至少还有 xx,信息不会丢失;

  • 反向传播:梯度可以通过 xx 回传,不需要完全依赖 f(x)f(x) 的梯度,梯度消失问题大大缓解。

残差连接就像给梯度多修了一条高速公路:不管中间的 f(x)f(x) 多么曲折,梯度总能畅通无阻地传回前面的层。

残差连接的位置

GPT 模型里,网络深度主要由 Transformer 模块构成。Transformer 模块包含两个子层:自注意力和前馈网络。每个子层都需要加上残差连接:

  • 自注意力:x=x+attention(x)x = x + \text{attention}(x);

  • 前馈网络:x=x+feedforward(x)x = x + \text{feedforward}(x)。

这样,不管堆叠多少层 Transformer 模块,梯度都可以顺畅地传达到第一层,避免梯度消失。

加入残差连接的 GPT 基础模块示意图:注意力层和前馈网络层各自有一条绕过该层的残差连接
图例:加入残差连接的 GPT 基础模块

数据集

字符编码数据集

下三角矩阵层

激活函数

高斯误差线性单元激活函数(GELU)

损失函数

GPT 交叉熵损失函数

模型

GPT 嵌入层

GPT 注意力层

我们在 GPT 注意力层的最后加上残差连接。将输出从 self.output(...) 变成 x + self.output(...)。

GPT 前馈网络层

同样,我们在 GPT 前馈网络层的最后也加上残差连接。将输出从 self.output(...) 变成 x + self.output(...)。

GPT Transformer 模块

GPT 输出层

GPT 模型

GPT 训练器

超参数

学习率

批大小

轮数

上下文尺寸

嵌入尺寸

头数

Transformer 模块数

建模

训练

评估

prediction:	1742 steps, each (4, 32, 65)
loss:	1.8085668785700706

推理

ROMEO:
Well, I'll poisen, swearn thee, haprite,
Will me is is fatherior offenretcher rangershed is in tet Catie, there name the king,
Lets Comiou, who no: well I delieve what bow,
And
Berancionr her; and love stime and in him esceasured,
That try love.

SIY:
HtU

在这一章,我们给 Transformer 模块的两个子层都加上了残差连接。梯度有了直达通道,深度神经网络的一个训练难题,梯度消失,迎刃而解。

但是残差连接也有一个副作用:每一层的输出都是“输入 + 变换”,随着层数增加,数值会不断累积,越来越大,导致训练不稳定。下一章,我们将着手解决这个问题。

课后练习

  1. Transformer 模块的两个子层都加上了残差连接。试试去掉其中一个,看看训练结果如何?