想让模型"多想一会儿",标准做法是让它多生成文字——这就是思维链。 但这条路有个绕不开的收费口:每想一步,都要先把想法压成一个离散的、人能读的词, 而且一次只能输出一个。
还有另一个做法:楼不加高,让数据在同一段楼梯上多绕几圈。 绕三圈就相当于走了三倍的层数,参数一个没多加。2018 年就有这个想法了。
2025 到 2026 年,这条路线上突然出现了一批真东西:3.5B 参数训出来的模型 可以在推理时自由加圈换准确率;清华和字节 Seed 的论文在同时锁死算力、 参数、KV Cache 三本账的条件下,仍然测出 6.8%–18.0% 的训练 FLOPs 节省。
但它有一个没人愿意付的代价,而且这个代价和收益是同一件事的两面。
一、两个默认出口,各自在机制上必然收费
先说清楚这条路到底想要什么。
现在的语言模型想做多步串行计算,默认只有两个出口:
出口一:把楼盖高(加层)
串行深度 = 层数,这是写死在结构里的上界
收费:每加一层都要一份新参数
→ 深度和参数量被焊死
→ 你多存了一批东西,哪怕这批东西不是拿来存知识的
出口二:让它多生成文字(思维链)
深度不受层数限制,写出来的每步都能当下一轮输入
收费:每一步都要先压成离散的、人能读的词
→ 窄(一次一个 token)
→ 慢(串行解码)
→ 有损(模型内部用连续向量表示概念,翻译成词必然丢信息)
第二条收费值得展开。模型内部"想"一个概念,是一长串连续的数,可以同时压着好几种可能性。而输出的词只能挑一种,而且一旦输出就改不了。翻译这道关口既慢又有损。
第三条路就是:楼梯不造新的,让数据在同一段楼梯上多绕几圈。核心就是这三行:
block = TransformerBlock() # 楼梯只造一份
for _ in range(num_loops): # 循环几次,临时定
h = block(h) # 每一次用的是同一份参数
后面十篇论文的分歧,全在这三行之外:循环次数由谁定、每一遍之间存什么、循环时人能不能看见。
二、机制:Huginn 的 P/R/C 与两个容易被忽略的设计
以 ELLIS Institute Tübingen 的 Jonas Geiping 等人的 Huginn(arXiv:2502.05171)为例。它把网络拆成三段:
┌─────────┐ ┌──────────────────┐ ┌─────────┐
输入 ──▶│ Prelude │───▶│ Core │───▶│ Coda │──▶ 输出概率
│ (P) │ │ (R) │ │ (C) │
└─────────┘ └──────────────────┘ └─────────┘
2 层 4 层,循环 r 次 2 层
▲ │
└──────┘ 同一份权重
每轮重新注入输入嵌入 e
具体配置:2 层 Prelude + 4 层共享 Core + 2 层 Coda = 8 层参数。Core 循环 32 次时:
执行深度 = 2 + 4×32 + 2 = 132 层
参数深度 = 8 层
执行了 132 层,只存了 8 层。 这就是"物理深度(physical depth)"和"有效深度(effective depth)"的分离。
两个反直觉的设计
第一,循环核心的隐藏状态不是从输入嵌入开始,而是从零(或高斯噪声)初始化。
第二,每一轮循环都重新注入原始输入嵌入 e。
e = model.encode(ids) # [B, T, d],只算一次
h = torch.zeros_like(e) # 隐藏状态初始化一次
for _ in range(loops):
h = model.update_state(h, e) # 每轮都把 e 重新拼进来
logits = model.lm_head(model.coda(h))
为什么不直接把 e 当初始状态一直循环?因为那样模型会过度依赖第一次进入循环时的状态,循环次数一多,微小偏差被不断放大,隐藏状态可能逐渐丢失原始输入信息。
每轮重新注入 e,等于给迭代过程加了一个固定锚点——无论内部状态怎么漂,模型始终知道自己正在处理什么问题。
随机初始化则是在逼模型学"路径无关性(path independence)":从不同起点出发,仍然能把状态推向相近的有效表示。它要学的不是一条只能从固定起点执行的计算链,而是一种能反复修正、逐渐趋于稳定的更新规则。
训练:随机采深度 + 截断 BPTT
loops = random.choice((2, 4, 8, 16)) # 每个样本随机采一个深度
logits = model(inputs, loops=loops)
loss = F.cross_entropy(logits.view(-1, V), targets.view(-1))
但反向传播很贵。Core 权重虽然共享,每调用一次都会在计算图里产生新的中间激活。完整保留 R 轮的图,反向要穿过整条状态链。折中办法:
with torch.no_grad(): # 前 R-k 轮:只前向
for _ in range(R - k):
h = model.update_state(h, e)
for _ in range(k): # 最后 k 轮:保留梯度
h = model.update_state(h, e)
Huginn 的做法是按对数正态-泊松分布采样循环次数(平均 32),反向传播只对最后 8 步做。
三、先说代价:省下的算力和丢掉的可读性,是同一件事的两面
这一节必须放在收益之前讲。
循环之所以省 token,正是因为它不输出 token。那几遍多出来的计算既然不经过"生成一个词"这道关口,就没有任何地方会把它变成人能读的东西。
Coconut(Meta FAIR, 2024.12)是最早尝试"连续思维"的工作之一,而它自己的消融实验给出了一个很不体面的结果:
| 变体 | ProsQA 成绩 |
|---|---|
| 完整版(6 步连续思维) | 97.0% → 99.8% |
| 把潜向量换成一串无意义的停顿符占位 | 96.6% → 100.0% |
| 只保留分阶段训练法,拆掉潜向量 | 95.5% → 99.9% |
三组数字落在同一个区间里。 功劳大概率在那套分阶段训练课程上,而不在"用连续向量思考"这个卖点上。
更直接的证据来自 Huginn 本身:外部探针在它的中间状态里找不到可读的推理步骤。
这条线在 2026 年 9 月引发了不小的争吵,值得记一笔:
- The Information(9/1)报道 OpenAI 的 Astra 用了"受限形式"的循环深度,落点是"思考被藏起来了"
- Jakub Pachocki(OpenAI 首席科学家)罕见直接回应,说包括 Astra 在内的前沿模型,计算图深度"在 GPT-4 的两倍以内";同时承认 CoT 监控"是脆弱的,而且不幸正在朝坏的方向走"
- Sebastian Raschka 泼冷水:复用层本身并不会压制可见的思维链,它只是在输出下一个 token 之前多算几轮。更短的 trace 更可能反映"模型犯错更少、回溯更少"
我不打算判断 Astra 用了什么——它只有匿名信源,OpenAI 的发布材料里从未出现过"循环深度"字样。但这个争论点出了一个真实的结构性张力:
如果监控工具把"trace 长度"当作"思考深度"的代理指标,那么任何让模型少写字的技术都会打破这个代理——不管它是不是循环架构。
四、收益侧的证据:三条独立的支持
4.1 推理靠深度,记忆靠参数(可以分开买)
Google Research 的 Reasoning with Latent Thoughts(2025.02)用等参数、等深度的对照实验把缩放律拆成了两半:
| 侧 | 结果 |
|---|---|
| 推理侧 | 1 层循环 12 遍,把多位数加法从 0.1% 拉到 99.9%,参数一个没加 |
| 4 层循环 6 遍在四项推理原语上拿 56.9,超过参数多 6 倍的 24 层基线(47.5) | |
| 记忆侧 | 参数只有基线 1/6,困惑度 8.79 vs 7.40;闭卷问答 6.7 vs 11.2 |
代价很干净:你在买推理深度的同时,是在卖记忆容量。 这正好解释了为什么后来的工作越来越喜欢把循环和 MoE 放在一起——前者增加处理次数,后者补充参数容量。
4.2 Huginn:推理时加圈,准确率真的会涨
同一个 checkpoint、同样的 800B token 训练,只在测试时改循环次数 r:
| 基准 | r=1 | r=8 | r=16 | r=32 |
|---|---|---|---|---|
| ARC-Easy | 34.89 | 65.11 | 69.49 | 69.91 |
| ARC-Challenge | 24.06 | 35.15 | 37.71 | 38.23 |
| HellaSwag | 29.34 | 58.54 | 64.67 | 65.21 |
| MMLU | 23.60 | 25.29 | 31.25 | 31.38 |
| OpenBookQA | 26.80 | 35.40 | 37.60 | 38.80 |
| PiQA | 55.33 | 73.45 | 75.79 | 76.22 |
| SciQ | 47.10 | 92.10 | 93.90 | 93.50 ← 掉了 |
| GSM8K (CoT) | 0.00 / 0.15 | — | — | 34.80 / 42.08 |
三个读法:
- 从 r=1 到 r=8 是断崖式提升,之后快速饱和。ARC-C 上 0-shot 大约在 8–12 次饱和,1-shot 到 20 次,25–50 few-shot 时才需要 32 次。问题越依赖上下文,越吃得住更多潜空间算力。
- SciQ 在 r=32 反而降了(93.90 → 93.50)。加圈不是单调的。
- GSM8K 从 0.00/0.15 到 34.80/42.08——不带 CoT 时几乎做不了,带上 CoT 才起来。潜空间循环不替代 CoT,两者是叠加关系。
最后这点很关键,后面还要用。
4.3 一个被遗忘的对照实验
Universal Transformer(2018)早就做过一件现在很多人忘了的事:让每个位置自己决定跑几遍。
结果是:自适应版本平均跑 8.2 遍,困惑度 142;而把遍数固定成 8 遍是 202,固定 9 遍是 239。
收益来自"每个位置自己决定跑几遍",不来自单纯多跑几遍。
这个前提后来被大多数工作丢掉了。七年后有人回头捡起来(KAIST 和 Google 的 token 级自适应版本),撞上了另一堵墙。
五、公平比较:SMELT 的三本账
到这里为止,所有比较都有一个控制问题:循环模型多执行了几遍,它拿到的预算本来就更多。 分数高不代表架构好。
SMELT(arXiv:2609.01343,2026-09-01,清华 + 字节 Seed)就是把这本账算清楚的工作。它同时锁死三个预算:
| 预算 | 对应什么 | 怎么匹配 |
|---|---|---|
| 每 token FLOPs | 训练/推理成本 | 缩窄 hidden width |
| 非嵌入总参数量 | 知识容量 | 增加 MoE 专家数补回来 |
| KV Cache | 可服务的最大上下文 | 调整 GQA / head dim |
MoE 是关键——它把"总参数量"和"每 token 计算量"解耦了,才让三本账同时匹配成为可能。
5.1 配方很克制:只让中间一半跑第二遍
在 200M active、12 物理层、约 85% 稀疏下的 ablation:
| 循环跨度 | 有效层数 | Val. loss | DCLM Core |
|---|---|---|---|
| 0%(基线) | 12 | 1.9445 | 24.92 ± 0.13 |
| 17% | 14 | 1.9384 | 26.20 ± 0.14 |
| 33% | 16 | 1.9275 | 25.13 ± 0.16 |
| 50% | 18 | 1.9257 | 27.57 ± 0.13 |
| 67% | 20 | 1.9374 | 25.84 ± 0.10 |
| 83% | 22 | 1.9413 | 24.45 ± 0.17 |
| 100%(全循环) | 24 | 1.9322 | 25.31 ± 0.17 |
50% 是最优,全循环反而更差。 作者的解释:首部靠近输入编码、尾部靠近输出预测,这两段承担专门化职责,全部共享会损失专门化能力。这正好支持 P–R–C 那种"前奏–循环中段–尾声"的布局。
5.2 两次最优,三次四次退化
| 配置 | 有效深度 | Val. loss | DCLM Core |
|---|---|---|---|
| 基线(1×) | 12 | 1.9445 | 24.92 ± 0.13 |
| 循环 2× | 18 | 1.9257 | 27.57 ± 0.13 |
| 循环 3× | 24 | 1.9385 | 27.15 ± 0.20 |
| 循环 4× | 30 | 1.9360 | 27.30 ± 0.19 |
原因不是"循环多了不好",而是为了维持 FLOPs 匹配,循环越多模型就得越窄。窄到一定程度,多出来的执行深度抵不过宽度损失。
这个结论和三个月前 LoopCoder-v2(7B dense)独立收敛到同一个数——两篇论文、两个半月、不同架构族、不同规模,都指向"两次"——其中一篇现在还给了解释。这比任何单独一篇都强。
5.3 规模化结果与机制
四个激活规模(100M / 200M / 600M / 1.6B)× 四个稀疏度,最大到 54B 非嵌入参数,共 16 对匹配配置。给每个架构单独拟合 Chinchilla 式 scaling law:L = E + A/(F^a · S^b) + K/D^c
| 指数 | Baseline | SMELT |
|---|---|---|
算力指数 a | 0.3703 | 0.3892 |
数据指数 c | 0.6594 | 0.7011 |
两个指数都更大 = loss 随算力和数据下降得更快。在计算最优前沿上,节省 6.8%–18.0% 训练 FLOPs,且节省比例随预算增大而增大。
下游:DCLM 96 个配置中 83 个胜出,MMLU 30 个 above-chance 配置中 29 个胜出,而且收益超过 val loss 预测的部分(同等 loss 下 SMELT 得分更高,gap 随规模变大)。
领域分布:Code > Finance, Math/STEM > Web。长上下文样本的收益显著大于短上下文——而这个模式在单纯加专家或加参数时观察不到,说明它是循环独有的。
机制上,作者给了两个可观测的东西:
- 第二次访问会削弱 attention sink(注意力质量堆在少数无信息量的首/分隔 token 上的现象),把质量重定向到内容相关 token。这解释了为什么收益随上下文变长而变大——要区分的东西越多,sink 越伤。
- 专家路由:第二次经过同一个物理 MoE 层时,router 没有照搬第一次的选择。约 97% 稀疏度下,top-8 专家通常只重合 2–3 个。
5.4 Loopie 的警告:优势可能来得很晚
另一篇按实际训练时间(而非理论 FLOPs)匹配的工作是 Loopie(2026.07)。它的结果里有一条对所有团队都重要:
Loopie-20B-A2B 与同等硬件、同等 token 预算的 Qwen3 风格 30B-A3B MoE 相比,训练早期落后,约到 600B token 才反超。
如果实验停在 300B token,结论可能正好相反。
对没有这个训练预算的团队,这条路线未必合算。
六、五个工程死结
6.1 循环不减少串行计算,p99 可能更难看
Prime Intellect 的 Elie Bakouch 的质疑最直接:vanilla recurrent depth 不会自动缩短训练或推理时间。 信息仍要走完全部有效深度,而且循环带有串行依赖,单请求 p99 甚至可能更难看。
这不是说循环没用,而是说收益的来源不是"算得更少",而是"存得更少"。权重和 optimizer state 变少后,显存和通信开销下降,省出的预算可以拿去放大 microbatch、加专家或加宽度。这是系统层的收益,不是算法层的。
6.2 KV Cache 不会因为你"没多生成 token"就不涨
一个很容易踩的坑。循环的 KV 缓存需要区分维度:
cache[层号][循环轮次][token 位置]
循环没有增加序列长度 T,但增加了"执行层数"。所以"不生成更多 token"推不出"KV Cache 不增长"。标准循环 Transformer 在长上下文下,KV 膨胀是直接 OOM 的级别。
(这也是为什么 SMELT 要把 KV Cache 单列为一本账——不算这本账的循环模型,在服务时就不是 drop-in 替代。)
6.3 Coconut 的消融至今没有被正面回应
重复一遍那个表:把潜向量换成无意义停顿符,成绩不变。
这个结果说明"在潜空间里思考"这件事,在某些任务上的贡献可能主要是训练课程带来的,而不是连续表示带来的。SMELT 的 attention-sink 机制分析是目前最好的正面回应(它给出了一个可测量的、循环独有的效应),但它解释的是"第二次访问改变了注意力分配",不是"潜向量承载了比文字更丰富的推理"。
6.4 SMELT 是 arXiv v1,且架构搜索只在 200M 完成
必须说清楚:
- 没有独立复现
- 关键架构搜索(循环跨度、深度宽度比、循环次数)只在约 200M active 参数完成,然后外推到 1.6B
- 匹配的是算术预算,不是真实 wall-clock
- 残差不匹配虽然小但不为零:FLOPs 最大 3.9%、参数 1.0%、KV Cache 3.6%(作者用实测 FLOPs 进入拟合,方法上比"贴个 matched 标签就当相等"更严谨,但残差仍在)
- span 的选择基于 val loss,而下游指标排序不一致:约 95% 稀疏下,DCLM Core 偏好 67% 跨度,val loss 偏好 50%
不能直接把 6.8%–18.0% 外推到商业模型。
6.5 循环不替代 CoT
Huginn 的 GSM8K 数字已经说明了:不带 CoT 时 0.00/0.15,带上才到 34.80/42.08。
Nous Research 的 Shannon Sands 说得更直白:循环模型的计算路径接近把普通模型加深 2–3 倍,recurrent depth 不会取代 CoT。
它们的分工应该是:循环提供"每步更深的加工",CoT 提供"更多步 + 可审计的中间态"。 想用循环把 CoT 全省掉,既做不到,也不该做。
七、决策树与可执行判断
你的瓶颈到底是哪一个?
│
├── 显存 / 参数通信 / optimizer state
│ → 循环有真实收益(Loopie 的路径)
│ → 但确认你有 >600B token 的训练预算
│
├── 算术 FLOPs
│ → 循环不省算术量。省不了多少。
│
├── 单请求延迟 / p99
│ → 循环是负收益(串行依赖变长)
│
├── 长上下文的 KV Cache
│ → 循环会加重问题,除非你做跨循环 KV 共享
│
└── 可审计性
→ 循环明确是负的。潜空间不可读是机制上的必然。
如果要做,配方是这四条
- 只循环中间约 50% 的层,跑两遍。 三遍四遍会因为 FLOPs 匹配迫使模型变窄而退化。全循环也不如半循环。
- 首部和尾部保留独立参数。 它们承担输入编码和输出预测的专门化职责。
- 循环模型偏好更大的执行深度/宽度比。 额外执行深度不增加参数,共享参数同时收到浅位和深位的梯度信号,训练反而更稳。
- 每轮重新注入输入嵌入,隐藏状态从零/噪声初始化。 这是路径无关性的来源。
系统层必做的三件事
- 跨循环深度共享 KV Cache——所有循环轮次共享权重,这是天然的优化点
- 投机解码:低
r起草、高r验证,草稿状态可复用(r=4的 s0→s3 可以直接续到r=12) - per-token 早退:简单 token 的潜状态收敛得更快,不需要跑满
八、我的判断
第一,这条线真正的价值可能不在"省算力",而在"把深度和参数解耦"。
过去加深度必然加参数,是因为深度和参数被焊在同一个旋钮上。循环把这根焊点拆开了——于是你可以分别回答"这个任务需要多少连续计算步"和"这个任务需要存多少知识"。SMELT 最重要的结果不是 6.8%–18.0%,而是证明了这本账拆开之后仍然有收益。
第二,"两次"这个数字比任何单项收益都更值得记住。
两篇论文、两个半月、一个 dense 一个 MoE、规模差一个数量级,独立收敛到同一个循环次数,而且后一篇还给了解释(第三次访问时,为匹配 FLOPs 而被迫变窄的宽度损失超过了深度收益)。这种交叉验证在架构研究里很罕见。
第三,最被低估的风险是可审计性,而它恰好和收益同源。
省下的算力和丢掉的可读性是同一件事的两面——这不是工程没做好,是机制上的必然。Coconut 的消融、Huginn 的探针失败、Astra 的 trace 缩短,指向的是同一件事。
如果你的系统里有任何一层依赖"读模型的推理过程"来做安全检查或合规审计,那么"让模型少写字"的每一项优化都在削弱这一层——不管它叫循环深度、潜空间推理还是别的什么。 这类系统应该把 trace 长度当作一个要主动监控的指标,而不是一个顺带变小的数字。
第四,对大多数团队,现在还不是上车的时候。
Loopie 的 600B token 才反超是个硬警告。SMELT 是 v1、无复现、架构搜索在 200M 完成。而收益的实现路径(更大的 microbatch、更少的通信)只对自己从头预训练大模型的团队有意义。
如果你是在做微调、做应用、做 agent——这条线目前对你没有任何可执行的动作。 值得做的是记住那个决策树,等开源生态出现可调 loop count 的成熟权重(字节的 Ouro 已经开了个头),再实测。
下一个值得看的信号:有没有第二个团队在 SMELT 的三本账口径下复现 6.8%–18.0%,尤其是在真实 wall-clock 而不只是算术 FLOPs 上。如果复现成功且 wall-clock 也对得上,这条线会从"有意思的架构研究"变成"预训练的默认选项之一";如果对不上,那它就只是把成本从显存挪回了时间。
参考
- Huginn / Recurrent Depth:Jonas Geiping et al.(ELLIS Institute Tübingen),Scaling up Test-Time Compute with Latent Reasoning: A Recurrent Depth Approach,arXiv:2502.05171。3.5B 参数、约 7950 亿 token、Frontier 超算 4096 张 MI250X。本文第二节机制与第四节实验表出自此文。
- SMELT:Jian Li, Jiaheng Liu, Ge Zhang 等(清华 + 字节 Seed),SMELT: Scaling Laws for Compute-Matched MoE Looped Transformers,arXiv:2609.01343,2026-09-01 提交。三本账、配方 ablation、scaling law 指数、attention sink 与专家路由分析均出自此文。
- Coconut:Shibo Hao et al.(Meta FAIR),2024-12。潜向量消融实验出自此文。
- Reasoning with Latent Thoughts:Nikunj Saunshi et al.(Google Research),2025-02。深度/参数分离实验出自此文。
- Universal Transformer:Mostafa Dehghani et al.(Google Brain),arXiv:1807.03819,2018。自适应 vs 固定遍数的对照出自此文。
- Loopie:Loop the Loopies!,2026-07。600B token 反超的观察出自此文。
- Parcae:循环训练稳定性,谱范数约束注入参数。
- 争议与评论:Jakub Pachocki(OpenAI)关于计算图深度与 CoT 监控的公开回应;Sebastian Raschka,Ahead of AI,2026-09-09;Elie Bakouch(Prime Intellect)关于串行计算与 p99 的质疑;Shannon Sands(Nous Research)。ARC Prize Foundation 对某个病毒式传播结果的独立复现发现其"起效的原因与宣传的不同"。
数据来源与免责说明
- Huginn 的测试时 scaling 表(r=1/8/16/32)引自该论文公开表格;SciQ 在 r=32 的回落(93.90→93.50)为原表数据,非本文推断。
- SMELT 的 6.8%–18.0% 为计算最优前沿上、按各自拟合的 scaling law 曲面在相同算力与稀疏度坐标下比较得出的结果;论文明确匹配的是算术预算而非真实 wall-clock,架构搜索在约 200M active 完成。该论文为 arXiv v1,无独立复现,不应直接外推至商业模型。
- Coconut 的消融数据(潜向量换成停顿符后成绩不变)为该论文自报,本文如实引用;该结果至今未见正面回应。
- 关于 OpenAI Astra 是否采用循环深度:仅有 The Information 的匿名信源报道,OpenAI 从未在发布材料中使用"循环深度"字样,Pachocki 的回应也未确认架构。本文不对此下判断,只记录三方说法。
- 文中"省下的算力和丢掉的可读性是同一件事的两面"是本文基于上述证据的归纳,非任何单一论文的原文表述。
- 本文未对任何方法做独立实验验证。