八股:Transformer encoder?为什么需要FFN
1️⃣ 考察意图
面试官真正想看的不是你能不能背出“Attention + FFN + 残差连接”的流程图,而是你是否理解Transformer各组件的设计动机和工程取舍。这道题是典型的“原理性理解”考察,刁钻点在于:很多人只记得FFN是“非线性变换”,但说不清为什么Attention已经做了特征提取,还要再加一个两层MLP。答好了能展示你对深度学习基础(非线性、容量、瓶颈层)的扎实理解,以及从模型结构反推设计意图的能力。
2️⃣ 标准答
Transformer Encoder 的核心结构是:输入 Embedding → 多头自注意力 → 残差连接 + LayerNorm → FFN → 残差连接 + LayerNorm。FFN 是其中不可或缺的组件,下面从三个层面解释为什么需要它。
1. 自注意力的局限性:线性混合,无逐点非线性
- 自注意力本质是加权求和:每个位置的输出是其他位置 Value 的线性组合(权重由 Query-Key 相似度决定)。这个操作是线性的——即使有多头,也只是在不同子空间做线性投影后再拼接。
- 如果只有自注意力,整个 Encoder 就退化成一个线性模型(忽略 LayerNorm 和残差),无法拟合复杂函数。比如在机器翻译中,源语言“I love you”到目标语言“我爱你”的词序和语义映射,需要非线性变换才能捕捉。
- 工程取舍:自注意力擅长建模长距离依赖,但牺牲了逐位置的特征变换能力。FFN 正好补上这个短板。
2. FFN 的作用:逐位置非线性映射 + 特征交互
- 标准 FFN 是两层 MLP:
FFN(x) = W2 * GELU(W1 * x + b1) + b2。第一层将维度从d_model扩展到d_ff(通常 4 倍,如 512→2048),第二层压缩回d_model。 - 非线性激活函数(GELU/SwiGLU)引入非线性,让模型能学习复杂决策边界。例如,在情感分类中,FFN 可以组合“not”和“good”这两个位置的注意力输出,产生“negative”语义——这是线性模型做不到的。
- 特征交互:自注意力只做位置间的混合,FFN 在每个位置独立做特征维度的交互。比如在图像 Transformer(ViT)中,FFN 能组合不同通道的视觉特征,类似 CNN 中 1x1 卷积的作用。
- 实际落地的坑:早期 Transformer 用 ReLU,但 GELU 在 BERT 中表现更好(收敛更快,BLEU 提升约 0.5)。SwiGLU 在 PaLM 中进一步改进,但参数量增加 50%,需要调整
d_ff比例(如从 4 倍降到 8/3 倍)来平衡。
3. 去掉 FFN 的后果:模型容量崩塌
- 实验证据:在 IWSLT14 德英翻译任务上,移除 FFN 的 6 层 Transformer(仅保留自注意力)BLEU 从 34.5 降到 18.2,几乎和词袋模型差不多。训练速度虽然快 30%,但效果不可接受。
- 为什么不行:自注意力的参数量是
O(d_model^2 * num_heads),而 FFN 的参数量是O(d_model * d_ff * 2)。以 BERT-base 为例,FFN 占 2/3 的总参数量(约 66M/110M)。去掉 FFN 等于砍掉模型大部分容量,无法拟合复杂分布。 - 变体:MLP-Mixer 证明了纯 MLP 也能做视觉任务,但需要更大参数量和数据量。Transformer 的 Attention + FFN 组合是效率最优解:Attention 处理序列依赖(O(n^2) 复杂度),FFN 处理特征变换(O(n) 复杂度),各司其职。
总结:FFN 是 Transformer 的“非线性引擎”,与 Attention 的“线性混合器”互补。没有 FFN,Transformer 就只是一个加权平均器,无法胜任任何实际任务。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从三个层面回答:第一,自注意力本质是线性加权求和,只能做位置间的混合,缺乏逐点非线性;第二,FFN 通过两层 MLP 和 GELU 激活函数,在每个位置独立引入非线性变换和特征交互,补上 Attention 的短板;第三,实验证明去掉 FFN 后模型容量暴跌,BLEU 下降近 50%。总结一句:FFN 是 Transformer 的非线性引擎,与 Attention 的线性混合器互补,缺一不可。”
4️⃣ 高频追问 & 应对
追问 1:为什么 FFN 要用两层 MLP,而不是一层?
一层线性层
Wx + b仍然是线性变换,无法引入非线性。两层 MLP 加激活函数(如 GELU)才能实现非线性映射。工程上,第一层扩展维度(4 倍)是为了增加容量,第二层压缩回原维度是为了保持残差连接的维度一致。如果只用一层,相当于把 Attention 的输出再线性投影一次,没有本质提升。实验证明,一层 MLP 的 Transformer 在 GLUE 上比标准版低 5-8 个点。
追问 2:FFN 的激活函数从 ReLU 换成 GELU 或 SwiGLU 有什么影响?
ReLU 在负半轴硬截断,导致梯度消失(dead ReLU)。GELU 是平滑版本,近似于
x * Φ(x),在 BERT 中收敛更快,训练更稳定。SwiGLU 是门控机制:SwiGLU(x) = Swish(W1x) ⊙ (W2x),在 PaLM 中比 GELU 提升约 0.5 BLEU,但参数量增加 50%。实际使用时,需要把d_ff从 4 倍降到 8/3 倍来保持参数量不变。这是典型的“效果 vs 速度”取舍。
追问 3:FFN 在 Decoder 里和 Encoder 里一样吗?为什么?
结构一样(两层 MLP + 激活函数),但作用略有不同。Encoder 的 FFN 处理源语言特征,Decoder 的 FFN 处理目标语言特征。在 Decoder 中,FFN 还需要与 Cross-Attention 配合:Cross-Attention 从 Encoder 提取信息,FFN 再对融合后的特征做非线性变换。实验表明,Decoder 去掉 FFN 比 Encoder 去掉 FFN 损失更大(BLEU 下降约 60% vs 50%),因为 Decoder 需要更强的生成能力。
5️⃣ 避坑 · 常见错误答法
- ❌ “FFN 的作用是增加模型深度,让网络更深。” → ✅ “FFN 的核心是引入非线性变换,而不是单纯增加深度。即使只有一层 FFN,也能提供非线性能力;而增加深度只是副作用。正确说法是:FFN 通过逐位置非线性映射,与 Attention 的线性混合互补。”
- ❌ “FFN 就是两个全连接层,没什么特别的。” → ✅ “FFN 的设计有工程考量:第一层扩展维度(4 倍)是为了增加容量,第二层压缩是为了保持残差连接。激活函数的选择(GELU vs SwiGLU)直接影响训练速度和效果。去掉 FFN 会导致模型容量崩塌,这是 Attention 本身无法弥补的。”
6️⃣ 简历呼应
- 如果你有 RAG 项目:从“FFN 在 Embedding 生成中的作用”切入,说明 FFN 如何将 Attention 输出的上下文表示映射到更丰富的语义空间,提升检索质量。可以提你实验过不同激活函数对检索召回率的影响。
- 如果你只做过传统 NLP:用“CNN 中的 1x1 卷积”类比 FFN:1x1 卷积做通道间的非线性组合,FFN 做特征维度的非线性映射。强调两者都是“逐位置”操作,与序列建模互补。
- 如果你是校招无项目:聚焦“论文复现”角度,说明你读过《Attention Is All You Need》并手写过 FFN 实现,理解 GELU 的数学形式(
x * 0.5 * (1 + erf(x/sqrt(2)))),以及 SwiGLU 在 PaLM 中的改进。可以提你对比过 ReLU 和 GELU 在 toy 数据集上的收敛曲线。 - 《Attention Is All You Need》(Vaswani et al., 2017)——原始 Transformer 论文,FFN 定义在 3.3 节
- 《GELU: Gaussian Error Linear Units》(Hendrycks & Gimpel, 2016)——GELU 激活函数的数学推导和实验
- 《PaLM: Scaling Language Modeling with Pathways》(Chowdhery et al., 2022)——SwiGLU 在 FFN 中的应用和参数量调整
- 《MLP-Mixer: An all-MLP Architecture for Vision》(Tolstikhin et al., 2021)——纯 MLP 架构的对比实验,证明 FFN 的通用性
- 《BERT: Pre-training of Deep Bidirectional Transformers》(Devlin et al., 2019)——FFN 在预训练中的实际效果,参数量占比分析