从零构建 LLM(第32部分):干预实验与指令微调结果更新Writing an LLM from scratch, part 32l -- Interventions: updated instruction fine-tuning results
作者基于 Sebastian Raschka 的《Build a Large Language Model (from Scratch)》一书,持续开发一个类 GPT-2-small 模型,并通过多种干预手段尝试逼近原始 OpenAI GPT-2-small 在保留测试集上的损失表现。文章更新了最新的指令微调实验结果,探讨不同训练策略对模型性能的影响。
Giles Thomas
Archives
Categories
Blogroll
我一直在基于 Sebastian Raschka 的著作《Build a Large Language Model (from Scratch)》开发一个 GPT-2-small 风格的 LLM,并尝试了多种不同的方法,试图让它逼近原始 OpenAI GPT-2-small 的质量水平——衡量标准是在一个保留的测试数据集上的损失值。在上一篇博文中,经过一系列尝试后,我最终训练出了一个几乎(如果说还没完全达到)达到该水平的模型。
在开始深入这些改进措施之前,我为每个构建的模型都做了三项评估:一项冒烟测试(看它能否对 “Every effort moves you” 给出连贯的补全),一项测试集损失评估,以及一项指令遵循测试——该测试会对模型在 Alpaca 数据集上进行微调,让它为指令测试集生成结果,然后用一个 LLM 作为裁判来打分。
这样做的思路是:测试集上的损失是一个衡量模型质量的有意思的技术指标,但它并不能真正告诉我们这个模型在实际使用中可能有多大的用处。
遗憾的是,今年一月我意识到我的方法有问题:因为我让 LLM 单独对某个模型打分,而 LLM 本身具有天然的随机性,这就导致结果不具备真正的可比性,尤其是当模型之间质量相近时。
例如,如果两个模型对
Name the author of 'Pride and Prejudice'.的回复都是:
The author of 'Pride and Prejudice' is Sarah Palin.……那么某一次指令遵循测试可能会“碰上裁判 LLM 心情好”,给出比如 5% 的分数——毕竟模型确实尝试回答了,甚至还用了一个真实人物的名字,哪怕答案完全错误。但在另一次运行中,裁判可能“心情较差”,直接打 0%。
我的解决方案是使用两个脚本:
具体细节见此处。
由于这种方式工作量显著增加,我在“干预措施”迷你系列中一直没有进行这些测试。我觉得更合理的做法是,先尝试多种干预措施,积累一批可供测试的模型,再统一进行评估。
现在我已经有了这些模型,那就动手试试吧!
背景与上一次测试
在上一轮 IFT 测试结束时,我得到了如下表格。它按测试集损失(保留三位小数)排序,并显示了模型在一次指令微调运行中获得的分数:
总体上存在一种松散的相关性:损失越低,IFT 分数越高,但有两个奇怪的例外:FineWeb-Edu 的两次训练运行,其得分远高于根据其损失所预期的水平。
我的工作假设是,模型获得高分有两个组成部分:
这么说来,OpenAI 的模型以及 Cloud FineWeb、8x A100 40 GiB 这类模型可能很“聪明”,但知识储备未必丰富;而 FineWeb-Edu 的模型则可能显得“愚钝”,但知识面广。至于介于两者之间的模型,则可能既不够聪明,知识也不够多。
还有一个奇怪之处:Cloud FineWeb、8x A100 40 GiB 模型在 IFT 结果上的表现,相对于其 loss 值来说好得令人意外——也许存在某种阶跃函数效应,即一旦模型的 loss 降到某个阈值(比如 3.7)以下,它就会突然在关键方面变得“聪明”起来。
当然,这些都只是粗略的推测,但也算是一种假设。新的模型是否符合这种模式?是时候验证一下了。
初步运行与谜团
我不认为有必要把我在干预测试中训练的全部 14 个模型都加进那张表格,所以决定只添加其中四个:
对于其他模型,我已经有了其微调后版本的响应文件,因此只需对这四个新模型运行我的两个微调脚本中的第一个即可。
我照做了,并同时修改了评判脚本,使其不再使用 GPT-5.1,而是改用 GPT-5.4。即使多次运行脚本,每次给出的分数通常也会不同;希望排名大致保持一致。既然无论如何都得重新运行脚本来获取新的汇总结果,而这些结果本身也无法与原始结果真正可比,那么为了( hopefully)获得一个更聪明的评判器,这个代价似乎是合理的。
我运行了一次,得到了一些让我惊讶的结果——惊讶到决定再跑三次,看看结果是否稳定。确实如此;以下是新表格,包含每次运行的得分、平均值,以及基于平均值得出的排名。
可以看出,在 IFT 运行中,各模型的相对排名相当一致。但总体而言,尽管 loss 较低的模型通常 IFT 表现更好,如今这一趋势的例外情况却比之前更多了。
我们来看“IFT 排名”这一列,它是基于 IFT 平均值得出的:
这种情况确实很奇怪。如果所有使用梯度累积而非 DDP 的训练任务 consistently 更差(或者反过来),那我们或许还能找到某种关联。但实际情况是:第一次实验中 GA 优于 DDP,第二次却反过来。
除此之外,我们仍能观察到两个 FineWeb-Edu 模型的表现明显优于其他模型。其余模型在损失值和排名上都相当接近,只有 Local FineWeb 训练模型例外,它在两方面都表现不佳。
然而值得注意的是,Local FineWeb-Edu 扩展训练模型虽然训练数据量是 Local FineWeb-Edu 的两倍,但在 IFT 指标上 consistently 更差。这在我之前的测试中并未出现。
所有这些结果都让我感到困惑。“知识越多,模型在此任务上表现越好”这一观点,似乎被两个 FineWeb-Edu 模型的相对排名削弱了(毕竟,如果该观点成立,我们理应看到训练数据更多的模型 consistently 更优)。而“聪明、低损失的模型表现更好”这一边,也被 8xa100m40-stacked-interventions-1 和 1xrtx3090-baseline 的糟糕结果所 contradicted。
这里到底发生了什么?
微调轮次(Epochs of fine-tuning)
查看训练代码时,有一件事引起了我的注意。流程如下:
实际上,提前退出的机制总是很快触发。我在最初生成新模型结果时就注意到了这一点:
我决定重新生成所有模型的响应,并再次让 LLM 评判器评估这些新响应。但这一次,我会记录提前退出前实际训练了多少轮:
结果越来越难看出任何有用的规律!不过有一点确实突出:那个仍然异常高的 Cloud FineWeb、8x A100 40 GiB 模型接受了七轮指令微调。同样明显的是,两个 FineWeb-Edu 模型都表现出相同的“优势”(如果这算优势的话)。但 Local FineWeb 训练也跑了七轮,得分却很差;OpenAI 模型每轮只跑了两轮,却领跑榜单;而 1xrtx3090-baseline 尽管训练了六轮,结果也相当糟糕。
不过,如果我们排除这个干扰因素会怎样?我又做了一轮实验;这次,我修改了微调/生成脚本,强制固定为四轮训练——不再提前退出。我选四轮是因为它在之前的训练中是众数——除此之外并无特别理由。
四轮训练
最终结果如下:
依然没有明显的规律。
训练七个周期
如果我们让所有模型都训练七个周期,会怎么样?这样它们都能获得和 FineWeb-Edu 模型一样多的“好处”(如果这算好处的话)?
还是一头雾水……
汇总结果
下表汇总了这些测试中我们得到的所有排名:
从中很难得出太多结论,但有几点是明确的:
一方面,在这种评估中对不同模型采用不同训练周期数似乎不妥,因为它们被“区别对待”了。但另一方面,如果目标是真实世界中模型实用性的良好评估,那么各个模型本应根据验证损失进行不同程度的微调。所以也许这样反而更好?
但这些差异化的结果仍然令人费解。我想,现代 AI 应该能轻松为我构建一个数据探索界面,专门用于分析原始结果和七周期训练的结果,于是我问了 Claude,得到了一个相当不错的工具。
然而仔细研究之后,我仍未能找到确凿证据——例如,8xa100m40-stacked-interventions-1 总是犯某种系统性错误,导致其得分偏低。
目前我所能构建的最好的——尽管有些模糊且不完整——心理模型大致如下:如果我们考虑这些模型所处的损失 landscape,它们都已被训练至尽可能达到低损失的位置。当我们对其进行指令微调时,实际上是在改变这个 landscape——“更好地遵循指令”这一目标与“最小化损失”并不相同。
现在,这两个 landscape 可能完全不同!你可以想象一个替代指令遵循的任务,它可能与损失最小化完全无关,甚至呈负相关。
但指令遵循还算相对接近;它至少共享“生成连贯文本”这类特征。因此,在进行指令微调时,我们的目标是将模型从预训练结束时的位置,移动到在新目标——指令遵循——上表现最佳的位置。
接下来我要说得更加模糊一些。你可以很容易地设想:在某些损失较低的位置,可能存在指向新指令遵循 landscape 中优良位置的下坡路径。通过指令微调,你就能得到一个不错的 IFT 模型。
但在其他一些损失较低的位置,可能就没有这种优势;也许它们正处于或接近 IFT landscape 中的一个糟糕“局部最小值”——也就是说,那里没有通往更优位置的下坡路径。因此,像这样简单的微调可能永远无法得到好的结果!
在这种思路下,我们可以说 OpenAI 的权重不仅处于损失景观(loss landscape)中的有利位置,在指令微调(IFT)景观中也同样如此。FineWeb-Edu 模型算是运气好,恰好落到了一个(尽管损失值较高)但对 IFT 目标而言位置优越的地方。相比之下,8xa100m40-stacked-interventions-1 和 1xrtx3090-baseline 则运气不佳:它们到达的位置中,损失景观与 IFT 景观之间缺乏良好相关性。
这个解释在我看来足够合理,可以作为我目前的工作模型,并尝试找出某种方法来验证它。在指令微调过程中跟踪验证损失无疑是一个良好的开端;遗憾的是,我是在完成上述所有测试之后才意识到这一点,而重新做一遍工作量会相当大。
最后还有一点值得重申:我们那两个“运气不佳”的模型——8xa100m40-stacked-interventions-1 和 1xrtx3090-baseline——各自都有一个“孪生”模型。前者是梯度累积版 1xrtx3090-stacked-interventions 对应的 DDP 训练版本,而后者则是 8xa100m40-baseline 对应的梯度累积版本。因此,虽然显然发生了某些异常情况,但 DDP 或梯度累积本身似乎并非罪魁祸首。
我认为此时最好就此打住——我还有很多其他事情想做,而这项研究目前更像是一个支线任务。
不过,我从中得出一个主要结论:追求更低的损失值虽然在技术上有其趣味,但并非唯一目标。在某些情况下,损失更低的模型在实际使用中反而可能表现更差。
接下来:我将结束这个关于“干预措施”的迷你系列,转向我从零开始构建 LLM 之旅的最后阶段。到时见!
需要完整排版与评论请前往来源站点阅读。