从0训练LLM · 现代大模型体系 阅读 + 实验 ≈ 40 分钟 页内实验 ×3
C4 一个 Transformer 块:FFN、残差、归一化、门控 第 4 课

门控:为什么现代 FFN 有三个矩阵,注意力的 q_proj 还要多输出一倍?

门控:SwiGLU 与注意力输出门
把「放行多少」和「放行什么」拆成两条投影再逐元素相乘,就是门控。FFN 里它叫 SwiGLU,多出的那个矩阵就是门;注意力里它是 SDPA 输出上的 sigmoid 门,q_proj 多出的一半就是它。两者更好都是实验选出来的。

本课一问:门控:为什么现代 FFN 有三个矩阵,注意力的 q_proj 还要多输出一倍?

这一课先不碰:给门控加「软封顶」的 SiTU-GLU 与各家的激活截断(C15)、48 层 Gated DeltaNet 自带的输出门(C11)、这些门一共占多少参数(岔路 B1)。

② 从已有出发

从已有出发 · 累计数据流 点已学环节看形状与参数
解码层

L1 的 FFN 有两个矩阵:W_up 读、W_down 写,中间一个 GELU。C3 的注意力里,q_proj 把 5,120 维投影成 24 个头 × 256 维 = 6,144 维。可 Qwen3.8 的权重里是这样的(safetensors 头里读出的真实形状):

张量形状按 L1 / C3 的理解应该是
mlp.gate_proj[17,408, 5,120](没有这个矩阵)
mlp.up_proj[17,408, 5,120]W_up
mlp.down_proj[5,120, 17,408]W_down
self_attn.q_proj[12,288, 5,120][6,144, 5,120]

贯穿例句「小明把苹果给了小王」的 5 个 token,每一层都要各自穿过这三个 FFN 矩阵,每一个全注意力层都要经过这个加宽了的 q_proj(下面张量图里的 T = 5 就是它)。多出来的 gate_proj,和 q_proj 多出来的那一半,是同一个想法的两个用法:门。

③ 先自己设计:多出来的矩阵,是不是只是「多了参数」?

最省事的解释:gate_proj 就是多加的一份参数,三矩阵的 FFN 更好,只因为它更大。检验这个解释的办法是拿 GELU FFN 和 SwiGLU FFN 比一比——关键在于怎么比。

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案把 gate_proj 当成多加的参数:中间维都取 4d,直接比
方案中间维矩阵个数单层 FFN 参数

差距不大,但参数一样多时它站得住。那多出来的矩阵到底在做什么?作者自己在结论里坦白没有解释,把成功归于「divine benevolence」(Shazeer 2020 结论)——这正是对话样本里那句话:「为什么 SwiGLU 比普通 ReLU MLP 好?也不是证明」。我们能做的,是把它在做什么看清楚。

④ 改进到现代做法

第 1 步:门——把「放多少」和「放什么」拆开

回到 L1 的神经元:第 i 个神经元的输出是 act(x · w_i),写回时乘 W_down 的第 i 行。「亮不亮」和「亮多少」是同一个数算出来的——x 在读取方向 w_i 上的投影,过一次 GELU。

门控的做法是给每个神经元两个读取方向:

这就是 GLU 家族(Dauphin 等 2016 提出 GLU,act 是 sigmoid;Shazeer 2020 换成别的激活,act = SiLU 时叫 SwiGLU)。一个门控神经元只取决于 (g, u) 两个数,所以可以把它整个画在一张平面上:

← g 负(门关)g:门前值g 正(门开)→
不带门的单变量对照
GELU(z)(GPT-2 的 FFN)SiLU(g)(SwiGLU 的门)
🎯

试三件事:① 在平面左半边(g 为负)随便点:SiLU(g) 很小,不管 u 多大输出都接近 0——门关着;② 点 g = 0 附近:门的值是 0,可 ∂h/∂g 不是 0,门随时能被梯度「推开」——切到 ReGLU(门是 ReLU)再点 g 为负的地方,∂h/∂g 恰好为 0;③ 点 g = −3、u = −2:门的值是 −0.142,输出变成 +0.285——SiLU 门可以是负数,它不是 0 到 1 的开关;切到 GLU,门变回 sigmoid,取值只在 (0, 1) 之间。

门控神经元自带乘法(回扣 L1)。 把「好吃 / 不好吃 / 难吃 / 不难吃」的两个特征改用 ±1 编码(是 = +1,否 = −1),目标「偏正面」恰好是 −p × n:好吃 −(+1)(−1) = +1,不好吃 −(+1)(+1) = −1,难吃 −(−1)(−1) = −1,不难吃 −(−1)(+1) = +1。一个不带激活的门控神经元(Bilinear:h = g × u,g 读 p、u 读 −n)一个就够,而 L1 用 ReLU 要两个 。乘法交互,加上「值分支的梯度只被门缩放」,是门控被认为可能有效的两个理由——都是理论动机,不是证明。

第 2 步:SwiGLU 的完整形状

SwiGLU FFN(Qwen3.8 的 mlp,行向量写法)
= ( ) ·
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
三个矩阵都没有偏置。原文的式 (6):FFN_SwiGLU(x, W, V, W₂) = (Swish₁(xW) ⊗ xV)W₂。
Qwen3.8 的一层 SwiGLU FFN(d = 5,120,中间维 17,408)
Y = (SiLU(X·Wgate) ⊙ (X·Wup))·Wdown
输入参数(可学习)输出中间结果
边长按对数比例缩放,块边上的数字是真实值;同一维度符号的边在全图等长。
维度含义 数值
T 序列长度(「小明把苹果给了小王」在 Qwen3.8 分词器下是 5 个 token) 5
d 隐藏维 hidden_size 5120
I FFN 中间维 intermediate_size(= 3.4 × d) 17,408
单层参数 3 × 5,120 × 17,408 = 267,386,880;和同宽的两矩阵 FFN 比,多出的正好是 W_gate 这一份。

第 3 步:注意力的输出门——q_proj 为什么多输出一倍

朴素方案在哪失败:注意力「必须分出 100%」。

C3 的岔路课讲过 attention sink:softmax 的权重和恒为 1,一个头在当前位置没有合适的对象可看时,也必须把 100% 的注意力分出去,于是常常倒在第 1 个 token 上。Qwen 团队在一个 15B 参数(激活 2.54B)的 MoE 模型上量过:没有门时,各层平均有 46.7% 的注意力分给了第 1 个 token,某一层高达 83% 。

还有第二个结构问题:值投影 W_V 与输出投影 W_O 之间什么都没有。一个头里 W_V 把 5,120 维压到 256 维,W_O 再展回 5,120 维,两次线性变换合起来仍是一个线性映射,而且秩不超过 256 。

改进:在 SDPA 输出上乘一个 sigmoid 门。

Qwen3.8 的 Gated Attention(24 个头 × 256 维 = 6,144)
Y = (SDPA(Q, K, V) ⊙ σ(X·Wg))·Wo
输入参数(可学习)输出中间结果
边长按对数比例缩放,块边上的数字是真实值;同一维度符号的边在全图等长。
维度含义 数值
T 序列长度(示例 5) 5
d 隐藏维 5120
Hd 24 个 Q 头 × head_dim 256 6144
门每层多 5,120 × 6,144 = 31,457,280 个参数,16 个全注意力层共 503,316,480。

门由当前 token 自己的输入算出,逐头、逐元素地决定这个头这次取回的东西放行多少:一个头没什么可看时,它可以把 softmax 分出去的 100% 整个关掉。这也在 W_V 与 W_O 之间插进了一个非线性。论文在 30 多种位置与形式里比较,SDPA 输出后、逐头逐元素的 sigmoid 门最好:首 token 注意力占比 46.7% → 4.8%,各层最大隐藏激活 1053 → 94,困惑度 6.026 → 5.761,门的平均取值只有 0.116(大多数时候接近关闭) 。这一项确实是 Qwen 首创,Qwen3-Next 起用于量产模型。

「门」这个说法的精确映射与失效点。

演进图:本课在第几代

门控在 2019 年之前的 Transformer 里没有;GLU 在 2016 年已经有了,2020 年才被放进 FFN,2025 年又被放到注意力的输出上。

一个 Transformer 块的演进:每一代都被上一代的某个真数字逼出来
零件 \ 年代
2017 · 原版Vaswani 等
2019 · GPT-2OpenAI
2020–2023 · Llama 式Shazeer 2020 起
2025–2026 · Qwen3.8本课程锚点
2026 · 分歧C15 展开
FFN
两矩阵 + ReLU,d_ff = 4d(512 → 2048) 卡在d_ff 取 1024 / 2048 / 4096,开发集困惑度 5.12 / 4.92 / 4.75:越宽越好,只能拿参数换
两矩阵 + GELU,768 → 3,072 卡在参数对齐后仍输给门控版:GELU 1.983 对 SwiGLU 1.944(T5-base)
SwiGLU 三矩阵,中间维 8d/3:DeepSeek-LLM-67B 为 8,192 → 22,016 卡在8d/3 只是公平对照时的换算,真实模型按预算另取宽度
SwiGLU,5,120 → 17,408(3.4d),占全模型参数 61.6% 卡在输出没有上界:SiLU(10) × 10 = 99.995,低精度下会溢出
给 SwiGLU 截断(gpt-oss 7、DeepSeek V4 10)或软封顶(Kimi K3 的 SiTU-GLU);再往后拆成很多小 FFN(MoE,C11)
每个子层 x + F(x)(ResNet 2015 的想法搬进 Transformer) 卡在残差流越加越大:128 次单位方差写入后,标准差 √129 = 11.36
残差输出投影按 1/√N 初始化(我们的项目:0.02 ÷ √8 = 0.00707) 卡在一条 d 维向量要承载所有层的读写,层数一多成了瓶颈(各家自报)
普通残差,同 GPT-2
普通残差:64 层 × 2 个子层 = 128 次写入
加宽成 4 条流(mHC、Gated Residual),或让每层对前面所有层做注意力(AttnRes)
LayerNorm(2016,逐 token 统计;取代按批统计的 BatchNorm)放在加法之后:Post-LN 卡在离不开学习率 warmup(原因在 C8 兑现)
LayerNorm 移到子层入口(Pre-LN)+ 最终 LayerNorm 卡在还要减均值、带 β;Zhang & Sennrich 认为平移不变可以不要
Pre-RMSNorm:只除以均方根,没有 β 卡在标准增益 g 被 weight decay 拉向 0
zero-centered RMSNorm:乘 1 + w,w 初始化 0,eps 1e-6;另有 QK-Norm
OLMo 2 把归一化挪到子层输出端;DeepSeek V4 用 QKV RMSNorm 取代 QK-Clip(C8)
门控 本课
没有(GLU 在 2016 年已提出,用在卷积语言模型里)
没有
FFN 里的门:SwiGLU = SiLU(x·W_gate) ⊙ (x·W_up) 卡在注意力 softmax 必须分出 100%:首 token 平均占 46.7%(Qwen 的 15B MoE 实验)
再加注意力输出门:q_proj 5,120 → 12,288 = 2 × 6,144,一半过 sigmoid 当门(首 token 占比降到 4.8%)
Kimi K3 的 Gated MLA;Qwen3.8-Flash-Next 把线性注意力的输出门也换成 sigmoid(C11)
数字口径:中间维、比例、FFN 占比、q_proj 宽度、写入次数由 anchor-model.json / frontier-models.json 的官方 config 在构建时现算;4 倍宽的对照出自 Vaswani 2017 表 3(本地 PDF),GELU 对 SwiGLU 出自 Shazeer 2020 表 1,首 token 占比出自 Qiu 等 2025 表 4(Qwen 自报),截断值出自各家 config(R3 §3.6);√129 假设每次写入独立、方差为 1。

门控本身已经是共识;分歧在它周边:SwiGLU 的输出没有上界(g = u = 10 时 SiLU(10) × 10 = 99.995),在低精度算术下有溢出风险,于是 2025–2026 年的前沿模型都在给它「封顶」,只是封法不同 ——这是 C15 的内容。

⑤ 极小真数字算一次

一个 SwiGLU 神经元,g = 1.5、u = −2:σ(1.5) = 0.8176,SiLU(1.5) = 1.5 × 0.8176 = 1.2264,h = 1.2264 × (−2) = −2.453;∂h/∂u = 1.2264(值分支的梯度只被门缩放,不经过激活函数的导数),∂h/∂g = σ(g)(1 + g(1 − σ(g))) × u = −2.083。换成 g = −3:σ(−3) = 0.0474,门的值 SiLU(−3) = −0.142,h = +0.285——门是负的,输出的符号被翻了过来。这几个数在上面的门控平面上点对应位置就能读到。

注意力输出门:取 SDPA 输出的某一维为 0.8(随手取的输入,只为演示乘法),门前值 −2.0 时 σ(−2.0) = 0.119,放行 0.8 × 0.119 = 0.095;门前值 +2.0 时 σ = 0.881,放行 0.705。论文里门的平均取值只有 0.116——大多数时候,一个头取回的东西只放行一成左右。

真训练日志 · 我们自己的模型:GELU 与 SwiGLU(参数已对齐)

基线用 SwiGLU(中间维 688),对照组 c4_gelu 只把 FFN 换成 GELU(中间维 1024),单层参数 528,384 对 524,288。差异小于 0.02 时,页面会标「在噪声内」——这是 C14 实验课用同配置 5 次重跑定的噪声底线(标准差 0.0066、极差 0.016;差距小于 3σ ≈ 0.020 不下结论)。

项目实测 · GELU / SwiGLU

读图(2026-09-26 导出的数据,以组件显示为准): 单种子时 SwiGLU 4.6263、GELU 4.6410,差 0.015,小于同配置 5 次重跑的极差 0.016(C14 实验课),下不了结论。于是每组再补 4 个种子(种子 1337–1341):SwiGLU 4.6218 ± 0.0060,GELU 4.6657 ± 0.0206,GELU 差 0.044,超过 3σ 阈值 0.020,约是种子波动标准误的 4.6 倍——在参数对齐的前提下,这个项目上可以说 SwiGLU 更好,方向与 Shazeer 2020 一致 。上面门控平面里的黑点是同一个基线模型第 2 层的 688 个神经元在「曰」字上的真实 (g, u):61.9% 的门前值为负,19.0% 的门几乎关闭(|SiLU(g)| < 0.1);同一层同一个字,GELU 版模型 1,024 个神经元里有 92.9% 的输入为负。

⑥ ⚠ 常见误解

⚠️

「SwiGLU 的门是 0 到 1 之间的开关」✗ —— SiLU(g) 的值域是 [−0.278, +∞)。0 到 1 之间的只有 sigmoid 门:原始 GLU 和注意力输出门。

「SwiGLU 更好,是因为它多了一个矩阵、参数更多」✗ —— 公平的对比都把中间维乘了 2/3,参数一样多;真实模型的中间维是按预算另取的(Qwen3.8 取 3.4d)。

「门控被证明更好」✗ —— 乘法交互、线性梯度通路是理论动机;「更好」来自对照实验,原作者明说无法解释。

「注意力输出门是一个固定的开关 / 一种 dropout」✗ —— 门由当前 token 的输入算出,每个 token、每个头、每一维都不同;dropout 是训练时随机置零,推理时关掉。

⑦ 证据三问

⑧ 一句话

门控 = 两条投影逐元素相乘:一条决定放行多少,一条提供内容;它更好是实验选出来的,不是证明出来的。

⑨ 下一个缺口

一个块的零件到这里全齐了:两个 zero-centered RMSNorm、一个带输出门的注意力(或 Gated DeltaNet)、一个 SwiGLU FFN、两次残差相加。零件的参数加起来是多少?FFN 真的占了六成吗?去岔路课 参数到底花在哪 算清总账;主线接着进入 C5 优化:块搭好了,参数怎么更新得又快又稳?

⑩ 你可能会问