注意力取回信息之后,每个 token 自己还要做什么加工?
本课一问:注意力取回信息之后,每个 token 自己还要做什么加工?
这一课先不碰:现代 FFN 为什么有三个矩阵(SwiGLU,L4)、FFN 到底占多少参数(岔路 B1)、把 FFN 拆成很多个专家(MoE,C11)。
② 从已有出发
到 C3 为止,「小明把苹果给了小王」的每个 token 都通过注意力拿到了上下文:「给了」这个位置已经知道是谁把什么给了谁。
这一课换个例子,原因是:贯穿例句里没有哪个词的意思需要「两件事同时成立」才能确定,线性方案在它上面找不到一个干净的失败数字;而本课要证明的恰恰是「线性组合做不到某种组合」。所以借用同一只「苹果」的四种评价——好吃、不好吃、难吃、不难吃。注意力已经把「不」这个字的信息搬进了评价词所在的位置,于是这个位置同时知道两件事:
- p:评价词本身是正面的吗?(好吃 = 1,难吃 = 0)
- n:前面有没有「不」?(有 = 1,没有 = 0)
要回答「这句评价偏正面吗」,答案是 p 和 n 恰好一个成立、一个不成立的时候才是「是」:好吃(1, 0)→ 是,不好吃(1, 1)→ 否,难吃(0, 0)→ 否,不难吃(0, 1)→ 是。信息已经都在这个位置上了,问题是怎么把它们组合起来。
先回忆注意力对一个位置做了什么。第 i 个位置的输出是
输出_i = Σ_j a_ij · (x_j · W_V) · W_O
权重 a_ij 来自 softmax,这里确实有非线性;但权重一旦定下来,从 x 到输出这条「值通路」就只剩两次矩阵乘法。最极端的是第 1 个位置:因果掩码下它只能看自己,softmax 在一个元素上恰好等于 1 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条softmax 只有一个元素时,e^s ÷ e^s = 1;于是第 1 个位置的注意力输出就是 x₁·W_V·W_O,是 x₁ 的线性函数。 出处本页推导 ↗ ,它的输出就是 x₁ · W_V · W_O——对它自己的特征完全是线性的。
③ 先自己设计:只靠注意力行不行?
最省事的方案:不加任何新零件,让每个位置的输出直接是自身特征的线性组合(加一个常数),ŷ = a·p + b·n + c。你来找 a、b、c。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
拖动 a、b、c,或者直接点「用最小二乘求最优」。
教学构造:p、n 两个特征名是为了讲解手工起的;真实模型里某一维不能读成「是否正面」。
| 评价 | p | n | 目标 y | 线性输出 ŷ |
|---|
给这个位置加两个「神经元」:每个神经元先用一组权重读出一个数、加上偏置,过一个非线性函数,再按另一组权重写回输出。默认权重是手工构造的精确解。
教学构造:p、n 两个特征名是为了讲解手工起的;真实模型里某一维不能读成「是否正面」。
| 评价 | p | n | z₁ → h₁ | z₂ → h₂ | ŷ | 目标 |
|---|
失败的原因可以证明。 对任何 a、b、c:ŷ(1,0) + ŷ(0,1) = (a + c) + (b + c) = a + b + 2c,ŷ(1,1) + ŷ(0,0) = (a + b + c) + c = a + b + 2c,两边永远相等 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条仿射函数 f(p,n) = a·p + b·n + c 满足 f(1,0) + f(0,1) = f(1,1) + f(0,0);目标值 1 + 1 ≠ 0 + 0,所以不存在精确解。最小二乘最优解 a = b = 0、c = 0.5 由正规方程解出,组件里现算。 出处本页推导 ↗ 。而目标两边分别是 2 和 0。线性方案能做到的最好,是对四句一律给 0.5——它完全分不出哪句是夸、哪句是骂。
两个神经元为什么够?看它们各自读出了什么:
- 神经元 1 读 p + n,不设门槛:只要「有正面词或有『不』」就亮,亮度 = 成立的条数。
- 神经元 2 读 p + n,门槛 −1:只有两件事同时成立(「不好吃」)才亮。
- 写回时神经元 1 乘 +1、神经元 2 乘 −2:「不好吃」上是 2 − 2 = 0,其余三句是 1、0、1。
试三件事:① 在朴素方案里随便拖 a、b、c,盯着表格下面那行恒等式——两边永远相等,MSE 从来低不过 0.25;② 先点「看它在哪失败」「换成改进方案」展开右边的 FFN,再点「无(去掉)」:两层线性合成一层 ŷ = −p − n + 2,MSE 变成 1.0,非线性一去掉,多一层也没用;③ 把神经元 2 的偏置从 −1 拖到 0,它不再只在「两件事同时成立」时亮,先错的是哪一句?点表格里那一行,看列式展开。
④ 改进到现代做法
第 1 步:两个神经元 → 一个前馈网络
把「每个神经元读一行、过非线性、写一列」一次做完,就是 Transformer 原文的 position-wise feed-forward network:
一个常用的类比入口: 把 FFN 想成一张「键-值」表——W_up 的每一列是一把键(在找什么模式),激活值是这把键和当前 token 的匹配程度,W_down 的每一行是这把键对应的值(匹配上之后往输出里写什么)。
- 精确映射:键 = W_up 第 i 列;查询 = 当前位置的 x;匹配度 = act(x·W_up[:, i] + b₁[i]);取回 = 匹配度 × W_down 第 i 行;所有键的取回相加 = FFN 输出。
- 失效点:① 真实的键不是一对一的——一个神经元常常对好几种互不相关的模式都亮(superposition,3Blue1Brown 第 7 章 17:04 起),一种模式也会分散在很多神经元上;② 普通的表只取最匹配的一行,FFN 是所有键按匹配度加权求和,负的匹配度(GELU、SiLU 允许负值)还会往反方向写;③ 这张「表」里存的是什么,只能事后在真实模型里统计出来 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条Geva 等在 16 层语言模型(WikiText-103)上统计出 W_up 的键与训练文本模式、W_down 的值与下一个词分布的对应关系;这是对训练好的模型做的解释,不是设计原理。 出处Geva et al. 2021 ↗需联网 ,不是设计时写进去的。
第 2 步:为什么升到 4 倍宽?
两个神经元解决了一个手工问题;真实模型要同时处理成千上万种「组合」,就需要成千上万个读取方向。升维到 d_ff = 4d 就是给每个 token 配 4d 个神经元。「为什么偏偏是 4 倍」没有推导。原文 Table 3 做过对照:d_model = 512 时,d_ff 取 1024 / 2048 / 4096,英德翻译开发集困惑度 5.12 / 4.92 / 4.75,参数 53M / 65M / 90M——越宽越好,但也越贵,2048 是在两者之间选的 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条Vaswani 2017 Table 3 (C) 组,newstest2013 开发集、每个 wordpiece 的困惑度;只在那个翻译模型与数据上成立。 出处Vaswani et al. 2017 Table 3 ↗ 。GPT-2 沿用了 4 倍(768 → 3072);现代模型各按预算取宽度,Qwen3.8 是 3.4 倍(L4 会讲为什么门控版的倍数不能直接和 4 比)。
下面是 GPT-2 small 一层 FFN 的真实形状(官方 config):
| 维度 | 含义 | 真实规模 | 小规模 |
|---|---|---|---|
| T | 序列长度(这里取 5,仅为画图) | 5 | 5 |
| d | 隐藏维 n_embd | 768 | 2 |
| dff | FFN 中间维(4 × d) | 3072 | 2 |
第 3 步:逐位置,是分工而不是缺陷
FFN 对第 t 个 token 的计算只用到第 t 行。把句子里的 token 打乱顺序,FFN 的输出只会跟着打乱,每一行的数值不变——它不在 token 之间传信息。这正是和注意力的分工:注意力决定「从谁那里取什么」,FFN 决定「取回来之后在自己这里怎么组合」。一个块里两者交替出现:先交流,再各自加工。
演进图:本课在第几代
L1 讲的是这张表的第一行:从 2017 年两矩阵 + ReLU 的 FFN,到 GPT-2 的 GELU,再到第 4 课才讲的门控版。本课的两个神经元对应最左边那一格。
⑤ 极小真数字算一次
在上面的 FFN 组件里点「不好吃」这一行、再点神经元 2 的「看它怎么算」,组件会逐项算给你:z = 1 × 1 + 1 × 1 + (−1) = 1 → ReLU → 1 → 乘写回系数 −2 = −2;神经元 1 读到 z = 2 → 写回 +2;合计 0。点组件里的「GELU」:四句的输出变成 0.841、0.272、0.318、0.841,不再精确,但按 0.5 一刀切仍然全对——这就是「非线性的具体形状不重要,有没有非线性才重要」的现场证据。
下面是项目基线模型(4 层、d = 256、SwiGLU 中间维 688,在《三國志演義》上训练)第 2 层 FFN 的真实神经元。同一段验证集文字,文字本身就是热力图。
读图(2026-09-26 导出的数据,以组件显示为准): 去掉 FFN 的 4 层模型只剩 1,574,144 个参数,val loss 从 4.626 升到 5.205;把层数加到 12、参数补到 3,673,344(和基线只差 0.42%)的纯注意力模型是 5.330——参数一样多,全用在注意力上反而更差,差距 0.70 远超噪声底线(C14:同配置 5 次重跑极差 0.016)。上面的神经元也值得看:按最大激活挑出的 #641 在「公」上最亮,#27 盯着「依」,#22 在「鎮」「征」「右」这类官衔用字上亮;随机抽的 #359、#110 最亮的地方多是被拆开的字节(显示为 �),看不出规律。
⑥ ⚠ 常见误解
「FFN 也在 token 之间传信息」✗ —— 它对每个位置单独计算,打乱 token 顺序只会打乱输出的行。token 之间的信息只在注意力(以及 C11 的线性注意力)里流动。
「注意力里有 softmax,已经是非线性了,FFN 可有可无」✗ —— softmax 的非线性只作用在「取多少」上;权重定下之后,值通路 x → x·W_V·W_O 是线性的。第 1 个位置甚至只能取自己,输出就是 x 的线性函数。
「一个神经元对应一个可以命名的概念」✗ —— 上面两个神经元能命名,是因为权重是我手工构造的。真实模型里多数神经元同时响应好几种互不相关的模式,随机挑一个往往什么规律都看不出(真模型实验里的「随机对照」就是为此放的)。
⑦ 证据三问
- 它解决什么问题? 让每个 token 能把注意力搬来的信息在自己内部做非线性组合,产生原来任何一个位置都没有的新特征(「夸」还是「骂」)。
- 数学上为什么可能有效? 线性函数分不开「好吃 / 不好吃 / 难吃 / 不难吃」这类组合,这一点可以证明 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条f(1,0) + f(0,1) = f(1,1) + f(0,0) 对任何仿射 f 成立。 出处本页推导 ↗ ;加一层带非线性的隐藏层就能表示它们,宽度越大能同时表示的组合越多(这是理论动机,不是「越宽越好」的证明) 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条单隐藏层网络的表示能力随宽度增加;但表示得出来不等于训练得出来,也不说明 4 倍最优。 出处待补 。
- 实验上为什么最后选了它? 原文和之后的模型都用对照实验定下了「注意力 + FFN 交替」和 FFN 的宽度 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条Vaswani 2017 Table 3 的 d_ff 对照;我们项目里去掉 FFN、参数对齐的 12 层纯注意力对照,见上方实测(数据生成后显示)。 出处Vaswani 2017 Table 3 ↗ ;在我们自己的小模型上,参数对齐的 12 层纯注意力 val loss 5.330,比基线的 4.626 差 0.70(单种子,远超噪声底线:C14 实测同配置 5 次重跑极差 0.016)。
⑧ 一句话
注意力在 token 之间搬信息,FFN 在每个 token 内部做非线性组合。
⑨ 下一个缺口
一个块 = 注意力 + FFN。Qwen3.8 把这样的块堆了 64 层。最直接的做法是一层的输出直接当下一层的输入,一路叠上去——叠深了会怎样?下一课:为什么要残差。
⑩ 你可能会问
- 「FFN 到底占多少参数?」 —— Qwen3.8 全模型的 61.6%,一层 FFN 是一层全注意力的 2.55 倍。完整账本和「参数多不等于计算多」见岔路课 参数到底花在哪。
- 「为什么 Qwen3.8 的 FFN 有三个矩阵?」 —— 那是门控版 FFN(SwiGLU),第 4 课讲。
- 「FFN 里存的是知识吗?」 —— 有实验支持「事实性关联多半能在 FFN 里定位到」的说法,但这是对训练好的模型的解释,不是它被设计出来的理由。
🔍 这个说法的证据到哪一步
Geva 等 2021 在真实语言模型里统计到 W_up 的列与文本模式、W_down 的行与下一个词分布有对应;3Blue1Brown 第 7 章用「Michael Jordan 打篮球」讲同一个直觉。它们说明的是「可以这样解读」,而且 superposition 让「一个神经元 = 一条知识」不成立。本课只用到最稳的那部分:FFN 是逐位置、带非线性的加工。