如何在不构建更大模型的情况下提高模型质量
原文:towardsdatascience.com/how-to-improve-model-quality-without-building-larger-models-d6c8e76a86fe最近,OpenAI 公布了他们最新的模型 o1。OpenAI 并没有强调这个模型的参数大小,而是展示了由于它花费了更多时间,这个模型的表现显著更好。当你向模型提问时,它通常需要几秒钟的时间来回答——这与大
原文:
towardsdatascience.com/how-to-improve-model-quality-without-building-larger-models-d6c8e76a86fe
最近,OpenAI 公布了他们最新的模型 o1。OpenAI 并没有强调这个模型的参数大小,而是展示了由于它花费了更多时间,这个模型的表现显著更好。当你向模型提问时,它通常需要几秒钟的时间来回答——这与大多数人现在对大型语言模型(LLMs)期望的毫秒级速度大相径庭。尽管如此,这额外的时间似乎得到了回报,因为 o1 在 LMSYS Chatbot Arena 上的得分显著高于其他模型。
在性能有了这样的飞跃之后,每个人都在问的问题是,他们是如何做到这一点的?
Lmsys Chatbot Arena 数学排名截图,日期为 2024 年 9 月 23 日
尽管 OpenAI 没有公开说明他们是如何取得这些成果的,但最近有几篇论文可能是幕后发生事情的好候选。其中一篇论文是"Optimally Scaling LLM Test-Time Compute Can Be More Effective than Scaling Model Parameters"。这篇论文探讨了如何利用测试时间计算来提高模型的准确性。
让我们深入探讨这篇论文。
你可能会问的第一个问题是,什么是测试时间计算?一般来说,在构建 LLMs 时,有两个主要的计算点:预训练和推理。预训练是我们将大量标记通过我们的模型,并使用熵损失和反向传播来教会模型如何更好地预测下一个标记的时候(更多关于这一点在我的系列文章中)。推理是当用户提示我们的模型时,我们需要向该用户提供结果的时候。推理也被称为“测试时间”。
这里的基本问题是,我们能否以牺牲用户等待时间为代价,给用户提供更好的结果?
构建优化问题
论文的作者将这个问题框架为一个优化问题。我们被给予有限的计算量和用户的查询,我们的目标是确定对该查询的最佳计算分配。如果我们给它太多,那么我们就浪费了金钱。如果我们给它太少,那么我们就失去了客户的信任。
重要的是,并非所有查询都是平等的。有些容易,需要的计算量比难度大的查询要少。因此,为了真正优化我们的计算,我们需要了解查询的难度。他们确定难度的方法是通过pass@1
难度
正如你可以想象的,我们的问题越困难,我们就越希望模型进行推理。重要的是,难度取决于你使用的模型——一种方法并不适合所有人。因此,我们必须以可以适应新模型的方式确定难度。对于这篇论文,作者计算了 PRM800K 数据集中的问题的pass@1。
你可以通过将每个问题运行 2048 次来找到pass@1。得到正确答案的比率就是你的pass@1比率。自然地,找到这些值是非常昂贵的——粗略的计算表明你需要计算大约 163,840,000 次前向传递!请注意,这种定义难度的方法与模型回答问题直接相关。如果你改变模型,预期是相同的问题的pass@1比率将会改变。
作者决定,精确的pass@1比率并不像相对难度那样重要。因此,他们将问题根据其pass@1比率分成五分位数。
在问题明确之后,作者探索了两种方法来改进测试时的模型行为。首先,他们设计了让模型探索多个答案并选择最佳答案的方法。其次,他们探索了微调模型,使其自然地对其自己的答案进行评估。他们将这种调整称为调整提案分布。
与验证者一起扩展测试时间计算
我们的第一种策略是大量依赖验证者。我们将一次性生成几个答案,当 LLM 输出这些答案时,我们将在特定时间停止它以获取验证者的反馈。基于那个验证者的反馈,我们将确定哪些答案需要继续工作。
过程监督奖励模型验证者
自然地,有许多方法可以构建验证者。我们可以使用 LLM 作为评判者(我们要求 LLM 对答案进行评分),但这可能会非常昂贵。
相反,我们的作者构建了一个单独的较小模型,该模型在 PRM800K 数据集上进行了训练(该数据集是在"Let’s Verify Step by Step"论文中创建的)。在该论文中,作者创建了一个名为 PRM800K 的数据集(MIT 许可)。PRM 代表过程监督奖励模型,这个名字给我们提供了关于这里意图的良好提示。奖励模型被训练得如此之好,以至于当主模型生成答案时,奖励模型可以介入并确保其思考过程是正确的。
作者探索了三种方法来确定何时停止潜在的答案并从验证者那里获取反馈。
图 2 来自论文
N 中最佳
在这里,我们简单地生成 N 个不同的响应,然后使用我们的验证器选择最佳的一个。这是最便宜的选择,因为在最后你只有 N 个选项,如果其中一个走错了方向,就无法纠正。这里的减速也是最小的,因为我们通过 N(基模型的 N 次前向传递)来减速,然后无论验证器模型确定哪个分支最佳所需的时间如何。
束搜索
束搜索类似于BFS(广度优先搜索)。在这里,我们也生成 N 个样本,但在每一步(生成一些任意数量的标记)后,我们评估哪个 M 个分支最有希望,并继续从这些分支生成更多标记。这继续进行,我们再采样 N 个样本,然后从这些样本中选择 M 个分支。
我们使用验证器来确定哪些是可行的。这的优势是查看许多不同的可能性,同时仍然将计算集中在最有希望的分支上。缺点是必须更频繁地运行验证器,这增加了时间成本。
预先搜索
预先搜索进一步扩展了束搜索。我们不是通过使用验证器对到目前为止产生的标记进行验证来确定分支的可行性,而是进一步采样 k 步(这是在 0 温度下进行的)。然后我们将这个更长的链传递给验证器以确定其可行性。这里的优势是你可以拥有最多的信息,但这也带来了最大的时间成本和计算开销。
验证器方法的结果
我们首先比较了在有限计算资源下搜索的比较情况。使用束搜索时,我们将约束 M 设置为从每个批准的分支继续向下扩展的分支数量。使用预先搜索时,我们将约束 M 设置为在验证器运行之前生成的标记数量。下面的左图显示,虽然最初束搜索比 Best-of-N 和预先搜索表现更好,但一旦计算预算足够大,其他方法很快就能迎头赶上。
图 3 来自论文
右边的图根据问题的五分位数难度比较了这些选项。正如预期的那样,束搜索由于其考虑的可能性更多,在难度较高的水平上比 Best-of-N 表现更好。
精炼提案分布
作者现在将注意力转向在测试时让模型迭代改进其答案。虽然要求模型简单地改进其答案并不总是能产生更好的结果,但他们决定调整他们的语言模型,以便模型本身在给出最终答案之前决定迭代其第一想法。
微调数据生成
作者希望他们的数据能够展示多轮交流(想象一下许多参与者相互交谈的对话)中,在答案的第一轮迭代中犯的小错误会在之后得到纠正。这种设置被假设为教会模型如何挑选这些错误并进行修正。当然,这里的危险在于你可能会教会模型犯某些错误,从而增加它们在测试时重复这些错误的风险。
有趣的是,为这个生成足够的微调数据具有挑战性。为了充分利用他们的计算资源,作者为每个问题并行采样了 64 个回答。然后他们取所有正确答案,并随机在 0 到 4 个错误答案之间添加到上下文中。这段最后的文本将被添加到微调数据集中。
他们希望错误的答案逐渐接近正确答案,因此为了找到最接近的错误答案,他们使用字符编辑距离度量来对错误答案进行排序并选择最佳错误答案。对于他们需要的剩余错误答案,他们简单地从错误答案中随机采样。他们没有透露他们使用哪种编辑度量,但一些常见的字符编辑算法是Levenshtein 距离和Damerau–Levenshtein 距离。似乎很可能是从这些度量中的一个派生出来的。有趣的是,他们没有使用他们的编辑度量来选择逐渐减少错误的答案添加到上下文中——据我所知,他们没有提到为什么没有选择这种方式。
图 5 的部分来自论文显示序列与并行采样
推理时对微调模型的调整
作者发现,通过多次在同一问题上运行模型,然后将最近的 4 个答案放入上下文中,可以提高模型的pass@1率。下面的图表显示,随着继续生成,准确性会有相当大的提升。
图 6 的部分来自论文
由于模型被训练为期望上下文中的错误答案,它有时会将正确答案变成错误答案。作者发现大约 38%的上下文中的正确答案会变成错误答案。为了避免这个问题,作者使用了上述技术和验证器模型来帮助引导模型使用正确答案。
图 5 的部分来自论文
平衡序列和并行生成
在应用了他们的修正后,作者们好奇并行生成答案与测试时顺序生成答案相比如何。他们比较了多次使用微调模型生成正确答案与让它并行生成答案的情况。他们发现顺序生成略优于并行生成。
图 6 的部分 来自论文
作者们假设并行和顺序生成有不同的优势和劣势。并行生成让模型考虑更多的选项(不受先前答案的影响),而顺序生成则让模型专注于先前答案的思考。简单来说,如果你在正确的道路上,顺序生成是关键,但如果你不在正确的道路上,并行生成非常有帮助。
为了在两者之间取得平衡,作者们尝试了多种不同的顺序和并行生成的比率。他们发现,在选择比率时,问题难度最为重要——简单的问题从更多的顺序计算中受益更多,而难度更大的问题则需要更多的平衡。
图 7 来自论文
使用预训练计算优化测试时花费
现在我们已经看到增加测试时的计算可以增强模型的答案,作者们想知道测试时计算可以推进到什么程度。有没有一种方法可以通过测试时计算使较小的模型比较大的模型更好?
作者们特别从计算花费的角度来看这个权衡。他们使用以下公式来估计训练和推理特定参数大小模型所需的浮点运算次数(FLOPS)。N 代表参数数,D 代表使用的标记数(无论是预训练还是推理时间)。
对于像预训练这样的任务,可以通过将数据集中的标记数乘以你将要训练的 epoch 数来找到使用的标记数。一般来说,对于更大的参数模型,预训练需要更多的计算。对于推理,我们的估计将会有更大的变化——预测总查询数并将其乘以平均响应的标记数。
记住,这里的想法是我们有一个固定的计算预算,因此我们需要在训练模型和推理模型之间分配它。
用于估计预训练 FLOPS 的方程 来自论文
用于估计推理 FLOPS 的方程式来自论文
下面的图表显示了两个方面的内容——(1)增加测试时计算的开支如何提高性能;(2)在推理和预训练上投入资金哪个更有效。
要解释如何理解(2),我们需要关注星号。星号出现在图表上,以显示用 14 倍更多参数预训练模型所花费的等效 FLOPS 的性能。如果星号位于测试时计算线以下,那么它表明计算在测试时得到了更好的利用。如果星号位于线上方,则表明计算在预训练上得到了更好的利用。
简而言之,这些结果表明,难度更高的题目需要比难度低的题目更复杂的模型(以及更多的预训练计算),尽管性能的提升通常与更高的计算预算相关。此外,如果我们预期会有大量的推理标记,那么在预训练上投入更多的计算将更为有效。
结束语
随着测试时计算能力的提升所带来的性能增益,我们可以预期人们会迅速采用这种方法。虽然 PRM80K 数据集是免费提供的,但我们尚未看到许多公开可用的验证器模型。如果这些模型成为开源,那么观察这些模型需要多么复杂才能确保高质量的性能将会非常有趣。此外,我们在这里看到的是,关于客户用例的数据越多,你的推理成本结构就可以越低。
现在是构建的激动人心时刻。
[1] Snell, C.,等人,“最优地扩展 LLM 测试时计算比扩展模型参数更有效”(2024),arXiv
[2] Lightman, H.,等人,“让我们一步步验证”(2023),arXiv
[3] Open AI 团队,“介绍 OpenAI o1”(2024),OpenAI
更多推荐



所有评论(0)