上一课,我们终于把 Multi-Head Attention(多头注意力)这件事拆明白了。

一个 Token 不再只能用一套 Attention Distribution(注意力分布)去理解上下文。

不同 Head(注意力头)可以拥有不同的 Q、K、V Projection(投影),在不同 Representation Subspace(表示子空间)里形成不同的信息路由。

有人负责看近处。

有人可能捕捉长距离关系。

有人关注结构。

也可能有一些 Head 学到我们根本无法用人类语言准确命名的 Pattern(模式)。

最后:

多个 Head 的结果拼接起来,再经过 (W_O) 融合,得到一个新的 Token Representation(Token 表示)。

于是上一课我们得到了一句话:

Attention 的本质,是 Contextual Information Routing——上下文信息路由。

但第十三课最后,我故意没有让这个故事结束。

因为一个更奇怪的问题马上就出现了:

信息都已经找回来了,然后呢?

Attention 可以告诉当前 Token:

“你应该去看谁。”

也可以告诉它:

“从谁那里拿多少信息。”

但它有没有真正回答另一个问题:

这些信息拿回来以后,你自己到底要怎么加工?

没有。

这就是第十四课真正要填上的那块拼图。上一课原文也正好停在“Attention 主要解决 Token Mixing,而当前 Token 内部的 Feature 如何继续加工”这个问题上。

所以今天,我们不从 FFN 公式开始。

先从一个非常现实的问题开始。


一、开完会,不代表问题已经解决了

假设你是公司负责人。

今天出了一个严重的问题。

你把几个部门的人全叫过来开会。

技术负责人告诉你:

服务器快扛不住了。

财务负责人告诉你:

预算只剩 200 万。

销售负责人告诉你:

最大客户要求下个月必须上线。

法务负责人告诉你:

合同里还有几个风险条款没有解决。

现在你已经获得了大量信息。

但问题解决了吗?

当然没有。

你现在只是完成了:

Information Gathering

信息收集。

接下来真正困难的是:

服务器到底扩不扩?

预算应该优先投在哪里?

客户的上线时间能不能答应?

技术风险、商业风险、法律风险应该怎么权衡?

这些事情已经不是:

“再去找谁问一句”。

而是:

把已经拿到的信息重新组合、筛选、判断,最后形成一个新的结论。

这其实就是 Attention 和 MLP 最直观的区别。

Attention 更像:

把相关的人叫进会议室。

MLP 更像:

会议结束以后,真正坐下来消化这些信息。

所以今天第一句话,我希望你先记住:

找到信息,不等于处理信息。

再进一步:

Attention 主要解决“信息从哪里来”,MLP 主要解决“信息来了以后怎么变”。

只要这句话真正理解,后面 FFN、GELU、SwiGLU 就已经成功一半了。


二、Attention 真正擅长的,其实一直都是 Token 和 Token 之间的关系

继续看上一课的例子:

小明把苹果递给小红,因为她饿了。

现在模型正在处理:

“她”。

经过 Multi-Head Attention 以后,“她”可能已经拿回了很多上下文信息。

某个 Head:

重点关注“小红”。

另一个 Head:

可能捕捉“苹果”和“饿”之间的语义联系。

还有一个 Head:

可能更关注“因为”前后的逻辑关系。

所以现在的“她”,已经和最开始进入模型的时候完全不同。

最开始:

它只是一个 Token Representation。

经过 Attention:

它变成了:

Contextualized Representation

上下文化表示。

换句话说:

原来的“她”只是:

“我是‘她’这个 Token。”

现在的“她”已经知道:

“前面出现过小红。”

“这里有苹果。”

“这是一个因果句。”

“我和前文某些实体存在关系。”

问题来了。

这些 Feature(特征)现在已经进来了。

那它们接下来应该怎么组合?

哪些应该增强?

哪些应该削弱?

某几个 Feature 同时出现的时候,能不能产生一种新的内部表示?

这件事,Attention 本身并没有完整解决。

因为 Attention 最强的地方,是:

Routing

信息路由。

它特别擅长回答:

我应该从哪里拿信息?

而 Transformer 还需要另外一种能力:

Transformation

表示变换。

也就是:

我拿到这些信息以后,要把自己变成什么?

所以可以再记一句:

Attention 解决的是“找谁”,MLP 解决的是“找到以后怎么办”。


三、如果你开始看 Tensor Shape,这两个模块的分工会突然变得特别清楚

假设我们现在有:

N=3

也就是:

3 个 Token。

每个 Token 的 Hidden Size(隐藏维度)是:

dmodel=8

那么输入:

X∈ℝ3×8

翻译成人话:

3 个 Token。

每个 Token 有 8 个 Feature。

你可以想象成:

Token F1 F2 F3 F4 F5 F6 F7 F8
Token 1 · · · · · · · ·
Token 2 · · · · · · · ·
Token 3 · · · · · · · ·

现在其实存在两个完全不同的问题。

第一个:

Token 1 应该从 Token 2、Token 3 拿什么?

这就是 Attention 更关心的问题。

所以 Attention 可以粗略理解成:

Token Mixing

Token 之间的信息混合。

它主要解决:

不同 Position(位置)之间怎么交换信息。


但还有另一个问题。

假设 Token 1 已经把其他 Token 的信息拿回来了。

它现在内部有 8 个 Feature。

那这 8 个 Feature:

应该怎样重新组合?

哪些组合是重要的?

能不能从现有 Feature 中构造新的 Feature?

哪些 Feature 当前应该发挥更大的作用?

这就是 MLP 更关心的问题。

所以它经常可以粗略理解成:

Feature Transformation

或者:

Channel Mixing

特征维度上的变换。

于是你可以先建立一个非常好用的坐标系:

Attention:主要在 Token 之间交流。

MLP:主要在一个 Token 内部加工 Feature。

如果非要再形象一点:

Attention 让 Token 去开会,MLP 让 Token 开完会以后回工位干活。


四、MLP 有个非常反直觉的地方:每个 Token 其实是“各算各的”

这件事第一次知道的时候很容易困惑。

假设经过 Attention 后:

[ x1, x2, x3 ]T

其中:

x1,x2,x3∈ℝ8

现在进入 FFN。

第一个 Token:

y1=FFN(x1)

第二个:

y2=FFN(x2)

第三个:

y3=FFN(x3)

这里 FFN 不会重新计算:

Token 1 应该看 Token 2 多少。

也不会重新建立:

Token 2 和 Token 3 的 Attention Weight。

在 FFN 这一阶段:

每一个 Token 都独立经过同一套网络。

所以经典 Transformer 里它有一个名字:

Position-wise Feed-Forward Network

逐位置前馈网络。

这里的 Position-wise 特别重要。

意思不是:

每个位置有一套不同的 FFN。

而是:

所有位置共享同一套 FFN 参数,但每个位置独立计算。


看到这里你很可能马上产生一个问题:

等等。

既然每个 Token 自己算自己的:

那 MLP 不就没有上下文了吗?

这就是这节课非常容易卡住的地方。

答案是:

MLP 的确不会在这一阶段主动重新访问其他 Token。

但是别忘了:

它拿到的 (x_i) 是什么?

不是原始 Embedding。

而是:

Attention 处理后的 Contextualized Representation。

换句话说:

其他 Token 的信息,Attention 已经提前搬进来了。

所以 MLP 不需要再跑出去找别人。

它只需要处理:

现在已经摆在自己桌面上的信息。

这句话非常值得留下:

MLP 不需要重新寻找上下文,因为 Attention 已经把上下文送到它桌上了。


五、现在终于来看 FFN,它其实简单到有点出乎意料

经典 FFN 可以写成:

FFN(x)=W2φ(W1x+b1)+b2

第一次看可能还是觉得有点抽象。

我们直接用数字。

假设:

dmodel=8

也就是说:

一个 Token 当前是 8 维。

首先经过:

W1

假设:

W1∈ℝ8×32

于是:

8→32

原来的 8 维 Representation:

变成 32 维。

这一步可以理解为:

Up Projection

升维投影。

接着:

经过一个 Activation Function(激活函数)。

比如:

GELU。

然后:

再通过第二个矩阵:

W2∈ℝ32×8

于是:

32→8

又回来了。

这一步:

Down Projection

降维投影。

所以经典 FFN 的结构其实就是:

8 → 32 → 8

抽象以后:

dmodel → dff → dmodel

没有想象中复杂。

真正值得问的其实不是:

“公式是什么?”

而是:

为什么模型非要先把 8 维撑到 32 维,然后又压回来?


六、FFN 为什么要先变宽?因为模型需要一个更大的“临时加工车间”

假设:

dmodel=4096

每个 Token 在 Transformer 主干里都是:

4096 维。

现在我们希望模型对当前 Token 的 Feature 做更加复杂的加工。

最直接的一种办法就是:

暂时把它送进一个更宽的空间。

比如:

4096→16384

注意:

这并不是把一句话变长。

也不是增加 Token。

它扩大的是:

当前 Token 内部进行 Feature Computation 的空间。

可以想象成:

主干只有一个 4096 平方米的通道。

真正加工的时候:

临时把 Token 送进一个 16384 平方米的车间。

里面可以形成更多 Intermediate Feature(中间特征)。

加工完成以后:

再压回:

16384→4096

为什么一定要压回来?

因为下一层 Transformer 仍然希望接收统一的:

dmodel

否则:

第一层 4096。

第二层 16384。

第三层 65536。

一路膨胀下去,模型根本没法维持稳定的主干结构。

所以 FFN 实际上像:

主干宽度保持不变,但允许每一层临时进入一个更大的计算空间。

这比单纯记:

“FFN 会升维”

有用得多。

因为你终于知道:

它为什么升。


七、但真正关键的还不是“变宽”,而是中间那个看起来不起眼的激活函数

现在我们做一个思想实验。

假设 FFN 只有:

xW1

然后:

(xW1)W2

中间什么都不加。

于是:

xW1W2

由于两个矩阵可以重新组合:

W=W1W2

所以最后:

xW1W2=xW

发现问题了吗?

你表面上:

8 → 32 → 8。

折腾了一大圈。

但最终:

它依然只是一个 Linear Transformation(线性变换)。

也就是说:

如果中间没有非线性,两层 Linear 本质上仍然可以压缩成一层 Linear。

那整个巨大中间层的表达能力就会受到非常大的限制。

所以必须加入:

Non-linearity

非线性。

于是:

FFN(x)=W2φ(W1x)

里面看起来最不起眼的:

φ

反而成为关键。

这一节真正应该留下的一句话是:

Linear Layer 负责重新组合 Feature,Activation Function 负责让这种组合真正拥有复杂性。

再狠一点:

没有非线性,你堆再多 Linear Layer,本质上仍然只是在做一个更大的 Linear Layer。


八、GELU 不要再背成“Transformer 用的激活函数”

经典 Transformer 中很常见:

GELU

Gaussian Error Linear Unit

高斯误差线性单元。

这里不用背完整公式。

你真正应该知道的是:

为什么神经网络需要这种东西。

最容易理解的是先看 ReLU:

ReLU(x)=max(0,x)

如果输入小于 0:

直接变成 0。

如果大于 0:

保留。

非常像一个硬开关:

开。

或者关。


而 GELU 更平滑。

它不会简单地说:

负数全部判死刑。

而是根据输入大小:

平滑地改变这个 Feature 的输出。

所以从直觉上:

可以把 GELU 看成一种比较柔和的非线性 Feature Transformation。

注意:

GELU 本身不是后来 SwiGLU 那种显式 Gate(门控)结构。

但它已经带出了一个很重要的思想:

不是所有 Feature,在所有输入下,都应该产生同样的影响。

而继续沿着这个方向走:

现代 LLM 就越来越喜欢显式加入:

Gating

门控。

这就到了 SwiGLU。


九、为什么现在的大模型源码里经常出现 gate_projup_projdown_proj

如果你以后打开一个现代 LLM 的 MLP 源码:

经常会看到三个名字:

gate_proj

up_proj

down_proj

第一次看很容易懵。

刚才不是说:

升维一次。

降维一次。

两个矩阵吗?

怎么突然三个了?

因为现代 LLM 里常见的结构已经不只是最简单的:

Linear → GELU → Linear。

而是类似:

SwiGLU

Swish-Gated Linear Unit

可以理解为:

基于 SiLU/Swish 的门控线性单元。

别急着背名字。

我们直接拆。


输入:

x

先走一条路:

u=xWup

这条可以理解成:

Content Path

内容路径。

它负责产生一批候选 Feature。

也就是:

“我能加工出什么?”


与此同时:

输入再走另外一条路:

g=xWgate

然后经过:

SiLU(g)

这条是:

Gate Path

门控路径。

它更像在学习:

“刚才那些 Feature,这次应该放行多少?”

接下来:

h=SiLU(g)⊙ u

其中:

表示逐元素相乘。

最后:

y=hWdown

重新压回 Hidden Size。

所以整个 SwiGLU 可以粗略理解为:

SwiGLU(x)= [ SiLU(xWgate) ⊙ (xWup) ]Wdown

公式看着复杂。

翻译成人话只有一句:

一条路负责生产 Feature,另一条路负责控制这些 Feature 当前应该发挥多少作用。

瞬间就简单了。


十、SwiGLU 真正强的地方,不是“多了一个矩阵”,而是多了“选择”

假设 Up Projection 生成:

[u1,u2,u3,u4]

与此同时 Gate 产生一组控制信号。

于是当前输入下:

Feature 1:

可以被强烈保留。

Feature 2:

可以被明显压制。

Feature 3:

只通过一部分。

Feature 4:

可能几乎不起作用。

换一个 Token:

门控结果又可以完全不同。

这意味着:

同一个 MLP:

面对不同输入时,并不需要让所有内部 Feature 以同样方式发挥作用。

所以普通 FFN 更像在问:

“我能构造什么 Feature?”

门控 MLP 又多问了一层:

“这些 Feature 里面,这一次到底该让谁发挥作用?”

这就是一个非常重要的思想升级:

Conditional Computation

条件计算。

当然,现在还只是:

Feature 级别的门控。

但如果继续想一步:

假设我不是决定:

哪几个 Feature 应该打开。

而是决定:

100 个不同的 FFN 里面,这个 Token 到底应该送给哪几个?

你是不是已经开始闻到:

MoE

Mixture of Experts

混合专家模型

的味道了?

所以很多知识一旦按照因果顺序学:

根本不需要死记。

它是自己长出来的。


十一、现在你终于可以真正看懂 intermediate_size

打开很多模型的 Config:

经常会看到:

hidden_size

以及:

intermediate_size

比如假设:

hidden_size = 4096

intermediate_size = 16384

以前看到:

可能只觉得是两个配置参数。

现在再看:

hidden_size = 4096

代表:

Transformer 主干中一个 Token 的 Representation Width(表示宽度)。

而:

intermediate_size = 16384

代表:

这个 Token 进入 MLP 之后,内部临时扩展到多宽的 Feature Space。

于是:

Expansion Ratio = dffdmodel

这里:

163844096=4

也就是:

4× Expansion

四倍扩展。

但是这里千万不要从一个坑跳进另一个坑:

“懂了,大模型 FFN 都是 4 倍。”

不是。

4× 是经典 Transformer 中非常常见的设计。

但是现代 SwiGLU 等 Gated MLP(门控 MLP)经常会重新选择 Intermediate Size。

不同模型也会根据:

参数预算。

FLOPs。

Tensor Parallelism(张量并行)。

Kernel Efficiency(计算内核效率)。

训练效果。

硬件结构。

重新设计。

所以:

Expansion Ratio 从来不是“越大越聪明”的能力旋钮。

它真正代表的是:

Capacity vs Compute

表示容量和计算成本之间的架构权衡。

以后你看到一些奇怪的:

intermediate_size = 11008

或者其他并不整齐的数字,

先不要问:

“为什么不是 16384?”

更好的问题是:

这个模型到底在平衡什么参数预算和计算预算?

这已经是看模型 Config 时非常重要的思维升级。


十二、为什么说 MLP 根本不是配角?直接算一次参数你就明白了

假设:

dmodel=4096

先看经典 MHA。

Q:

4096×4096

K:

4096×4096

V:

4096×4096

Output Projection:

4096×4096

忽略 Bias(偏置),总共大约:

4×40962

也就是:

约 6710 万参数。

已经不少了。


现在再看经典 4× FFN。

假设:

dff=16384

第一层:

4096×16384

第二层:

16384×4096

所以总参数大约:

2×4096×16384

约:

1.34 亿。

也就是说:

在这个经典配置里:

FFN 的参数量,大概是 Attention 的两倍。

这时候你再看 Transformer:

就不会觉得 MLP 是:

“Attention 后面顺手接的一个小模块”。

根本不是。

它是整个模型容量非常重要的承载者。

当然,现代 GQA、MLA、SwiGLU、MoE 会改变具体比例。

所以不要把刚才的 2 倍硬套到所有模型。

这里真正应该记住的是:

Attention 是 Transformer 最出名的模块,不等于它一定拥有最多参数。

明星模块和参数大户:

完全是两个概念。


十三、这时候我们终于可以非常清楚地说:Attention 和 MLP 到底分别负责什么

Attention 更擅长:

Communication

通信。

当前 Token 应该和谁交流?

哪些位置值得读取?

从那里拿多少信息?

所以它非常强调:

Token-to-Token Interaction。


而 MLP 更擅长:

Computation / Transformation

计算与表示变换。

已经拿到的信息:

应该怎样重新组合?

怎样形成新的高阶 Feature?

哪些 Feature 应该增强?

哪些应该抑制?

当前 Token 最终应该形成怎样的新 Representation?

于是:

Attention 更像信息网络。

MLP 更像加工车间。

但这里一定注意。

这只是帮助理解的类比。

千万不要继续简化成:

“Attention 不负责计算。”

或者:

“MLP 才是模型真正思考的地方。”

这都过头了。

更加严谨的表述应该是:

Attention 主要提供内容相关的跨 Token 信息路由;MLP 主要提供逐 Token 的高容量非线性特征变换。

以后真正看论文:

建议记这一版。


十四、所以 Transformer 为什么不能一直堆 Attention?

现在回到文章最开始的问题。

既然 Attention 那么厉害:

为什么不:

Attention

Attention

Attention

Attention

一路堆到底?

因为 Attention 最大的优势:

是动态改变 Token 之间的信息流。

但如果拿回来的 Representation:

缺乏足够强的逐 Token Non-linear Transformation(非线性变换),

模型内部 Feature 的加工能力仍然会受到限制。

所以一个 Transformer Block 才会形成这种非常有意思的交替:

Attention

MLP

Attention

MLP

Attention

MLP

如果把术语暂时都拿掉:

它其实一直在重复:

Communication

交流。

Computation

加工。

Communication

再交流。

Computation

再加工。

这让我觉得 Transformer Block 最值得记住的一句话其实不是公式。

而是:

先把信息找回来,再把信息消化掉;带着新的表示,再进入下一轮信息交换。

Attention 和 MLP:

不是竞争关系。

是分工。


十五、现在让一个 Token 真正走完整个 Transformer Block

到这里,我们终于可以把前面四课真正串起来。

一个 Token 进入 Attention。

首先计算:

Q。

K。

V。

然后:

不同 Head 使用自己的 Representation Subspace。

计算:

QKT

Scaling(缩放)。

Causal Mask(因果掩码)。

Softmax。

得到 Attention Weight。

乘 V。

拿回上下文信息。

多个 Head 拼接。

经过:

WO

重新融合。

于是:

当前 Token 得到:

Contextualized Representation

上下文化表示。


接下来:

进入 MLP。

如果是现代 SwiGLU 风格:

当前 Representation

up_proj

产生候选 Feature。

同时:

gate_proj

产生门控信号。

SiLU。

两条路径逐元素相乘。

得到经过选择和加工的 Intermediate Feature。

down_proj

回到原来的 Hidden Size。

于是:

产生这一层新的 Token Representation。

整个故事其实可以压成:

Context Retrieval

上下文读取

Feature Transformation

特征变换

也就是说:

Attention 把上下文搬进 Token,MLP 再把这些上下文加工成新的 Token 表示。

如果这一句你能真正讲明白:

这一课已经懂了八成。


十六、再从 Shape 看一次,你会理解为什么现代 LLM 出现了两条完全不同的优化路线

还是:

X∈ℝN× d

Attention 会形成类似:

N× N

的 Attention Matrix。

为什么?

因为每个 Token 都需要和其他位置发生关系。

所以 Full Attention 经典复杂度会出现:

O(N2)

当 Context 从:

4K

变成:

32K

128K

甚至 1M,

Attention 就会越来越贵。

于是后面大家开始研究:

MQA。

GQA。

MLA。

Sparse Attention。

Linear Attention。

Delta Attention。

这些技术,本质上都在重新思考:

历史信息到底应该怎样被访问。


而 MLP 面临的是另外一个问题。

它没有构造:

N× N

的 Token Relation Matrix。

每个 Token 只是执行:

d → dff → d

但是:

如果 (d_{ff}) 越来越巨大呢?

每个 Token:

都必须跑一次巨大的 Dense MLP。

于是问题变成:

我要怎样扩大模型的 Feature Capacity,却不让每个 Token 的计算成本一起爆炸?

是不是发现:

Attention 和 MLP:

分别把 Transformer 推向了两类完全不同的架构创新。

Attention 侧解决:

Memory / Routing Efficiency

信息访问效率。

MLP 侧解决:

Capacity / Computation Efficiency

容量和计算效率。

理解这个以后:

后面那些所谓“现代大模型新架构”,就不会再像一堆毫无关系的缩写。

它们都是从具体瓶颈长出来的。


十七、Dense FFN 最大的矛盾,终于暴露出来了

现在假设:

MLP 越大:

模型 Feature Capacity 越强。

那我们直接疯狂增加:

dff

不就好了?

比如:

4096→16384

觉得不够。

那就:

4096→65536

还不够?

4096→262144

参数容量当然越来越大。

但有一个问题一直没有消失:

Dense。

Dense 的意思就是:

几乎每一个 Token,都要运行这整个 FFN。

你的 FFN 有 1 亿参数:

Token A 跑。

Token B 跑。

Token C 还是跑。

现在扩大到 10 亿:

所有 Token 继续跑。

扩大到 100 亿:

还是如此。

于是 Dense Model 出现一个非常现实的矛盾:

想扩大 Capacity,就得让每个 Token 一起承担更多 Compute。

这叫:

Capacity–Compute Coupling

容量和计算被绑定在一起。

那能不能解耦?

比如:

模型一共拥有:

100 个很大的 FFN。

但当前这个 Token:

只需要其中 2 个。

下一个 Token:

可能去另外几个。

于是:

模型总参数可以非常巨大。

但真正处理一个 Token 时:

只激活其中一小部分。

你现在甚至已经不需要我说名字了。

这就是后面的:

MoE

Mixture of Experts

混合专家模型。

所以 MoE 最好的学习方式,从来不是:

“MoE 有 Router 和 Expert。”

而应该从今天这条矛盾推出来:

Dense FFN

想扩大容量

增加参数

所有 Token 都执行

Compute 一起暴涨

那能不能只运行一部分参数?

Sparse Computation

稀疏计算

MoE

你会发现:

MoE 不是因为研究人员突然觉得“专家”这个词听起来很高级。

它是 Dense FFN 的 Capacity–Compute 矛盾被逼到一定程度以后,非常自然的一条答案。

这就是后面学习 MoE 最重要的地基。课程设计里,第十四课本身也被明确放在 MoE 之前,作为 FFN、GELU、SwiGLU 和 Expansion Ratio 的直接前置。


十八、这一课有几个特别容易被讲歪的地方,我想一次说清楚

第一个误区:

“Attention 负责理解,MLP 只是补充计算。”

不对。

它们是两类不同的变换。

Attention 更侧重跨 Token 路由。

MLP 更侧重逐 Token Feature Transformation。


第二个误区:

“MLP 每个 Token 单独计算,所以没有上下文。”

也不对。

MLP 当前这一阶段不主动读取其他 Token。

但它的输入早已经过 Attention。

上下文已经进入当前 Representation。


第三个误区:

“FFN 就是把维度放大,再缩小。”

这只描述了 Shape。

没描述能力来源。

真正关键的是:

中间加入 Non-linearity。

否则:

两层 Linear 依旧可以合并成一层 Linear。


第四个误区:

intermediate_size 越大,模型肯定越强。”

不能这么说。

更大意味着更多 Capacity。

也通常意味着更多:

Parameters。

FLOPs。

Memory。

通信和硬件成本。

它是架构 Trade-off。


第五个误区:

“SwiGLU 就是多了一层 Linear。”

也不是。

真正重要的是:

它增加了一个输入相关的 Gate。

模型不仅学习:

“我要生成什么 Feature?”

还学习:

“这一次哪些 Feature 应该发挥作用?”


还有最后一个很常见的说法:

“知识全都存在 MLP 里。”

这也过度简化。

模型的能力是:

Embedding。

Attention Projection。

MLP。

Residual Stream。

多层组合。

训练数据和优化。

共同形成的。

MLP 的确承担了大量参数和非线性表示能力。

但不要把整个 Transformer 的知识机制简化成:

“FFN 就是数据库。”

这会让后面的理解越来越歪。


十九、这一课如果公式全忘了,我希望你至少能留下这几句话

第一句:

找到信息,不等于处理信息。

第二句:

Attention 决定信息从哪里来,MLP 决定信息来了以后怎么变。

第三句:

Attention 让 Token 去开会,MLP 让 Token 开完会以后真正消化会议内容。

第四句:

FFN 扩大的不是 Context Length,而是一个 Token 内部进行 Feature Computation 的临时空间。

第五句:

没有 Non-linearity,两层 Linear 再宽,本质上仍然可以塌缩成一个 Linear Transformation。

第六句:

SwiGLU 真正增加的不是一个矩阵,而是“内容”和“门控”两条路径:一条负责产生 Feature,一条负责决定这些 Feature 这次该发挥多少作用。

第七句:

Attention 是 Transformer 最出名的模块,不代表它就是参数最多的模块。

第八句:

Dense FFN 真正的问题不是参数不能继续做大,而是参数一旦做大,所有 Token 都要一起买单。

最后一句,也是我认为这一课真正应该刻进脑子里的:

Attention 解决“我应该知道什么”,MLP 解决“知道这些以后,我应该形成什么新的表示”。

如果这句话懂了:

以后再看 Transformer 架构图:

Attention 后面那个 MLP,

就再也不会是一个可以随便扫过去的小方块。


二十、别急着进入下一课,先检查自己到底懂没懂

现在不要往前翻。

直接试着回答。

为什么 Attention 已经读取了整个 Context:

还需要 MLP?

为什么 MLP 明明逐 Token 独立计算:

仍然可以加工 Contextual Information?

为什么 FFN 经常设计成:

dmodel → dff → dmodel

为什么要先升维:

再降回来?

为什么两层 Linear 中间:

必须加入 Non-linearity?

如果直接:

xW1W2

会发生什么?

hidden_size

和:

intermediate_size

到底分别是什么?

Expansion Ratio:

实际在权衡什么?

为什么现代 LLM 会出现:

gate_proj

up_proj

down_proj

SwiGLU 的两条路径:

到底分别在干什么?

为什么 Attention 可以粗略理解为:

Token Mixing,

而 MLP 可以粗略理解为:

Feature Transformation?

最后一个问题最重要:

假如 Dense FFN 越做越大:

为什么:

Model Capacity

和:

Per-token Compute

会越来越紧地绑在一起?

如果这个矛盾你已经能够自己讲出来:

那你学到的就不再只是:

FFN。

GELU。

SwiGLU。

几个名词。

而是已经可以自己推出:

为什么现代大模型下一步会开始研究:

Sparse Computation。

这才是我希望这门课真正训练出来的能力。

不是背架构。

而是看到一个技术以后,能够反过来问:

它到底是为了解决前一个方案的什么矛盾?


下一课:Transformer 一层层把 Representation 改下去,为什么几十层之后没有把自己“改坏”?

到今天为止:

一个 Transformer Block 的两大核心计算终于都齐了。

Attention:

负责跨 Token 信息交换。

MLP:

负责逐 Token Feature Transformation。

看起来已经完整了。

但一个新的问题马上出现。

模型不是只有一层。

可能是:

32 层。

64 层。

80 层。

甚至更深。

每一层都在:

Attention。

MLP。

然后重新修改一次 Representation。

那第一层的信息:

到了第八十层还剩多少?

如果每一层都把输入彻底变一次:

模型不会越算越乱吗?

训练的时候:

Gradient 又怎么从最后一层,一路稳定地传回第一层?

为什么 Transformer 里一定会出现一句看起来简单得有点过分的:

xl+1=xl+F(xl)

为什么一个小小的:

Residual Connection

残差连接

会成为深层 Transformer 能够训练起来的关键?

而现代大模型为什么又大量使用:

RMSNorm

均方根归一化

而不是简单把 LayerNorm 原封不动搬下去?

下一课,我们继续不背定义。

先从一个更根本的问题开始:

大模型训练原理(15)|Transformer 堆到几十层为什么还没有“失忆”?Residual 和 RMSNorm 到底在保护什么?

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐