我们平时解决一个问题,大致是这样走的:先出一个方案,落地看看结果,开会评审符不符合预期,提几条修改意见,改出第二版。第二版也不一定比第一版好,于是再评审、再改。一个方案来来回回倒腾好多轮,最后定下来的也只是“目前最满意的”,谁也不敢说它最优。
训练一个大模型,看起来却完全是另一回事。我们在《Transformer 是怎么训练的》里手算过:算出损失对每个参数的坡度,每个参数朝下坡挪一小步,重复。屏幕上的损失从 0.615 一路降到 0.030,中间没有人开会,也没有人拍板说“这一版不行,推倒重来”。几千亿个参数,靠这么一条规则,就被调到了一个相当好的地方。
这就让人想问:人要反复权衡、反复评审才能做好的事,训练里是怎么省掉的?按梯度走一步,凭什么就是在往对的方向改?走到后来,是不是每个参数都已经调到了最优?如果是,这里面到底用了什么魔法。
本文就顺着这几个疑问,一层一层往下讲。
一、训练里的评审
现象:看起来没人评审
先把训练的一步,和人改方案的一轮,放在一起看(图 1)。
左边是人。方案落地之后,评审会回答的是“好还是不好”,最多再给几条方向性的意见:“这里再想想”“那里改激进一点”。具体改哪、改多少,还得靠人自己琢磨,所以改完常常发现改歪了。
右边是训练的一步。损失就是评审。 它是一个提前写死的分数,比如语言模型的损失就是“下一个词猜错了多少”,用当前参数答一批题,算出这个分数,评审就完成了。然后反向传播把这个分数往回拆,拆出每一个参数的偏导数,也就是梯度:这个参数往大调,损失会涨还是降,涨降有多快。这相当于评审会给 1750 亿个参数各写了一条意见,每条都精确到“往哪边、改多少”。
所以训练不是没有评审,而是每一步都是一轮评审。GPT-3 一步要答约 320 万个词元的题,一共走了约 9.4 万步1,也就是被评审了 9.4 万轮。
评审意见为什么能这么具体
人的评审给不出这么具体的意见,是因为没人知道“方案”和“结果”之间的公式:改一下预算,口碑会变好多少?只能改了再看。训练里,从参数到损失的每一步运算都是我们自己写的公式,能求导,所以评审可以顺带算出“每个参数对结果的影响”。上一篇第十一节专门比过这一点:只看结果好坏的搜索,参数一多就走不动;能拿到每个参数坡度的梯度下降,步数几乎不随参数个数上涨。
不过,评审意见具体,不代表照着改就一定变好。这正是人担心的那件事:新方案可能还不如旧方案。训练里会不会也这样?
现象:每一步并不保证变好
会,而且非常频繁。
我们训练一个小网络来做一个分类题:平面上有两条交错的螺旋,200 个点,每个点属于其中一条,网络要学会判断任意一个点属于哪条。
这个网络由神经元搭成,后文的实验都用它。一个神经元只做一件很小的事:把收到的几个数各乘一个系数,加起来,再加一个常数,最后把结果压进 −1 到 1 之间(图 2 左)。乘的系数叫权重,表示每个输入有多重要;加的常数叫偏置,用来整体抬高或压低;压的那一步用的函数叫 tanh,结果越大越贴近 1,越小越贴近 −1,在 0 附近差不多原样输出。“神经元”这个名字来自它粗略地模仿了脑细胞:收到好几路信号,各有轻重,总量够了才兴奋起来。如果没有最后压的那一步,不管叠多少层,整个网络都只是一次加权求和,只能用一条直线去分两类点;有了它,网络才能画出弯曲的分界线。
把很多个神经元并排放,就是一个网络(图 2 右)。每个神经元都读同一个点的两个坐标,但各有各的权重,于是各自对平面上不同的区域敏感;最后把它们的输出再各乘一个权重(叫这个神经元的输出权重)加起来,再加一个偏置,得到一个分数,大于 0 判为第一条螺旋,小于 0 判为另一条。训练要调的参数,就是所有这些权重和偏置。
这里用 64 个神经元,一共 257 个参数。真实的大模型训练不会每步都用全部数据,而是每步随机抽一小批,这里每步只抽 20 个点来算梯度。
每走一步,我们都用全部 200 个点量一次损失(图 3)。本文的实验都只用 numpy 写成,脚本和日志见参考资料2。
细线上下乱跳。前 1000 步里,有 494 步走完以后整体损失比走之前还高;一共 10000 步里,有 3774 步是在“改坏”。原因不难理解:每一步的评审只看了 20 道题,照着这 20 道题改,对这 20 道题有利,对其他 180 道题可能不利。可是把前后几十步平均起来看,粗线一路往下,最后整体损失从 0.70 降到 0.0012,200 个点全部判断正确。
这和人改方案其实是一回事:单独一轮的改动可能是错的,但只要评审不断,下一轮会把它纠回来。 训练的不同之处只是一轮极便宜,改坏了也就是几毫秒的事,所以它敢每轮只改一点点、改上几万轮,而不必像人那样每轮都想清楚再动手。
可是,每一步只看脚下的坡度,就像在雾里下山。会不会走进一个小坑,四面都是上坡,再也出不来?
二、会不会卡在半路
一个参数时,确实会卡
先看最简单的情况:只有一个参数 w,损失随 w 变化的曲线有两个谷(图 4)。
从 −0.6 出发,坡度一直指向左边,走到更深的谷,损失 −5.64。从 0.6 出发,坡度指向右边,走到右边那个浅一点的谷,损失 −2.44。到了那里,往左往右都是上坡,坡度是 0,梯度下降就停了。它并不知道左边还有一个更深的谷,因为它只看脚下。
这种四面都是上坡、但又不是最低的地方,叫局部极小。如果大模型的损失地形里到处都是这种坑,训练就会像人凭局部经验改方案一样,常常停在一个“改哪儿都更差、但其实不是最好”的方案上。
那真实的网络里到底卡不卡?我们直接试。
实验:神经元越多,越不容易卡
第一个任务是 XOR,也就是“异或”:平面上 4 个点,(−1, −1) 和 (1, 1) 标 0,(−1, 1) 和 (1, −1) 标 1。它很小,但一条直线分不开这两类,所以网络里至少要有 2 个神经元才学得会。第二个任务是上面那两条螺旋。两个任务都用全部样本一起算梯度,走法里没有任何随机性,唯一随机的是参数的起点。我们只改隐藏神经元的个数,每种个数从很多个随机起点各训练一遍,看有几次学会(表 1)。
| 神经元 | 参数个数 | 学会的次数 | 最差一次停在 |
|---|---|---|---|
| XOR(4 个点) | |||
| 1 | 5 | 0 / 100 | 0.693 |
| 2 | 9 | 74 / 100 | 0.347 |
| 3 | 13 | 98 / 100 | 0.347 |
| 4 | 17 | 100 / 100 | 0.001 |
| 8 | 33 | 100 / 100 | 0.001 |
| 32 | 129 | 100 / 100 | 0.000 |
| 两条螺旋(200 个点) | |||
| 2 | 9 | 0 / 40 | 0.679 |
| 4 | 17 | 0 / 40 | 0.340 |
| 8 | 33 | 40 / 40 | 0.004 |
| 16 | 65 | 40 / 40 | 0.001 |
| 32 | 129 | 40 / 40 | 0.001 |
| 64 | 257 | 40 / 40 | 0.001 |
学会:训练后平均损失低于 0.05。XOR 每种 100 个起点、走 5000 步;螺旋每种 40 个起点、走 2 万步。学习率都是 0.5,全部样本一起算梯度,没有随机性。
规律很清楚。XOR 用 2 个神经元时,100 个起点里有 26 个卡住了,每个都停在同一个损失 0.347;用 3 个时只剩 2 个卡住;4 个以上,100 个起点全部学会。螺旋也一样:2 个、4 个神经元一次都学不会,8 个以上次次学会。同样的任务、同样的走法,只是参数多了,卡住就没了。
这和直觉相反。参数多了,要调的东西更多,按说应该更难才对。为什么反而更容易?
卡住的地方长什么样
我们去看 XOR 那 26 个卡住的起点。它们停下的样子都一样:4 个点里 2 个判断对了,另外 2 个判断成“一半一半”,平均损失 0.347。再多走 10 万步,损失只从 0.3470 降到 0.3466,确实是停住了。
怎么知道四周有没有下坡?对一个参数,看曲线是向上弯还是向下弯就行。对 9 个参数,可以算出损失在各个方向上的弯曲程度:往某个方向挪一点,损失像开口向上的抛物线那样变大,就是向上弯;像开口向下的抛物线那样变小,就是向下弯。结果是:9 个方向里,1 个向上弯,8 个几乎完全平,没有一个向下弯。这是一片四周没有下坡的平地,梯度下降在这里没有任何方向可走。
现在给这个卡住的网络加第 3 个神经元,它的输入权重和输出权重全部设成 0。这个神经元什么也不输出,网络算出来的结果和原来一模一样,损失还是 0.3466。可是参数从 9 个变成了 13 个,我们再量一次各个方向的弯曲:多出了一个向下弯的方向(图 5)。
图 5 里有个很像人改方案的细节。在这个点上,13 个参数单独改哪一个,从 −3 一直改到 3,损失都纹丝不动,最好还是 0.3466。原因是新神经元的两个权重互相“卡着”:输出权重是 0,输入权重怎么改都传不出去;输入权重是 0,这个神经元什么也没算出来,输出权重怎么改也没用。只有两个一起改,一正一负,损失才往下掉,一个改到 3、一个改到 −3 时只剩 0.025。
我们给 26 个卡住的网络都加上这样一个神经元,只是把它的权重设成很小的随机数(0.01 量级)而不是正好 0,然后接着训练。26 个全部走了出来:100 步后损失降到 0.03 到 0.08,2 万步后都在 0.0003 左右。小随机数的作用是让它不正好站在平地中央,一旦偏离一点点,向下弯的方向就会把这点偏离越放越大。真实训练里,随机初值和小批量带来的抖动,起的就是这个作用。
像这样“有的方向向上弯、有的方向向下弯”的点,叫鞍点,像马鞍:顺着马背方向是上坡,横着马背方向是下坡。梯度下降在鞍点附近会走得很慢,看起来像卡住了,但它不是死路。
为什么参数越多,死路越少
一个点要成为真正的死路,必须每个方向都向上弯,或者至少没有一个方向向下弯。方向越多,这个条件越难满足。
可以用一个粗糙的模型感受一下:假设每个点在各个方向上的弯曲是随机的,有的向上、有的向下。我们随机生成这样的弯曲,数一数“所有方向都向上弯”的比例:1 个方向时是 50%,2 个方向 14.7%,3 个方向 2.5%,4 个方向 0.26%,5 个方向 0.01%,到 6 个方向,20 万次里一次也没有出现。比例掉得比“每多一个方向减半”还快得多。
真实网络的弯曲当然不是随机的,所以这只是一个直觉。但研究者对大网络的分析得出了同样方向的结论:在损失还很高的地方,绝大多数停下来的点都是鞍点而不是死路3;网络越大,真正的局部极小越集中在损失很低、彼此差不多的一小段里4。换句话说,参数多到一定程度以后,大部分“坑”都有出口,没有出口的坑本身就已经很深了。
好的解不是一个,而是一大片
还有一个原因让训练不需要“找准”:好的解非常多。
XOR 用 8 个神经元时,100 个起点全部学会,但它们最后的参数值各不相同。原因之一是对称:把第 1 个神经元和第 3 个神经元的全部权重对调,网络算出来的东西完全不变;把一个神经元的输入权重和输出权重同时取反,结果也不变。8 个神经元的排列有 8! = 40320 种,每个还能取反,于是每一个解都至少有 40320 × 2⁸ ≈ 1032 万个参数不同、效果完全相同的“分身”。大模型每层有上万个神经元,这个数大到没有意义。
更进一步,研究者发现,从不同起点训出来的两个解,往往能找到一条连着它们的路径,路上的损失一直很低56。好的解不是散落在山里的几个针尖,而是连成一片的低洼地带。训练不需要找到“那一个”解,只需要走进这片洼地。
到这里,第一个疑问有了答案:训练能找到不错的解,不是因为它每一步都对,而是因为参数足够多时,死路很少、好解很多、连成一片,只要一直往下走,大概率会走进去。
那么,走进去之后继续训练,能不能把每个参数都调到最优?
三、继续训,能不能让每个参数都最优
“每个参数都最优”指的是什么
先得想清楚这句话的意思。一个参数的最好取值,取决于其他所有参数现在是多少:图 5 里新神经元的输入权重,在输出权重为 0 时取什么都一样,在输出权重为 3 时,取 3 就比取 0 好得多。所以单独说“某个参数的最优值”没有意义,就像单独说“一个方案里预算的最优值”没有意义,它要看方案里的其他部分怎么定。
梯度下降最多能保证的是:走到坡度为 0 的地方,此时单独把任何一个参数往任何方向微调一点,损失都不会再降。但图 5 的那个点也满足这一条,13 个参数每一个单独看都“最优”,整体却离最好差得很远。所以梯度下降从来没有保证过每个参数都最优,它连“走到坡度为 0”都不保证。
大模型根本没走到底
真实的大模型训练,是在还没走到底的时候主动停下的。
训练一个模型的算力预算是固定的。2022 年 DeepMind 的 Chinchilla 研究算过:同样的预算,与其把一个大模型训到底,不如把模型做小一点、多喂一些数据7。照这个算法,80 亿参数的模型大约喂 2000 亿个词元最划算。Meta 训练 Llama 3 时给 8B 和 70B 两个模型都喂到了 15 万亿个词元,远超这个数,并且说两个模型到这时性能仍在稳定提升8。也就是说,它们发布时都还走在下坡路上。训练末期学习率会降到很小,那是为了让参数在当前位置停稳,而不是因为到了谷底。
训练损失越低越好吗
就算有无限的算力,能把训练损失一直降下去,也未必是好事。
我们换一个更像现实的实验:螺旋只给 120 个点,而且故意把其中 22 个点的标签标错,模拟真实数据里的噪声和错误。网络有 256 个神经元,1025 个参数,比点多得多。另外准备 4000 个训练时没见过、标签正确的点,用来检查模型是否真的学会了(图 6)。
训练损失一路从 0.71 降到 0.004,120 个训练点全部“判断正确”,连那 22 个标错的点也照着错的标签背了下来。可是在没见过的点上,损失在第 3000 步最低,只有 0.44,之后一路升到 2.97;判断的正确率也从 77% 降到 73%。训练越久,模型越是在迁就那 22 个错误,越不像真正的螺旋。参数足够多的网络连完全随机的标签都能背下来9,所以“训练损失降得越低”和“模型越好”并不是一回事。
这就是人类评审里常说的“为了过评审而过评审”。评审标准一旦写死,把它做到极致,就不等于把事情做好。 训练损失只是我们关心的东西的一个代理。所以实际训练会单独留一份不参与训练的数据,专门看模型在没见过的题上表现如何,在那里变差之前停下,这叫早停。大模型的数据多到每段文字大多只看一遍,背题的问题轻得多,但同样会留出验证数据一直盯着。
所以训练里那一个写死的评审并不完美。人的那些来回评审,是被它取代了吗?
四、人的评审去了哪里
没有被取代,而是被挪到了训练外面(图 7)。
定评审标准,本身就是最难的一轮评审。 训练只会把写好的损失做低,不会问这个损失定得对不对。人做方案时“要考虑这么多”的那些因素,好用、安全、不胡说、符合语气,要么被折进损失和数据里,要么就不会被训练关心。语言模型的损失只是“下一个词猜得准不准”,训练语料选什么、怎么配比,决定了“猜得准”最后意味着什么。
定怎么训,也只能一轮轮地试。 模型多大、学习率多少、训多久,这些没有梯度可算。上一篇讲过,大模型团队通常先在小模型上试好这些选择,再放大;放大后训一次就要几周到几个月。
训练完,还是要人来看。 在没见过的题和基准测试上评测,让人读模型的回答、挑毛病,发现问题就改数据、改设置,重新训练。这一圈才是真正对应人改方案的那个循环,一轮很贵,一共也就转几十轮。
人的评审也可以被做成损失。 ChatGPT 这一类模型的做法是:让人对同一个问题的几个回答排序,用这些排序训练一个专门打分的模型,叫奖励模型,再拿它当评审去训练语言模型10。人的判断就这样被折进了一个可以求导的分数里,内层循环又能自动转起来了。可它同样会被钻空子:对着奖励模型一直优化,奖励模型给的分一直涨,换更可靠的方式去评,真实质量却是先升后降11,和图 6 是同一个形状。所以这个评审本身,还需要人在外层继续评审。
五、回到开头
现在可以回答开头那个问题了:这里面没有魔法,那些来回评审一轮也没有省掉,只是被拆开重新分配了。
能写成公式的那部分评审,交给了损失。它每一轮给出的不是“好或不好”,而是每个参数各自该往哪边改、改多少;一轮又便宜到可以转上几万几十万次,所以单独一轮改坏了没关系,下一轮会纠回来。参数多到一定程度以后,损失地形里的死路很少,好解很多、连成一片,只要一直往下走,大概率会走进好解的洼地。
但它找到的不是最优解,也不需要是。“每个参数都最优”本来就说不清;大模型都是在还在下坡时就主动停下;训练损失做到极致,反而可能离我们真正想要的更远。
写不成公式的那部分评审,评审标准定得对不对,模型训出来到底好不好,依然要人一轮一轮地看、一轮一轮地改,和我们平时改方案没什么两样。
小结
- 训练里谁在评审? 损失。它是一个写死的分数,每一步都评一次;反向传播再把它拆成每个参数的修改意见,精确到方向和大小。GPT-3 被这样评审了约 9.4 万轮。
- 每一步都会变好吗? 不会。每步只看一小批题,我们的实验里前 1000 步有近一半让整体变差,但前后平均一直往下:单轮改坏了,下一轮会纠回来。
- 会不会卡在半路? 参数少时会:XOR 用 2 个神经元,100 个起点卡住 26 个。参数多了,卡住的点会变成鞍点,多出的参数提供了下坡方向,4 个神经元以上就再没卡过。方向越多,“所有方向都向上弯”越难满足,所以大网络里死路少。
- 为什么不需要找准? 好解非常多。仅神经元的对调和取反,就让每个解有海量完全等价的分身;不同起点训出的解之间往往有一条低损失的路连着。
- 继续训能让每个参数都最优吗? 不能,也不必。一个参数的最好取值取决于其他参数;坡度为 0 只说明单独微调哪个参数都没用,鞍点也满足这一条。大模型在还在下坡时就主动停下;训练损失做到极致还可能背下数据里的错误,所以要用没见过的数据盯着、及时停下。
- 人的评审去哪了? 挪到了训练外面:定损失和数据、定训练设置、评测、人看回答、改了再训。人的判断还可以训成奖励模型,变成新的损失,但它同样会被钻空子,仍需人在外层把关。
参考资料
Footnotes
-
Language Models are Few-Shot Learnersarxiv.org ↗表 2.1:175B 模型批大小 320 万词元,共训练 3000 亿词元,两者相除约 9.4 万步。https://arxiv.org/abs/2005.14165 ↩
-
本文的实验脚本与日志项目共享目录
gradient-why-works-research/:experiment/mlp.py是一隐层网络和手写的反向传播,e_sgd.py小批量锯齿,e_width.py宽度与卡住,e_stuck.py、e_escape_hess.py、e_one_at_a_time.py卡住的点和加一个神经元,e_saddle.py随机弯曲的比例,e_overfit.py过拟合,build_figs.py生成文中的图和表。只用 numpy。 ↩ -
Identifying and attacking the saddle point problem in high-dimensional non-convex optimizationarxiv.org ↗论点:高维优化的主要障碍不是误差很高的局部极小,而是大量鞍点,它们周围的平地会让训练变慢,看起来像卡住。https://arxiv.org/abs/1406.2572 ↩
-
The Loss Surfaces of Multilayer Networksarxiv.org ↗在简化假设下论证:网络越大,局部极小的损失越集中在一个很窄的低值带里,差的局部极小越来越少。https://arxiv.org/abs/1412.0233 ↩
-
Loss Surfaces, Mode Connectivity, and Fast Ensembling of DNNsarxiv.org ↗https://arxiv.org/abs/1802.10026 ↩
-
Essentially No Barriers in Neural Network Energy Landscapearxiv.org ↗https://arxiv.org/abs/1803.00885 ↩
-
Training Compute-Optimal Large Language Modelsarxiv.org ↗https://arxiv.org/abs/2203.15556 ↩
-
Introducing Meta Llama 3ai.meta.com ↗原文:8B 模型按 Chinchilla 算法约 2000 亿词元就够;8B 和 70B 训到 15 万亿词元后仍在按对数线性提升。https://ai.meta.com/blog/meta-llama-3/ ↩
-
Understanding deep learning requires rethinking generalizationarxiv.org ↗常见的图像网络可以把随机打乱的标签也背到训练误差为 0。https://arxiv.org/abs/1611.03530 ↩
-
Training language models to follow instructions with human feedbackarxiv.org ↗https://arxiv.org/abs/2203.02155 ↩
-
Scaling Laws for Reward Model Overoptimizationarxiv.org ↗对着奖励模型优化时,奖励模型给的分一直涨,用更可靠的评分去看,真实质量先升后降。https://arxiv.org/abs/2210.10760 ↩