对应:Stanford CS329A Autumn 2025 Lecture 2(Fri 9/26,Test-time Compute Scaling)。阅读材料:Large Language Monkeys(Brown et al. 2024)、Archon(Saad-Falcon et al. 2024)、Scaling LLM Test-Time Compute Optimally can be More Effective than Scaling Model Parameters(Snell et al. 2024)、How Do Large Language Monkeys Get Their Power (Laws)?(Schaeffer et al. 2025)。幻灯片没有公开,本讲依据这四篇论文编写。 配套代码:
code/lecture02/(只用 Python 标准库;最慢的文件约 12 秒) 预计阅读时间:3~4 小时(含运行代码)
0. 本讲导航
0.1 学完本讲,你应该能够
- 把各种 test-time 技巧放进一张地图:改变生成分布(并行采样、顺序修改、更长的 CoT)vs 对着 verifier 搜索(best-of-N、beam search、lookahead);并行 vs 顺序。
- 说出 Large Language Monkeys 的主要发现:coverage 随采样数跨越四个数量级持续增长、可以用 exponentiated power law 拟合、在可验证的任务上直接变成成绩、在不可验证的任务上被挑选方法卡住。
- 解释”每道题的失败率是指数衰减,整体却是 power law”这个谜题,推导出 power law 的指数等于单次成功率分布在 0 附近的形状;说出什么时候会偏离 power law。
- 说出 Snell et al. 的核心结论:最优的 test-time 策略取决于题目难度——简单题适合顺序修改,难题需要并行探索(或两者的某个比例);按难度分配(compute-optimal)比 best-of-N 高效好几倍。
- 写出 FLOPs-matched 比较的公式,解释为什么”小模型 + test-time compute 能不能替代大模型”取决于题目难度和推理负载 。
- 说出 Archon 的思路:把推理技巧的组合当作架构搜索问题;说出不同任务上最有用的组件为什么不同(推理任务靠验证、代码靠 unit test、开放式任务靠融合)。
- 在比较 test-time 方法时,正确地对齐预算、区分开发集和测试集、注意挑选方法本身的上限。
0.2 先修知识
| 知识点 | 用在哪里 | 最低要求 |
|---|---|---|
| 第 1 讲 | 全讲 | coverage、pass@k 的无偏估计、temperature、generation–verification gap、toy world |
| 概率 | 第 3 节 | 期望、积分的直觉(“按分布加权平均”);Beta 分布第 3.3 节会介绍 |
| 对数与幂 | 第 3、4 节 | log-log 图上的直线 = power law; |
| 搜索的直觉 | 第 4.2 节 | 知道”树搜索""beam search”大概是什么(不知道也没关系,第 4.2 节会讲) |
0.3 本讲地图
第1节 背景:为什么要研究 test-time compute 的"扩展规律"
第2节 一张地图:改变分布 vs 对着 verifier 搜索;并行 vs 顺序
第3节 重复采样的 scaling law:Large Language Monkeys 与它的 power law 从哪里来 ← 代码 01
第4节 compute-optimal:按难度分配并行与顺序;和 14 倍大的模型比 ← 代码 02
第5节 Archon:自动搜索推理技巧的组合 ← 代码 03
第6节 实践中的几个问题:成本、延迟、什么时候不该多花计算
第7–10节 小结、练习、延伸阅读、下一讲预告
0.4 本讲对 toy world 的扩展
本讲继续使用第 1 讲的 toy_llm.py,并在 tts_tools.py 里加入三种 test-time 操作:
| 操作 | 做法 | 刻画了什么 |
|---|---|---|
| revise(顺序修改) | 模型逐步复查自己的解答:每一步以较低的温度(0.3,“仔细地”)重算一次;第一处不一致的地方用重算的值替换,再从那里往后重写 | 手滑(careless)容易被发现;模型”最相信”的错误套路(bug 的 logit 比 correct 高)复查也发现不了;修改偶尔会把对的改错 |
| verifier | 正确答案平均高 2 分,再加标准正态噪声;噪声按”(题号, 答案)“固定 | 和第 1 讲一样:同一个错误答案每次得到同样的(可能偏高的)分数 |
| fuse(融合) | 从第一步开始,看”前缀一致”的候选在这一步写了什么值,过半一致就采纳,否则融合模型自己算 | Archon 的 Fuser:把”各自错在不同步骤”的候选拼成一个全对的解答 |
为什么复查要用低温? 如果复查和生成一样”随手”,正确的步骤也会经常被误报,修改就退化成”随机重写后半段”。低温复查更接近模型”最相信”的答案。这带来一个重要的性质:反复修改会收敛到模型自己最相信的解答附近。修改是在利用(exploit)模型已有的知识,而并行采样是在探索(explore)它不太相信的做法。第 4 节的结论都可以从这一点理解。
toy world 的一个局限:greedy 太强。 在第 1 讲的模型里,所有错误都来自”逐步采样时选到了非最优的做法”。所以 greedy 解码(temperature = 0)特别强:10B 模型 greedy 的 pass@1 约 0.75,而 temperature = 0.7 采样只有约 0.5(编写本讲时的探索实验)。真实的 LLM 不是这样,它们的错误大多是”最相信的答案本身就是错的”,greedy 和适度温度采样的 pass@1 通常相差不大。为了让比较有意义,本讲所有方法都统一用 temperature = 0.7 采样,把它当作模型的”标准用法”。
关于本讲的数字:论文里的数字会注明出处;模拟实验的数字都来自 01~03 号代码的实际输出(固定随机种子,Python 3.9 与 3.13 逐字相同)。模拟说明的是机制,不代表真实模型的数值。
1. 背景:为什么要研究 test-time compute 的扩展规律?
1.1 从第 1 讲出发
第 1 讲看到了 test-time compute 最简单的形式:同一道题采样很多次,用一个 verifier 挑出对的。几个现象:
- coverage 随采样数持续增长,小模型采样足够多次可以超过大模型采一次;
- temperature 太低没有多样性,太高每次都容易错;
- 没有完美的 verifier 时,majority vote 有天花板,reward model 甚至会随样本增多而变差。
但这些都是”现象”。要把 test-time compute 当成一种可以规划的资源,就像 pretraining 的 scaling law 让大公司敢于花一亿美元训练模型一样,我们需要回答更定量的问题:
- 性能怎样随推理计算增长? 有没有一条可以预测的曲线?(第 3 节)
- 给定预算,怎样花最好? 并行采样还是顺序修改?所有题都花一样多吗?(第 4 节)
- 能不能把多种技巧组合起来? 组合怎么选?(第 5 节)
1.2 Snell et al. 的提问方式
Snell et al. 2024 的摘要开头说:让 LLM 能用更多的推理计算来改进自己的输出,是构建能在开放的自然语言上自我改进的 agent 的关键一步。他们把问题表述为:
如果允许一个 LLM 使用固定但不算少的推理计算,它在一个困难的 prompt 上能改进多少?
这个问题的答案还关系到一个更大的问题:预训练和推理之间,计算应该怎样分配? 如果推理时多花计算能替代更大的模型,那就不必无止境地扩大预训练(第 1 讲第 2.4 节讲过,那条路越来越贵)。
1.3 人类和 AlphaGo 的类比
人做难题时会多想一会儿:试几种思路,检查一下答案,发现不对再改。下围棋的 AlphaGo 在每一步之前都要做大量的树搜索:神经网络给出”直觉”(哪些走法值得考虑、局面大概有多好),搜索在这个直觉的基础上往前推演很多步。没有搜索的 AlphaGo 要弱得多。
语言模型的 test-time compute 就是在问:能不能给 LLM 也加上”搜索”? 第 1 讲第 2.2 节提到的 The Bitter Lesson 说,能随计算扩展的通用方法只有两种:学习和搜索。pretraining 把”学习”推到了极致,test-time compute 是把”搜索”重新带回来。
2. 一张地图
2.1 两种机制
Snell et al. 把各种 test-time 技巧归结为两种机制:
机制一:改变生成的分布(modify the proposal distribution)。 让模型自己产生更好的输出:
- 并行采样:独立采样很多次(第 1 讲)。
- 顺序修改(sequential revision):让模型看着自己之前的答案,修改出一个新的答案。
- 更长的思考:让模型在回答之前写更长的 CoT。o1、R1 这类 reasoning model 就是通过训练,把”在一个回答内部反复修改”内化了(第 1 讲第 5.5 节)。
机制二:对着 verifier 搜索(search against a verifier)。 用一个打分函数指导搜索:
- best-of-N:采样 N 个完整答案,选 verifier 分数最高的(或 weighted:同一答案的分数相加)。
- beam search:一步一步地生成,每一步只保留 verifier(通常是给每一步打分的 process reward model,PRM,第 3 讲)分数最高的几个部分解答,再从它们继续往下生成。
- lookahead search:beam search 的每一步,先往前 rollout 几步,用 rollout 的结果评价当前这一步。
- 树搜索(MCTS 等,第 5 讲)。
2.2 两个维度
另一种看法是按计算的”形状”分:
| 并行(parallel / wider) | 顺序(sequential / deeper) | |
|---|---|---|
| 做法 | 同时生成很多个独立的候选 | 在前一个结果的基础上继续改进 |
| 擅长 | 探索:覆盖不同的解法,“碰”出模型不太相信但正确的答案 | 利用:在一个接近正确的答案上修修补补 |
| 弱点 | 不利用候选之间的信息;需要一个好的挑选方法 | 容易在错误的方向上越走越远;模型看不到自己的盲点 |
| 延迟 | 可以同时跑,延迟低 | 必须一步接一步,延迟高 |
| 例子 | best-of-N、majority vote | revision、self-refine、长 CoT |
第 5 讲的 AB-MCTS(“Wider or Deeper?”)会把这两个维度放进同一棵搜索树里,每一步自适应地决定”往宽走还是往深走”。本讲第 4 节先看最简单的组合: 条修改链,每条长 。
2.3 统一的视角:proposer + verifier
所有 test-time 方法都可以看成两个部件的配合:
- proposer(提议者):产生候选。它决定了候选里有没有正确答案(coverage)。
- verifier(验证者):评价候选。它决定了能不能把正确答案挑出来(precision)。
第 1 讲的 generation–verification gap 就是这两者之间的差距。本讲第 3 节研究 proposer 的规律(coverage 怎样增长),第 4 节研究怎样在 proposer 的两种用法之间分配,第 5 节研究怎样组合多个 proposer 和 verifier。第 3 讲专门研究 verifier。
3. 重复采样的 scaling law
3.1 Large Language Monkeys
第 1 讲介绍过这篇论文(Brown et al. 2024,讲师 Azalia Mirhoseini 实验室的工作),这里补充更多细节。
实验设置:
- 任务:GSM8K、MATH(数学应用题和竞赛题,答案可以核对)、MiniF2F-MATH(用 Lean 4 写形式化证明,证明器自动检查)、CodeContests(竞赛编程,测试用例检查)、SWE-bench Lite(修复真实 GitHub 仓库的 issue,跑测试检查)。
- 模型:Llama 3(8B、70B)、Gemma(2B、7B)、Pythia(从 70M 到 12B 的一个系列)、DeepSeek-Coder-V2 等。
- 每道题最多采样 10000 次。
主要发现:
- coverage 随采样数跨越四个数量级持续增长。 几乎所有模型、所有任务都是如此。
- 曲线的形状很规律。 coverage 和 的关系常常接近线性,可以用 exponentiated power law 很好地拟合:
也就是说, 是 的 power law,在 log-log 图上是一条直线。这暗示存在 inference-time scaling law。 3. 在可以自动验证的任务上,coverage 直接变成成绩。 SWE-bench Lite 上,DeepSeek-Coder-V2-Instruct 从采样 1 次的 15.9% 提高到 250 次的 56%,超过了当时单次采样的最好成绩 43%。 4. 便宜的模型多采样,可能比昂贵的模型少采样更划算。 论文按 API 价格比较了”用便宜模型采很多次”和”用最强的模型采一次”,在一些任务上前者以更低的成本解决了更多的题。 5. 没有自动 verifier 时,挑选方法跟不上。 在 GSM8K、MATH 上,majority voting 和 reward model 在几百个样本之后就不再进步,远低于 coverage(第 1 讲第 5.4 节)。
3.2 一个谜题
第 3 条发现里藏着一个谜题。对单独一道单次成功率为 的题,采样 次全部失败的概率是
这是 的指数衰减。指数衰减比任何 power law 都快得多: 每增加一倍,失败率就平方一次()。
而 power law 衰减得很慢: 每增加一倍,只乘以一个固定的因子 。
一堆指数衰减的题加在一起,怎么会变成 power law? Schaeffer et al. 2025(How Do Large Language Monkeys Get Their Power (Laws)?,作者里也有讲师 Azalia Mirhoseini)首先用实验确认:每道题单独看,确实是指数衰减。然后他们给出了答案:
关键在于单次成功率 在题目之间的分布。 如果有一小部分题的 极其接近 0(分布的”左尾”很重),这些题需要极多的采样才能被解决,它们合在一起就把整体的曲线”拖”成了 power law——尽管每道题自己都是指数衰减。
01_power_laws.py 演示 2(a) 在 toy world 里验证了第一步(1B 模型,每题采样 10000 次估计 ):
| 题 40( = 0.0467) | 题 34( = 0.0035) | 题 42( = 0.0012) | |
|---|---|---|---|
| 1 | 0.953 / 0.953 | 0.997 / 0.997 | 0.999 / 0.999 |
| 10 | 0.620 / 0.620 | 0.966 / 0.966 | 0.988 / 0.988 |
| 100 | 8.17e−3 / 8.37e−3 | 0.703 / 0.704 | 0.886 / 0.887 |
| 1000 | 1.23e−22 / 1.70e−21 | 0.0249 / 0.0300 | 0.282 / 0.301 |
(每格是”实测的失败率 / ”。 那一行实测值偏小一些,因为 已经是样本数的 1/10,“不放回”的无偏估计和”有放回”的 不再相同,见第 1 讲练习 1。)每道题都是指数衰减:题 40 的失败率从 的 0.008 掉到 的 。
3.3 推导:power law 的指数从哪里来
设题目的单次成功率 服从某个分布,密度为 。一组题整体的失败率是”按分布加权的平均失败率”:
直觉: 只有在 时才不可忽略( 大于 的题, 次里几乎一定能做对)。所以 很大时,积分主要来自 这一小段,也就是分布在 0 附近的质量:
如果 在 0 附近像 (),那么 ,于是
这正是 power law,指数就是 。 越小,0 附近的题越多( 时密度在 0 处趋于无穷),曲线越平。
用 Beta 分布精确地算。 Beta 分布 的密度是 ,正好在 0 附近像 。它的好处是积分有精确的公式:
其中 是 Beta 函数。(推导: 乘上密度 ,变成 ,积分就是 。)
01_power_laws.py 演示 1(b) 用这个公式算出 ,括号里是相邻两行之间 log-log 的斜率:
| Beta(0.3, 3) | Beta(1, 3) | Uniform[0.05, 1] | |
|---|---|---|---|
| 1 | 2.40 | 1.39 | 0.644 |
| 10 | 0.985(−0.39) | 0.262(−0.72) | 0.0560(−1.06) |
| 100 | 0.407(−0.38) | 0.0296(−0.95) | 5.86e−5(−2.98) |
| 1000 | 0.185(−0.34) | 0.00300(−0.99) | 5.29e−26(−21.0) |
| 10000 | 0.0884(−0.32) | 3.00e−4(−1.00) | 1.72e−227(−201) |
- Beta(0.3, 3):斜率趋近于 −0.3;Beta(1, 3):趋近于 −1。都是 power law,指数等于 。
- Uniform[0.05, 1]:最难的题也有 5% 的成功率。起初斜率约 −1,看起来也像 power law;但 一旦超过 的若干倍,斜率就越来越陡,最后是指数衰减。没有左尾,就没有 power law。
3.4 什么时候会偏离 power law?
这个”分布视角”同时解释了实践中观察到的偏离:
- 左尾被截断(最难的题也有一定的成功率):曲线后段比 power law 下降得更快,像 Uniform 的例子。
- 有些题根本做不对(,例如题目本身有错,或者远超模型能力):coverage 永远到不了 1,曲线后段停在一个平台上。
- 题目的难度分布在不同的数据集之间不同:同一个模型在 GSM8K 和 MATH 上的指数可以很不一样。
所以 inference-time 的 power law 不是模型的”物理定律”,而是模型 × 数据集的性质:它取决于这组题里有多少”对这个模型来说极难”的题。
3.5 能不能用少量样本预测大预算下的 coverage?
这个视角还有一个实用的价值。如果想知道”采样 10000 次能做对多少题”,最直接的办法是真的每题采 10000 次——非常贵。Schaeffer et al. 提出:先用少量样本估计 的分布(尤其是左尾),再用公式算出任意 下的 coverage。论文报告,这样估计 power law 的指数,相对误差可以小一个数量级,或者说只需要少 2~4 个数量级的推理计算。
01_power_laws.py 演示 2(b) 在 toy world 里试了两种预测方法,都只用每题前 100 个样本(真正的 1%):
- 直接拟合:在 上拟合 ,然后外推(得到 )。
- 分布拟合:用 beta-binomial 最大似然估计 (得到 、),再用第 3.3 节的公式算。
| 真实 coverage | 直接拟合外推 | 分布拟合 | |
|---|---|---|---|
| 10 | 0.4608 | 0.4590 | 0.4761 |
| 100 | 0.7998 | 0.7866 | 0.7889 |
| 1000 | 0.9729 | 0.9287 | 0.9223 |
| 3000 | 0.9975 | 0.9587 | 0.9520 |
| 10000 | 1.0000 | 0.9774 | 0.9717 |
结果和我们预想的不一样:
- 在样本覆盖的范围内(),两种方法都很准。
- 再往外推,两种方法都偏悲观,而且彼此差不多: 时真实的失败率是 0.027,两种预测都在 0.07 左右; 时所有题其实都被解决了,预测却还剩 2~3%。分布拟合在这里并没有比直接拟合更准。
为什么? 前 100 个样本里有 21 道题一次都没做对。它们的 到底是 0.005 还是 0.000001,100 个样本给不出这个信息。拟合出的 Beta() 假设分布一直延伸到 0,但这组题里最难的一道 也有约 0.001——左尾在这里被截断了,就像 Uniform 的例子。(编写时还试了两组更难的题,412 步和 612 步,两种方法同样都偏悲观、彼此接近。)
这个”失败”的实验其实很有教育意义:
任何外推都依赖对”没见过的那部分难题”的假设。 分布视角告诉我们该关心什么(左尾的形状),在左尾确实像 power law 时,它能用很少的样本估计出指数;但没有任何方法能凭空得到”从未被解出过的题”的信息。
3.6 对评测的启示
- 报告 pass@k 曲线,而不只是 pass@1。 两个 pass@1 相同的模型,pass@1000 可能差很多——左尾不同。
- 小心”采样很多次才解出来”的题。 这些题对 coverage 的贡献最大,但也最可能是”碰巧”做对的(例如选择题蒙对了)。第 3 讲会讨论 verifier 的 false positive 怎样放大这个问题。
- 数据集里有没有不可能做对的题,会改变曲线的形状。 例如答案标错了的题,coverage 永远到不了 1。
- 这个分析也适用于”攻击”:Best-of-N jailbreaking(对一个有害请求随机改写很多次,只要有一次让模型”破防”就算成功)的成功率也服从同样的 power law,而防守方关心的恰恰是左尾。
4. Compute-Optimal:按难度分配计算
4.1 实验设置
Snell et al. 2024(Google DeepMind 与 UC Berkeley)在 MATH 上做了系统的研究:
- 基础模型:PaLM 2-S*。
- Verifier:一个 process reward model(PRM),给解答的每一步打分。训练标签不是人标的,而是用 Monte Carlo rollout 自动估计的(从某一步往后续写很多次,看有多少能做对)——这正是第 3 讲 Math-Shepherd 的方法。
- Revision model:专门微调的模型,输入题目和之前的几次(错误的)尝试,输出一个修改后的答案。
4.2 机制二:对着 verifier 搜索
论文比较了三种搜索方法:
- best-of-N weighted:采样 N 个完整解答,把同一个最终答案的 PRM 分数加起来,选总分最高的答案。
- beam search:每一步生成若干个候选的”下一步”,用 PRM 打分,只保留分数最高的 个继续往下。
- lookahead search:beam search 的每一步,先往前 rollout 步,用 rollout 末端的 PRM 分数评价当前这一步。
主要发现:
- 预算小时,beam search 比 best-of-N 好;预算大时,best-of-N 追上甚至超过 beam search。
- 在简单题上、预算大时,beam search 反而更差:它会”过度优化”PRM 的分数,找到 PRM 喜欢但其实错误的解答(又是 verifier 被”攻破”的问题)。在难题上,beam search 一直更好。
- lookahead search 在同等预算下通常最差,因为 rollout 太贵。
- 结论:最好的搜索方法取决于预算和题目难度。
4.3 机制一:并行采样 vs 顺序修改
另一组实验研究 revision model。给定 次生成的预算,可以:
- 全部并行: 个独立的样本;
- 全部顺序:1 个样本,修改 次;
- 中间: 条修改链,每条长 ,。
最后从所有 个解答里用 verifier 挑一个。论文发现:
- 简单题上,纯顺序修改最好。
- 难题上,存在一个最佳的顺序 / 并行比例:太多顺序(一条链改到底)不行,太多并行(完全不修改)也不行。
直觉:
- 简单题,模型的初始答案通常”已经差不多了”,错误多半是小的疏漏。修改擅长修小错,把预算花在打磨上更划算。
- 难题,模型的初始答案常常”方向就错了”。顺着一个错误的方向修改,往往越改越偏,或者在同一个错误里打转;需要多条独立的链去尝试不同的方向。
在 toy world 里,这个直觉有一个清楚的机制(第 0.4 节):低温复查能发现手滑,却会坚持模型”最相信”的错误套路。简单题的错误主要是手滑,修改一两次就能修好;难题的错误常常出在模型的”误解”上,修改再多次也改不过来,只能靠采样去”碰”出不同的做法。
02_compute_optimal.py 演示 1:10B 模型,300 道 3~8 步题,按 pass@1(32 次采样估计)分成五个难度档(档 1 最简单,平均 pass@1 = 0.85;档 5 最难,0.07)。预算 :
| 配置 | 档 1 | 档 2 | 档 3 | 档 4 | 档 5 | 全部 |
|---|---|---|---|---|---|---|
| 16 条 × = 1(纯并行) | 0.994 | 0.994 | 0.911 | 0.778 | 0.350 | 0.806 |
| 8 条 × = 2 | 0.994 | 0.994 | 0.911 | 0.811 | 0.461 | 0.834 |
| 4 条 × = 4 | 1.000 | 1.000 | 0.944 | 0.750 | 0.372 | 0.813 |
| 2 条 × = 8 | 1.000 | 1.000 | 0.967 | 0.789 | 0.350 | 0.821 |
| 1 条 × = 16(纯顺序) | 1.000 | 1.000 | 0.950 | 0.778 | 0.350 | 0.816 |
- 简单的档(1、2):预算 16 已经足够,各种配置都接近 1.0。
- 中等的档(3):偏顺序的配置( = 8、16)明显好于纯并行(0.967、0.950 vs 0.911)。
- 最难的档(4、5):纯顺序不比纯并行好,最好的是混合(8 条 × = 2)。每条链修改一两次就能顺手修掉手滑,而多条独立的链负责探索。
这和 Snell et al. 的结论一致。(每档 60 道题 × 重复 3 次,相邻配置之间 0.03 左右的差别可能只是随机波动。)
4.4 Weighted best-of-N:为什么不能只看最高分
编写这一节的代码时,最初用”只看 verifier 最高分”来挑选,结果 best-of-N 在 之后随预算下降:从 时约 0.72 一路掉到 时约 0.50。这是第 1 讲第 5.4 节的老问题:候选越多,越有可能某个错误答案”运气好”拿到很高的分数。这个效应压过了”怎样分配预算”本身。
Snell et al. 和 Lightman et al.(第 3 讲)都用的是 weighted best-of-N:把 verifier 分数变成”答案正确的概率”,再把同一个答案的所有样本的概率加起来:
它同时用到了两种信号:出现次数(majority vote)和 verifier 的判断。一个只出现一两次的错误答案,即使分数很高,也比不过反复出现、分数也不错的正确答案。换成 weighted 之后,best-of-N 随预算单调上升(:0.682,:0.802,:0.878,:0.902,:0.891)。本讲之后的代码都用 weighted best-of-N(tts_tools.select_weighted)。
weighted best-of-N 也继承了 majority vote 的弱点:如果模型最常犯的错误答案恰好也被 verifier 看好,它也会选错。
4.5 Compute-optimal:先估计难度,再分配计算
既然最优策略取决于难度,自然的想法是:先估计每道题的难度,再为每个难度选最好的策略。Snell et al. 把它叫做 compute-optimal scaling strategy:
其中 是策略的超参数(例如顺序 / 并行的比例、beam 的宽度)。实际做法是把题目按难度分档,在开发集上为每一档选出最好的 。
怎样知道难度? 论文用了两种:
- oracle 难度:用大量采样(论文里是 2048 次)估计每道题的真实 pass@1,再按分位数分成 5 档。这需要知道标准答案,只能用来做分析。
- 预测难度:不看标准答案,用 verifier 对若干样本打分的平均值来估计难度。实际可用,但估计本身也要花计算。论文发现预测难度的效果接近 oracle 难度。
结果:无论是搜索还是修改,compute-optimal 策略都能用大约 1/4 的计算达到 best-of-N 的效果。
02_compute_optimal.py 演示 2:在 150 道开发题上为每档选 ,在另外 150 道测试题上评估:
| 预算 | best-of-N | compute-optimal | best-of-N 追上它需要的预算 |
|---|---|---|---|
| 4 | 0.682 | 0.729 | = 8(2 倍) |
| 16 | 0.802 | 0.856 | = 32(2 倍) |
| 64 | 0.878 | 0.887 | = 128(2 倍) |
- 三个预算下 compute-optimal 都更准,best-of-N 要 2 倍预算才能追上(toy world 里的差距比论文的 4 倍小)。
- 预算越大,优势越小: 时只差 0.009,开发集上几乎所有档都选了 。并行采样的 coverage 随预算增长,大预算下”探索”本身就够了。按难度分配在预算紧张时最有价值。
- 选 用开发集、评估用测试集。如果在同一批题上既选又评,结果会偏乐观(第 5.5 节还会看到这个问题)。
4.6 FLOPs-matched:test-time compute 能替代更大的模型吗?
最后一个、也是最有冲击力的问题:一个小模型加上 test-time compute,能不能打败一个大得多的模型? 比较必须在相同的总计算量下进行,而总计算量包括预训练和推理:
( 是训练的常用估算:前向 、反向 每 token;推理只有前向 。)设大模型的参数是小模型的 倍(论文里 ),预训练数据相同,大模型每题采样一次;小模型每题可以采样 次。令两者总计算量相等:
是推理 token 总数和预训练 token 数的比值,反映模型上线后的推理负载:
- :推理量很小(例如一个只做少量难题的研究系统),省下的预训练计算可以换来大量的推理, 很大;
- :推理量巨大(例如服务上亿用户的聊天产品),,小模型只能多采 次左右。
论文考察了 约 0.16、0.79 和 22 三种情况,发现:
- 简单和中等难度的题:test-time compute 往往比扩大预训练更划算——小模型加推理可以打败 14 倍大的模型。
- 最难的题,或者推理负载很高时:扩大预训练更有效。小模型”不知道”的东西,推理时花再多计算也很难补上。
02_compute_optimal.py 演示 3(10B vs 140B,,测试集):
| 档 1 | 档 2 | 档 3 | 档 4 | 档 5 | 全部 | |
|---|---|---|---|---|---|---|
| 140B 采样一次 | 0.974 | 0.958 | 0.879 | 0.731 | 0.560 | 0.823 |
| 10B, = 92( = 0.5) | 1.000 | 0.979 | 0.965 | 0.899 | 0.601 | 0.888 |
| 10B, = 33( = 2) | 0.988 | 0.979 | 0.969 | 0.870 | 0.484 | 0.858 |
| 10B, = 17( = 10) | 0.996 | 0.975 | 0.973 | 0.793 | 0.427 | 0.834 |
- 档 1~4:三种推理负载下,10B 模型加 test-time compute 都追平或超过了 14 倍大的模型。
- 最难的档 5:只有推理负载很低( = 0.5,每题 92 次生成)时小模型才赢; = 2 和 10 时大模型领先。
和论文的结论一致:test-time compute 和 pretraining compute 不是谁替代谁的关系,要看题目难度和推理负载。 对一个要服务海量用户的产品,训练一个更大的模型可能更划算;对一个只解少量难题的科研系统,多花推理计算更划算。
5. Archon:自动搜索推理技巧的组合
5.1 动机
第 4 节只比较了两种技巧的组合。实际可用的技巧多得多:
| 组件 | 做什么 |
|---|---|
| Generator | 用某个模型生成候选;可以同时用多个不同的模型(ensemble) |
| Fuser | 读入多个候选,综合成一个新的、更好的回答 |
| Ranker | 给候选排序,挑出前几名 |
| Critic | 对每个候选写出优缺点,供后面的 Fuser 参考 |
| Verifier | 判断候选是否正确,过滤掉不正确的 |
| Unit Test Generator / Evaluator | 为代码题生成测试用例,用测试结果给候选打分 |
它们的效果取决于模型和任务,彼此之间还有相互作用(例如 Critic 的输出要喂给 Fuser 才有用)。再加上可用的模型有很多、每个组件有参数(采样几个、留前几名、融合几层),组合的数量是天文数字。Saad-Falcon et al. 2024 指出,正是因为对每种技巧的作用、技巧之间的相互作用理解得还不够,加上搜索空间巨大,怎样组合这些技巧还没有成熟的最佳实践。
5.2 把推理系统看成一个”神经网络”
Archon 的做法是把推理系统组织成层:
第 1 层:Generator × 多个模型(各采样若干次)
│
第 2 层:Critic(给每个候选写批评)
│
第 3 层:Ranker(留下前 k 名)
│
第 4 层:Fuser × 若干(各自融合出一个新的回答)
│
第 5 层:Fuser(再融合一次) ……
│
最后一层:Verifier / Unit Test(挑出最终答案)
就像神经网络的”架构”有层数、宽度等超参数,推理系统的”架构”也有:用哪些模型、每层放什么组件、每个组件的参数。于是”怎样组合推理技巧”就变成了一个架构搜索问题,论文把它叫做 ITAS(inference-time architecture search):给定可用的模型和预算,在开发集上搜索最好的架构。
搜索算法用的是贝叶斯优化(Bayesian optimization):每评估一个架构都很贵(要在开发集上跑一遍),所以用一个代理模型预测”哪些架构可能更好”,优先评估它们。论文报告,贝叶斯优化在 96.0% 的搜索中找到了最好的架构,比贪心搜索少评估 88.5% 的架构。
5.3 主要结果与发现
在 MT-Bench、Arena-Hard-Auto、AlpacaEval 2.0、MixEval、MATH、CodeContests 上,Archon 搜索出的架构平均比 o1、GPT-4o、Claude 3.5 Sonnet 等前沿模型高 15.1%。更有意思的是不同任务上最有用的组件不同:
- 指令遵循类任务(MT-Bench、Arena-Hard-Auto 等):Fuser 带来很大的提升;最好的结构是”先用 Ranker 排序,挑出前 5 名,再融合”;加上 Critic 还能进一步提高。
- 推理类任务(MATH、MixEval):Verifier 最有效。
- 代码任务(CodeContests):集成、融合、排序的作用都很有限,Unit Test 的生成与评估占主导,pass@1 从 17.9% 提高到 29.3%。
背后的道理是:最有用的组件,是能为这类任务提供最可靠反馈信号的那个组件。 代码有测试,数学答案可以核对,就靠验证;开放式的回答没有对错分明的答案,“综合多个回答的优点”就更有价值。这又回到了第 1 讲的原则。
5.4 toy world 里的架构搜索
03_archon_search.py 实现了一个缩小版:生成器是 1B / 10B / 100B 之一,采样 次;最后一层是 first / vote / rank(weighted verifier)/ fuse / rank + fuse(先挑前 4 名再融合)之一,融合模型也可以选。成本以”10B 模型生成一次”为单位(1B = 0.1,100B = 10,verifier 打分一次 0.1,融合要读入所有候选,成本更高)。共 51 个配置,在 100 道开发题上评估、100 道测试题上检验。
几个有代表性的配置:
| 配置 | 成本 | 开发集 | 测试集 |
|---|---|---|---|
| 10B × 1 → first | 1.0 | 0.470 | 0.485 |
| 100B × 1 → first | 10.0 | 0.815 | 0.825 |
| 10B × 16 → vote | 16.0 | 0.645 | 0.700 |
| 10B × 16 → fuse(10B) | 21.0 | 0.615 | 0.695 |
| 10B × 16 → rank | 17.6 | 0.805 | 0.840 |
| 10B × 16 → fuse(100B) | 66.0 | 0.795 | 0.825 |
| 10B × 16 → rank + fuse(100B) | 37.6 | 0.875 | 0.850 |
| 1B × 16 → rank + fuse(100B) | 23.2 | 0.490 | 0.570 |
- 同一组候选,最后一层的选择差别很大。vote 和”用同样大小的模型融合”差不多(0.6 左右);rank(verifier)和”用强得多的模型融合”差不多(0.8 左右);先排序、再用强模型融合最好——和 Archon 在指令遵循任务上找到的最佳结构一样。
- 在这个”答案可以验证”的数学类任务上,verifier 是最有用的单个组件,和 Archon 在 MATH 上的发现一致。
- 融合的效果取决于融合模型本身:和生成器一样强的融合模型并不比投票好。
- 候选太差时,什么组件都救不了:1B 的候选即使用 100B 排序再融合,也只有 0.5 左右。
按预算选配置:
| 预算 | 开发集上最好的配置 | 成本 | 开发集 | 测试集 | 预算内最好的单个模型 |
|---|---|---|---|---|---|
| 1 | 10B × 1 → first | 1.0 | 0.470 | 0.485 | 0.485 |
| 10 | 100B × 1 → first | 10.0 | 0.815 | 0.825 | 0.825 |
| 30 | 100B × 1 → first | 10.0 | 0.815 | 0.825 | 0.825 |
| 100 | 100B × 4 → rank | 40.4 | 0.975 | 0.955 | 0.825 |
- 预算小时,最好的往往是”预算内最大的模型采样一次”;预算足够大时,组合技巧才明显胜出(预算 100:0.955 vs 0.825)。
- 挑选偏差:预算 30 时,开发集上 100B × 1(0.815)以微弱优势胜过 10B × 16 → rank(0.805),但测试集上后者更好(0.840 vs 0.825)。开发集上”接近平手”的胜负由噪声决定。开发集前 10 名的配置,在测试集上平均低 0.016。配置越多、开发集越小,这种偏差越大。
5.5 从 Archon 学到什么
- 没有万能的架构。 最好的组合取决于任务、可用的模型和预算。
- 组件的价值来自它提供的信号。 有可靠 verifier 的任务,验证最重要;没有的任务,融合和批评更重要。
- 搜索要有独立的测试集。 在开发集上挑出的冠军通常会被高估。
- 推理架构搜索本身也很贵。 每评估一个架构都要在开发集上跑一遍,所以需要贝叶斯优化这样”省评估次数”的方法。这和第 7 讲的 ADAS(自动设计 agent)是同一类问题:用搜索来改进系统的设计。
6. 实践中的几个问题
6.1 怎样计算成本?
不同的论文用不同的”预算”单位,比较时要小心:
- 采样次数:最简单,但忽略了每次生成的长度和模型大小。
- FLOPs: 参数量 token 数。适合比较不同大小的模型(第 4.6 节)。
- token 数:适合比较长度差别很大的方法(例如长 CoT vs 短回答)。
- 美元:实际部署时最关心的;不同模型的 API 价格和参数量不一定成正比。
- 延迟:用户等待的时间。并行采样可以同时跑,延迟几乎不随 增长;顺序修改和长 CoT 必须一步接一步,延迟随步数线性增长。
6.2 什么时候不该多花推理计算?
- 没有可靠的 verifier 时:coverage 再高也挑不出来(第 1 讲第 5.4 节)。
- 题目超出模型能力时:第 4.6 节的档 5——小模型”不知道”的东西,采样再多也很难碰到。
- 简单题:多花的计算基本是浪费。好的系统应该按难度分配,这也是 reasoning model 要学会”想多久”的原因(“overthinking”:对简单问题也想很久,浪费计算)。
- 推理负载很高时:第 4.6 节的 ,训练一个更大的模型更划算。
6.3 和 reasoning model 的关系
o1、R1 这类模型把”顺序修改”内化到了一次回答里:它们的长 CoT 里充满了”等等,我检查一下""这里不对,换个方法”。从本讲的角度看,这是一种学出来的顺序 test-time compute。它们依然可以和并行采样结合(第 1 讲第 5.5 节:o1 在 AIME 上单次 74%,64 个样本投票 83%,1000 个样本重排序 93%)。怎样用 RL 训练出这种能力,是第 6 讲的主题。
7. 小结
- 两种机制、两个维度:test-time 技巧要么改变生成的分布(并行采样、顺序修改、长 CoT),要么对着 verifier 搜索(best-of-N、beam search、lookahead);计算可以花在”宽”(并行探索)或”深”(顺序打磨)上。所有方法都是 proposer(决定 coverage)和 verifier(决定能不能挑出来)的配合。
- Large Language Monkeys:coverage 随采样数跨越四个数量级持续增长, 近似是 的 power law;可验证的任务上直接变成成绩,不可验证的任务上被挑选方法卡住。
- power law 从哪里来:每道题的失败率 是指数衰减;整体的 power law 来自单次成功率 的分布在 0 附近的”左尾”。若密度在 0 附近像 ,则 。左尾被截断时曲线衰减得更快,有 的题时曲线停在平台上。外推大预算下的 coverage,本质上依赖对”从未被解出的题”的假设。
- compute-optimal:最优策略取决于难度。简单题适合顺序修改(修手滑),难题需要并行探索或两者的混合(模型看不到自己的盲点)。先估计难度再分配,比 best-of-N 高效好几倍(论文约 4 倍,toy world 约 2 倍),预算越紧张越有价值。挑选时用 weighted best-of-N,避免 verifier 被大量候选”攻破”。
- FLOPs-matched:小模型 + test-time compute 在简单和中等的题上可以打败 14 倍大的模型;在最难的题上、或推理负载 很高时,扩大预训练更划算。
- Archon:把推理技巧的组合当作架构搜索。最有用的组件因任务而异——推理任务靠验证、代码靠 unit test、开放式任务靠融合与批评——因为组件的价值来自它提供的反馈信号。搜索要有独立的测试集,开发集上的冠军通常被高估。
8. 练习
1. 指数 vs power law(第 3.2 节) (a) 一道题 。 从 100 增加到 200,失败率变成原来的多少倍?从 1000 增加到 2000 呢? (b) 一组题的 。 从 100 增加到 200,失败率变成原来的多少倍?从 1000 增加到 2000 呢? (c) 两者的区别说明了什么?
参考答案
(a) ;从 1000 到 2000:。指数衰减越往后越快:失败率越小,下降得越”狠”。 (b) 两次都是 。power law 每翻一倍都乘同一个因子。 (c) 一道题自己的曲线越往后越陡;整体曲线”保持同样的斜率”,是因为每扩大一次 ,都有新的一批更难的题”刚刚开始被解决”。
2. 推导 power law 的指数(第 3.3 节) 设 的分布在 上的密度为 。 (a) 证明 ()。 (b) 用” 只在 时不可忽略”的近似,说明 。 (c) 如果一个 benchmark 有 3% 的题 (永远做不对), 在 时趋于多少?在 log-log 图上曲线会是什么样子?
参考答案
(a) 。 (b) 。更精确地,。 (c) 趋于 0.03。log-log 图上,曲线先沿 power law 下降,然后逐渐变平,停在 这条水平线上。
3. FLOPs-matched 的公式(第 4.6 节) (a) 从总计算量相等的条件推导 。 (b) , 时 是多少?这说明了什么? (c) 公式里假设两个模型用相同的预训练数据量。如果按 Chinchilla 的配比(数据量和参数量成正比),大模型的预训练数据是小模型的 倍, 的公式会怎样变化?
参考答案
(a) ,两边除以 :,即 。 (b) 。推理负载很高时,小模型只能多采样约 14 次,几乎没有从”省下的预训练”里得到额外的推理预算。 (c) 大模型的预训练计算变成 ,于是 。大模型的预训练更贵了,小模型能分到的推理预算更多。
4. 并行还是顺序(第 4.3 节)
用第 0.4 节”修改是利用、采样是探索”的观点回答:
(a) 如果把 revise 的复查温度 check_temperature 从 0.3 改成 0(完全按模型最相信的做法复查),对简单题和难题分别会有什么影响?
(b) 如果改成 0.7(和生成一样),又会怎样?
(c) 动手试一试:改 tts_tools.CHECK_TEMPERATURE,运行 02 号文件,结果和你的预测一致吗?
5. Weighted best-of-N(第 4.4 节) 三个候选答案的情况如下:答案 X 出现 6 次,verifier 认为正确的概率 0.4;答案 Y 出现 1 次,概率 0.95;答案 Z 出现 3 次,概率 0.7。 (a) 只看最高分,选哪个?weighted best-of-N 选哪个?majority vote 选哪个? (b) 构造一个例子,让 weighted best-of-N 选错而”只看最高分”选对。这种情况在什么样的 verifier 下常见?
参考答案
(a) 最高分:Y(0.95)。weighted:X 是 ,Y 是 0.95,Z 是 ,选 X。majority vote:X。 (b) 例如正确答案只出现 1 次但 verifier 给了 0.99,而一个 systematic error 的答案出现 10 次、verifier 给了 0.2(总分 2.0 > 0.99)。当 verifier 非常可靠、而模型有强烈的错误倾向时,“只看最高分”更好;verifier 噪声大、候选很多时,weighted 更稳健。
6. 设计 compute-optimal 策略 你有一个 verifier,能给每个样本一个”正确概率”。不知道标准答案,你怎样估计一道题的难度?估计难度要花多少计算?这部分计算应该算进预算吗?
7. Archon(第 5 节)
(a) 为什么”和生成器一样强的融合模型”不比投票好,而”更强的融合模型”有帮助?用 tts_tools.fuse 的机制解释。
(b) 在 03 号文件里加一种最后一层”rank+vote”:先用 verifier 挑出前 8 名,再在其中做 majority vote。它会比 rank 好还是差?试一试。
(c) 把开发集从 100 题减到 30 题,挑选偏差会变大吗?
8. 研究问题 第 3.5 节的实验里,两种预测方法都偏悲观。如果你要为一个新模型预测”采样 10 万次能做对多少题”,但预算只够每题采 1000 次,你会怎样设计实验、怎样报告预测的不确定性?
9. 延伸阅读
本讲的阅读材料
- Brown et al. 2024. Large Language Monkeys: Scaling Inference Compute with Repeated Sampling.
- Schaeffer et al. 2025. How Do Large Language Monkeys Get Their Power (Laws)?
- Snell et al. 2024. Scaling LLM Test-Time Compute Optimally can be More Effective than Scaling Model Parameters.
- Saad-Falcon et al. 2024. Archon: An Architecture Search Framework for Inference-Time Techniques.
相关工作
- Wang et al. 2022. Self-Consistency Improves Chain of Thought Reasoning.(majority vote over CoT)
- Madaan et al. 2023. Self-Refine: Iterative Refinement with Self-Feedback.(顺序修改)
- Wu et al. 2024. Inference Scaling Laws: An Empirical Analysis of Compute-Optimal Inference for Problem-Solving with Language Models.
- Hughes et al. 2024. Best-of-N Jailbreaking.(同样的 power law 出现在攻击中)
- Chen et al. 2024. Are More LLM Calls All You Need? Towards Scaling Laws of Compound Inference Systems.(投票的效果可能先升后降)
10. 下一讲预告
第 3 讲:鲁棒的验证(Robust Verification)
本讲反复看到:test-time compute 能走多远,取决于 verifier 有多好。第 3 讲专门研究 verifier:
- 检查结果还是检查过程? Outcome reward model(ORM)vs process reward model(PRM);Cobbe et al. 2021 和 Lightman et al. 2023(PRM800K)。
- 没有人工标注,怎样得到过程监督? Math-Shepherd 用 Monte Carlo rollout 自动标注每一步——也就是本讲第 4.1 节 Snell et al. 训练 PRM 的方法。
- 很多不完美的 verifier,能不能合成一个好的? Weaver 用弱监督(weak supervision)估计每个 verifier 的准确率,再加权组合。