研究笔记 · 2026 年 10 月 23 日
循环语言模型把同一组层反复使用,参数不变,计算却能一轮轮加深。代价是训练很贵,Parcae 的训练配方让每条样本平均循环 8 轮。我们在一张 5090 24G 上训练了 60 多个小模型,想弄清楚这 8 轮里有多少是必要的,省下来的算力又能换来什么。
如何理解文中数据:文中的 loss 是验证集上的交叉熵,越低越好。在我们的规模上,loss 低 0.01,大约相当于多训 2% 到 5% 的数据。同一个配方换一个随机种子重新训练,loss 会有 0.001 到 0.01 的出入,所以差距在 0.01 以内的,我们一律算作随机噪声。
普通 Transformer 的每一层只用一次。循环语言模型把中间几层做成一个循环块,让同一个序列反复穿过它,每多循环一轮,就相当于多了一层深度,参数却没有增加。我们用的结构和 Parcae 相同:开头 2 层和结尾 2 层各跑一次,中间 2 层组成循环块,重复 T 轮,每一轮都会重新读入开头两层的输出(图 1)。
循环块多跑一轮,就多一份计算,训练时还要加上反向传播。Parcae 是目前公开的效果较好的循环模型训练配方,下文称为原配方。它给每条样本随机抽一个循环轮数,平均 8 轮;为了省显存和计算,只有最后 4 轮计算梯度,前面的轮次只做前向。推理时一般循环 8 到 12 轮。
因此我们逐项检查这笔算力到底合不合算:平均 8 轮一定需要吗?如果只训练,最后 4 轮划不划算?每一轮都必须看完整的上下文吗?
先看原配方训出来的模型在推理时做了什么。我们取一个 1.44 亿参数、训练了 10 亿 token 的模型,让它分别循环 1 到 32 轮,测验证 loss(图 2)。从 1 轮到 4 轮,loss 从 3.50 降到 3.26;从 4 轮到 8 轮只再降了 0.016;8 轮以后几乎是一条平线。前 4 轮拿到了 1 到 8 轮全部收益的 94%。我们训练的 7 个这个规模的原配方模型都是如此。
原配方模型:推理时循环几轮,loss 是多少
| 推理时循环轮数 | 种子 43 | 种子 44 | 平均 |
|---|---|---|---|
| 1 | 3.5066 | 3.4944 | 3.5005 |
| 2 | 3.3393 | 3.3357 | 3.3375 |
| 3 | 3.2840 | 3.2822 | 3.2831 |
| 4 | 3.2622 | 3.2610 | 3.2616 |
| 6 | 3.2487 | 3.2478 | 3.2483 |
| 8 | 3.2463 | 3.2451 | 3.2457 |
| 12 | 3.2458 | 3.2446 | 3.2452 |
| 16 | 3.2459 | 3.2447 | 3.2453 |
| 24 | 3.2461 | 3.2449 | 3.2455 |
| 32 | 3.2461 | 3.2449 | 3.2455 |
隐状态的变化也是这样。每多循环一轮,隐状态的改动大约只有上一轮的一半到三分之二,到第 12 轮已经小到和 bf16 的舍入误差相当。模型很快停在一个固定的状态上,再循环下去状态也不会变。原配方训练时平均跑的 8 轮里,后面几轮对结果几乎没有贡献,花的算力却和前几轮一样多。
那么很自然的,取到 elbow point 会不会也行?
据此,我们对原配方做了两处改动,合称精简配方(图 1 第三行)。第一,训练时每次固定循环 4 轮,4 轮都计算梯度,不再随机抽轮数,也不再有只做前向的轮次。第二,循环块只在第 1 轮看完整的上下文,第 2 到第 4 轮只看最近 64 个 token;开头和结尾的 4 层不变。
同样的训练数据下,精简配方循环 4 轮的效果,和原配方在它最好的轮数(12 轮)下一样好。1.44 亿参数的模型训练 10 亿 token,两个种子上精简配方都低 0.005,在误差范围内;8650 万参数的模型训练 5 亿 token,三个种子上精简配方都更好,平均低 0.025。训练也快了约 1.4 倍。下面两节分别解释这两处改动为什么不损失效果,然后再看速度上的差距。
| 模型 | 训练数据 | 种子 | 原配方(最好的轮数) | 固定 4 轮 | 精简配方 |
|---|---|---|---|---|---|
| 8650 万参数 | 5 亿 token | 43 | 3.5502 | 3.5396 | 3.5319 |
| 44 | 3.5475 | 3.5419 | 3.5201 | ||
| 45 | 3.5537 | 3.5440 | 3.5232 | ||
| 1.44 亿参数 | 10 亿 token | 43 | 3.2458 | 3.2433 | 3.2413 |
| 44 | 3.2446 | 3.2407 | 3.2392 | ||
| 1.44 亿参数 | 20 亿 token | 43 | 3.0937 | — | 3.1024 |
| 44 | 3.0927 | — | 3.0981 |
验证 loss。原配方取 1 到 32 轮中最好的一档(都是 12 轮),另两种取 4 轮。同一行的几种配方用同一个种子,初始化和数据顺序相同。测试集上的方向和验证集一致。
我们测了两种模型在每一轮让隐状态改变了多少(图 3)。原配方的模型,第 2、3、4 轮的改动每轮减半,很快停了下来。精简配方的模型,这三轮的改动一直很大,每一轮都在大幅改写隐状态,到最后也没有收敛下来,前后差得很多。
每一轮让隐状态改变了多少
| 模型 | 第 2 轮 | 第 3 轮 | 第 4 轮 |
|---|---|---|---|
| 原配方(20 亿 token) | 0.37 | 0.18 | 0.09 |
| 精简配方(20 亿 token) | 0.62 | 0.56 | 0.63 |
| 固定 4 轮、全注意力(10 亿 token) | 0.70 | 0.54 | 0.46 |
我们的理解是,差别来自训练时梯度经过了哪些轮次。原配方的轮数随机,平均 8 轮,但只有最后 4 轮有梯度。只有约十分之一的样本会抽到 4 轮以内,这时从初始状态出发的前几轮才会被训练到;其余样本训练的都是已经接近不动点的那几轮。模型于是学会了尽快收敛,然后停住。固定 4 轮时,从初始状态到输出的每一轮都有梯度,模型就学会了把每一轮都用上。
两个对照实验支持这个解释,各做了一次。第一个在相同的训练时间里比较两种用法:循环 4 轮、4 轮都算梯度,比循环 6 轮、前 3 轮不算梯度的 loss 低 0.023,多跑的那几轮不如让每一轮都参与训练。第二个保持原配方随机抽轮数的做法,但只让最后 1 轮算梯度,模型从循环中得到的收益,也就是从循环 1 轮到 8 轮 loss 的降幅,从 0.23 缩到了 0.11,模型对循环的利用少了将近一半,少掉的这一截在数字上相当明显。
固定轮数也有代价,模型只能循环 4 轮(图 4)。少跑或多跑,loss 都明显变差,循环 8 轮时比 4 轮高 0.07,只循环 1 轮时高 0.8。原配方的模型则可以在 6 到 32 轮之间随意选,效果差不多。这等于放弃了循环模型的一个卖点,即推理时多循环几轮来换更好的结果。不过图 2 也说明,原配方在这一点上本来就很有限,超过 8 轮就没有收益了。Huang et al. (2026) 在 1 亿到 16 亿参数的模型上观察到了同样的两点。
推理时循环几轮,loss 是多少:两种配方对比
| 推理时循环轮数 | 原配方 · 种子 43 | 种子 44 | 精简配方 · 种子 43 | 种子 44 |
|---|---|---|---|---|
| 1 | 3.5066 | 3.4944 | 4.0478 | 4.0400 |
| 2 | 3.3393 | 3.3357 | 3.6453 | 3.6365 |
| 3 | 3.2840 | 3.2822 | 3.4292 | 3.4358 |
| 4 | 3.2622 | 3.2610 | 3.2413 | 3.2392 |
| 6 | 3.2487 | 3.2478 | 3.4620 | 3.4139 |
| 8 | 3.2463 | 3.2451 | 3.3057 | 3.3114 |
| 12 | 3.2458 | 3.2446 | 3.3387 | 3.3439 |
| 16 | 3.2459 | 3.2447 | 3.3495 | 3.3513 |
| 24 | 3.2461 | 3.2449 | 3.3538 | 3.3521 |
| 32 | 3.2461 | 3.2449 | 3.3541 | 3.3518 |
所以如果决定了就是要推理四轮,或许就应该在训练时也固定四轮,当然这符合直觉到十分 trivial。
第二处改动来自一组削减实验。我们在 8650 万参数的模型上,从固定 4 轮模型的循环块里各削掉一部分计算,看哪些可以省(图 5)。
从循环块里削掉一部分计算,loss 怎么变
| 循环块的改动 | 验证 loss | 相对基准 | 训练时间 |
|---|---|---|---|
| 基准:固定 4 轮、全注意力 | 3.5396 | 0 | 1.99 小时 |
| 第 2–4 轮只看最近 64 个 token | 3.5319 | −0.008 | 1.80 小时 |
| 4 轮都只看最近 64 个 token | 3.5317 | −0.008 | 1.70 小时 |
| 第 2–4 轮只看最近 256 个 token | 3.5385 | −0.001 | 1.81 小时 |
| 第 2–4 轮宽度减半(注意力头和 MLP 都减半) | 3.5684 | +0.029 | 1.76 小时 |
| 第 2–4 轮去掉注意力,只留 MLP | 3.5870 | +0.047 | 1.60 小时 |
| 第 2–4 轮复用第 1 轮的 KV | 3.5705 | +0.031 | 1.93 小时 |
| 只循环 2 轮 | 3.5653 | +0.026 | 1.56 小时 |
| 参照:原配方 | 3.5502 | +0.011 | 2.59 小时 |
| 参照:普通 Transformer(6 层,不循环) | 3.5540 | +0.014 | 1.33 小时 |
只有缩短注意力范围不伤效果。第 2 到第 4 轮只看最近 64 个或 256 个 token,loss 都没有变差;连第 1 轮也只看 64 个 token,结果也一样。其他削减都明显变差。后几轮的宽度减半,loss 高 0.029;后几轮去掉注意力只留 MLP,高 0.047;后几轮直接复用第 1 轮的 KV,高 0.031;只循环 2 轮时,loss 则高了 0.026。
所以循环块的每一轮都需要完整的宽度和自己的注意力,只是不需要看远处的 token,远处的信息由开头和结尾那 4 层完整注意力来处理。只看最近 64 个 token 的做法,在另外两个种子和 1.44 亿参数的模型上都复现了。精简配方保留了第 1 轮的完整注意力,是偏保守的选择。
这个算力节省也不是免费的。逐个 token 拆开看,需要从 500 多个 token 以前复制内容的 token,loss 高了约 0.02,这类 token 约占 3%;其余 token 的 loss 略低。下游任务上两种配方的高下之分,还有待更大规模的实验分析。
两处改动合起来,1.44 亿参数模型的训练速度从每秒 3.5 万 token 提高到 4.9 万,快 1.42 倍。这里面有一部分来自原配方现有实现的一个低效之处。它给每条样本单独抽轮数,同一批里的样本要陪着轮数最多的那条一起跑,15% 到 20% 的计算花在补齐上。如果改成整批抽同一个轮数,原配方自己能快约 15%,精简配方的优势降到 1.25 倍。
更快的训练可以换成更低的 loss。我们让原配方少训一些数据,使它的训练时间和精简配方相同,两边都完整走完学习率的衰减,再来比较(图 6)。同样训练 5.7 小时,精简配方的 loss 低 0.11;同样训练 11.3 小时,低 0.06;8650 万参数的模型同样训练 1.8 小时,低 0.18。6 组重复的方向全部一致。这里比的是原配方的现有实现。修掉上面那个补齐开销之后,差距大约会缩小三分之一到一半,剩下的主要是循环本身的开销。
同样的训练时间,谁的 loss 更低
8650 万参数
1.44 亿参数
| 模型 | 训练时间 | 种子 | 原配方(训练数据) | 精简配方(训练数据) | 差 |
|---|---|---|---|---|---|
| 8650 万参数 | 约 1.8 小时 | 43 | 3.6979(3.45 亿 token) | 3.5319(5 亿 token) | −0.166 |
| 44 | 3.7024 | 3.5201 | −0.182 | ||
| 45 | 3.7081 | 3.5232 | −0.185 | ||
| 1.44 亿参数 | 约 5.7 小时 | 43 | 3.3521(7.04 亿 token) | 3.2413(10 亿 token) | −0.111 |
| 44 | 3.3547 | 3.2392 | −0.116 | ||
| 1.44 亿参数 | 约 11.3 小时 | 43 | 3.1654(14.1 亿 token) | 3.1024(20 亿 token) | −0.063 |
其他点:原配方 1.44 亿参数训练 10 亿 token 用 8.07 小时(3.2452),20 亿 token 用 15.98 小时(3.0932);8650 万参数训练 5 亿 token 用 2.61 小时(3.5505)。普通 Transformer(8650 万参数,种子 43)训练 5 亿 token 用 1.33 小时(3.5540),7.5 亿 token 用 1.99 小时(3.4673)。
生成文本时差别更大。循环模型每循环一轮,就要为这一轮单独存一份 KV 缓存,原配方循环 8 轮就要存 8 份。精简配方只循环 4 轮,后 3 轮又只需要存最近 64 个 token。我们按 1.44 亿参数模型的结构测了生成一个 token 的耗时(图 7),精简配方比原配方循环 8 轮快 2.3 到 3.1 倍,KV 缓存约为三分之一。上下文 1.6 万 token 时,它和同样大小的普通 6 层 Transformer 差不多快,缓存也一样大,因为两者都只有 6 层需要看完整的上下文。上下文只有 2000 token 时,普通 Transformer 的耗时还要少约 20%。
生成一个 token 的耗时(毫秒)
KV 缓存(MB)
| 结构 | 2000 token 一次 1 条 | 2000 token 一次 64 条 | KV 缓存 | 1.6 万 token 一次 1 条 | 1.6 万 token 一次 8 条 | KV 缓存 |
|---|---|---|---|---|---|---|
| 原配方(循环 8 轮) | 4.66 ms | 20.17 ms | 120 MB | 25.07 ms | 27.01 ms | 960 MB |
| 固定 4 轮 | 3.09 ms | 12.47 ms | 72 MB | 15.26 ms | 16.23 ms | 576 MB |
| 精简配方 | 2.00 ms | 7.01 ms | 37 MB | 8.11 ms | 8.63 ms | 289 MB |
| 4 轮都只看 64 个 token | 1.67 ms | 5.31 ms | 26 MB | 5.80 ms | 6.12 ms | 194 MB |
| 普通 Transformer(6 层) | 1.57 ms | 6.39 ms | 36 MB | 7.87 ms | 8.13 ms | 288 MB |
bf16,静态 KV 缓存,整个生成步骤用 CUDA graph 捕获,局部注意力的轮次用 64 格的环形缓存。耗时只取决于结构,与权重的具体数值无关,所以用的是随机权重。KV 缓存是一次 1 条时的大小。
同样训练时间下的差距,从较小模型的 0.18,到较大模型训练 5.7 小时的 0.11,再到训练 11.3 小时的 0.06,一路在缩小。按同样的训练数据比,趋势也一样。1.44 亿参数的模型训到 20 亿 token 时,原配方循环 12 轮的 loss 比精简配方低 0.005 到 0.009,两个种子都是如此,原配方反超了。它要循环 12 轮才做到,是精简配方的 3 倍;如果它也只循环 4 轮,loss 仍比精简配方高出 0.013 到 0.014,两个种子上都看得到。这有 loss 收敛的原因,也有可能节省的算力 scale 上去后便不值一提。
看起来训练量越大,多循环几轮越值得,这和 Parcae 论文里的缩放规律一致。固定循环更多轮能不能保住优势,较小模型上固定 8 轮比原配方低 0.034,更大训练量上的结果还有待实验分析。
在 8650 万参数的模型上,我们还训练了一个参数量相同、不循环的 6 层 Transformer。同样训练约 2 小时,它的 loss 比所有循环版本都低,比精简配方低 0.03 到 0.04(图 6 上图的绿线)。在这么小的规模上,循环本身还不划算,精简配方缩小了差距,但没有扭转。
所有结论都来自最多 1.44 亿参数、20 亿 token 的训练,只用了一个数据集(FineWeb-Edu)和一张 5090 24G。这两个模型的参数大部分在词嵌入上,真正参与计算的分别只有 19.4 M 和 43.7 M。
这里的大部分现象印证了已有的结论,也补充了一些新的观察。
我们补充的有三点:在同一套设置里,把训练时间、生成速度和效果放在一起算账,包括实现上的开销;用每一轮隐状态的变化,解释固定轮数为什么不吃亏;以及循环块里哪些计算能省、哪些不能省,做了一组对照实验。
复制以下 BibTeX 条目用于论文或研究笔记。
讨论