你有没有想过,为什么把模型的隐藏维度从 512 硬涨到 4096,有时候效果提升巨大,但涨到某个点之后,continue 加宽却越来越不划算?这背后不只是”参数越多越聪明”那么简单——最后一层的几何结构,天生就有一个数学上无法绕过的容量上限。

故事从这里开始

假设你在设计一个翻译软件的自动补全功能。用户刚打完”我想吃一个”,你的模型需要预测下一个词。可能是”苹果”,可能是”三明治”,可能是”披萨”,也可能是”午饭”。这些词在意义上八竿子打不着——苹果是水果,三明治和披萨是快餐,午饭是抽象概念——但在这句话的语境下,它们都合理。

现在把语境换成”我想吃一个红色的”。这时候候选词骤然收窄:苹果、番茄、辣椒……几乎不可能是”披萨”(除非披萨真的是红色的,这不太常见)。同一个动词”吃”,前面加一个”红色的”,整个概率分布就发生了剧烈的、几乎不连续的跳变。

这类现象在语言里无处不在:同一个语境的微小变化,可能导致下一个词的概率分布发生巨大且不规则的改变。这听起来是理所当然的常识,但如果你去问一个训练好的语言模型是怎么把”看到的文字”转换成”对下一个词的判断”的,你会发现这个转换过程其实有一个非常朴素、甚至有点粗糙的实现方式——而这个粗糙的实现方式,天生带着一个数学限制。这个限制有个名字,叫 Softmax 瓶颈(Softmax Bottleneck)

它不是一个工程 bug,也不是训练不够久导致的欠拟合。它是一个几何上、代数上就写死了的容量上限——2018 年被 Yang 等人用一篇论文证明存在,2024 年被另一组研究者在真实的预训练语言模型里找到了实锤证据。今天我们就来把这件事讲透:它究竟是什么、为什么会发生、以及大家是怎么想办法绕过它的。

"我想吃一个" 上下文 context 隐藏向量 h (维度 d) 词表概率分布 苹果 ■■■■■■ 三明治 ■■■■ 披萨 ■■■ 午饭 ■■ ... (共 V 个词)

输出层到底在做什么

在深入数学之前,先把整件事拆解成一个日常动作:用一根固定长度的”尺子”去衡量一整本词典

具体来说,绝大多数语言模型的最后一步是这样的:

  1. 经过所有 Transformer 层之后,模型对当前上下文产生了一个隐藏向量 $h$,维度是 $d$(比如 4096)。
  2. 模型有一张词嵌入表,词表里每个词 $x$ 都对应一个同样维度 $d$ 的向量 $w_x$。
  3. 用 $h$ 和每个 $w_x$ 做点积,得到一个数字叫”logit”,代表这个词在当前语境下有多”匹配”。
  4. 把所有 logit 扔进 softmax,归一化成一个概率分布。

这个流程简单、优雅、训练起来非常稳定,几十年来几乎是语言模型的标配。但它有一个隐含的假设很少有人去质疑:用一个固定长度为 $d$ 的向量,去表达”这段上下文该往哪个方向发展”这件事,信息量够不够?

想象一下,$d$ 就像你手里一根固定长度的绳子,你要用这根绳子去”框住”整本词典里每个词在这个语境下应该有多大概率。语境千变万化——”我想吃一个” vs “我想吃一个红色的” vs “银行的存款” vs “河边的银行”——每种语境理应产生一种完全不同形状的概率分布。问题是:这根绳子的长度是固定的,而语境的花样几乎是无穷的。当语境的花样多到超出绳子能表达的范围,会发生什么?

H (N×d 上下文矩阵) × Wᵗ (d×M 词嵌入矩阵) = 秩 ≤ d 的矩阵 但语言真实需要的对数概率矩阵 A, 真实秩往往远远超过 d ← 这就是「瓶颈」

Softmax 瓶颈:用数学把这件事说清楚

问题是什么

Yang、Dai、Salakhutdinov 和 Cohen 在 2017 年提出了一个很巧妙的重新表述:把语言建模问题看作一个矩阵分解问题

假设语言里一共有 $N$ 种不同的上下文,词表大小是 $M$。我们可以定义三个矩阵:

  • $H_\theta \in \mathbb{R}^{N \times d}$:每一行是一个上下文对应的隐藏向量 $h_c$
  • $W_\theta \in \mathbb{R}^{M \times d}$:每一行是一个词的嵌入向量 $w_x$
  • $A \in \mathbb{R}^{N \times M}$:每一行是”真实的”对数概率分布 $\log P^*(x c)$,也就是这个语境下每个词该有的、真正正确的概率(取对数之后)

标准的 softmax 语言模型在做的事情,本质上是用 $H_\theta W_\theta^\top$ 去逼近 $A$(先不管 softmax 的归一化细节)。而 $H_\theta W_\theta^\top$ 这个矩阵乘法有一个铁律:它的秩最多是 $d$——不管 $N$、$M$ 有多大,这个乘积矩阵最多只能有 $d$ 个”独立的方向”。

翻译回人话:不管你的模型body多深多宽,最终它对每个上下文只能产出一个 $d$ 维向量,而这 $d$ 维向量通过和词嵌入做点积所能表达的概率分布”花样”,最多只有 $d$ 种独立的模式。

那真实的 $A$(自然语言真正需要的对数概率矩阵)的秩是多少?论文的核心论断是:因为自然语言极度依赖上下文,$A$ 的真实秩往往远远超过 $d$。想想”苹果”这个词——它在”我想吃一个”后面的概率,在”我在电脑品牌里最喜欢”后面的概率,在”每天一个xx医生远离我”后面的概率,这三种语境下”苹果”这个词的合理程度天差地别,而且这种差异跟其他一堆词(三星、诺基亚、医生……)的差异模式几乎是”独立”的——每一种语境组合都在创造一种新的、几乎线性无关的概率分布形态。语境的组合数是天文数字,而这些语境所诱导出的概率分布形态之间,很多都彼此”正交”,堆起来的矩阵秩就会非常高。

于是矛盾就产生了:模型能表达的秩被死死限制在 $d$,但真实需要的秩却远超 $d$。这个数学事实,就是 Softmax 瓶颈。

直觉:一根绳子和一整本词典

换个更直白的类比。假设你要给全班学生按照不同科目的成绩排名,每个学生你只允许用一个数字来描述他(比如”综合分”)。如果只看一个科目,一个数字够用。但如果学生真实的能力是多维的——数学好但语文差、体育好但英语差——用一个数字去排”谁该在语文考试前更认真复习”这种细粒度问题,你会发现总有学生的排名不对劲,因为一个数字根本装不下多维的真相

隐藏向量 $h$ 就是这个”一个数字”(当然它是 $d$ 维,但 $d$ 是固定的、有限的)。语言里每一种语境组合诱导出的概率分布,就像是学生的”多维能力”——语境种类太多、太微妙,当维度 $d$ 不够大时,模型被迫在不同语境之间”共享”表达空间,某些细微但重要的区分就会被抹平。

这也解释了为什么有一篇后续研究(Chang & McCallum, 2022)会说 Softmax 天生不擅长表达”多峰”分布。想象”我想吃一个”后面可能是”苹果”(水果类)或者”披萨”(快餐类)——这两类词在嵌入空间里可能是两个相距很远、互不相邻的”聚类”。而 softmax 的几何结构是:一个隐藏向量 $h$ 对所有词嵌入做点积,这本质上是在嵌入空间里画一个”方向”,凡是跟这个方向对齐的词都会拿到高分。这种机制天生适合”一个连续的高概率区域”,却很难同时在两个互不相邻的、遥远的簇上都给出高分而中间地带给出低分——就像用一个手电筒的光束,很难同时照亮房间两个对角却让中间保持黑暗。

技术细节(选读):为什么秩最多是 $d$ 差 1 都不行

论文里有一个精巧的证明技巧值得展开。因为 softmax 对每一行做的是”减去一个常数不影响结果”(softmax 是”平移不变”的——给一行logit全部加上同一个常数,归一化后概率分布不变),所以能够表示同一个真实分布 $P^*$ 的 logit 矩阵不是唯一的一个,而是一整个集合:

\[F(A) = \{A + \Lambda J \mid \Lambda \text{ 是对角矩阵}\}\]

这里 $J$ 是全 1 矩阵,$\Lambda J$ 的效果就是给 $A$ 每一行加上一个(可以不同的)常数。论文证明了这个集合里所有矩阵的秩,相差最多不超过 1 ——也就是说,不管你怎么”平移”每一行,秩基本是这份数据的一个”本质属性”,挪不动太多。这就让”真实需要的秩到底是多少”这个问题变得有意义、可以被谈论,而不是被平移这种无关操作干扰。结论就是:如果这个本质的秩超过了 $d$,那不管模型怎么训练,都无法完美还原真实分布——这是表达能力的硬限制,不是优化没做好

这事真的会发生吗?2024 年的实锤

2018 年的论文更多是理论证明加小模型实验(RNN、Penn Treebank/WikiText 这类相对小的数据集)。真正让这件事在 2020 年代的大模型语境下”实锤”的,是 Nathan Godey 等人 2024 年的论文,标题就很直接:《为什么小语言模型表现不佳?——从 Softmax 瓶颈角度研究语言模型的”饱和”现象》。

他们观察到一个现象:一些小模型(隐藏维度较小的那种)在预训练过程中,loss 曲线走到某个阶段会突然”卡住”——性能不再随训练增加而提升,甚至掉头往下走一点,然后进入长长的平台期。这个现象此前被叫做”饱和”(saturation),但没人说清楚根本原因。

Godey 等人的解释是:这正是 Softmax 瓶颈在实践中的表现。当隐藏维度小于某个阈值(论文里给出的经验值是约 1000 维以下)时,模型被迫在训练后期采用”退化”的隐藏表征——也就是说,模型的隐藏向量分布变得异常集中、失去了本该有的多样性(这在论文里跟”各向异性”(anisotropy)这个概念相关:理想情况下隐藏向量应该均匀地散布在高维空间的各个方向,但当秩不够时,向量会被压缩挤到一个低维的”薄片”里)。这种退化直接拖累了下游评测的表现——即使训练 loss 数字看起来还不错。

这个发现的价值在哪?它把一个纯理论的数学论断(2018)和一个真实存在、困扰了很多人的实际现象(预训练”卡住”)连接了起来,并给出了一个可操作的经验判据:如果你的模型隐藏维度小于 1000,你需要格外警惕 Softmax 瓶颈带来的性能损失。这也部分解释了为什么工业界的”小模型”设计者(做端侧小模型的团队)常常会在架构上做出一些”看似违反直觉”的选择——比如刻意让最后几层变宽,或者用参数共享省下来的预算去加大 embedding 维度,而不是简单粗暴地把整个网络等比例缩小。

训练进程中的 Loss 曲线(示意) Loss 训练步数 大模型(d 足够大)持续下降 小模型(d<1000)先降后"饱和"卡住

面对瓶颈,大家做了什么

理论说清楚了限制在哪,接下来自然的问题是:能不能绕过去? 过去这些年,研究者们大致沿着四条路子想办法。

第一条路:多套几个 softmax,凑出更高的”有效秩”。 这就是论文原作者自己提出的解法——Mixture of Softmaxes(MoS)。核心想法很简单:既然一个隐藏向量的表达力有限,那就不要只用一个,用 $K$ 个不同的隐藏向量,每个各自算一次 softmax,然后按照一个(依赖上下文的)权重把这 $K$ 个概率分布加权平均起来:

\[P_\theta(x|c) = \sum_{k=1}^{K} \pi_k(c) \cdot \text{softmax}(h_{c,k}^\top w_x)\]

翻译回人话:把”一个人拿一根固定长度的绳子去衡量整本词典”,换成”$K$ 个人各拿一根绳子,分别衡量,然后综合大家的意见”。这样一来,有效能表达的”模式数”就从 $d$ 提升到了跟 $K \cdot d$ 相关的量级。实验证明 MoS 确实能学出秩明显更高的输出矩阵,在 Penn Treebank、WikiText-2 等基准上取得了当时的最好成绩。代价也很直白——每多一个 $K$,输出层的计算和内存开销就多一倍,这在词表动辄十几万的现代大模型里不是小数目。

第二条路:换掉 softmax 本身的形状。 2018 年 NeurIPS 上的 Sigsoftmax 论文换了一个思路:不增加参数、不多算 $K$ 次,而是在归一化之前,把每个 logit 从简单的 $\exp(x)$ 换成 $\exp(x) \cdot \text{sigmoid}(x)$。这个小改动改变了输出函数的”形状”,让它在数学上不再受制于原来那个秩上限的证明前提,从而在几乎不增加计算量的前提下部分缓解瓶颈。这条路后来还衍生出”可学习的单调逐点变换”(Ganea 等人 2019 年的 LMS 方法)——本质上都是”不加规模,改造归一化本身”的思路。

第三条路:意外的帮手——权重共享和 MoE。 这条路挺有意思,因为它不是”专门为了解决瓶颈”设计的,却顺带缓解了瓶颈。第一个是输入输出权重共享(weight tying)——现代 LLM 常见的一个省参数技巧,让输入 embedding 和输出 embedding 共用一套权重。有分析发现,在某些配置下,这样做反而对瓶颈问题有帮助——因为共享的输入 embedding 训练信号更丰富(既受语言建模损失约束,也隐含地编码了更多的词-词关系),输出投影层”继承”了这份丰富性。第二个更值得琢磨:Mixture of Experts(MoE)。当不同的输入激活不同的专家网络时,输出阶段的有效表达力其实是随着”被激活的专家数量”在扩展的——这跟 MoS 的思路有几分神似:本质上也是”多套几个函数,按需组合”。这被认为是MoE模型能”以小博大”(相同激活参数量下,效果超出预期)的一个被低估的原因。

第四条路:干脆加宽最后几层。 最直接但也最”硬”的办法——既然瓶颈发生在输出投影这一步,那就专门针对这一步把维度加宽,而不必把整个网络都等比例放大。一些架构选择在最后几个 Transformer block 用更宽的隐藏维度,或者用一个专门更宽的投影头,正是因为意识到”瓶颈最尖锐的地方就在最后一步”。

① Mixture of Softmaxes K 套 softmax 加权组合,有效秩 ↑K倍 ② Sigsoftmax / LMS 改造归一化函数本身,零额外参数 ③ 权重共享 / MoE 非专门设计,但顺带缓解瓶颈 ④ 加宽最后几层 直接针对瓶颈最尖锐处扩容 共同目标:让有效可表达"秩" 超越单一线性投影维度 d 的天花板

这意味着什么

把这些线索串起来,我们能得到几个对实践很有用的直觉:

第一,模型的”聪明程度”不只取决于总参数量,还取决于信息在架构里的哪个环节被”卡了脖子”。 Transformer body 可以堆很多层、很宽,但如果所有信息最终都要压缩成一个 $d$ 维向量去撞词表这堵墙,那么这个 $d$ 才是决定输出层表达能力的关键瓶颈之一,而不是模型总参数量。这也是为什么很多小模型设计里会有意识地保留一个相对宽裕的 embedding/隐藏维度,即使整体参数预算很紧。

第二,”训练更久”不是万能药。 如果你观察到模型 loss 在某个点之后停滞不前,先别急着怪数据不够、学习率不对——有可能是架构层面的容量已经封顶了。Godey 等人的论文提供了一个具体的经验信号:隐藏维度低于 1000 时要格外小心。

第三,MoE 的成功可能有一部分”意外之喜”来自这里。 大家谈论 MoE 时,常常聚焦在”用更少的激活参数换取更大的总容量”这个计算效率视角。但从 Softmax 瓶颈的角度看,MoE还额外解决了一个别人没太在意的问题:让输出层的有效表达秩,随激活专家数扩展,而不是死死锁死在隐藏维度上。这可能是为什么 MoE 模型经常”以小博大”的另一半解释。

第四,这提醒我们,语言模型架构里有很多”看不见的墙”。 我们习惯于用参数量、FLOPs、训练 token 数这些指标衡量模型能力,但 Softmax 瓶颈是一个典型的”不体现在这些数字里,却真实限制模型表达能力”的架构约束。理解这类约束,是从”调参侠”进化到”真正理解架构”的分水岭。

下一篇预告

Softmax 瓶颈只是输出层这一个环节的故事。如果你想继续往下追问:”既然 softmax 会有几何上的表达限制,那 attention 里的 softmax 是不是也有类似的问题?”——这其实指向了另一整条研究脉络(本系列此前讨论过 attention sink、秩坍缩等现象),感兴趣的读者可以回顾系列中相关篇章。这篇则更像是给整个系列的一个”意外补丁”:提醒我们即便是最朴素、最不起眼的最后一层,也可能藏着值得认真对待的数学结构。