如果说 2018 年把预训练这件事讲清楚了,那 2019 年就在回答另一个更直接的问题:既然这条路有效,接下来怎么把它做大、做稳、做得真正能用。
这一年有两个特别醒目的点。一个是 GPT-2,让大家第一次认真看到,模型和数据规模继续往上推,零样本能力会开始冒出来;另一个是 T5,它没有只追一个新点子,而是把迁移学习里一大堆选择摊开来做系统实验。与此同时,工程侧也没闲着。Top-p 采样、Tensor Parallel、ZeRO、MQA 这些东西,看上去不像 GPT-2 那样抢眼,但后来几乎都成了大模型工具箱里的常驻选项。
2019 年的 GPT-2 很重要,不只是因为它更大,而是因为它让“规模本身会带来新能力”这件事第一次显得没那么像猜测。
BERT 在 2018 年之后非常强势,很多人自然会觉得,下一步是不是该全面转向双向编码器。但 OpenAI 没这么走。他们继续押注自回归语言建模,而且押得更彻底。GPT-2 关心的是,如果模型一直做“预测下一个词”这件事,规模上去之后到底会学到什么。
GPT-2 用的 WebText 数据集也很关键。它从 Reddit 上高票链接抓取网页文本,最后整理出大约 40GB 数据。这个数据集不只是大,问题在于它够杂,也够接近真实互联网文本。模型在里面能碰到摘要、问答、翻译、故事、论坛回复,各种分布混在一起。后来论文提到,哪怕是 15 亿参数的 GPT-2,在 WebText 上也还没吃透数据,这个判断其实很耐人寻味。
架构上,GPT-2 没有彻底换框架,还是 Transformer 解码器,但做了几处影响很大的调整。比如把 LayerNorm 放到残差连接前面,也就是常说的 Pre-LN;再比如对残差路径的初始化做缩放,避免深层网络训练时梯度一路堆上去。单看都像小修小补,放到大模型训练里就不是小事了。
最让人记住的,还是它的零样本能力。给模型一个类似 “TL;DR:” 或 “translate English to French:” 这样的前缀,它就能在不微调的情况下做摘要或翻译。今天看这件事已经不新鲜,但在 2019 年,这种“任务写在输入里”的感觉是很新的。它不是说 GPT-2 当时已经在所有任务上都足够强,而是说明模型开始能靠同一套参数去适应不同任务形式了。
当然,GPT-2 也不是没有短板。它在 One Billion Word Benchmark 这类打乱句序的数据上表现不好,因为那种预处理会把长程结构拆掉,而自回归 Transformer 恰恰依赖这个结构。零样本翻译效果也远谈不上能替代专门模型。但它把一件事先做实了:单一模型通过提示切换任务,是有可能的。
Top-p 采样,也叫核采样,处理的是生成阶段一个特别实际的问题:怎么让文本既别太死板,也别发散到收不回来。
之前更常见的是 Top-k。它的逻辑很直白,每一步只保留概率最高的 k 个词,再从里面采样。问题是,k 一旦固定,就会在不同上下文里显得很别扭。模型特别确定的时候,候选词其实没必要留那么多;模型不太确定的时候,候选集又可能太窄。
Top-p 的做法是按累计概率截断。先把词按概率从高到低排序,再从前往后加,直到总概率达到某个阈值 p,比如 0.9。留下来的这一小撮词就是候选集。概率分布尖的时候,候选集自然小;分布平的时候,候选集会自动变大。它不需要手动预设一个固定的 k。
这篇工作还点明了一个常被忽略的问题:语言模型的尾部概率分布很长。单看每个词,概率低得几乎可以忽略,但尾巴太长了,加起来又不是完全没分量。生成质量差的时候,很多问题就出在模型偶尔从这段长尾里抽到不合适的词。Top-p 本质上就是把这段尾巴截短。
后来大家经常把 Top-p 和温度一起用,也很正常。温度负责把分布拉平或拉尖,Top-p 再决定从哪里截断。两者配合起来,比单独调一个参数更顺手。
模型一过十亿参数,问题立刻变得现实:单张 GPU 放不下怎么办。Megatron-LM 给出的答案是张量并行,也就是把单层里的矩阵计算拆到多张卡上。
这个思路的关键,不是简单把层分给不同设备,而是尽量让通信次数少一点。对 MLP 来说,第一层线性变换可以做列切分,各张卡各算一部分输出,然后直接接激活函数;第二层再做行切分,最后用一次 All-Reduce 把结果合起来。这样设计,是为了别在非线性操作前后反复同步。
自注意力层也能这么拆。因为多头注意力本来就带着天然并行性,不同头之间相对独立,所以可以把不同头分到不同 GPU 上。Q、K、V 的投影和最后的输出投影,也都能按类似方式切分。
张量并行的价值很直接:模型终于不必受限于单卡显存。但代价也摆在那里。它对 GPU 间带宽要求高,代码实现复杂,通信调度稍微做不好,收益就会迅速掉下去。后来大模型训练一般不会只靠这一招,而是把张量并行、流水线并行、数据并行混着用。
如果说张量并行是在想“怎么把计算拆开”,那 ZeRO 更像是在问另一个问题:数据并行里那些重复存储,到底能不能少一点。
传统数据并行的浪费很明显。每张 GPU 不只是算同样的前向和反向,还要各自保存一整份模型参数、梯度和优化器状态。模型一大,这种重复就很伤显存。
ZeRO 把这件事拆成三个阶段来做。Stage 1 先把优化器状态分片,每张卡只负责其中一部分;Stage 2 再把梯度也分片,通过 Reduce-Scatter 来同步;Stage 3 进一步连模型参数本身都分片,前向和反向需要哪部分参数时再临时 Gather,用完就放掉。
这个方案的妙处在于,它没有推翻数据并行这套大家已经很熟的训练方式,而是在保留使用习惯的前提下,把显存冗余一点点削掉。后来很多超大模型之所以能训练起来,靠的不是某一个惊人的新架构,而是这类“把原本浪费的地方抠干净”的工程优化。
T5 是 2019 年另一篇绕不开的工作。它和 GPT-2 的气质不太一样。GPT-2 更像是在展示规模带来的能力边界,T5 则像是在认真整理一整套方法论。
Google 团队在这篇论文里做了大量消融实验,去比较预训练目标、模型架构、数据集选择、迁移设置这些问题。最后给出的结论是,把各种 NLP 任务统一写成文本到文本,很多事情会简单很多。
T5 的文本到文本框架说起来很朴素。翻译是输入一段带前缀的文本,输出另一段文本;分类也一样,只不过输出标签词;问答、摘要也都照这个方式处理。这样做的好处,不只是接口统一,更重要的是模型不需要为每一类任务专门加一套头部结构。
数据上,T5 构建了大约 750GB 的 C4 数据集,来源是清洗后的 Common Crawl。架构上,它最后选的是编码器-解码器,因为在这个统一框架下,这种结构在理解和生成之间比较均衡。预训练目标则用了 Span Corruption,也就是一次掩掉连续的一段 token,再让模型把整段补回来。和 BERT 那种单个 token 掩码相比,这个任务更难一点,也更接近日常文本缺失的样子。
工程细节里也有不少后来反复出现的东西。比如 SentencePiece 的 Unigram 分词、相对位置偏置、AdaFactor 优化器,还有适合长训练过程的学习率调度。单个点看上去都不算戏剧化,但它们凑在一起,决定了 T5 不是一篇只停留在概念层的论文,而是一套真能复用的方法。
论文结果也很明确:模型越大,微调带来的收益通常越明显。T5-11B 在当时多个基准上都很强。它后面还顺手摸到了参数高效微调的一些早期方向,比如适配器和逐步解冻。今天回头看,这部分也不算枝节。
T5 真正留下来的东西,不只是一个模型名,而是一个很稳的观念:别急着追逐某个局部技巧,先把问题统一表述,再用系统实验把选择一项项筛过一遍。
训练之外,2019 年还有一个越来越绕不开的话题:推理到底怎么做得起。MQA,也就是 Multi-Query Attention,就是在这个背景下出现的。
自回归生成时,模型要把历史 token 的 Key 和 Value 缓存在显存里,也就是常说的 KV Cache。序列一长,这部分开销会线性增长。标准多头注意力里,每个头都有自己独立的 K 和 V,所以头数一多,缓存就非常可观。
MQA 的办法很干脆:保留多个 Query 头,但让它们共享同一组 Key 和 Value。这样 KV Cache 的大小就不再跟头数线性绑定。对头数很多的模型来说,省下来的显存很可观,解码速度也会更好。
实验结果显示,这种共享虽然会带来一点质量损失,但通常不大,换来的推理收益却很实在。后来的 GQA 可以看作是沿着这条路继续折中:不让所有头完全共享,而是按组共享,在表达能力和缓存成本之间找一个更稳的点。再往后,很多模型都走到了这里。
2019 年的主线其实很清楚。第一,大家开始相信规模本身会改变模型行为,不只是把旧能力做得更强;第二,统一任务形式这件事开始变得重要,T5 把这条思路讲得很完整;第三,训练和推理的工程问题被正面摆上桌面,不再是假设未来再解决。
所以这年留下来的东西,有一半在模型上,有一半在工程上。GPT-2 和 T5 负责把方向推开,Top-p、Tensor Parallel、ZeRO、MQA 则负责让这条路别卡死在显存、通信和推理成本上。后面的大模型热潮当然不是 2019 年一年造出来的,但很多关键零件,确实都是这一年装上的。
- Language Models are Unsupervised Multitask Learners (GPT-2), 2019.02.14, https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf
- The Curious Case of Neural Text Degeneration (Top-p), 2019.04.22, https://arxiv.org/abs/1904.09751
- Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism (Tensor Parallel), 2019.09.17, https://arxiv.org/abs/1909.08053
- ZeRO: Memory Optimizations Toward Training Trillion Parameter Models (Data Parallel), 2019.10.07, https://arxiv.org/abs/1910.02054
- Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer (T5), 2019.10.23, https://arxiv.org/abs/1910.10683
- Fast Transformer Decoding: One Write-Head is All You Need (MQA), 2019.11.06, https://arxiv.org/abs/1911.02150