循环 Transformer 的甜点居然是「只跑两圈」——LoopCoder-v2 把循环次数掰开揉碎讲清楚了

上周在跟一个做推理加速的朋友聊天,他丢给我一个问题:循环 Transformer(looped transformer)不是号称「同样的参数,循环越多次等效深度越深、效果越好」吗?那为什么大家实际部署的时候都不敢循环太多次?

我当时下意识的回答是「延迟和显存撑不住啊」。循环 R 次,KV-cache 就涨 R 倍,延迟也涨 R 倍,这谁顶得住。

但这篇论文给了我一个更扎心的答案:就算你把延迟和显存的问题都解决了,让循环次数变成一个「随便选」的设计参数,性能照样不是越循环越好——它在循环两次的时候达到顶点,然后掉头向下。

而且掉得很难看。SWE-bench Verified 这个 benchmark 上,循环 2 次能从 43.0 飙到 64.4,但循环 3 次直接崩到 27.6——比不循环还差。

这就有意思了。今天就来聊聊这篇 LoopCoder-v2。


先把核心结论摆出来

一句话总结:作者从零训了一个 7B 的并行循环 Transformer 代码模型家族(循环次数分别为 1/2/3/4),喂了 18T token,然后发现一个强烈的非单调(non-monotonic)现象——循环 2 次是甜点,3 次及以上反而退化。更关键的是,他们没停留在「发现现象」,而是用一套诊断工具把「为什么是 2 次」这件事从机制上讲清楚了:额外循环带来的精炼增益快速衰减,而并行化引入的位置错配成本却几乎不变,两条曲线像剪刀一样交叉,交点就在循环 2 次的位置。

我觉得这篇论文最值钱的地方不是那个 64.4 的漂亮数字,而是它把「循环几次」这个原本靠暴力试错的超参,变成了一个可以用轻量诊断指标提前判断的事情。这个思路,比单纯刷榜有意思多了。

论文标题:LoopCoder-v2: Only Loop Once for Efficient Test-Time Computation Scaling arXiv ID:2606.18023 作者:Jian Yang, Shawn Guo, Wei Zhang, Tianyu Zheng, Yaxin Du, Haau-Sing Li, Jiajun Wu, Yue Song, Yan Xing, Qingsong Cai, Zelong Huang, Chuan Hao, Ran Tao, Xianglong Liu, Wayne Xin Zhao, Mingjie Tang, Weifeng Lv, Ming Zhou, Bryan Dai 等 发布日期:2026/06/16 链接:https://arxiv.org/abs/2606.18023


🧠 背景:循环 Transformer 到底在循环什么

先给不太熟这块的朋友补个课。

标准的循环 Transformer 思路很简单:与其堆 100 层不同参数的网络,不如拿一个共享的 Transformer 块,反复跑它 R 遍。这样有效计算深度是 R·L(L 是层数),但参数量 N 始终不变。

\[h^{(0)} = \text{Embed}(x), \quad h^{(r)} = f_\theta(h^{(r-1)}), \quad r = 1,\dots,R\]

听起来很美——用计算换深度,不用养更多参数。但顺序循环(sequential looping)有两个绕不开的坑:

  • 延迟:每多一次循环就得完整跑一遍共享块,延迟随 R 线性涨,是 \(O(R \cdot C_{block})\)
  • 显存:标准实现里每层每次循环都缓存 KV,KV-cache 占用是 \(O(R \cdot L \cdot S \cdot d)\),单次推理的 R 倍

这就是我那个朋友说的「不敢循环太多」的现实原因。

而 PLT(Parallel Loop Transformer,并行循环 Transformer)就是冲着把这两个成本干掉去的。它用两个独立的机制:

维度 顺序循环 Sequential 并行循环 PLT
执行方式 串行 并行,单次前向
延迟 \(O(R \cdot C_{block})\) \(C_{block}\)
KV-cache \(O(R \cdot L \cdot S \cdot d)\) \(O(L \cdot S \cdot d)\)
循环间输入 \(h^{(r-1)}\) \(\text{Embed}(x) + \text{shift}(h^{(r-1)})\)

注意最后一行——这是整篇论文的命门所在,我们待会儿细说。

PLT 把延迟压到接近单次前向,KV-cache 压到跟 R 无关。换句话说,循环次数从一个「奢侈品」变成了一个「随便挑」的设计选项。那么问题来了:既然成本不再随循环次数暴涨,那循环次数到底该选几?

图1:PLT 循环次数选择的全景图。左侧对比了顺序循环(成本随 R 线性增长)和 PLT(用 CLP+G-SWA 把成本压到近恒定);中间是 gain-cost 权衡的核心直觉,精炼增益早期达峰后收缩、而 CLP 偏移成本大致恒定,使 R=2 成为最优操作点;右侧是逐循环诊断——loop 2 表现出连贯的隐藏状态移动、注意力路由的明显改变和表征多样性的增加,loop 3 则变得冗余甚至有害

图1:这张总览图基本把全文讲完了。最值得看的是中间那块——蓝色的「精炼增益」曲线先升后降,红色的「CLP 偏移成本」几乎是一条水平线,两者的交点(那颗星星)就落在 r=2,这就是甜点。


🔧 方法:PLT 怎么做到「并行」的,代价又是什么

PLT 的核心其实就两个动作,但理解它们的副作用,比理解它们本身更重要。

动作一:KV 共享 + 门控滑窗注意力(G-SWA)

为了让 KV-cache 不随循环次数膨胀,PLT 只缓存第一个循环的 KV,后面所有循环都共用它:

\[K_{share}, V_{share} = KV(h^{(1)})\]

但只用冻结的第一圈 KV 会丢失后续循环的新信息,所以又加了一个滑动窗口注意力(窗口宽度 w=64)来补充局部信息,再用一个门控把两者融合:

\[\tilde{y}^{(r)} = g \odot y_{global}^{(r)} + (1-g) \odot y_{local}^{(r)}, \quad g = \sigma(f_{gate}(\text{RMSNorm}(h)))\]

这里 \(y_{global}\) 是在冻结的 loop-1 KV 上做全上下文注意力,\(y_{local}\) 是在当前循环 KV 上做滑窗注意力。门控 g 是 head-wise 的,每个头自己学一个标量,决定多大程度信任那个冻结的全局缓存。

记住这个门控 g,它在后面的诊断里会暴露一个关键问题。

动作二:跨循环位置偏移(CLP)——天才设计,也是阿喀琉斯之踵

这是 PLT 实现并行的核心招式,也是我读完最佩服、同时又觉得最纠结的地方。

标准循环里,token \(x_i\) 的第 r 圈必须等它自己的第 r-1 圈算完才能开始——这是严格的顺序依赖,没法并行。CLP 的做法是把循环间的输入「右移一个 token」:

\[B^{(r)} = \text{Embed}(x) + \text{shift}(h^{(r-1)}), \quad h^{(r)} = f_\theta(B^{(r)})\]

其中 \(\text{shift}(h^{(r-1)})_i = h^{(r-1)}_{i-1}\),第一个 token 补零。

这一移,神奇的事情发生了:token \(x_i\) 的第 r 圈,现在依赖的是邻居 \(x_{i-1}\) 的第 r-1 圈,而不是它自己的。于是 \(x_i\) 的第 r 圈和 \(x_{i-1}\) 的第 r+1 圈就能在同一次前向传递里并发计算了。顺序依赖被打破,并行成为可能。

漂亮吧?但代价是什么?

代价就是位置错配(positional mismatch)。 从第二圈开始,token \(x_i\) 拿到的输入不是「自己上一圈精炼好的状态」,而是「自己的 embedding + 邻居上一圈的状态」的混合。每过一个循环边界,就强行掺入一次邻居的信息。

说实话,第一次看到这个设计我是有点犯嘀咕的——你这等于每循环一次就往自己脑子里塞一点隔壁桌的笔记,循环越多次,掺的杂质不就越多吗?

作者很诚实地把这个代价量化了出来,定义了一个内在偏移成本 \(\Omega^{(r)}\)

\[\Omega^{(r)} = \frac{1}{S}\sum_i \|h^{(r-1)}_i - h^{(r-1)}_{i-1}\|_2\]

就是相邻 token 表征的平均欧氏距离。直觉很清楚:相邻 token 差异越大,这一「移」造成的错配就越严重。而它经验上几乎恒定——这正是后面剪刀效应的成本侧。


🏗️ 训练:18T token、1M GPU 小时砸出来的家族

为了认真研究循环次数这件事,作者没偷懒,是真的从零训了 4 个模型。配置如下:

超参数
层数 L 14
隐藏维度 d 5120
注意力头数 40(GQA,8 组 KV)
FFN 中间维度 27,648(SwiGLU)
位置编码 RoPE(base 5×10⁵)
词表 76,800
总参数量 ≈7B
训练数据 18T token,文本:代码 = 1:1
循环次数 R 1, 2, 3, 4
滑窗宽度 w 64

代码数据跨 100+ 种编程语言,Top 几位是 Java(10.3%)、Python(10.1%)、JavaScript(9.4%)、Markdown(8.7%)、TypeScript(8.3%)。

关键的实验设计是训练和推理的循环次数严格匹配——R=2 的模型就训成 2 圈、评估也用 2 圈,不搞「训一个推多个」的取巧。4 个模型用完全相同的 SFT recipe(6M 指令样本)微调,保证唯一变量就是循环次数。

整个家族训下来烧了约 1M GPU 小时。说实话这个研究的成本是相当奢侈的——为了搞清楚一个超参的规律,把每个取值都从零训一遍,这种「钞能力级别的消融」在学术界不多见,多半是有工业资源撑着。


🧪 主实验:2 次封神,3 次翻车

直接上主表(Ours 7B,不同循环次数):

Benchmark Baseline R=1 R=2 R=3 R=4
HumanEval+ 81.1 84.1 75.0 76.8
MultiPL-E(多语言) 69.5 73.9 69.8 67.3
BigCodeBench-Full 40.1 46.1 43.3 40.8
LiveCodeBench 27.4 35.4 28.6 24.5
SWE-bench Verified 43.0 64.4 27.6 22.4
SWE-bench Multilingual 14.0 31.0 11.0 9.3
Terminal-Bench v1 26.3 34.2 30.0 26.3
Terminal-Bench v2 11.2 21.0 12.2 9.0
Mind2Web 35.3 34.5 35.1 41.4
BFCL(工具调用 v3) 32.2 40.1 36.3 39.5
平均 38.0 46.5 36.9 34.3

看几个点:

SWE-bench Verified 上 43.0 → 64.4,涨了 21 个点出头。 这个幅度在 agentic 软件工程任务上是相当能打的。作者特别强调,这个 R=2 的 7B 模型在 SWE-bench Verified 上的 64.4,已经超过了 30B-72B 量级的一票开源模型,逼近 480B 规模的 Qwen3-Coder(67.0)。一个 7B 模型靠多循环一次就摸到几十倍参数量的水平,这事确实让我愣了一下。

但 R=3 直接崩了——SWE-bench Verified 掉到 27.6,比不循环的 43.0 还低 15 个点。 R=4 更惨,22.4。这种「多循环一次反而大幅退化」的非单调现象,是这篇论文真正想讲的东西。

唯一的例外是 Mind2Web,R=4 反而最高(41.4)。作者没回避这个反例,但整体趋势上 R=2 在 11 个 benchmark 里有 9 个是最优,平均分 46.5 一骑绝尘。

这里我得稍微泼一点冷水:SWE-bench Verified 从 43 涨到 64 固然惊艳,但你看 HumanEval+ 只从 81.1 涨到 84.1,涨幅就温和多了。循环带来的增益在难任务(agentic、长程软件工程)上特别明显,在相对简单的单函数生成上就没那么夸张。 这其实挺合理——越是需要反复推敲的任务,多一圈表征精炼越有用。


🔬 诊断:为什么偏偏是 2 次?三把「透镜」交叉验证

如果这篇论文只到这里,那也就是个「我们试了发现 2 次最好」的工程报告。它真正的硬核之处在于后半段——用三套互相独立的诊断指标,从机制上回答「为什么是 2」。作者管这三套指标叫三把「透镜」,只有当三把透镜的结论一致时,才认定一个机制成立。这种交叉验证的严谨度,我是真的欣赏。

透镜一:隐藏状态在怎么变?

图2:隐藏状态动态的四个指标随循环索引的变化。(a) 每 token 隐藏状态步长 δ,(b) 连续更新的方向对齐度 cosθ,(c) scale-free 有效秩 erank,(d) 到不动点的距离。三条曲线分别是 PLT2/PLT3/PLT4,黄色高亮区是 loop 2

图2:重点看左下角 (c) 有效秩——它在 loop 2 达到峰值,之后每深入一圈就往下掉。有效秩衡量的是 token 表征的几何多样性,峰值意味着 loop 2 把表征撑得最开、信息最丰富;之后下降说明后续循环在「收窄」表征子空间而不是「丰富」它。再看右上角 (b) 的 cosθ,精炼循环里普遍是负的(<0),说明连续两次更新的方向是反着来的——这不是稳步收敛,是来回振荡。

这里有个特别有意思的发现:右上角 cosθ 在精炼循环里普遍小于 0。我得解释一下这意味着什么——cosθ 衡量的是相邻两次隐藏状态更新方向的夹角,≈1 是持续同向精炼(好),≈0 是正交,<0 就是方向反转,也就是模型在「左右横跳」而不是「稳步逼近」。看到这个负值的时候我有点意外,因为按理想中的循环 Transformer,它应该像迭代求解器一样越来越逼近某个不动点才对。但数据告诉你,深层循环根本没在收敛,是在原地打转。

透镜二:gain-cost 剪刀——全文最关键的一张图

图3:gain-cost 剪刀效应(PLT4)。蓝色是每循环精炼增益 Δp(输出 KL 散度,左轴对数刻度),红色虚线是 CLP 内在偏移成本 Ω(右轴)。增益在 loop 2 后崩塌且不再恢复,而偏移成本始终维持在高位且大致恒定

图3:这张图我愿称之为全文的灵魂。蓝线(增益)在 loop 2 之后断崖式下跌然后趴在地上再也起不来,红线(成本)从头到尾几乎是一条水平线。作者算了一笔账——每个额外循环,偏移成本超过每循环增益足足 30 到 45 倍。换句话说,loop 3 以后你每多循环一次,掏的「位置错配税」是收到的「精炼红利」的几十倍,纯亏。

这就是「Only Loop Once」标题的真正含义——在 baseline 之上,真正划算的额外循环只有一次(也就是从 R=1 到 R=2 那一步),再往后都是赔本买卖。

为什么会这样?逻辑链条其实很清晰:

  1. 精炼增益本身就随深度快速递减(loop 2 抓住了绝大部分有用的精炼);
  2. 而 CLP 那个位置偏移成本 \(\Omega\) 是固定的「过路费」,不管你循环到第几圈,每过一个边界都得交一次;
  3. 当递减的增益跌破固定的成本,净效果就由正转负。

剪刀的交点,就是甜点。

透镜三:注意力和输出分布也在「冻结」

注意力侧的证据同样指向 loop 2 之后的停滞:

图4:head×head 注意力分布的余弦相似度热图(PLT3),从左到右是 loop 1/2/3,对角线已掩码。越亮表示两个头越冗余。三张图的平均相似度从 0.57 升到 0.67 再到 0.71,说明随着循环加深,注意力头越来越「长得像」

图4:颜色越来越暖(亮),说明注意力头之间越来越冗余。loop 1 时各个头还各司其职(平均相似度 0.57),到 loop 3 大家都趋同了(0.71)。多样性在塌缩——这是「后续循环在做重复劳动」的直接证据。

图5:注意力三指标。(a) 注意力熵 H,(b) 循环间注意力分布的 KL 散度,(c) G-SWA 门控值 g(对全局分支的权重)

图5:中间 (b) 那个循环间 KL 散度最说明问题——它在 loop 2 之后急剧跌到地板并保持低位,意味着注意力的「信息路由」从 loop 3 开始基本冻结了,后面几圈注意力分布几乎不变。右边 (c) 的门控值 g 始终卡在 0.5 以上几乎不动,说明后续循环一直死死依赖那个冻结的 loop-1 全局缓存,没在用新信息。

图6:输出分布偏移三指标。(a) Logit-lens 下 ground-truth token 的排名,(b) 每循环预测变化 Δp(KL 散度,对数刻度),(c) 输出熵

图6:左边 (a) 看着挺好——ground-truth token 的排名随循环单调下降,说明预测确实越来越准。但中间 (b) 才是关键:每循环的预测变化 Δp 在 loop 2 之后崩塌,最后一圈那点小回升其实只是「读出最终预测」而非产生新的精炼。这跟前面所有透镜的结论严丝合缝。

三把透镜汇总:精炼到底分布在哪几圈

图7:以 PLT4 为例,把后上下文精炼(r≥2 的循环)在三把独立透镜下的份额拆开。三行分别是输出偏移 Δp、注意力重路由 KL、每 token 峰值贡献循环的覆盖度。loop 2 在前两个透镜上占主导(38%、50%),loop 3(灰色)在每个透镜上份额都最小

图7:这张图把账算得明明白白。输出偏移里 loop 2 占 38%、注意力重路由占 50%——都是大头。而中间那圈 loop 3(灰色)在三个维度上份额都垫底(28%/25%/13%),作者直接形容它是「几乎死掉的 pass-through」,信息从它身上流过却几乎没被加工。loop 4 那个看起来不小的输出份额(34%)其实是「最终读出」,不是真精炼——因为它的有效秩是全场最低的。

Table 3 把这些诊断浓缩成了几个数字(PLT4 模型,500 个留出样本平均):

循环 步长 δ 输出偏移 Δp 有效秩 方向对齐 cosθ
r=2 846 1.75 174.6 −0.72
r=3 464 1.32 172.5 −0.46
r=4 1014 1.58 158.2 0.04

r=2 在步长、输出偏移、有效秩三项上全是最大值——它干了最多的实活。r=4 步长虽大(1014),但有效秩最低(158.2),印证了「它只是在读出最终答案、而非丰富表征」。


💡 一个意外的彩蛋:潜在循环和显式 CoT 是超加性的

论文 4.3 节还藏了个我觉得很有价值的发现。作者在 R=2 配置下,对比了「只有潜在循环的指令模型」和「显式 CoT + 循环的 thinking 模型」:

模型(R=2) LiveCodeBench CRUX MultiPL-E FullStackBench BCB-Hard
Instruct(仅潜在循环) 35.4 86.9 73.9 47.2 23.7
Thinking(显式 CoT + 循环) 62.3 93.5 77.8 49.9 26.4
Δ 涨 26.9 +6.6 +3.9 +2.7 +2.7

LiveCodeBench 上直接涨了 27 个点左右。作者的观点是这两种机制是超加性的——联合收益超过各自单独贡献之和。原因也讲得通:显式 CoT 在「文本层面」把问题拆成步骤,潜在循环在「表征层面」精炼每一步的底层表示,两者在不同粒度上各干各的活,互不抢戏。

这个发现对实践挺有启发——它暗示「让模型多想几步(CoT)」和「让模型把每步想得更深(循环)」不是二选一,而是可以叠加的两个维度。


🤔 我的判断:这篇论文好在哪,又有哪些地方该打问号

先说好的。

最大的价值是「把超参变成可诊断的对象」。 以前选循环次数基本靠暴力网格搜索,每个取值训一遍看效果。这篇论文给了一个更聪明的替代方案:盯着有效秩轨迹看就行——如果有效秩还在涨,说明额外循环还在带来真精炼,可以继续;一旦它开始掉头向下,就别循环了,再循环只是白交 CLP 的过路费。这个 per-model 的轻量诊断,比从零训一个新模型便宜太多了。

剪刀模型这个 framing 我也很喜欢。 把「增益递减」和「成本恒定」两条曲线摆在一起,非单调现象一下子就有了直观的物理解释,而不是一句空洞的「我们发现 2 次最好」。

再说几个我打问号的地方。

第一,这个结论有多大普适性? 整个研究是在一个特定架构(PLT + CLP + G-SWA)、特定规模(7B)、特定领域(代码)上做的。CLP 的位置偏移成本是这个特定并行化方案的副产物——如果换一种并行机制、或者顺序循环(没有 CLP 偏移成本),那条「成本恒定」的红线还在不在?甜点还是不是 2?论文没有正面回答。所以「Only Loop Once」更准确的说法应该是「在 PLT 这套方案下,只值得多循环一次」,而不是循环 Transformer 的普遍规律。

第二,会不会是 CLP 设计本身的锅? 退一步想,如果偏移成本是退化的元凶,那是不是说明 CLP 这个并行化方案本身有缺陷?也许换一个不引入位置错配的并行方法,就能把甜点往后推、循环更多次也不亏。作者在未来工作里也提到了「自适应偏移机制」,等于侧面承认了这一点。所以这篇论文与其说证明了「循环就该只跑两次」,不如说精准定位了当前并行循环方案的瓶颈在哪

第三,成本是真的高。 为了一个超参规律烧掉 1M GPU 小时,这个研究范式普通团队根本复现不了。结论再漂亮,可迁移性也得打个折扣——别的架构想验证,又是一笔天文数字。

但瑕不掩瑜。我觉得这篇论文的方法论价值大于它那个 64.4 的数字本身。它示范了一种「不止于刷榜、而是把现象拆到机制层面」的研究姿态,这种把诊断指标做扎实、三把透镜交叉验证的做法,值得做模型分析的同行学一学。

如果你也在折腾循环 Transformer 或者任何形式的 test-time 计算扩展,我的建议是:别一上来就堆循环次数,先把「每循环的边际增益」和「每循环的固定成本」这两条曲线画出来,交点在哪,你的甜点就在哪。


觉得有启发的话,欢迎点赞、在看、转发。跟进最新 AI 前沿,关注我