Modular Connections
残差流之间的连接,本身也可以是模块化的模型
DeepSeek 提出的 mHC(Manifold-Constrained Hyper-Connections)把 Transformer 的单条残差流扩展为 N 条并行的流。于是每个子层都要回答三个问题:从哪些流读取输入,把输出写回哪些流,流与流之间又如何混合。这三件事合起来,就是残差流之间的连接。
在 mHC 中,这些连接只是几组系数:每个 token 经过一个小投影(再加上静态偏置),当场算出自己的读、写和混合权重。我的发现是,残差流之间的连接本身也可以是一个模块化的模型。每个子层可以维护一组读、写和混合模块,每个 token 像在 MoE 中那样路由到其中几个,再把它们加权组合。MoE 把子层内部的计算拆成了可路由的模块,这里拆开的则是残差流之间的连接。我把这种做法称为 Modular Connections,简称 MoC。
最近一项针对 DeepSeek-V4-Flash 的分析,从反方向印证了这个观点(Zhao et al., arXiv:2609.05309)。该模型的 mHC 本可以为每个 token 生成不同的连接,训练出来却很少用到这份自由:各子层读写的有效流数平均约为 2,同一段输入中近九成 token 共享同一条主导流;把 43 层中前 22 层的混合矩阵固定为各自在数据上的均值,困惑度仅上升 0.2%;后 21 层的混合矩阵则整体接近单位阵。换言之,连接本来就是模块化的:每个子层都有相对稳定的连接模式,只是被 mHC 逐 token 生成系数的方式掩盖了。
这个想法来自我在纸上推演 mHC 对单个 token 的计算。只要把 N 条流换一种顺序排开,读、写、混合就分别成了一个卷积、一个反卷积(转置卷积)和一个滑动的 4×4 映射(第 2 节)。从这个角度看,每个 token 的连接就是一组核,而核完全可以有很多个,交给 token 去挑选。第 3 节给出 MoC 的具体形式,第 4 节用它重新解读 DeepSeek-V4-Flash 中的观察,第 5 节报告 MoC 带来的实际收益。
1. mHC 的一步
标准的残差连接只有一条流:
Hyper-Connections 把 C 维的残差状态扩展为 N 条流,记作 Xl ∈ ℝN×C,mHC 取 N = 4。每个子层(Attention 或 MLP)围绕这些流做三件事:
- 读 Hpre ∈ ℝ1×N:把 N 条流加权合成一路,作为子层 F 的输入;
- 写 Hpost ∈ ℝ1×N:把 F 的输出按权重加回每一条流;
- 混合 Hres ∈ ℝN×N:让各条流相互混合。
在 mHC 中,这三组系数都由当前 token 的状态生成:Hpre = σ(·),Hpost = 2σ(·),Hres 则经 Sinkhorn-Knopp 投影为双随机矩阵。因此对单个 token 而言,这三组系数就是一组确定的数。
下面的动画演示单个 token 的计算过程。为了便于观察,这里取 N = 4 条流,每条 C = 4 维。
2. 发现:mHC 的一步是一组卷积
关键:交错排布
取 N = 4 条流,每条 C = 4 维,把它们交错排成一个 16 维向量 v,让位置 c·N + i 存放第 i 条流的第 c 维:
这样排布之后,每 4 个相邻位置恰好是同一维度在 4 条流上的取值。mHC 的三步运算都只发生在同一维度的 4 条流之间,因此都变成了这个向量上窗口和步长均为 4 的操作:
- 读 = 卷积。卷积核就是 hpre 的 4 个权重,kernel = stride = 4。每个窗口输出一个数 uc = Σi hpre,i · xi,c,滑动 4 次即得到 4 维的子层输入。
- 写 = 反卷积。反卷积核就是 hpost 的 4 个权重,kernel = stride = 4。F 的每个输出 oc 被展开成第 c 个窗口里的 4 个值 hpost,i · oc。
- 混合 = 滑动的 4×4 映射。同一个 4×4 线性映射 Hres 依次作用在每个窗口上,移动 4 次。它等价于一个输出 4 通道、kernel = stride = 4 的卷积。
两条支路相加,就得到下一层的状态。下面的动画逐步演示这一过程,可以随时暂停、单步执行,或点击下方的圆点跳到任意一步。
概括起来,对每个 token,在系数给定时有:
⟺
vl+1 = MixHres(v) + Deconvhpost(F(Convhpre(v)))
这一等价成立需要三个条件:v 按上述方式交错排布;卷积和反卷积的 kernel 与 stride 都等于 N,窗口互不重叠;滑动的 4×4 映射是纯线性的。
两种算法,同一结果
下面用随机数把同一步分别按两种方式算一遍:中间一栏用 mHC 的原始公式,右边一栏用卷积视角,依次做交错、卷积、F、反卷积,再加上滑动的 4×4,最后拆回 4 条流。这里的 F 取一个随机的「线性层 + tanh」。
用 PyTorch 也能直接验证,conv1d 和 conv_transpose1d 的核正是 mHC 的系数:
import torch, torch.nn.functional as F
N, C = 4, 4
x = torch.randn(N, C) # x[i, c]:第 i 条流的第 c 维
h_pre, h_post = torch.rand(N), torch.rand(N)
H_res = torch.rand(N, N)
f = torch.tanh # 任意的层函数
# 按流:mHC 原式
ref = H_res @ x + h_post[:, None] * f(h_pre @ x)[None, :]
# 按卷积:交错排布,位置 c*N + i 放 x[i, c]
v = x.T.reshape(1, 1, N * C)
u = F.conv1d(v, h_pre.view(1, 1, N), stride=N) # 读:卷积
dv = F.conv_transpose1d(f(u), h_post.view(1, 1, N), stride=N) # 写:反卷积
m = F.conv1d(v, H_res.view(N, 1, N), stride=N) # 混合:滑动 4×4
m = m.transpose(1, 2).reshape(1, 1, N * C)
out = (m + dv).view(C, N).T # 拆回 4 条流
print(torch.allclose(out, ref, atol=1e-6)) # True
3. 方案:Modular Connections(MoC)
从卷积的角度看,mHC 中每个 token 都在「生成」自己的一组核:一个读卷积核 hpre、一个写反卷积核 hpost,以及一个滑动的 4×4 映射 Hres。
MoC 的做法是把这些连接做成模块:不再让 token 直接生成核,而是让模型学习一批卷积 / 反卷积专家和 4×4 混合专家,每个 token 像在 MoE 中那样路由到其中几个,再把它们加权组合。
三组专家
和 MoE 一样,每个子层都有自己的专家库,分为三组:
- 读卷积专家 {K(1)pre, …, K(E)pre}:每个是一个长度为 N 的卷积核;
- 写反卷积专家 {K(1)post, …, K(E)post}:每个是一个长度为 N 的反卷积核;
- 4×4 混合专家 {M(1), …, M(E)}:每个是一个 N×N 映射,在 16 维向量上滑动。
这些专家都是可学习的参数,由所有 token 共享。混合专家同样经过 Sinkhorn-Knopp 归一化,但归一化作用在专家参数本身:训练中每次参数更新后计算一次,结果由所有 token 共用;训练结束后,则可以一次算好并存下来。
用若干矩阵的组合来构造混合矩阵,并不是 MoC 首创。mHC-lite 把混合矩阵写成固定置换矩阵的凸组合,从而完全绕开了 Sinkhorn(Yang and Gao, arXiv:2601.05732)。MoC 的不同之处在于,读、写、混合三组都是可学习的专家,并且各自做稀疏路由。
路由与加权
对每个 token,路由器根据它的状态为每组专家打分,保留得分最高的 k 个,并在这 k 个分数上做 softmax,得到权重 g:
随后用选中的专家完成这一步计算:
Δv = Σe∈Rpost ge · Deconv(F(u); K(e)post)
m = Σe∈Rres ge · Mix(v; M(e))
vl+1 = m + Δv
由于卷积对核是线性的,Σe ge · Conv(v; K(e)) = Conv(v; Σe ge K(e)),实际计算时可以先把选中的专家核按权重合成一个核,再做一次卷积;反卷积和混合同理。权重 g 非负且和为 1,因此合成的混合矩阵是所选专家的凸组合。
下面的动画按「打分、选出 top-k、合成、接入」的顺序连续处理三个 token。为了演示,每组设 E = 6 个专家,每组选 k = 2 个。专家图标中颜色越深,表示对该流的权重越大;4×4 混合专家的第 i 行表示输出流 i 从各条流取多少。
与 mHC 的对照
| mHC | MoC | |
|---|---|---|
| 读、写、混合的核从哪里来 | 每个 token 由投影直接生成 | 从三组专家中路由、加权组合 |
| token 决定什么 | 核的具体数值 | 选哪几个专家、各占多少权重 |
| 需要学习的参数 | 生成核的投影和静态偏置 | 专家核本身和路由器 |
| Sinkhorn 归一化 | 每个 token、每个子层各做一次 | 对专家参数做,结果由所有 token 共用;训练完可以预先算好 |
4. 回看:mHC 实际学到的连接
引言提到的那项分析,测量了 DeepSeek-V4-Flash 全部 86 个子层(43 层,每层含 Attention 和 FFN 各一个)上 mHC 实际生成的连接,并在推理阶段做了干预实验。放在 MoC 的框架下看,它的每一项观察都对应着 MoC 的一个设计选择:
| DeepSeek-V4-Flash 中的观察 | 在 MoC 中 |
|---|---|
| 读写集中在少数几条流上。读、写的有效流数平均分别约为 2.0 和 1.8;同一段输入中,平均 87%(读)和 90%(写)的 token 共享同一条主导流;主导流随深度变化。 | 读、写专家本身就是固定的连接模式,例如「主要从流 1、2 读取」。每个子层有自己的专家库,不同深度可以学到不同的模式。 |
| 每个 token 只需要少数几条通路。在所有子层上只保留每个 token 最大的 3 个读(或写)权重,并按比例放大以保持总和不变,困惑度仅上升 2.4%(或 2.7%);只保留 2 个时则上升 12%–14%。 | 每个 token 只从专家库中选出 k 个专家组合,而不是得到一组取值任意的新系数。需要说明的是,这里剪去的是流的权重,而 MoC 选择的是专家,两者并不完全对应,但指向同一个方向:token 需要的只是少数几种选择。 |
| 混合主要由子层决定,逐 token 的变化作用很小。把前 22 层各子层的混合矩阵固定为其在 C4 样本上的均值,困惑度仅上升 0.2%。 | 混合专家是子层的静态参数,子层特有的结构就保存在专家里,token 只在少数几个专家之间选择。当每个子层只有一个混合专家时,混合矩阵不再随 token 变化,相当于这里「固定为均值」的干预。 |
| 深层的残差混合很弱。后 21 层的混合矩阵整体接近单位阵,全部替换为单位阵后,困惑度仅上升 1.9%。 | 单位阵只是混合专家可以学到的一种模式。哪些层需要混合、哪些层把各条流原样传下去,交给各层的专家库自己学习。 |
也就是说,在训练好的 DeepSeek-V4-Flash 中,连接已经接近「每个子层相对固定的模式,加上少量逐 token 的选择」。MoC 正是按这种结构设计的:模式由模块承载,选择交给路由器。
这些观察来自一个训练好的 mHC 模型,而 MoC 学到的连接也呈现同样的结构:无论是 512 步的短实验,还是正式训练第 6,000 步的 checkpoint,路由统计都是如此(见第 5 节)。训练全部完成后的情况,还有待进一步检验。
5. MoC 的优势
以下数据均来自笔者的实测。除正式训练外,所有测试都在同一型号的单张 GPU 上完成。模型为 1.36B 参数、23 层,代码与配置和正式训练一致:MoC 每组 4 个专家(E = 4),每个 token 选 2 个(k = 2),读、写、混合分别路由。作为对照的 mHC 和普通残差使用同一套代码。
推理时无需 Sinkhorn
MoC 的混合矩阵是专家参数,与 token 无关。训练结束后,只需对每个专家做一次 Sinkhorn 并缓存结果;推理时只要计算路由权重,再对选中的两个 4×4 矩阵加权求和。mHC 的混合矩阵则是逐 token 计算的,按照 mHC 论文的配置,推理时每个 token 在每个子层都要执行 20 轮 Sinkhorn 迭代。
下表给出单次前向传播的耗时(推理模式,bf16,取 30 次测量的中位数)。未编译部分的括号内,是 46 个子层中连接部分单独测得的耗时。
| 输入(条数 × 长度) | 普通残差 | mHC | MoC(专家矩阵已缓存) | MoC 相对 mHC |
|---|---|---|---|---|
| 未编译 | ||||
| 1 × 256 | 15.7 ms | 110.3 ms(93.2) | 34.7 ms(17.2) | 3.2× |
| 1 × 2048 | 27.7 ms | 113.2 ms(93.5) | 52.5 ms(25.4) | 2.2× |
| 8 × 2048 | 176.9 ms | 390.7 ms(218.5) | 345.1 ms(173.3) | 1.13× |
用 torch.compile 编译后 | ||||
| 1 × 256 | 6.8 ms | 26.8 ms | 18.1 ms | 1.48× |
| 1 × 2048 | 20.6 ms | 43.2 ms | 41.2 ms | 1.05× |
| 8 × 2048 | 127.4 ms | 259.8 ms | 263.3 ms | 0.99× |
| 首次编译耗时 | 约 25 秒 | 约 4.7 分钟 | 约 55 秒 | |
未编译时,MoC 的优势最明显,而且输入越短,差距越大。token 较少时,mHC 在每个子层固定执行的 20 轮 Sinkhorn 会变成大量细碎的 kernel 调用,占据了前向耗时的大头。用 torch.compile 编译后,Sinkhorn 循环被融合,差距随之大幅缩小:短输入(1 × 256)下 MoC 仍快约 1.5 倍,长输入和大批量下两者基本持平。不过编译本身也有代价,同样的推理前向,mHC 需要编译约 4.7 分钟,MoC 只需约 55 秒。
缓存专家矩阵不会改变模型输出,缓存前后的 loss 逐位一致。即使不缓存,MoC 每次前向也只为全部子层的专家统一做一次 Sinkhorn,未编译时比缓存版本仅慢约 3.5 毫秒。
需要说明的是,这些测量基于笔者的 PyTorch 实现,没有使用 mHC 论文中手写的融合 kernel;这套代码目前也不支持 KV cache 解码,因此用短输入的完整前向来近似对延迟敏感的场景。此外,两种多流连接都明显慢于普通残差,这主要来自多条流读写带来的访存开销,而这正是 mHC 论文的融合 kernel 重点优化的部分。
编译快得多
下表测量的是单个训练 micro-step:在单卡上对 8 × 2048 个 token 做一次前向和反向传播,不含优化器更新,取 20 次的中位数。编译耗时为空缓存下的冷启动时间,两个模型同时编译,条件相同。
| mHC | MoC | |
|---|---|---|
| 未编译:每步耗时 | 1.086 s | 1.003 s |
| 未编译:峰值显存 | 55.1 GiB | 52.9 GiB |
| 首次编译耗时 | 40.4 分钟 | 2.5 分钟 |
| 编译后:每步耗时 | 0.866 s | 0.808 s |
| 编译后:峰值显存 | 46.7 GiB | 46.7 GiB |
编译完成后,两者的速度和显存相差无几,真正的差别在编译本身:MoC 需要 2.5 分钟,mHC 需要 40.4 分钟,约为前者的 16 倍。每次修改代码或模型配置都要重新编译,这项开销会反复出现。编译后的 MoC 已用于正式训练,至今运行稳定,第 1,350 至 6,340 步之间按理论 FLOPs 计算的 MFU 中位数约为 51%。当然,mHC 论文用手写的融合 kernel 优化了逐 token 的 Sinkhorn,mHC-lite 也指出 Sinkhorn 的高效实现离不开高度定制的 CUDA kernel。因此,这里的优势在于工程上更省事,而不是 mHC 无法做到。
可解释、可检查
MoC 中每个专家都有明确的编号,因此可以直接按专家做统计:哪些层偏好哪些专家,什么样的 token 走哪种模式;也可以逐个专家检查约束是否成立。相比之下,分析 mHC 需要直接处理逐 token 的系数矩阵,参考文献 4 正是这样做的。笔者在 512 步的短实验和正式训练第 6,000 步的 checkpoint 上做了这两类分析,路由统计分别基于 dev 分片的 4,194 万和 839 万个 token:
| 每组 4 个专家,按使用率排序 | 第 512 步 | 第 6,000 步 |
|---|---|---|
| 最常用的专家被多少 token 选中 | 98.7% | 99.4% |
| 第二常用 | 83.2% | 84.2% |
| 第三、第四常用 | 15.3%、3.2% | 14.3%、2.4% |
| 两个名额几乎固定的组(共 138 组) | 61 | 63 |
| 第二个名额明显随 token 变化的组 | 21 | 19 |
| 几乎没被选中的专家(共 552 个) | 67 | 85 |
| 列和偏离 1 超过 0.05 的混合专家(共 184 个) | 55 | 81 |
从统计中可以直接读出路由的结构,而且这一结构在正式训练中保持稳定:每组中几乎总有一个专家被选中,第二个名额才在其余专家之间随 token 变化。这与第 4 节的观察一致,即相对固定的模式加上少量逐 token 的选择。
约束是否成立,也可以直接从参数上检查。所有混合专家的行和都精确为 1(误差小于 10−6),但 20 轮 Sinkhorn 并没有让每个专家的列和都收敛到 1:第 6,000 步时,184 个混合专家中有 81 个的列和偏离超过 0.05,中位偏差为 0.04。mHC 的逐 token 矩阵同样存在这个问题(mHC-lite 测得单层列和最多偏离 100%),但要发现它,需要对大量 token 的矩阵做统计。
6. 小结
- 发现:残差流之间的连接本身可以是模块化的模型。把 N 条流交错排开后,mHC 的读、写、混合分别是 kernel = stride = N 的卷积、反卷积和一个滑动的 N×N 映射,每个 token 的连接就是一组核。
- 方案:Modular Connections(MoC)把逐 token 生成的核,替换为可路由的卷积专家、反卷积专家和混合专家,每个 token 像在 MoE 中那样选出几个专家并加权组合。
- 证据与收益:在 DeepSeek-V4-Flash 中,训练好的 mHC 在每个子层上的连接都相对稳定,逐 token 的变化作用很小,MoC 正是按这种结构设计的。MoC 推理时无需 Sinkhorn(未编译时快 2–3 倍,编译后短输入仍快约 1.5 倍),编译耗时短得多,连接方式也可以逐个专家检查。
7. 展望
我正在推进相应的实验,关注的问题只有一个:MoC 的效率优势要真正被采用,前提是效果与 mHC 相当。
目前的正式训练已经初步体现出这一点。我沿用第 5 节的配置(1.36B 参数、23 层),在约 49B tokens 上训练 MoC(共 46,875 步),每 250 步在同一验证集上测一次 BPB,并与已完成的 mHC 正式训练在相同步数上比较。截至 2026 年 11 月 6 日,训练已进行到第 6,360 步(约 14%)。自第 2,000 步起,MoC 与 mHC 的验证 BPB 之差始终在 −0.0009 到 +0.0017 之间,同时比普通残差低 0.013–0.016。需要注意,这只是单个种子在训练早期的结果;而且这次训练开启了 torch.compile,所用硬件也与作为参照的 mHC 训练不同。最终结论有待训练完成后给出。
如果你有任何建议或合作意向,欢迎直接联系我:selenyuesu@gmail.com。
引用
如果这篇文章对你的工作有帮助,欢迎引用:
@misc{su2026modular,
author = {Su, Yue},
title = {Modular Connections: The Connections Between Residual Streams Can Themselves Be Modular Models},
year = {2026},
month = nov,
url = {https://selen-suyue.github.io/modular-connections/},
note = {Blog post}
}
参考
- Zhu et al. Hyper-Connections. arXiv:2409.19606.
- DeepSeek-AI. mHC: Manifold-Constrained Hyper-Connections. arXiv:2512.24880.
- Shazeer et al. Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. arXiv:1701.06538.
- Zhao et al. How Does mHC Use Its Residual Streams? Selective Routing and Near-Identity Mixing. arXiv:2609.05309.
- Yang and Gao. mHC-lite: You Don’t Need 20 Sinkhorn-Knopp Iterations. arXiv:2601.05732.