大语言模型能从单个示例中学习吗?
我们在微调大语言模型时观察到一个不寻常的训练模式。最初我们以为这是个错误,但现在我们认为这表明大语言模型能够从单个示例中有效学习。
神经网络如何学习
我们通过向神经网络展示输入和输出的示例来训练神经网络分类器,它们学会根据输入预测输出。例如,我们展示狗和猫的图片以及每个品种,它们学会从图像中猜测品种。更准确地说,对于可能的品种列表,它们输出对每个品种概率的猜测。如果不确定,它会猜测每个可能品种的概率大致相等;如果高度自信,它会猜测预测品种的概率接近1.0。
训练过程包括将训练集中的每个图像以及正确标签展示给网络。遍历所有输入数据称为“一个周期”。我们需要提供许多训练数据示例,模型才能有效学习。
在训练期间,神经网络试图减少损失,这(粗略地说)是衡量模型出错频率的指标,高度自信的错误预测受到最大惩罚,反之亦然。我们在每个批次后计算训练集的损失,并不时(通常在每个周期结束时)也计算模型无法学习的一批输入的损失——这是“验证集”。以下是我们在11个周期训练时的实际情况:
如您所见,训练损失逐渐(且颠簸地)相对快速改善,随时间推移减慢,验证损失改善更慢(如果训练时间更长,最终会完全平坦,然后最终变差)。
您无法从图表中看到周期开始和结束的位置,因为模型需要许多周期才能了解任何特定图像的外观。这是神经网络发展几十年来的基本约束——它们需要非常长的时间来学习任何东西!实际上,关于为什么神经网络如此“样本低效”是一个活跃的研究领域,特别是与儿童学习方式相比。
非常奇怪的损失曲线
我们最近一直在从事Kaggle大语言模型科学考试竞赛的工作,该竞赛“挑战参与者回答由大语言模型编写的困难科学问题”。例如,这是第一个问题:
问题:以下哪个陈述准确描述了修正牛顿动力学(MOND)对星系团中观测到的“缺失重子质量”差异的影响?
(选项A-E略)
显然,正确答案是D。
幸运的是,我们不必依赖对修正牛顿动力学的知识来回答这些问题——相反,我们的任务是训练模型来回答这些问题。当我们将模型提交到Kaggle时,它将针对数千个我们看不到的“保留”问题进行测试。
我们在朋友Radek Osmulski创建的大型问题数据集上训练了我们的模型3个周期,并看到了以下最意想不到的训练损失曲线:
这里的问题是,您可以清楚地看到每个周期的结束——损失突然下降。我们以前见过类似的损失曲线,它们总是由于错误。例如,很容易意外地让模型在评估验证集时继续学习——这样在验证后模型突然显得更好。因此我们开始寻找训练过程中的错误。我们使用的是Hugging Face的Trainer,所以我们猜那里一定有错误。
当我们开始逐步检查代码时,我们还在Alignment Lab AI Discord上询问了其他开源开发人员是否见过类似的奇怪训练曲线,几乎每个人都说“是的”。但每个回复的人都也在使用Trainer,这似乎支持了我们关于该库中存在错误的假设。
但随后Discord上的@anton告诉我们,他在自己的简单自定义训练循环中也看到了这种曲线:
……他还向我们展示了这个伴随的极其令人惊讶的验证损失曲线:
然后我们开始听到越来越多Discord朋友说他们见过类似的奇怪行为,包括不使用Trainer时。我们想知道这是否是我们使用的LoRA方法特有的奇怪现象,但我们听说在进行完全微调时人们也看到了相同的模式。事实上,在大语言模型微调社区中,这基本上是常识,当您做这类工作时就是这样!……
深入挖掘
我们从开源同事那里不断听到的假设是,这些训练曲线实际上显示的是过拟合。起初,这似乎相当不可能。这意味着模型仅从一两个示例中学会识别输入。如果您回头看我们展示的第一个曲线,您可以看到损失在第一个周期后从0.8下降到0.5,然后在第二个周期后从0.5下降到0.2以下。此外,在第二和第三个周期中的每一个期间,它根本没有真正学到任何新东西。因此,除了在第一个周期开始时的初始学习外,几乎所有明显的学习都是(根据这个理论)对训练集的记忆,每行仅用3个示例发生!此外,对于每个问题,它只获得少量信号:它对答案的猜测与真实标签相比如何。
我们尝试了一个实验——我们训练我们的Kaggle模型两个周期,使用以下学习率计划:
如今这种计划并不那么常见,但这是Leslie Smith创建后取得很大成功的方法,他在2015年的论文《Cyclical Learning Rates for Training Neural Networks》中讨论了它。
这是我们因此看到的疯狂外观的训练和验证损失曲线:
我们想出的(到目前为止!)完全解释这张图片的唯一事情是假设是正确的:模型正在快速学会识别示例,即使只看到它们一次。让我们依次研究损失曲线的每个部分……
看第一个周期,这看起来是一个非常标准的损失曲线。我们在周期的前10%有学习率预热,然后按照余弦计划逐渐减小。一旦学习率达到温度,训练和验证损失迅速减少,然后随着学习率减小和“快速胜利”被捕获,它们都减慢。
第二个周期是变得有趣的地方。我们在周期开始时没有重新洗牌数据集,所以第二个周期的第一批次是学习率仍在预热的时候。这就是为什么我们没有看到像我们在第一个损失曲线中从周期2到3那样的立即阶跃变化——这些批次只在学习率低时被看到,所以它无法学到太多。
在周期前10%接近结束时,训练损失暴跌,因为这些批次在第一个周期期间被看到时学习率高,模型已经学会了它们的样子。模型很快学会它可以非常自信地猜测正确答案。
但在此期间,验证损失受到影响。这是因为尽管模型变得非常自信,但它实际上在做出预测方面并没有变得更好。它只是记住了数据集,但没有提高泛化能力。过度自信的预测导致验证损失变差,因为损失函数对更自信的错误惩罚更高。
曲线末端是事情变得特别有趣的地方。训练损失开始变差——这真的不应该发生!事实上,我们两人都不记得在使用合理学习率时以前见过这样的事情。
但实际上,在记忆假设下,这完全合理:这些是模型在学习率再次下降时看到的批次,所以它无法像有效地记忆它们。但模型仍然过度自信,因为它刚刚几乎完美地正确获得了一大堆批次,并且尚未调整到它现在看到的批次它没有机会学得那么好的事实。
它逐渐重新校准到更合理的置信水平,但这需要一段时间,因为学习率越来越低。当它重新校准时,验证损失再次下降。
对于我们的下一个实验,我们尝试在3个周期上进行1cycle训练,而不是CLR——也就是说,我们在训练开始时对前10%的批次进行单一学习率预热,然后按照余弦计划在剩余批次上衰减学习率。以前,我们对每个周期进行了单独的预热和衰减循环。此外,我们增加了LoRA秩,导致学习变慢。这是产生的损失曲线:
形状大致遵循我们基于先前讨论的预期,除了一件事:验证损失在周期2没有跳升——直到周期3我们才看到那个跳升。然而以前训练损失在第二个周期左右约为0.2,这只有在做出高度自信预测时才可能。在1cycle示例中,直到第三个周期它才做出如此自信的预测,直到那时我们才看到验证损失的跳升。
重要的是要注意,验证损失变差并不意味着我们在实践中过拟合。我们通常关心的是准确性,模型过度自信是可以的。在Kaggle竞赛中,用于排行榜的指标是平均精度@3(MAP@3),这是模型做出的排名前3多项选择预测的准确性。以下是先前图表中显示的1cycle训练运行的每批次验证准确性——如您所见,它持续改进,即使验证损失在最后一个周期变差:
如果您有兴趣深入挖掘,请查看这份报告,其中Johno分享了一些额外示例的日志,以及一个笔记本,供那些希望自己看到这种效果的人使用。
记忆假设如何可能是真的?
没有基本定律说神经网络不能从单个示例中学会识别输入。这只是研究人员和实践者在实践中普遍发现的情况。需要很多示例,因为我们试图使用随机梯度下降(SGD)导航的损失表面太颠簸,无法一次跳远。然而,我们确实知道有些东西可以使损失表面更平滑,例如使用残差连接,如经典论文《Visualizing the Loss Landscape of Neural Nets》(Li等人,2018)中所示。
很可能预训练大语言模型在接近最小损失的区域具有极其平滑的损失表面,并且开源社区中完成的许多微调工作都在这个区域。这是围绕微调通用语言模型原始开发的基本前提。这些模型最早由我们之一(Jeremy)和Sebastian Ruder在2018年的ULMFiT论文中记录。Jeremy最初构建ULMFiT算法的原因是因为似乎任何能够做好语言建模(即预测句子的下一个词)的模型都必须在内部构建丰富的抽象层次和能力。此外,Jeremy相信这个层次然后可以轻松适应使用少量微调解决需要类似能力的其他任务。ULMFiT论文首次证明这确实正是发生的事情。
大语言模型,今天比ULMFiT中研究的模型大几个数量级,必须具有更丰富的抽象层次。因此,微调其中一个模型以,例如,回答关于科学的多项选择问题,可以很大程度上利用模型中已经可用的能力和知识。这只是以正确方式浮现正确部分的情况。这些不应该需要许多权重被大幅调整。
基于此,想到预训练语言模型带有小的随机分类头可能位于权重空间的一部分,其中损失表面平滑且清晰地指向良好权重配置的方向,也许并不令人惊讶。当使用Adam优化器(如我们所做)时,具有一致和平滑的梯度导致有效的动态学习率上升再上升,使得步骤可以变得非常大。
现在怎么办?
拥有学习非常快的模型听起来很棒——但实际上这意味着许多关于如何训练模型的基本想法可能被颠覆!当模型训练非常慢时,我们可以训练它们很长时间,使用各种数据,多个周期,我们可以期望我们的模型逐渐从我们给它的数据中提取可泛化的信息。
但当模型学习如此快时,灾难性遗忘问题可能突然变得更加明显。例如,如果模型看到十个非常常见关系的示例,然后一个不常见反例的示例,它很可能记住反例,而不是仅仅稍微降低对原始十个示例的记忆。
现在数据增强对于避免过拟合可能也不太有用。由于大语言模型在提取给定信息的表示方面如此有效,通过释义和回译混合事物现在可能没有太大区别。模型无论哪种方式都会有效地获得相同的信息。
也许我们可以通过大大增加使用诸如dropout(已经在微调技术如LoRA中少量使用)或随机深度(在NLP中似乎尚未以任何显著程度使用)等技术来缓解这些挑战。
或者,也许我们只需要小心在整个训练中使用丰富的数据集混合物,以便我们的模型永远没有机会忘记。例如,尽管Llama Code确实遭受了灾难性遗忘(当它变得更好于代码时,它在其他一切上变得差得多),但它仅用10%的非代码数据进行了微调。也许使用接近50/50的混合物,它可能变得同样擅长编码,而不失去其现有能力。
如果您提出任何替代假设,并能够测试它们,或者如果您发现任何经验证据表明记忆假设是错误的,请务必告诉我们!我们也渴望听到在这个领域的其他工作(如果这里我们未能引用任何先前工作,请道歉),以及关于我们应如何(如果有的话)根据这些观察调整我们训练和使用这些模型的任何想法。我们将密切关注这个推特线程的回复,所以如果您有任何想法或问题,请在那里回复。