上一篇我们把 Transformer block 的最后一个零件——前馈网络——讲透了。到这里,整个模型的结构已经完全摆开:embedding、位置编码、多头注意力、残差、LN、FFN、stack 6 层。
但「结构对了」不等于「能训出来」。深度学习里有一个让人头疼的事实:同一个模型架构,配方稍微一动,结果可能差几个 BLEU。学习率怎么调、warmup 多长、batch 怎么算、dropout 放哪儿、label 平滑多少——这些超参数的取值,比模型结构本身更难猜对。
2017 年原论文之所以能让人信服,不只是因为提出了新结构,更是因为他们公开了一套完整的训练配方,并在 WMT2014 这个公认的 benchmark 上跑出了当时的 SOTA。这份配方后来被几乎所有 Transformer 实现奉为「标准答案」,直到现代 LLM 时代才慢慢演化出新版本。
这一篇要做的事情,是把这个配方一项一项地拆开,讲清楚每一个数字、每一个公式背后的含义。读完之后你应该能做到:
- 知道 base 和 big 模型分别用了多少 GPU、多长时间训出来;
- 解释清楚那个看起来很神秘的学习率公式
lr = d^(-0.5) · min(step^(-0.5), step · warmup^(-1.5)); - 回答「warmup_steps 为什么是 4000,去掉会怎样」;
- 知道 batch by tokens 是什么、为什么不是 batch by samples;
- 在你自己的项目里复现一份对得上原论文 BLEU 的训练;
- 理解现代大模型(GPT-3、LLaMA)训练配方相对 2017 的演化。
先把整套配方一次性贴出来,然后我们一节一节地拆:
模型: Transformer base / big
数据集: WMT 2014 En-De(4.5M 句对)/ En-Fr(36M 句对)
硬件: 8 × NVIDIA P100 GPU
训练时长:base 12 小时(100k 步) / big 3.5 天(300k 步)
batch: 每步约 25000 source token + 25000 target token
优化器: Adam, β₁=0.9, β₂=0.98, ε=1e-9
学习率: lr = d^(-0.5) · min(step^(-0.5), step · warmup^(-1.5))
warmup: 4000 步
正则化: dropout 0.1(embedding 之后、每个子层输出)
label smoothing 0.1
推理: beam search, beam=4, length penalty α=0.6
最终: En-De BLEU 27.3 (base) / 28.4 (big)
En-Fr BLEU 38.1 (base) / 41.8 (big)
每一行都有故事。
一、数据集与基准任务
1.1 WMT 2014:那个时代的 ImageNet
WMT(Workshop on Machine Translation)从 2006 年开始举办,是机器翻译领域的标准评测。每届会发布若干语言对的训练数据、开发集、测试集,参赛者提交翻译结果,组委会统一评分(人工或 BLEU)。
2017 年原论文用的是 WMT 2014 的两组数据:
- En-De(英语-德语):约 4.5M 句对,主要来自 Europarl、Common Crawl、News Commentary。这是当时最常用的 MT 基准之一,因为德语形态变化丰富、复合词长,对翻译模型的考验比 En-Fr 更大;
- En-Fr(英语-法语):约 36M 句对,规模是 En-De 的 8 倍。法语和英语在词汇、语法上更接近,但数据量更大,挑战的是模型在大数据上能不能持续受益。
两个任务的官方测试集是 newstest2014,每对约 3000 个句子。BLEU(Bilingual Evaluation Understudy)分数是在这个测试集上算出来的——具体说,是用 SacreBLEU 或 multi-bleu 这样的工具,把模型翻译和参考译文比较 n-gram 匹配率。
为什么选这两组而不是别的?因为它们在 2017 年是「公认的硬骨头」——之前几年的 SOTA 模型(GNMT、ConvS2S、ByteNet)都在这上面打榜,已经形成了稳定的对比基线。
1.2 数据预处理
原论文用的是字节对编码(Byte Pair Encoding,BPE)做子词切分,词表大小约 37000(En-De)或 32000(En-Fr)。这个细节后面 29 篇会专门讲,这里只要记住:
- 不是按词切(OOV 严重),不是按字符切(序列太长),而是按子词切;
- 源语言和目标语言共享词表——这一点很关键,让 encoder 和 decoder 的 embedding 矩阵可以共享。
句子按长度排序后再分 batch(后面讲 batching 时再展开),最大长度截到 100 token 左右。
1.3 为什么这个任务现在看起来「小」
在 GPT-3 那个 570GB 数据、1750 亿参数的时代,回头看 WMT 2014 的几百万句对、6 千万参数的 Transformer,会觉得「就这?」
但要明白:2017 年这是相当不小的工程。8 张 P100 在那时候是顶级配置(A100、H100 还要等 4-5 年才出来),单机 8 卡训 12 小时跑出 SOTA,是一个大组才能做的实验。
而且更关键的是:原论文的训练配方在它的尺度下是经过仔细调过的——后来人复现,照搬这套配方,结果稳定可复现;这是一个工程上的重要保证。
二、硬件与训练时长
2.1 8 张 P100 是什么概念
NVIDIA P100(2016 年发布):
- 16GB HBM2 显存;
- FP16 算力约 19 TFLOPS(FP32 约 9 TFLOPS);
- 单卡功耗 250W;
- 当时 NVLink 也支持,但带宽比后来的 V100/A100 低不少。
对比 2024 年的 H100:
- 80GB HBM3,是 P100 的 5 倍;
- BF16 算力约 989 TFLOPS(不算稀疏化),是 P100 FP16 的 ~50 倍;
- HBM 带宽 3.35 TB/s,是 P100 的 ~7 倍。
也就是说,今天一张 H100 大概顶 50-60 张 2016 年的 P100。原论文「8 张 P100」的总算力,按今天看大约相当于 0.15 张 H100。这能训出 SOTA 翻译模型,确实是工程上的奇迹。
2.2 base 12 小时、big 3.5 天
- base 模型:d=512, n_layers=6, n_heads=8, d_ff=2048。约 65M 参数。训 100k 步,每步约 0.4 秒(8 P100 同时算),合计约 11.1 小时(论文说「about 12 hours」)。
- big 模型:d=1024, n_layers=6, n_heads=16, d_ff=4096。约 213M 参数。训 300k 步,每步约 1 秒,合计约 83 小时(论文说「3.5 days」)。
两个模型的训练时长,主要由模型大小、序列长度、batch 大小三个因素决定。换到现代 GPU,整个训练时长会被压缩到几小时甚至更短——但配方本身不会变。
2.3 多卡同步
8 卡之间的同步方式是「数据并行」(Data Parallel):每张卡拿一份 batch 子集,独立前向反向,最后用 all-reduce 把梯度加到一起,再各自更新参数(参数完全相同)。
具体的 all-reduce 实现,原论文没细说,应该用的是 NCCL 或类似的工具。因为只有 8 卡同机,all-reduce 的通信成本不大;如果跨机,就要考虑 ring all-reduce、梯度压缩等。
后来 GPT-3、LLaMA 的训练用了「数据并行 + 流水线并行 + 张量并行」三套并行方案叠加(3D Parallelism),那是为千卡规模准备的;2017 年单机 8 卡的尺度,纯数据并行就够了。
三、优化器:Adam 的微调
3.1 Adam 简介
Adam(Adaptive Moment Estimation,Kingma & Ba, 2014)是当时最流行的自适应优化器。它维护两个移动平均:
- 一阶矩 m(梯度的指数加权平均,类似动量);
- 二阶矩 v(梯度平方的指数加权平均,类似方差估计)。
更新规则:
m_t = β₁ · m_{t-1} + (1 - β₁) · g_t
v_t = β₂ · v_{t-1} + (1 - β₂) · g_t²
m̂_t = m_t / (1 - β₁^t) # bias correction
v̂_t = v_t / (1 - β₂^t)
θ_t = θ_{t-1} - lr · m̂_t / (√v̂_t + ε)
直觉:m 给方向(带动量),v 给步长(在梯度方差大的方向走小步、方差小的方向走大步)。Adam 比纯 SGD 在多数任务上更稳更快,缺点是参数多一份(每个参数要存 m 和 v,显存占用 3x)。
3.2 原论文的 β₂ = 0.98(注意不是 0.999)
Adam 默认 β₂ = 0.999,但原论文用了 β₂ = 0.98。这是个小但重要的差异。
β₂ 控制 v(梯度平方的移动平均)的「记忆长度」。β₂ 越大,记忆越长,对噪声越鲁棒,但对学习率变化的响应越慢;β₂ 越小,记忆越短,对最近梯度更敏感。
β₂ = 0.999 对应「记忆 1000 步」,这个对长训练(百万步)很合适,但对 100k 步的训练就太长了——v̂ 的 bias correction 在前几千步还很大,可能导致更新不稳定。
β₂ = 0.98 对应「记忆 50 步」,更适合短训练,让 v 能更快跟上学习率的变化。这是原论文调出来的——后人复现 Transformer 翻译都沿用 0.98。
到了 GPT-3 时代,因为训练步数大幅增加(百万级),β₂ 又调回了 0.95 或 0.999。
3.3 ε = 1e-9(注意不是 1e-8)
Adam 的 ε 是分母里防止除零的小常数,默认 1e-8。原论文用 1e-9——比默认小一个数量级。
这个差异更细,影响主要在「梯度平方接近 0」时的步长。ε 小,分母可以更小,更新步长更大;ε 大,分母被压住,更新步长偏小但更稳。
实际复现时,ε 用 1e-8 还是 1e-9 影响不大,但要保持配方一致以便对照论文结果。
3.4 没有 weight decay
原论文没有 weight decay(权重衰减),这是另一个值得注意的点。
现代大模型(GPT-3、LLaMA)几乎都用 AdamW(Adam + decoupled weight decay),weight decay 设到 0.1 或 0.01。原论文那时还没有 AdamW(Loshchilov & Hutter 2019 才提出),他们也没用普通的 L2 正则。
为什么没用?我猜测两个原因:
- 当时 dropout + label smoothing 已经提供了相当充分的正则化;
- 翻译任务的训练数据相对模型容量已经足够大,过拟合不是主要矛盾。
到了现代大模型,因为参数量爆炸、数据相对模型容量未必充裕,weight decay 就重新成为标配了。
四、学习率公式:那个看起来很神秘的式子
4.1 公式与图像
原论文的学习率公式是:
lr(step) = d_model^(-0.5) · min(step^(-0.5), step · warmup_steps^(-1.5))
第一次看这个公式,多数人都会愣一下:为什么是这种形式?三个超参数(d_model、step、warmup_steps)混在一起,min 还把两支函数粘在一起。
把它拆开看就清楚了。min 里面是两个函数:
- 函数 A:
step · warmup_steps^(-1.5)—— 关于 step 是线性增长,斜率由 warmup_steps 决定; - 函数 B:
step^(-0.5)—— 关于 step 是平方根衰减。
两者交点在 step = warmup_steps
处——你可以代入验证:当 step = warmup_steps 时,A =
warmup_steps · warmup_steps^(-1.5) = warmup_steps^(-0.5) =
B。
所以这个公式描述的是一条「先线性升、再 1/√step 衰减」的曲线,转折点在 warmup_steps 步:
- step < warmup_steps:lr 沿 A 线性增长,从 0 升到峰值 lr_peak = d^(-0.5) · warmup^(-0.5);
- step > warmup_steps:lr 沿 B 衰减,按 1/√step 慢慢降。
4.2 为什么先 warmup
「为什么要 warmup」是个非常有意思的问题,2017 年的时候大家也没完全说清楚,到 2020 年前后才有比较像样的理论解释。
直觉版的解释是这样的:
训练刚开始时,模型参数是随机初始化的,梯度方向「指向哪儿」非常嘈杂。Adam 的 v(梯度平方移动平均)需要积累几百到几千步才能给出一个相对靠谱的「方差估计」。
如果你一开始就用大学习率,会发生什么?
- 模型参数被一组嘈杂的梯度推到一个奇怪的位置;
- 这个位置可能离合理的解空间很远,后续训练即使学习率慢慢降下来也很难恢复——「陷入坏的局部 basin」;
- LayerNorm 或 BN 的统计量也可能因此偏离正常分布;
- attention softmax 可能输出极端 sharp 的分布(某个权重接近 1,其它接近 0),梯度几乎流不动。
warmup 的作用是「给优化器和模型几千步缓冲,让 v 估计稳定下来、让参数从随机初始化温和地移动」。等到 v 比较准了,再放开学习率。
4.3 warmup_steps = 4000:魔法常数
为什么是 4000 步?这是论文实验出来的。
实测上:
- 0 步(无 warmup):训练直接崩,loss 不下降甚至发散;
- 100-500 步:训练能跑但极不稳定,BLEU 显著差;
- 4000 步:稳定且收敛快,论文最终选这个;
- 8000-16000 步:稳定但 wallclock 时间多花(因为前期 lr 太低,没在干活),最终 BLEU 略低或持平。
所以 4000 是「足够长以保证稳定,又不至于浪费」的点。
到了现代大模型,warmup_steps 通常按总步数的 1-2% 选——GPT-3 是 375M token 的 warmup(约 0.5% 的总训练 token),LLaMA-2 用 2000 步。这个比例和原论文(4000/100000 = 4%)大致是同一个数量级。
4.4 d_model^(-0.5) 是怎么来的
公式里 d_model^(-0.5)
这个因子的作用是「让学习率随模型宽度自动适配」。
直觉是:模型越宽,每个矩阵乘的输出方差越大;为了让参数更新幅度不随宽度爆炸,学习率要随宽度的某个幂次降下来。Vaswani 等人选了 -0.5 这个幂次,有点类似 Glorot/He 初始化的 1/√d 那个量。
具体说,对于 d=512:lr_peak = 512^(-0.5) · 4000^(-0.5) =
(1/22.6) · (1/63.2) ≈ 7e-4。
对于 d=1024(big):lr_peak = 1024^(-0.5) · 4000^(-0.5) ≈
4.95e-4。
big 模型的峰值学习率自动比 base 低一些——这正是「宽模型不能用太大 lr」这条经验的数学化。
4.5 后续 1/√step 衰减
warmup 之后按 1/√step 衰减。这个衰减率比 1/step(线性衰减)慢,比常数(不衰减)快——属于「中等强度」的衰减。
直觉是:
- 训练早期,梯度大、变化快,需要大步长;
- 训练后期,梯度小、变化慢,需要小步长精修;
- 1/√step 让步长在 100k 步内从峰值降到约 1/10——既不会让训练后期完全停下,也不会让 lr 维持太高。
后来有些工作(GPT-3、LLaMA)改用「cosine decay」——按 cos 函数从峰值降到一个最小值(通常是峰值的 10%)。cosine 在工程上更平滑,但和 1/√step 在效果上差异不大。
五、Label Smoothing 0.1
五.1 一个 one-hot 的问题
标准的语言建模损失函数是交叉熵:模型给每个词输出一个概率分布 p,目标是让 p 与「真实分布 q」尽可能接近。
但「真实分布 q」长什么样?通常是 one-hot——目标词的概率是 1,其它所有词的概率是 0。
这个 one-hot 目标有两个问题:
- 过自信(overconfident):模型被推着把目标词的概率推到 1。要做到这点,目标词的 logit 必须远远大于其它词的 logit——softmax 的指数性意味着「无穷大的 logit 差距才能推出 1.0」。模型倾向于输出极端 sharp 的分布,这种「过度自信」反而损害泛化;
- 零概率惩罚不可控:如果模型给某个非目标词分配了一点点概率(比如 0.001),交叉熵会照样惩罚它(因为目标分布是 0),这种惩罚对于罕见词的处理有时过于严格。
5.2 Label smoothing 是怎么做的
label smoothing(Szegedy et al., 2016, Rethinking the Inception Architecture)的做法是把 one-hot 目标稍微「软化」:
q_i = (1 - ε) · 1[i = target] + ε / V
其中 ε 是平滑系数(原论文取 0.1),V 是词表大小。
直观上:目标词的概率从 1 变成 0.9,剩下 0.1 平均分给所有其它词。
这样一来:
- 模型不再被推到「目标词概率 = 1」的极端;
- 它学到的分布会自然「软」一些,预测时其它候选词也会有合理概率;
- 模型 perplexity 反而可能变差(因为 loss 的最优解不再是 sharp 分布),但 BLEU 通常变好。
5.3 为什么 PPL 变差但 BLEU 变好
这是 label smoothing 的「反直觉」之处。
PPL(perplexity)= exp(交叉熵),它衡量的是「模型对真实数据的概率估计」。如果你让模型「不那么自信」,它给目标词的概率自然降低,PPL 自然变差。
但 BLEU 衡量的是翻译质量——具体说,beam search 解码出的句子和参考译文的 n-gram 匹配率。这里关键的是 beam search 的多样性:当模型分布太 sharp 时,beam search 早期就被某条路径锁定,错过更好的路径;分布柔和一点,beam search 能保留更多备选,最终找到更优解。
label smoothing 的好处主要体现在 beam search 的过程中——它让模型给「次优词」保留合理概率,beam search 能在这些次优词上展开更深的搜索。
原论文的 ε = 0.1 是经验值。后来很多工作沿用,但也有些尝试不同值(0.05、0.15)的,差异不大。
5.4 现代大模型还用吗
GPT 系列、LLaMA 系列基本不用 label smoothing。原因之一是:自回归生成(一步一个 token)在 beam search 不再常用(greedy 或 sampling 是主流);原因之二是:超大词表(50k+)下,label smoothing 把 ε 平摊到几万个词上,每个词得到的「软概率」太小,效果不明显。
但翻译任务、专门用 beam search 解码的场景,label smoothing 仍然是标配。
六、Dropout 0.1:放在哪些位置
dropout(Srivastava et al., 2014)是经典的正则化方法:训练时按一定概率随机把激活值置零,强制网络不依赖特定神经元。
原论文的 dropout 配置是 P_drop = 0.1,加在以下位置:
- Embedding + 位置编码之后:把 token embedding 和 PE 加起来后过一次 dropout;
- 每个子层的输出:attention 子层和 FFN 子层的输出,在加到残差之前过一次 dropout。
具体到一个 block 的写法:
x' = x + dropout(Attention(x))
y = x' + dropout(FFN(x'))
注意 dropout 是在「子层输出」上做的,不是在 attention 的内部 softmax 上。后来很多实现还会额外加:
- attention dropout(在 softmax 后的注意力权重上);
- FFN 中间 dropout(在 ReLU 之后)。
这些是从 fairseq、Tensor2Tensor 等开源实现里来的微调,原论文没明确说。
6.1 为什么 0.1 而不是 0.5
经典视觉模型(VGG、ResNet 上的 dropout)常用 0.5。Transformer 用 0.1,差很多。
直觉是:Transformer 的层数和参数量已经很大,加上 LN、残差、label smoothing、weight tying 等多重正则,再加重的 dropout 反而让训练不稳定、收敛变慢。0.1 是「轻量正则化」,给训练加点扰动就够。
6.2 现代大模型里 dropout 几乎被放弃
GPT-3 训练时 dropout=0(取消了),LLaMA 系列也是。原因:
- 数据量足够大(千亿 token),过拟合不是主要矛盾;
- dropout 让训练 step 变多(每步要重做随机),算力浪费;
- 大模型的隐式正则(参数压缩、scaling 本身的平均效应)已经够用。
但如果你做小数据量的 fine-tune,dropout 又会重新有用。它是「数据-模型容量比」的函数:数据相对模型小时有用,反过来没用。
七、Batching by Tokens:长度归一化的妙招
7.1 一个常被忽视的设计
原论文里有一句话:「Each training batch contained a set of sentence pairs containing approximately 25000 source tokens and 25000 target tokens.」
这句话的意思是:每个 batch 的大小不是「固定句对数」,而是「固定 token 数」。
这是一个非常重要的工程细节,但很多教程一带而过。
7.2 为什么不用固定 batch_size
机器翻译的句子长度差异巨大——短的 5 个词,长的 100 个词。如果你按固定 batch_size = 64 做:
- 一个全是短句的 batch:64 × 8 = 512 token,GPU 利用率极低;
- 一个全是长句的 batch:64 × 80 = 5120 token,可能爆显存。
更糟糕的是,显存占用主要由 batch 内最长句子决定——padding 让 batch 实际大小是 64 × max_len,短句白白占着位置。
按 token 数 batch,行为完全不同:
- 短句的 batch:50 句 × 平均 10 词 ≈ 500 token;动态扩到 50 句;
- 长句的 batch:5 句 × 平均 100 词 ≈ 500 token;动态缩到 5 句。
显存占用稳定,GPU 利用率最大化。
7.3 实现:buckets + dynamic batch
典型实现是把训练数据按长度分桶(bucket),每个桶内长度相近:
bucket 0: 句子长度 1-10
bucket 1: 句子长度 11-20
...
bucket 9: 句子长度 91-100
每次从一个 bucket 抽样,凑够 25000 token 就提交一个 batch。这样既保证 batch 内长度均匀(padding 浪费小),又能在 token 维度上保持稳定的 batch 大小。
fairseq、Tensor2Tensor 的实现都是这一套。
7.4 现代 LLM 怎么做
GPT-3、LLaMA 训练时同样按 token 数算 batch,但因为是单语自回归(不是翻译),处理简单一些:把所有训练文本拼成一长串、按固定上下文长度(2048、4096)切,每片就是一个样本。这样每个样本天然等长,padding 完全不需要。
但 token-based batching 的核心思想——「用 token 作为基本计算单位、而不是 sample」——一直延续到今天。
八、推理:beam search 与 length penalty
8.1 为什么不能 greedy
训练时模型用「teacher forcing」——每一步看真实历史预测下一个词。但推理时没有真实历史,必须用模型自己生成的词作为下一步输入。
最直接的做法是 greedy:每一步选概率最高的词。但 greedy 有一个致命问题——「早期局部最优锁死后续」。比如:
- step 1 选了 “A”,因为 P(A) = 0.4 > P(B) = 0.35;
- 但如果选 “B”,后面整体的 P(B + rest) 可能远大于 P(A + rest)。
greedy 看不到这个,它只看每一步当下的最优。
8.2 beam search
beam search 的想法是「保留多个候选路径」:
- step 1:选概率最高的 k 个词作为「beam」(k = beam size,原论文取 4);
- step 2:对每个 beam,扩展所有 V 个候选词,得到 k × V 条路径;从中再挑概率最高的 k 条;
- step 3:继续扩展,直到所有 beam 都生成 </s> 或达到最大长度;
- 最后从 k 个完成的句子中挑总概率(log-sum)最高的输出。
beam search 不能保证找到全局最优解(那需要遍历所有路径,exponential),但比 greedy 显著提升翻译质量。
8.3 length penalty α = 0.6
beam search 有一个臭名昭著的 bias:短句子总概率高。因为每生成一个词都要乘一个 P < 1,句子越长概率越低,beam search 倾向输出短句。
length penalty 的作用是抵消这个 bias。原论文用 GNMT 提出的版本:
score(y) = log P(y) / lp(|y|)
lp(|y|) = ((5 + |y|) / 6)^α
α = 0.6 时,长句的 score 被「除以一个比 1 大的数」之前先「除以一个比 1 还略小的数」,平衡掉短句偏好。
实际效果:α = 0 时 beam search 输出明显偏短,α = 1 时偏长,α = 0.6 是中间的甜点。
8.4 现代生成不用 beam search
GPT-3、LLaMA 的对话生成几乎都不用 beam search,而是用 temperature sampling、top-k、top-p(nucleus sampling)。原因:
- beam search 的输出「过于安全」,多样性差;
- 对话生成要的是「合理且有趣」,不是「严格意义上的最高概率」;
- 长生成时 beam search 算力开销大,sampling 一步一个 token 即可。
但翻译、摘要这类「有标准答案」的任务,beam search 仍然占主流。
九、复现性:fairseq、Tensor2Tensor 的微妙差异
原论文公开了大部分细节,但仍然有一些边角细节没明确写。后人的复现实现(Google 自家的 Tensor2Tensor、Facebook 的 fairseq、HuggingFace 的 transformers)在以下点上有差异:
9.1 Pre-LN vs Post-LN
原论文是 Post-LN(每个子层之后做 LN)。但后来发现这个写法在大尺度下训练不稳定——梯度在深层会爆炸或消失。
Pre-LN(先 LN 再过子层)由 Xiong et al. 2020 系统分析后成为主流。GPT-3、LLaMA 都用 Pre-LN。
但在 base 6 层的尺度上,Post-LN 和 Pre-LN 表现相近,原论文用 Post-LN 没问题。
9.2 Embedding 缩放
原论文有一行:「In the embedding layers, we multiply those weights by √d_model.」
也就是 token embedding 出来后要乘以 √d。这是为了让 embedding 的方差和位置编码的方差对齐——位置编码 sinusoidal 的幅度大约是 1,而 embedding 初始化方差 1/d,乘 √d 后方差变成 1。
这是论文里写了的,但很容易漏。fairseq 默认乘了,HuggingFace 的早期 transformers 实现里有过 bug。
9.3 Dropout 的精确位置
前面提到,原论文的 dropout 加在「子层输出」「embedding 之后」。但具体到细节:
- 是 LN 之前还是 LN 之后?fairseq 是 LN 后;T2T 早期是 LN 前;
- attention softmax 后要不要加 dropout?fairseq 加了(rate=0.1),T2T 没加。
这些差异让不同实现的 BLEU 在 ±0.2 范围内浮动。
9.4 初始化
原论文没明确说初始化方法。Xavier 是默认。但具体是 Xavier-uniform 还是 Xavier-normal?fan_in 还是 (fan_in + fan_out) / 2?这些细节不同实现有差异。
后来 GPT-2 系列用了一个特殊缩放:W₂(FFN 输出投影)和 W_O(attention 输出投影)的初始化额外乘 1/√(2 n_layers),目的是让深层残差累积方差不爆。这是 GPT-2 的细节,原 Transformer 没用。
9.5 总结
如果你照着论文复现,BLEU 大概能到 27.0 左右(base)。要稳定到 27.3,需要额外注意上述细节。fairseq 是公认最接近原论文的实现,可以拿它当参考。
十、训练损失曲线长什么样
虽然原论文没公开完整的训练曲线,但根据公开的 fairseq 复现日志,我们大致能描绘出来:
- step 0-4000(warmup):loss 从 ~10 快速降到 ~5;这是「模型学到 unigram 频率」的阶段;
- step 4000-20000:loss 从 5 降到 ~3;模型开始学到 bigram、trigram 模式;
- step 20000-60000:loss 从 3 降到 ~2.5;学到对齐、长距离结构;
- step 60000-100000:loss 从 2.5 降到 ~2.2;细化语义、稀有词处理。
BLEU 在 50k 步左右开始进入收益递减区——再训也只能再涨 0.3-0.5 BLEU。这是 base 模型选 100k 步的原因。big 模型因为容量大,能继续从训练中受益,所以训到 300k 步。
10.1 验证 vs 训练 loss
训练 loss 和验证 loss 大体重合——这个任务过拟合不严重。这也印证了前面 dropout 0.1、label smoothing 0.1 这种「轻正则」是合适的。
十一、现代大模型 vs 2017 年配方
时隔 8 年,原论文的训练配方哪些被沿用、哪些被改了?
11.1 沿用的部分
- Adam 类优化器:仍然主流(AdamW 是它的改良版);
- warmup:所有大模型都有,warmup_steps 的比例和 2017 年一个量级;
- token-based batching:基本没变;
- 学习率衰减:1/√step 换成了 cosine,但形式相近;
- embedding 缩放、weight tying:还在用。
11.2 改了的部分
- β₂:从 0.98 调到 0.95 或 0.999(依训练长度);
- weight decay:从 0 加到 0.1(AdamW);
- dropout:从 0.1 减到 0;
- label smoothing:从 0.1 减到 0;
- batch size:从 25000 token 升到几百万 token(LLaMA-2 用 4M token);
- 学习率峰值:相对小(~3e-4),因为模型大、batch 大;
- 训练 token:从 ~30 亿(En-Fr)升到 1.4-15 万亿(LLaMA-2、LLaMA-3);
- 混合精度:FP16/BF16 + loss scaling,原论文是 FP32。
11.3 没变的核心
最有意思的观察是:虽然 scale 变了 1000 倍,但训练配方的「形状」基本没变。
- 仍然是 Adam 系;
- 仍然有 warmup;
- 仍然按 token batch;
- 仍然要小心初始化;
- 仍然需要监控梯度范数、loss 曲线、验证 PPL。
这背后其实有一个深层原因:梯度下降优化的几何性质并不随模型规模变化太多。warmup 还是要 warmup(梯度估计需要稳定时间),衰减还是要衰减(后期需要小步精修)——这些「软规律」在不同 scale 下都有效。
11.4 一份对照表
把原论文 vs LLaMA-2 vs GPT-3 的配方放到一张表里,差异看得很清楚:
| 配方项 | Transformer base (2017) | GPT-3 175B (2020) | LLaMA-2 70B (2023) |
|---|---|---|---|
| 优化器 | Adam | Adam | AdamW |
| β₁ | 0.9 | 0.9 | 0.9 |
| β₂ | 0.98 | 0.95 | 0.95 |
| ε | 1e-9 | 1e-8 | 1e-5 |
| weight decay | 0 | 0.1 | 0.1 |
| warmup steps | 4000 | 375M tokens | 2000 |
| LR schedule | inverse √step | cosine | cosine |
| LR peak | ~7e-4 (d=512) | 6e-5 (d=12288) | 1.5e-4 (d=8192) |
| dropout | 0.1 | 0 | 0 |
| label smoothing | 0.1 | 0 | 0 |
| batch (tokens) | 25k src + 25k tgt | 3.2M | 4M |
| 训练 token | ~3B (En-Fr) | 300B | 2T |
| 训练步数 | 100k (base) / 300k (big) | ~95k | ~500k |
| 精度 | FP32 | FP16 + dynamic loss scale | BF16 |
| 梯度 clip | 0.0 (无) | 1.0 | 1.0 |
读这张表的几个有趣观察:
- 学习率峰值随模型变大而变小:从 7e-4 到 6e-5,约一个数量级;和 d^(-0.5) 的预测吻合;
- batch size 涨了 100 倍:从 25k token 到几百万 token;
- 训练 token 涨了 1000 倍:从 3B 到 2T;这是 Chinchilla scaling law 之后大家才意识到「数据是瓶颈」;
- 正则化几乎全部砍掉:dropout=0、label smoothing=0、但加了 weight decay;
- 梯度 clip 普遍开启:现代训练不再相信 schedule 能压住所有 outlier,gradient clip 是保险。
十二、训练成本与论文影响
12.1 算成本
把 base 模型的训练 FLOPs 估算一下:
- 每步 25000 source token + 25000 target token;
- 每个 token 大约 2 × 65M = 130M FLOPs(前向);
- 反向是前向的 ~2 倍:3 × 130M = 390M FLOPs/token;
- 每步:50000 × 390M = 1.95e13 FLOPs;
- 总步数 100000:1.95e18 FLOPs ≈ 2 PFLOPs。
8 张 P100 的 FP16 算力 ≈ 8 × 19 = 152 TFLOPS。如果利用率 50%,单步耗时 ≈ 1.95e13 / 7.6e13 ≈ 0.26 秒;100k 步 ≈ 7.2 小时。考虑数据加载、通信开销,实际 12 小时合理。
12.2 与对比方法
原论文 Table 2 给出了和 ConvS2S、GNMT、ByteNet 的对比。Transformer base 在 BLEU 上同时打过这三家,而且训练成本只有 GNMT 的 ~1/10、ConvS2S 的 ~1/30。
这个「算力 × 性能」的甜蜜点,是 Transformer 当年 take over 整个 NLP 的核心动力——不是它能做新事情,而是它能用更少算力做得更好。
12.3 影响力
到 2024 年,Attention Is All You Need 的引用数已经超过 12 万次(Google Scholar 统计),是 21 世纪被引最多的 AI 论文之一。
更重要的是:几乎所有现代大语言模型——GPT 系列、Claude、Gemini、LLaMA、Qwen、DeepSeek——都基于这个 2017 年提出的架构,只是 scale 大了 1000 倍、加了一些边角改进(RoPE 位置编码、SwiGLU FFN、RMSNorm 等)。
架构稳定 8 年是非常罕见的。深度学习历史上,每隔几年就有「这次真的不一样」的新架构出现(LSTM → GRU → Transformer),但 Transformer 的根基一直没被撼动。
十三、一个手算的学习率示例
为了让公式从纸上走到具象,把原论文的配方带几个具体的 step 进去算一下。
设 d_model = 512, warmup_steps = 4000。
step = 1: - 函数 A:1 · 4000^(-1.5) = 1 / 252982 ≈ 3.95e-6 - 函数 B:1^(-0.5) = 1.0 - min(A, B) = A = 3.95e-6 - lr = 512^(-0.5) · 3.95e-6 = (1/22.627) · 3.95e-6 ≈ 1.75e-7
非常小的学习率。这是 warmup 第一步的样子——模型几乎不动,等 v 估计稳定。
step = 1000: - 函数 A:1000 · 4000^(-1.5) ≈ 3.95e-3 - 函数 B:1000^(-0.5) ≈ 0.0316 - min = A = 3.95e-3 - lr ≈ (1/22.627) · 3.95e-3 ≈ 1.75e-4
已经不算小,但还在 warmup 中(step < 4000),仍按线性增长。
step = 4000(warmup 完成的拐点): - 函数 A:4000 · 4000^(-1.5) = 4000^(-0.5) ≈ 0.01581 - 函数 B:4000^(-0.5) ≈ 0.01581 - 两者相等 - lr = (1/22.627) · 0.01581 ≈ 6.99e-4
这是峰值学习率 ≈ 7e-4。论文配方就是按这个峰值的。
step = 16000(4 倍 warmup): - 函数 B:16000^(-0.5) ≈ 7.91e-3 - lr ≈ (1/22.627) · 7.91e-3 ≈ 3.5e-4
峰值的一半。
step = 100000(base 训练结束): - 函数 B:100000^(-0.5) ≈ 3.16e-3 - lr ≈ (1/22.627) · 3.16e-3 ≈ 1.4e-4
降到峰值的 1/5 左右。这是训练后期的精修阶段。
把这 5 个 step 连起来看,就是图里那条曲线——先线性快速升到 7e-4,然后慢慢降到 1.4e-4,整个过程跨越 100k 步。
13.1 改了 warmup 会怎样
把 warmup 从 4000 改成 8000,重算:
step = 4000(中点): - A:4000 · 8000^(-1.5) = 4000 · 1/715541 ≈ 5.59e-3 - B:4000^(-0.5) ≈ 0.0158 - min = A = 5.59e-3 - lr ≈ 5.59e-3 / 22.627 ≈ 2.47e-4
比 warmup=4000 的峰值(7e-4)小 2.8 倍。也就是说,warmup 拉长一倍,整个训练前期的 lr 都偏低,模型「学得慢」——这就是图里 warmup=16000 那条曲线偏右下的原因。
新峰值出现在 step = 8000: - lr_peak = 512^(-0.5) · 8000^(-0.5) = (1/22.627) · 0.01118 ≈ 4.94e-4
比 warmup=4000 的 7e-4 低 30%。
直观结论:warmup 长度越长,峰值学习率越低。这是公式 lr_peak = d^(-0.5) · warmup^(-0.5) 直接给出的。
如果你的训练总步数本来就少(比如只有 10k 步),warmup 取 4000 已经占了 40%——前期太慢,后期没几步收敛。这时该把 warmup 缩到 1000 左右。
13.2 改了 d_model 会怎样
把 d 从 512 改成 1024(big 模型):
step = 4000 处的峰值: - lr_peak = 1024^(-0.5) · 4000^(-0.5) = (1/32) · (1/63.25) ≈ 4.95e-4
比 d=512 的 7e-4 低约 30%。这印证了 「模型越宽、学习率越低」 的经验,是公式自动给出的。
实际工程里你会看到很多大模型的峰值 lr 在 1-3e-4 量级——它们的 d 通常 4096-12288,按 d^(-0.5) 缩,比 d=512 的 7e-4 低好几倍。
十四、训练循环的伪代码
把整个训练 loop 用伪代码写一遍,所有上面提到的部件放到位:
import math, torch
from torch.optim import Adam
def lr_schedule(step, d_model, warmup_steps):
return d_model ** -0.5 * min(step ** -0.5,
step * warmup_steps ** -1.5)
# 模型与优化器
model = Transformer(d_model=512, n_layers=6, n_heads=8, d_ff=2048,
vocab_size=37000)
optim = Adam(model.parameters(), lr=1.0,
betas=(0.9, 0.98), eps=1e-9)
# 注意:lr=1.0 是占位,真实 lr 由 schedule 给
# Label smoothing 损失
loss_fn = LabelSmoothingLoss(eps=0.1, vocab_size=37000, pad_id=0)
step = 0
for batch in dataloader: # batch 已经 token-balanced
step += 1
# 1. 设定本步学习率
lr = lr_schedule(step, d_model=512, warmup_steps=4000)
for g in optim.param_groups:
g["lr"] = lr
# 2. 前向
logits = model(batch.src, batch.tgt[:, :-1]) # teacher forcing
loss = loss_fn(logits, batch.tgt[:, 1:])
# 3. 反向 + 更新
optim.zero_grad()
loss.backward()
optim.step()
# 4. 日志
if step % 1000 == 0:
print(f"step {step} lr {lr:.2e} loss {loss.item():.3f}")
if step >= 100_000:
break这段代码概念上完整,但工程上还差几样东西:
- 梯度累积:如果单卡显存不够 25000 token,要把 batch 拆成多个小 batch 累积梯度;
- 多卡
all-reduce:
loss.backward()之后要做 DDP 的梯度同步(PyTorch DistributedDataParallel 自动处理); - 混合精度:FP16/BF16 训练要加 GradScaler;2017 年原论文是 FP32 的,bf16 是后来的优化;
- gradient clipping:很多复现里加了
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0),防止偶发的大梯度把训练弄崩。原论文没明确说,但 fairseq 默认开启; - checkpoint 保存:每 5000 步存一次模型;
- 验证:每 N 步在 dev set 上算一次 loss/BLEU。
加上这些工程细节,单文件训练脚本大概 300-500 行,可读性还可以——这正是 fairseq 早期版本的水平。
十五、原论文之外:averaging 与「test 提升术」
原论文有一个细节,很多教程忽略:最后报的 BLEU 是用 checkpoint averaging 算出来的。
具体说:训练结束时不是用最后那个 checkpoint,而是把最后 5 个(base)或 20 个(big)checkpoint 的参数逐元素平均,得到一个「averaged model」,再用这个 averaged model 做推理。
15.1 为什么 averaging 有效
参数平均的本质是「对训练后期的几个解做几何中点」。深度学习的损失曲面是高度非凸、但局部相对平坦的——后期的几个 checkpoint 在损失曲面上「走来走去」,每一个都是某种局部最优,但它们的中点往往比任何单点都好。
直觉上:
- 单个 checkpoint:某一步训练后的快照,它是「噪声 + 真实信号」的混合;
- 平均多个 checkpoint:把每个 checkpoint 的噪声相互抵消(不同方向的随机扰动),保留真实信号。
实测中,averaging 能给 base 提升 0.3-0.5 BLEU,给 big 提升 0.5-0.8 BLEU。
15.2 现代版本:EMA
现代大模型训练用的是 EMA(Exponential Moving Average):在训练过程中维护一份「影子参数」 θ_ema,每步按 θ_ema = α θ_ema + (1-α) θ 更新(α 通常 0.999 或 0.9999)。
EMA 比 checkpoint averaging 更连续——不需要显式存几个 checkpoint,每步自动累积。Stable Diffusion、扩散模型、强化学习的 actor-critic 都广泛使用 EMA。
但本质上 EMA 和 averaging 是同类技巧——都属于「让最终模型用一个相对平滑的参数版本,而不是某一刻的随机快照」。
十六、原论文里几个容易忽视的细节
在收尾之前,我想再补几个原论文文本里写了、但读快了容易错过的工程细节。这些细节单看每个不大,但加在一起决定了你能不能复现到 BLEU 27.3 这个具体值。
16.1 Embedding weight tying
原论文 §3.4 提到一句:「we share the same weight matrix between the two embedding layers and the pre-softmax linear transformation」。
意思是:
- encoder 输入的 token embedding;
- decoder 输入的 token embedding;
- decoder 输出层(把隐状态投影回 vocab 维度的 W_out);
这三个矩阵共享同一份参数——共用一个 [vocab_size, d_model] 的矩阵。
为什么这么做?
第一,省参数。词表 37000、d=512,单矩阵 19M 参数;如果三个独立,就是 57M。共享省下 38M,相当于一个完整的 base 模型大小。
第二,正则化效果。三个矩阵被强制保持一致,相当于「输入 → 表示」和「表示 → 输出」用同一个映射的转置——这种对称性约束让训练更稳。
第三,在小词表上几乎不损失性能;在大词表(GPT-3 的 50k)上仍然有效。
后来 Press & Wolf(2017)写了一篇专门的文章 Using the Output Embedding to Improve Language Models 系统验证了 weight tying 的好处。
实现上:
# 共享一个 nn.Embedding
shared_embed = nn.Embedding(vocab_size, d_model)
# 输出投影把 embedding 矩阵转置
output_logits = hidden @ shared_embed.weight.T16.2 没有 bias 的 attention 投影
很多复现里 W_Q、W_K、W_V、W_O 都不加 bias。LLaMA 系列也是这样。原论文文本里没明说,但代码里 W_Q/W_K/W_V/W_O 通常 bias=False——线性投影后立刻接 softmax 或残差,bias 的作用被吸收。
16.3 Dropout 在 attention 内部的位置
前面说过 dropout 加在「子层输出」。但实际 fairseq 实现还在 attention 的 softmax 之后加了一个 dropout:
attn_weights = softmax(QK^T / sqrt(d_k))
attn_weights = dropout(attn_weights) # 这一步原论文没明说
output = attn_weights @ V这个细节很微妙——它让某些 token 在某些 head 上的「看到」被随机屏蔽,强迫不同 head 不依赖单一来源。后来很多实现沿用,HuggingFace 默认开启。
16.4 训练用 FP32,推理可以 FP16
2017 年 P100 已经支持 FP16,但混合精度训练还不成熟(Apex 是 2018 年的事)。原论文用的是纯 FP32。
但他们提到:「We used 8 NVIDIA P100 GPUs.」P100 的 FP16 算力是 FP32 的 2 倍——意味着训练时其实没用上 FP16 的加速。
到了 2020 年之后,BF16 训练成为大模型主流(更少精度问题),FP16 + loss scaling 也很流行。这块工程演化非常快。
十七、评测方法学
最后讲一下 BLEU 是怎么算的,以及报数字时常见的「玄学」。
17.1 BLEU 公式简介
BLEU(Papineni et al., 2002)的核心是 n-gram 匹配率:
- 把模型翻译和参考译文都切成 unigram、bigram、trigram、4-gram;
- 算每种 n-gram 的精确率(模型翻译里有多少 n-gram 出现在参考译文里);
- 把 4 种精确率几何平均;
- 加一个「短句惩罚」(brevity penalty)——如果模型翻译比参考短太多,整体分数被砍。
BLEU 的范围 0-100(有时写成 0-1),翻译任务上 30+ 已经算很好。
17.2 不同 BLEU 不能直接比
这是 MT 圈一个长期的痛点:同一个翻译,用不同工具算 BLEU 能差几个点。
差异来源:
- 分词方式:去标点、小写化、是否合并连字符;
- 平滑方法:精确率为 0 时怎么处理;
- 参考译文数量:单参考 vs 多参考;
- 实现细节:multi-bleu.perl vs sacreBLEU vs NLTK 各有差异。
Post(2018)的 A Call for Clarity in Reporting BLEU Scores 推动了 SacreBLEU 工具的标准化,现在 MT 论文必须标注 SacreBLEU 的具体配置签名。
原论文 2017 年还没有这套标准,他们用的是 multi-bleu.perl(大小写敏感版),所以你直接跑 SacreBLEU 拿到的数字会和论文报的差零点几——不是模型不对,是评测方式不同。
17.3 测试集污染
现代大模型时代多了一个问题:训练数据可能不小心污染了测试集。如果你的 web 数据里包含了 newstest2014 的内容(参考译文也在里面),模型「记忆」了答案,BLEU 虚高。
这在 GPT-3、GPT-4 的评测里反复被讨论。LLaMA 论文里专门做了「污染检测」分析——把测试集每个句子去训练数据里搜,看出现率多高。
2017 年这还不是问题(4.5M 句对的 WMT 数据可控),但今天这是评测的一个隐藏雷区。
十八、训练时的监控指标
光有训练 loss 是不够的。一个稳健的训练循环还要监控以下指标,每个都能在出问题时给你信号。
训练 loss:最直接的指标。健康的曲线是单调下降(带噪声)。如果突然飙升,多半是数值不稳(NaN、爆炸梯度)。如果停滞不下,可能是学习率不对、warmup 没完、数据有问题。
验证 loss:每 N 步在 dev set 上算一次。健康的训练里 val loss 跟训练 loss 平行下降,最后差距很小。如果 val loss 开始反弹(训练 loss 还在降),说明过拟合了——加大正则、减小模型、扩大数据。
梯度范数(gradient norm):所有参数梯度的 L2 范数。健康的训练里这个值在 0.5-5 之间稳定波动。如果突然飙到 100+,多半是某个 batch 数据有 outlier、或者 attention 出现极端 sharp 分布。fairseq 默认 clip 到 1.0 防止这种 outlier 把训练弄崩。
学习率:监控它确认 schedule 正常工作——很多 bug 来自 schedule 写错(比如 warmup 步数和 step 计数不同步、resume 训练时 step 没对上)。
参数范数:所有参数的 L2 范数。健康的训练里这个值缓慢增长。如果迅速爆炸,要警惕。
激活的最大/最小值:在每层的输出上 sample 一下 max/min。健康范围 ±10 量级。如果某一层出现 ±100、±1000,bf16 表示就要溢出了。
attention 熵:把每个 head 的 attention 权重的熵(-Σ p log p)算出来。健康范围 1-3。如果某些 head 熵接近 0,那个 head 已经塌缩成 hard attention(看一个或几个固定 token),可能是「死了」。
这些监控不是必须的——很多人只看 train/val loss 就训完了。但当训练崩了或结果不对时,多看几个指标能更快定位问题。这是工程经验。
十九、关键概念回顾(散文式)
回头看这一篇,我们做了一件相对单调但很扎实的事:把 2017 年原论文的训练配方逐项打开,讲清楚每个数字背后的意图。
最关键的几条结论是:warmup 不是可选项——它给优化器 v 估计的稳定时间,去掉训练直接崩;学习率公式 lr = d^(-0.5) · min(step^(-0.5), step · warmup^(-1.5)) 不是凭空写出来的,它编码了「峰值随模型宽度反比、warmup 后按 1/√step 衰减」的工程经验;β₂ = 0.98 不是默认的 0.999,因为训练只有 100k 步、记忆窗口要短一点;label smoothing 0.1 是为 beam search 服务的——它让模型分布柔和,beam search 才能找到更优解;dropout 0.1 在 2017 还是必须,到了大模型时代就退场了。
整个配方放到 8 张 P100 + 12 小时这个尺度上,跑出 BLEU 27.3(base)/ 28.4(big),同时把 GNMT 当时的算力成本砍到 1/10。这是「架构 + 配方」共同作用的结果——单换架构而不调配方,达不到这个 BLEU;反过来,单换配方不换架构,老 RNN 也吃不下这种 batch。
最后值得记住的一点是:现代大模型的训练配方,相对 2017 年「形状」基本没变——还是 Adam 系、还是 warmup、还是 token-based batching、还是 1/√step 形态的衰减(cosine 也是这一类)。改动的只是细节:β₂、weight decay、dropout、label smoothing。这说明梯度下降的「几何性质」是相对 scale 不变的——这套东西大概还会再用 10 年。
二十、常见误解
误解一:warmup 可有可无,去掉只是慢一点。
错。warmup 完全去掉,Transformer 训练大概率直接崩——loss 不下降甚至发散。这是因为 Adam 的 v 在前几百步还没稳定下来,过大的学习率配合不准的方差估计会把参数推到坏区域。
误解二:Transformer 用 Adam 默认参数就行。
错。原论文用 β₂ = 0.98(不是 0.999)、ε = 1e-9(不是 1e-8)。这些不是细节,是经过 ablation 调出来的。直接用默认参数训出来的 BLEU 会差几个点。
误解三:label smoothing 让 PPL 变差,所以是个错误的设计。
不对。label smoothing 让训练 PPL 变差是预期内的(因为最优分布被人为软化),但 BLEU 变好——这才是机器翻译关心的指标。PPL 和 BLEU 不总是同向。
误解四:beam search size 越大越好。
错。beam=4 是原论文的选择。再大(beam=10、20)BLEU 几乎不动甚至变差,因为 length penalty 不再能完全平衡掉短句偏好。beam=4 是大多数翻译系统的甜点。
误解五:现代 LLM 训练完全用了不一样的配方。
部分对。变了很多细节(dropout=0、weight decay=0.1、cosine 衰减等),但「形状」没变——仍然是 Adam 系、warmup、token-based batching、按学习率峰值的某个分数衰减。Transformer 训练的「骨架」是 2017 年定下来的。
二十一、下一步
下一篇 28|原论文实验结果 会从「训练配方」切到「实验结果」——具体数字、消融实验、注意力可视化。我们会讲:
- 主结果 BLEU 27.3 / 28.4 / 38.1 / 41.8 是怎么测的;
- 消融实验告诉我们 head 数、d_k、d_model、dropout 各个超参数的最优点在哪儿;
- 附录里那些注意力可视化看到了什么;
- 这篇论文的「短板」——哪些消融它没做、后人是怎么补上的;
- 跨任务泛化的伏笔:从翻译到 BERT/GPT 的飞跃。
再往后:
- 29|Tokenization:BPE、WordPiece、SentencePiece 的取舍;
- 30|预训练目标:BERT 的 MLM 与 GPT 的自回归路线分歧。
二十二、参考文献
- Vaswani, A. et al. “Attention Is All You Need.” NeurIPS 2017. 训练配方的源头。
- Kingma, D. P., Ba, J. “Adam: A Method for Stochastic Optimization.” ICLR 2015. Adam 优化器原始论文。
- Loshchilov, I., Hutter, F. “Decoupled Weight Decay Regularization (AdamW).” ICLR 2019. 现代大模型用的优化器。
- Szegedy, C. et al. “Rethinking the Inception Architecture for Computer Vision.” CVPR 2016. Label smoothing 提出。
- Srivastava, N. et al. “Dropout: A Simple Way to Prevent Neural Networks from Overfitting.” JMLR 2014. Dropout 原始论文。
- Wu, Y. et al. “Google’s Neural Machine Translation System (GNMT).” arXiv:1609.08144, 2016. length penalty 公式来源。
- Gehring, J. et al. “Convolutional Sequence to Sequence Learning (ConvS2S).” ICML 2017. Transformer 之前的 SOTA。
- Kalchbrenner, N. et al. “Neural Machine Translation in Linear Time (ByteNet).” arXiv:1610.10099, 2016.
- Ott, M. et al. “fairseq: A Fast, Extensible Toolkit for Sequence Modeling.” NAACL 2019 demo. 最接近原论文的复现实现。
- Vaswani, A. et al. “Tensor2Tensor for Neural Machine Translation.” AMTA 2018. Google 自家的复现。
- Xiong, R. et al. “On Layer Normalization in the Transformer Architecture.” ICML 2020. Pre-LN vs Post-LN 系统分析。
- Liu, L. et al. “On the Variance of the Adaptive Learning Rate and Beyond (RAdam).” ICLR 2020. 解释 warmup 为什么重要。
- Goyal, P. et al. “Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour.” arXiv:1706.02677, 2017. linear warmup 的理论支持。
- Brown, T. et al. “Language Models are Few-Shot Learners (GPT-3).” NeurIPS 2020. 现代 LLM 训练配方对照。
- Touvron, H. et al. “LLaMA: Open and Efficient Foundation Language Models.” arXiv:2302.13971, 2023.
- Touvron, H. et al. “Llama 2: Open Foundation and Fine-Tuned Chat Models.” arXiv:2307.09288, 2023.
- Hoffmann, J. et al. “Training Compute-Optimal Large Language Models (Chinchilla).” NeurIPS 2022. 训练成本和数据规模的 scaling law。
- Kaplan, J. et al. “Scaling Laws for Neural Language Models.” arXiv:2001.08361, 2020. OpenAI 的 scaling law。
- Sennrich, R. et al. “Neural Machine Translation of Rare Words with Subword Units (BPE).” ACL 2016. 原论文用的子词切分方法。
- Press, O., Wolf, L. “Using the Output Embedding to Improve Language Models.” EACL 2017. weight tying 的来源。
- Bahdanau, D., Cho, K., Bengio, Y. “Neural Machine Translation by Jointly Learning to Align and Translate.” ICLR 2015. WMT MT 评测的早期 SOTA 之一。
- Papineni, K. et al. “BLEU: a Method for Automatic Evaluation of Machine Translation.” ACL 2002. BLEU 的原始定义。
- Post, M. “A Call for Clarity in Reporting BLEU Scores (SacreBLEU).” WMT 2018. 现代 BLEU 标准化工具。
← 上一篇:26|前馈网络 | 下一篇:28|原论文实验结果 →
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Transformer 与注意力机制】06|梯度下降与反向传播
神经网络真正会「学习」靠的是两件事:把误差变成可微分的损失函数,再沿着这个损失对参数的梯度方向一点点往下挪。本文从一维抛物线讲到多变量梯度,从两层网络的手算反向传播讲到为什么 backprop 是 O(参数量),再到 Transformer 为什么几乎一律选 Adam/AdamW,希望把「网络是怎么学的」这件事彻底讲透。
【Transformer 与注意力机制】04. 函数与神经网络:从 y=f(x) 到一台可学习的拟合机器
如果你问我「神经网络到底是什么」,我会先把所有教材合上,然后给你一句朴素得近乎敷衍的话——神经网络就是一个函数。
【Transformer 与注意力机制】05. 激活函数:让网络「弯下来」的非线性魔法
上一篇我们论证了一件事——纯线性的网络再深,也只是一个线性变换。把 $W2(W1\mathbf{x} + \mathbf{b}1) + \mathbf{b}2$ 展开就是 $W'\mathbf{x} + \mathbf{b}'$。线性的复合还是线性,这是线性代数的铁律。
【Transformer 与注意力机制】03 矩阵乘法的两种视角
把矩阵乘法掰开成两种等价但风格不同的视角——『行 × 列』的点积视角和『列的线性组合』视角,最终落到 QK^T 的形状分析。