第10章 Hyper-Connections:替代残差的 hc_mult 通路

“We assumed residuals were ‘just additions.’ Sometimes they need to be a small linear algebra of their own.” —— Hyper-Connections 论文摘要

V4 把传统残差换成了一个 4 路并行的”小代数”。每层的输入 / 输出都不再是单一 hidden,而是 4 份 hidden 的混合体。


10.1 引子:传统残差走到尽头了吗

ResNet 的 y = x + F(x) 是深度学习近十年最重要的发明之一。它解决了”深网络梯度消失” 的问题,让上百层、上千层的模型成为可能。Transformer 全盘继承了残差——每个 attention block 是 x + Attention(LN(x)),每个 FFN block 是 x + FFN(LN(x))

但在 1.6T 参数 + 384 expert + 稀疏 attention 这个量级上,V4 团队遇到了传统残差的局限

  1. 残差路径只有 1 条:每层的输入 hidden 只能”加一份残差”——信号传递的”通道数”被压在 1。当模型深度到 60+ 层、且每层有 384 expert 的多样性时,单残差路径成为瓶颈
  2. 不同 token / 不同 head 在每层应该用不同的 mixing 方式:传统残差是”全局统一”——所有 token 都按 x + F(x) 累加。但 V4 需要某些 token 走”全 attention 输出”、某些 token 走”半 attention 半残差”
  3. 梯度传递的”宽度”受限:单残差路径意味着早期层与晚期层之间只有一条梯度通道——稀疏 MoE 训练里这条通道容易被某些 expert 主导

Hyper-Connections (HC) 的提出就是为了打破这些局限。

V4 把这个想法工业化到 1.6T 规模——把每层的 hidden 从 1 条扩展到 4 条,每层都用一组学习的混合矩阵决定”4 条 hidden 怎么进、attention 输出怎么出、4 条 hidden 怎么再聚合”。


10.2 HC 的核心思想:hc_mult 维 hidden state

V4 的 Transformer.forward 第二行:

h = h.unsqueeze(2).repeat(1, 1, self.hc_mult, 1)

hc_mult = 4。这一行把 [B, S, D] 变成 [B, S, 4, D]——增加了一个新的”hc 维度”,hidden 被复制 4 份。从这一行开始,所有的 layer forward 都在 [B, S, 4, D] 上工作,不再是 [B, S, D]

每层 Block 的处理流程:

def forward(self, x: torch.Tensor, start_pos: int, input_ids: Optional[torch.Tensor]) -> torch.Tensor:
    residual = x
    x, post, comb = self.hc_pre(x, self.hc_attn_fn, self.hc_attn_scale, self.hc_attn_base)
    x = self.attn_norm(x)
    x = self.attn(x, start_pos)
    x = self.hc_post(x, residual, post, comb)

    residual = x
    x, post, comb = self.hc_pre(x, self.hc_ffn_fn, self.hc_ffn_scale, self.hc_ffn_base)
    x = self.ffn_norm(x)
    x = self.ffn(x, input_ids)
    x = self.hc_post(x, residual, post, comb)

    return x

每个 attention 与 ffn 各被 hc_pre / hc_post 包住——

  • hc_pre:4 条 hidden → 1 条 hidden(送进 attention / ffn)
  • hc_post:1 条 attention 输出 + 4 条原 residual → 4 条新 hidden

hc_pre 的输入是 [B, S, 4, D],输出是 [B, S, D] —— 它把 4 条 hidden 加权混合成 1 条。 hc_post 的输入是 [B, S, D](attention 输出)+ [B, S, 4, D](原 residual) + post / comb(hc_pre 留下的中间量),输出是 [B, S, 4, D]

flowchart LR
  In["h_in: [B,S,4,D]"] --> HCpre["hc_pre"]
  HCpre --> X1["x: [B,S,D]"]
  HCpre -.post,comb.-> HCpost["hc_post"]
  X1 --> Norm["RMSNorm"] --> Attn["Attention"]
  Attn --> X2["x_out: [B,S,D]"]
  X2 --> HCpost
  In --> HCpost
  HCpost --> Out["h_out: [B,S,4,D]"]

10.3 hc_pre:把 4 路 hidden 混成 1 路

Block.hc_pre 的源码:

def hc_pre(self, x: torch.Tensor, hc_fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor):
    # x: [b,s,hc,d], hc_fn: [mix_hc,hc*d], hc_scale: [3], hc_base: [mix_hc]
    shape, dtype = x.size(), x.dtype
    x = x.flatten(2).float()
    rsqrt = torch.rsqrt(x.square().mean(-1, keepdim=True) + self.norm_eps)
    mixes = F.linear(x, hc_fn) * rsqrt
    pre, post, comb = hc_split_sinkhorn(mixes, hc_scale, hc_base, self.hc_mult, self.hc_sinkhorn_iters, self.hc_eps)
    y = torch.sum(pre.unsqueeze(-1) * x.view(shape), dim=2)
    return y.to(dtype), post, comb

把这段代码拆成 5 步:

步骤 1:4 路 hidden 拼成 4×D 维向量

x = x.flatten(2).float()  # [B, S, hc_mult, D] → [B, S, hc_mult * D]

[B, S, 4, D] 压成 [B, S, 4D]——把 4 路当作一个大向量。

步骤 2:RMSNorm

rsqrt = torch.rsqrt(x.square().mean(-1, keepdim=True) + self.norm_eps)

对这个 4D 大向量做 RMSNorm 的 rsqrt——保证后续混合矩阵运算的数值稳定。

步骤 3:投影到混合矩阵的”参数空间”

mixes = F.linear(x, hc_fn) * rsqrt

hc_fn: [mix_hc, hc_mult * D],其中 mix_hc = (2 + hc_mult) * hc_mult = 6 * 4 = 24

输出 mixes: [B, S, 24]——24 个标量参数,决定本层这个 token 的混合方式。

为什么是 24?因为 24 = (2 + 4) × 4 = (pre + post + comb_per_dim) × hc_mult,对应:

  • 4 个 pre 权重(4 路 hidden 的混合系数)
  • 4 个 post 权重(attention 输出在 4 路上的分布系数)
  • 16 个 comb 矩阵元素(4×4 的 4 路 hidden 重组矩阵)

步骤 4:Sinkhorn 归一化得到三组系数

pre, post, comb = hc_split_sinkhorn(mixes, hc_scale, hc_base, self.hc_mult, self.hc_sinkhorn_iters, self.hc_eps)

hc_split_sinkhorn 把 24 维的 mixes 切成三段,分别归一化成”接近概率分布”的形式。第 10.4 节展开。

步骤 5:用 pre 加权求和

y = torch.sum(pre.unsqueeze(-1) * x.view(shape), dim=2)

pre: [B, S, 4]x: [B, S, 4, D]。逐 token 把 4 路 hidden 按 pre 系数加权求和——输出 [B, S, D]


10.4 Sinkhorn 归一化:让混合矩阵”接近双随机”

hc_split_sinkhorn 是 V4 的一个核心 kernel(在 kernel.py 中实现,由 FlashMLA 提供 CUDA 优化版本)。它做的事:

  1. 把 mixes [B, S, 24] 切成 pre [B, S, 4]、post [B, S, 4]、comb_raw [B, S, 16]
  2. 对 pre 和 post 单独做 sigmoid + scale
  3. 对 comb_raw reshape 成 [B, S, 4, 4],做 20 次 Sinkhorn 迭代让它接近双随机矩阵

Sinkhorn 迭代的简化伪代码:

def sinkhorn(M, iters=20, eps=1e-6):
    """让 [4, 4] 矩阵 M 接近双随机:每行和为 1, 每列和为 1"""
    M = torch.exp(M)  # 保证非负
    for _ in range(iters):
        M = M / (M.sum(dim=-1, keepdim=True) + eps)  # 行归一化
        M = M / (M.sum(dim=-2, keepdim=True) + eps)  # 列归一化
    return M

**为什么要 Sinkhorn?**因为 4 路 hidden state 的”混合矩阵”如果不归一化,会出现”信息总量不守恒”——某些路被过度放大,某些路被压扁。Sinkhorn 让混合矩阵保持”近双随机”性质:每条 hidden 的总输出权重为 1,每条 hidden 接收的混合权重总和也为 1——信息总量守恒。

20 次迭代是 V4 的工程默认值(hc_sinkhorn_iters=20)——足够让矩阵收敛到接近双随机,但不至于成为计算瓶颈。

flowchart LR
  Mixes["mixes: [B,S,24]"] --> Split{切分}
  Split --> PreRaw["pre_raw: [B,S,4]"]
  Split --> PostRaw["post_raw: [B,S,4]"]
  Split --> CombRaw["comb_raw: [B,S,16]"]

  PreRaw --> Sigmoid1["sigmoid + scale"] --> Pre["pre: [B,S,4]"]
  PostRaw --> Sigmoid2["sigmoid + scale"] --> Post["post: [B,S,4]"]
  CombRaw --> Reshape["reshape [B,S,4,4]"] --> Sinkhorn["20 次 Sinkhorn"] --> Comb["comb: [B,S,4,4]<br/>≈ 双随机"]

10.5 hc_post:1 路 attention 输出 + 4 路 residual → 4 路新 hidden

def hc_post(self, x: torch.Tensor, residual: torch.Tensor, post: torch.Tensor, comb: torch.Tensor):
    # x: [b,s,d], residual: [b,s,hc,d], post: [b,s,hc], comb: [b,s,hc,hc]
    y = post.unsqueeze(-1) * x.unsqueeze(-2) + torch.sum(comb.unsqueeze(-1) * residual.unsqueeze(-2), dim=2)
    return y.type_as(x)

公式:

y[b,s,h,d]=post[b,s,h]×x[b,s,d]+hcomb[b,s,h,h]×residual[b,s,h,d]y_{[b,s,h,d]} = \text{post}_{[b,s,h]} \times x_{[b,s,d]} + \sum_{h'} \text{comb}_{[b,s,h',h]} \times \text{residual}_{[b,s,h',d]}

这个公式表达:

  • 第 h 路新 hidden = post[h] × attention 输出(“派发” attention 输出到 4 路)
    • 对所有原 residual 做加权和(comb 矩阵的第 h 列决定哪几路原 hidden 贡献到新第 h 路)

举个具体例子:如果 post=[1, 0, 0, 0](attention 输出全部进第 0 路),comb=I(identity,每路保持自己):

  • 新第 0 路 = 1 × attn_out + residual[0]
  • 新第 1 路 = 0 × attn_out + residual[1] = residual[1]
  • 新第 2 路 = residual[2]
  • 新第 3 路 = residual[3]

这等价于”传统残差”——只有第 0 路被更新,其他路保持不变。

如果 post=[0.25, 0.25, 0.25, 0.25]、comb=I:

  • 每路新 hidden = 0.25 × attn_out + residual[i]

这等价于”attention 输出被均分到 4 路”——每路都收到 1/4 的 attention 信号 + 自己的 residual。

如果 comb 是 4×4 的全 1/4 矩阵:

  • 每路新 hidden = post[h] × attn_out + (residual[0] + residual[1] + residual[2] + residual[3]) / 4

这等价于”先把 4 路 residual 平均,再加上 post 加权的 attention”——4 路 hidden 互相”渗透”。

V4 让 comb 通过 Sinkhorn 训练成”接近双随机但 token-自适应”——每个 token 自己决定它的 4 路 hidden 怎么互相渗透。


10.6 HC 的几何直觉:4 维 hidden 几何

把 HC 想象成”hidden state 的 4 维并行宇宙”——每个 token 同时在 4 个 hidden 通道上活动,这些通道互相关联但保持独立。

每层 Block 的作用:

  • hc_pre:从 4 个并行宇宙中”提炼”出 1 个用于 attention 计算
  • attention:在这 1 个宇宙中工作
  • hc_post:把 attention 结果”分发”回 4 个宇宙,并允许它们互相渗透

这种”提炼 + 计算 + 分发 + 渗透”的循环让模型有 4 倍的”信号通道”——梯度反向传播时也有 4 条独立路径,避免了单残差的瓶颈。

代价是:所有 hidden 都变成 4 倍尺寸,激活内存翻 4 倍。但因为 attention / ffn 内部的计算没有变(仍然在 1 路上做),FLOPs 没有翻倍——只有激活内存增加。


10.7 ParallelHead 的 HC 处理

V4 的最后一层(lm_head)对 HC 有特殊处理:

class ParallelHead(nn.Module):
    def hc_head(self, x: torch.Tensor, hc_fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor):
        shape, dtype = x.size(), x.dtype
        x = x.flatten(2).float()
        rsqrt = torch.rsqrt(x.square().mean(-1, keepdim=True) + self.norm_eps)
        mixes = F.linear(x, hc_fn) * rsqrt
        pre = torch.sigmoid(mixes * hc_scale + hc_base) + self.hc_eps
        y = torch.sum(pre.unsqueeze(-1) * x.view(shape), dim=2)
        return y.to(dtype)

注意 hc_headhc_pre 的差别:

  • hc_pre 输出 3 个张量(pre / post / comb),用 Sinkhorn 归一化
  • hc_head 只输出 1 个张量(pre),用 sigmoid + scale + bias

这是因为 lm_head 的输入是 4 路 hidden,输出是单一 logits——只需要”4 路混成 1 路”,不需要”再分发回 4 路”。所以省掉了 post / comb 的 Sinkhorn,只保留 pre 的 sigmoid。

这个简化让最后一层的 hc 处理只有混合不再有分发——干净利落。


10.8 与 ResNet / DenseNet / NormFormer 的横向对比

把 HC 与历史上的”残差变体”对比:

方案残差通道数是否可学信息守恒训练复杂度
ResNet1是 (加法)
Highway Network1是 (gate)
DenseNetn (累加)否 (越来越大)
NormFormer1 (norm 多)
ReZero1 (× α 标量)是 (单标量)
Hyper-Connectionshc_mult=4是 (4×4 矩阵)是 (Sinkhorn)

V4 的 HC 在三个维度上独特:

  • 多通道(hc_mult=4):比 ResNet 的 1 通道丰富,比 DenseNet 的”累加所有 prev” 受控
  • 可学的 4×4 混合矩阵:比 Highway 的单 gate 表达力强
  • Sinkhorn 归一化:保证信息守恒

这种综合权衡让 HC 在 1.6T MoE 规模下成为最稳定的”残差升级方案”。


10.9 训练时的 HC 行为

HC 在训练时的几个关键观察(基于公开技术报告 + 设计推断):

观察一:4 路 hidden 会自发”分化”

训练过程中,4 路 hidden 会自发学到不同的”语义子空间”——例如某路偏向”语法信息”、某路偏向”语义类别”、某路偏向”位置感”。这种自发分化是 HC 让模型表达力提升的来源。

观察二:Sinkhorn 迭代次数对收敛影响显著

hc_sinkhorn_iters=20 是 V4 的默认值。少于 10 次时 comb 矩阵不够接近双随机,训练不稳定;多于 30 次时收益递减但增加计算开销。20 是经验值。

观察三:HC 与 RMSNorm 的协同

每个 attention / ffn 之前有 attn_norm / ffn_norm——V4 让 RMSNorm 与 HC 配合:HC 提供”幅度自适应”(通过 rsqrt + Sinkhorn),RMSNorm 提供”方向归一化”。两者一起保证训练稳定。

观察四:HC 在 FP4 / FP8 下需要 FP32 计算

源码里 hc_pre / hc_post 的中间计算都用 x.float()——HC 的混合系数对精度敏感,FP4 / FP8 直接算会破坏 Sinkhorn 的双随机性。这是 V4 在 HC 路径上保 FP32 的关键。


10.10 动手实验:mini HC

import torch
import torch.nn as nn
import torch.nn.functional as F

def sinkhorn(M, iters=10, eps=1e-6):
    M = torch.exp(M)
    for _ in range(iters):
        M = M / (M.sum(-1, keepdim=True) + eps)
        M = M / (M.sum(-2, keepdim=True) + eps)
    return M

class MiniHCBlock(nn.Module):
    def __init__(self, dim=128, hc_mult=4):
        super().__init__()
        self.dim = dim
        self.hc_mult = hc_mult
        self.attn = nn.Linear(dim, dim)  # 占位
        self.ffn = nn.Linear(dim, dim)   # 占位
        # mix_hc = (2 + hc_mult) * hc_mult
        self.hc_fn = nn.Parameter(torch.randn((2 + hc_mult) * hc_mult, hc_mult * dim))

    def hc_pre(self, x):
        # x: [B,S,hc,D]
        B, S, hc, D = x.shape
        x_flat = x.flatten(2).float()
        rsqrt = torch.rsqrt(x_flat.square().mean(-1, keepdim=True) + 1e-6)
        mixes = F.linear(x_flat, self.hc_fn) * rsqrt   # [B,S,(2+hc)*hc]

        # 切分
        pre_raw = mixes[..., :hc]
        post_raw = mixes[..., hc:2*hc]
        comb_raw = mixes[..., 2*hc:].view(B, S, hc, hc)

        pre = torch.sigmoid(pre_raw) + 1e-6
        post = torch.sigmoid(post_raw) + 1e-6
        comb = sinkhorn(comb_raw, iters=10)

        y = torch.sum(pre.unsqueeze(-1) * x, dim=2)
        return y, post, comb

    def hc_post(self, x, residual, post, comb):
        # x: [B,S,D], residual: [B,S,hc,D], post: [B,S,hc], comb: [B,S,hc,hc]
        y = post.unsqueeze(-1) * x.unsqueeze(-2) + torch.sum(comb.unsqueeze(-1) * residual.unsqueeze(-2), dim=2)
        return y

    def forward(self, h):
        # h: [B,S,hc,D]
        residual = h
        x, post, comb = self.hc_pre(h)
        x = self.attn(x)
        h = self.hc_post(x, residual, post, comb)
        return h


# 测试
block = MiniHCBlock()
h = torch.randn(2, 8, 4, 128)
out = block(h)
print(out.shape)   # [2, 8, 4, 128]

跑通后再回看 V4 源码,会觉得”原来 HC 的核心算法只有几十行”。剩下都是与 attention / FFN / TP 分布的工程粘合。


10.10·补 HC 训练稳定性的 4 个机制

HC 在 V4 的 1.6T 规模上跑通是工程奇迹——4 路 hidden 同时训练,理论上比单残差更容易出现”路径塌陷”(某路恒为 0、某路爆炸)。V4 通过 4 个机制保证 HC 训练稳定:

机制 1:Sinkhorn 双随机约束

20 次 Sinkhorn 迭代让 comb 矩阵接近双随机——保证每路 hidden 的”总输出权重”和”总接收权重”都接近 1。任何一路想”主导”或”消失”都会被 Sinkhorn 拉回来。

机制 2:FP32 中间计算

hc_pre 和 hc_post 的全部计算用 FP32——避免 BF16 / FP8 在 4 路混合时的精度损失累积。如果用 BF16,每层的 4 路混合误差会累积到第 60 层时让某些路彻底崩溃。

机制 3:RMSNorm 与 HC 的双重归一化

attn_norm / ffn_norm 给 hc_pre 输出做一次 RMSNorm,hc_pre 内部的 rsqrt 又做一次。两层归一化保证进入 attention/ffn 的 hidden 数值范围被严格控制——避免任何 hidden 异常放大。

机制 4:Sinkhorn 迭代次数的精确选择

hc_sinkhorn_iters=20 不是随便选的。少于 10 次:comb 不够接近双随机,训练不稳;多于 30 次:计算开销大但收益递减;20 次是经验调出来的”刚好够稳定”的数值。

这 4 个机制叠加让 HC 在 1.6T 规模上比传统残差更稳定——传统残差在长序列 + 深网络下还会出现 gradient vanishing/explosion,HC 的 Sinkhorn 约束让它免疫这两类问题。


10.10·补·补 HC 在 fine-tune 与推理时的特殊性

HC 在不同生命周期阶段的行为有差异:

预训练阶段:HC 的所有参数(hc_attn_fn / hc_ffn_fn / hc_attn_scale 等)从随机初始化开始学。Sinkhorn 让 comb 慢慢逼近”接近 identity 的混合矩阵”——意味着早期 HC 接近”传统残差”,训练后期才逐渐用上”4 路真正混合”的能力。

fine-tune 阶段:HC 的混合矩阵已经稳定。如果 fine-tune lr 太大,会破坏 Sinkhorn 训练好的双随机性——4 路 hidden 重新陷入塌陷风险。建议 fine-tune 时把 HC 参数(hc_*)冻结或用极小 lr,仅 fine-tune attention / ffn 部分。

推理阶段:HC 的所有参数固定,每个 token 通过 hc_pre 算一次 mix → 跑 attention/ffn → hc_post 重组。整个 HC 路径的计算开销约占 attention 的 5-10%——这是 HC 表达力提升的成本。

KV cache 与 HC 的关系:HC 让 hidden 是 4 路的,但 KV cache 不是 4 路的——KV cache 在 attention 内部存储,attention 的输入是已经被 hc_pre 混到 1 路的 hidden。所以 KV cache 与单残差 transformer 一样大,HC 不增加 KV 开销。这是 V4 设计的精妙之处——HC 让 hidden 表达力翻 4 倍,但只在”激活内存”上付代价,不在”持久 KV”上付。


10.10·延展 HC 与传统残差的”梯度通道”对比

把 HC 与传统残差在反向传播时的梯度通道对比:

传统残差

  • 每层只有 1 条梯度通道(identity 路径)
  • 100 层模型在 backward 时梯度通过 100 条 identity + 100 条 weighted 通道——可能消失或爆炸
  • ResNet 的成功在于 identity 通道避免了梯度消失,但 1 条通道仍是瓶颈

Hyper-Connections

  • 每层有 hc_mult=4 条 “近 identity” 通道(comb 的对角元素)+ 12 条 “渗透” 通道(comb 的非对角)
  • 100 层模型在 backward 时梯度通过 400 条主通道 + 1200 条渗透通道
  • 多通道让梯度信息分散——不同 token 的梯度可以走不同通道,避免某条通道被某种 token 主导

这种”梯度通道扩张”是 HC 让 V4 训练能容忍 384 expert + 稀疏 attention + FP4 等多种”梯度污染源”同时存在的根本原因。


10.11 延伸阅读

  • Hyper-Connections 论文(arXiv:2409.19606):HC 的最早期理论
  • ResNet 论文(arXiv:1512.03385):残差连接的源头
  • Sinkhorn-Knopp 算法(1967):双随机矩阵归一化的数学基础
  • ReZero 论文(arXiv:2003.04887):可学残差缩放的早期尝试
  • 本书第 1 章 §1.5:V4 在 Transformer.forward 那 4 行里 HC 入口的全景
  • 本书第 11 章:MTPBlock 也用 HC——MTP 的 hc_head 处理

10.11·补 HC 在小模型 vs 大模型上的表现猜想

HC 在 V4 的 1.6T 规模上是工程胜利,但它在小模型(< 100B)上的表现需要单独评估——大与小可能不同。把这个差异的几个推测列出来:

推测 1:HC 在大模型上的优势更明显

大模型层数多(V4 = 61 层),传统残差的”梯度通道瓶颈”更严重。HC 的 4 路并行扩展了梯度通道,对深网络更有用。小模型(10-20 层)梯度通道压力小,HC 的边际收益可能不如大模型。

推测 2:HC 的 Sinkhorn 开销在小模型上占比更高

20 次 Sinkhorn 迭代是固定开销。在大模型里这部分占总 forward 的 < 5%,可以忽略。在小模型里可能占到 10-15%——开销显著。

推测 3:HC 的混合矩阵在小模型上可能”无聊”

HC 让模型学会 4 路 hidden 的差异化分配。但小模型容量有限——4 路可能学不出有意义的差异,最终 comb 矩阵收敛到接近 identity(即等价于传统残差)。这种情况下 HC 是”白付出代价没换来好处”。

推测 4:HC 与 fine-tune 的协同

如果在 V4 上 fine-tune,HC 的混合矩阵已经训好,fine-tune 可以继承。但如果你想从零训一个小型 V4-like 模型,HC 需要从头训——训练曲线可能比 ResNet 风格的小模型更长。

对工程师的建议

  • 如果你做的是 1B-10B 模型 fine-tune,可以借鉴 V4 的 HC(成本可控)
  • 如果你做的是 1B-10B 从零训练,建议先用 ResNet 残差跑 baseline,再尝试 HC 看是否有 ROI
  • 如果你做的是 100B+ 训练,HC 大概率有 ROI(V4 的实证),值得直接采用

这些推测需要社区独立实验验证——HC 在不同尺度下的表现会成为后续半年开源研究的热点之一。


10.11·补·补 Sinkhorn 收敛性与 hc_sinkhorn_iters 的选择

Sinkhorn 迭代是把 4×4 矩阵 M 投影到双随机矩阵的迭代算法。理解它的收敛性,能解释 V4 选 hc_sinkhorn_iters=20 这个数字。

Sinkhorn 收敛速度

数学上 Sinkhorn 迭代的收敛速度是几何级——每次迭代误差缩小约一个常数因子(依赖矩阵的 spectral 性质)。对 4×4 矩阵,典型缩小因子是 0.5-0.8。

实际收敛

20 次迭代后,矩阵的双随机性误差通常 < 1e-6——足够保证 forward 的数值稳定。再多迭代收益递减——25 次的精度只比 20 次好 5%,但计算开销多 25%。

少于 10 次会怎样

迭代不足时 comb 矩阵不够接近双随机——信息守恒被破坏,4 路 hidden 的总能量在层间漂移。训练曲线表现为某些 layer 的 activation norm 异常增长。

数值稳定的边界

如果输入矩阵 M 的某个元素 exp(M) 极大(如 M > 100),Sinkhorn 的归一化会有数值问题。V4 通过 mixes * rsqrt(hc_pre 中的 RMSNorm 等价)让 mixes 的范围被压在合理区间——保证 Sinkhorn 数值稳定。

为什么不用 Hungarian / matching 算法

理论上”双随机矩阵投影”可以用 Hungarian 算法精确求解,O(n³)。但 Hungarian 不可微,没法在 GPU kernel 上高效跑——所以 V4 用 Sinkhorn,可微 + 适合 GPU。

hc_sinkhorn_iters 的可调性

V4 的 config 把它作为参数(hc_sinkhorn_iters=20)——理论上可以调。如果你 fine-tune V4,不要改这个参数——会破坏预训练学到的 comb 分布。如果你从零训练 V4-style 模型,可以从 20 开始,根据训练稳定性调整。


10.12 本章小结

  • V4 用 Hyper-Connections (hc_mult=4) 替代传统残差——每层有 4 路 hidden state 并行
  • hc_pre:4 路 → 1 路(用学到的 pre 系数加权求和),同时输出 post / comb 给 hc_post 用
  • hc_post:1 路 attention 输出 + 4 路 residual → 4 路新 hidden(用 post 派发 + comb 矩阵渗透)
  • hc_split_sinkhorn 用 20 次 Sinkhorn 迭代让 comb 接近双随机——保证信息守恒
  • HC 的代价是激活内存翻 4 倍,但 FLOPs 不变——这是 V4 在 1.6T 规模下能稳定训练的关键
  • 与 ResNet / DenseNet / Highway 等历史方案对比,HC 在多通道、可学混合、信息守恒三个维度独特

第 11 章:MTP 模块——V4 保留的 V3 训练加速器,以及在推理时如何变成投机解码。

评论 0