Linear = Hash 函数——输出层碰撞是翻译的信息瓶颈

512 维 hidden 撞进 32K 维词汇表:碰撞率 K_lang ≈ 0.003,有效碰撞桶 ~170 个。Linear 不是模型最后一步投影——它是翻译信息从连续空间到离散词汇的 Hash 函数。

碰撞在哪里?

NMT 的输出流程三步:

① Transformer:  输入序列 → h_t ∈ ℝ^512       (hidden space)
② Linear:       h_t → z = W·h_t + b         (logits in ℝ^{32000})
③ Softmax:      z → p ∈ Δ^{31999}           (概率单纯形)
④ Decode:       argmax / beam → token        (离散词)

每个人都在关注 ③ 和 ④。但碰撞发生在 ②

Linear = Hash Function

W 是一个

$$\mathbb{R}^{32000 \times 512}$$

的矩阵。每一行

$$W_i \in \mathbb{R}^{512}$$

是第 i 个 token 的嵌入向量(output embedding)。

$$W·h_t$$

做的是内积:

$$z_i = \langle W_i, h_t \rangle + b_i$$

把 512 维的 hidden 投影到 32K 维——32K 个内积。

这是 Hash 函数的标准定义: 把高维向量压缩到低维离散空间。

$$h_t \xrightarrow{W} z \xrightarrow{\text{argmax}} \text{token}$$

参数 W 决定了 hidden 空间中哪些方向对应哪些 token。512 维的 hidden 无法精确表示 32K 个 token 的语义——碰撞是必然的。

碰撞率 = K_lang

32K 个 token 共享 512 个维度,内积

$$W_i·h_t$$

受限于 hidden 的信息容量。有意义地区分的 token 数:

$$N_{\text{collision}} = K_{\text{lang}} \times |V| = 0.003 \times 32000 \approx 96$$

BPE 词表下(8K):

$$N_{\text{collision}} = 0.003 \times 8000 \approx 24$$

碰撞桶从 170 缩到 24——但每个桶承担的语义负载叠加了 7 倍。

词表类型 |V| K_lang×|V| 每桶语义负载
Word-level (IWSLT) 56K 170
BPE (IWSLT) 8K 24

IWSLT14 的 BPE 实验证实:8K 词表下,3 个 transformer 层不够深(B0, BLEU=10.66),但 6 层可以(B3, BLEU=11.70)。深度补偿了桶压缩。

梯度怎么从碰撞桶里提取信息?

CE loss 对

$$z_i$$

的梯度是

$$p_i - y_i$$

。对

$$W_i$$

的梯度是:

$$\frac{\partial \mathcal{L}}{\partial W_i} = (p_i - y_i) \cdot h_t$$

每个 token 的梯度向量与

$$h_t$$

平行。梯度只沿 hidden 方向更新,而 hidden 本身是高维压缩——所有 32K 个 token 的梯度都投影到同一个 512 维空间上,再分配回各自的

$$W_i$$

行。

y_i 为 1 的 token(真实标签)和 p_i 较大的 token(top-k collision set)得到显著梯度更新。其余大多数 token 的

$$p_i \approx 0$$

$$(p_i - y_i) \approx 0$$

,近乎 0 更新。

碰撞桶里的 token 共享 hidden 空间的方向信息。 Softmax 不做的事情是:它不分配方向——它只归一化大小。方向是 Linear 在投影时决定的。

回到我们实验的倒 U 曲线

A8-A12 的 K_lang 扫描结果就是对这个理论最好的验证:

A8(CE-only)  BLEU=3.45     ← K_lang 全部分流失(无 collision 意识)
A9(k=50)     BLEU=3.35     ← 桶太少,过拟合
A10(k=170)   BLEU=3.63     ← K_lang 精确匹配碰撞桶数
A11(k=500)   BLEU=3.09     ← 噪音开始回流
A12(k=56652) BLEU=3.35     ← 全表 softmax,无约束,信号消失

线性层的输出 z_i 的 top-k 选择(k = K_lang×|V| ≈ 170)不是随意选的——它是碰撞常数决定的。把 softmax 分母限制在碰撞桶内,梯度不再被稀释到无关 token 上。

碰撞是双向的——正反向 Hash 不对称

Linear 的碰撞不在单方向上。正向和反向的 Hash 路径是同一组参数,但经历不同的约束条件

Token (DE) → Encoder → h_t → W·h_t + b → Token (EN)
                              ↑ 碰撞发生在这里
                    向量回传 ← z_i = <W_i, h_t>

正向:释放

hidden 编码了一段包含多种语义的向量。Linear 把它释放到 32K 维词空间——每个 token 得到自己的内积分量。这个过程是稀疏的:一次翻译只输出一个 token,其他 31,999 个概率接近 0。

反向:碰撞

反向看同一个 W。在训练中,同一个 hidden 表示对应多个目标 token——不同的语言对同一个概念映射到同一个 hidden 空间。

以名词为例。名词的翻译大多是一一对应的:

德语 "Haus"  →  英语 "house"    同一个概念
德语 "Buch"  →  英语 "book"     同一个概念

当 “Haus” 和 “house” 分别用不同的 token ID 表示、但经过同一组 hidden → Linear 的重量时,梯度会把这两个 token 的

$$W_i$$

推向同一个方向——因为它们的 hidden 表示在语义空间里是相同的位置。

但 W 只有 512 维。两个名词挤在一起、三个名词挤在一起……所有翻译中一一对应的名词,都把 W 的对应行推到 hidden 空间的同一个区域。碰撞就此发生。

反向碰撞不是坏事——它恰恰是翻译模型学会 “Haus = house” 的方式。但如果碰撞太重(桶太小),token 之间开始混淆;如果碰撞太轻(全表),梯度被稀释到无关 token 上。

翻译的全过程:

① 编码: 源语言 → hidden      (压缩语义到连续空间)
② Hash: hidden → W·h_t       (连续→离散投影,碰撞发生)
③ 释放: z → 概率 → token     (稀疏表达在词空间)

碰撞不在第 ① 步(Transformer 本体),不在第 ③ 步(softmax 归一化),就在第 ② 步——Linear 把连续的 hidden 映射到离散的词汇空间。这是正反向不对称的核心。

结论

Linear(h_t) = logits_z 在代码里就一行。但它下面是:

$$\mathbb{R}^{512} \xrightarrow{\text{Hash}} \{1, 2, \dots, 32000\}$$

翻译的整个信息瓶颈就在这里——不是在 Transformer 的 attention 层,不是 decoder 的交叉注意力,是编码器最后一层 linear 把 continuous hidden 投射到 discrete vocab 的那一步。

K_lang 不是一个调参经验值——它是这个 Hash 函数的理论碰撞常数。

过拟合 = 碰撞桶太散

从朴素的线性回归看过拟合:

$$\hat{y} = w_0 + w_1x + w_2x^2 + \dots + w_{10}x^{10}$$

问题:

$$w_8, w_9, w_{10}$$

这些高频项的参数变得太大——它们不是在学习信号,是在记忆每个训练点的位置。曲线扭来扭去,拟合了噪声。

NMT 里的过拟合本质上同一个东西,只是表现形式不同:

线性回归:  高频项系数太大 → 记住了噪声的多项式
NMT:       碰撞桶太散 → 每个训练句独占一个 hash 桶 → 记住了训练样本本身

证据来自 B 系列的深度和宽度对比:

实验 配置 参数 BLEU 现象
B3 d256/6L 17M 11.70 碰撞有效,泛化正常
B2 d512/6L 56M 8.18 参数太多,过拟合
B4 d512/3L 56M 8.57 参数多+浅度,双倍失败

B2 有 56M 参数——在 IWSLT 的 160K 句上,每个训练样本可以独占几乎一个 hash 桶。W 有足够维度同时记住每对的德语句子和英语翻译。高频词(“的”、“了”、“is”、“the”)的梯度主导了反向传播,低频但有语义的名词被淹没在参数冗余里

B3 只有 17M 参数——因为碰撞被强制发生,“Haus” 和 “Gebäude” 必须共享参数。模型被迫去学习:“这两个德语词在语义上是相近的”,而不是死记 “Haus = house”。

K_lang 就是要保证碰撞桶够密、参数不能太大——让模型被迫去学语义共性,而不是死记训练样本。 这条线和线性回归里"控制多项式项数防止过拟合"完全平行。


MoE + 词频 = 按语言特征路由的碰撞桶

Hidden 不一定必须是一个矩阵。MoE(Mixture of Experts)早就把一个 FFN 拆成多个专家:

标准 Transformer:   h → 一个 FFN → 输出
MoE Transformer:    h → 路由 → 选专家 → 专家 FFN → 输出

             h ─┬─→ 专家1 (第0-2层共享)
                ├─→ 专家2 (第3-4层共享)    ← gating 网络根据 h 选
                └─→ 专家3 (第5-6层共享)

已有工作(Shazeer et al. 2017, GShard, Switch Transformer)按 token 级别做路由:每个 token 被分配到一个专家 FFN。但没有人按语言特征来划分专家:

  • 专家 A:短句(1-10 词)专用的 hidden 矩阵
  • 专家 B:长句(30+ 词)专用的 hidden 矩阵
  • 专家 C:高频词专用(“的”、“了”、“is”)

如果路由的 gating 信号不是从 h 学到的,而是从可观测的语言特征(句长、词频、TF-IDF)直接控制,MoE 就从"黑盒分配"变成了"语言学驱动的碰撞桶分配"。这等价于把 K_lang 的碰撞理论作为 MoE 架构的设计指南——每个专家就是一个碰撞桶簇。

这一思路至今未见发表。


May the Code be with us.


License: GPLv3
本文《SameTime WMT》系列采用 GNU 通用公共许可证第三版 (GNU General Public License v3.0) 协议进行开源发布与分发。