编程与 AI13 分钟阅读更新于 2026-08-03

FFN 为什么要在两次线性变换之间加入激活函数

围绕 Position-wise Feed-Forward Network 的描述,解释 FFN 的两次线性变换、隐藏维度、激活函数,以及它和注意力层的分工。

相关工具

FFN 处理的是注意力已经融合过的表示

Transformer 的一个编码器层通常先通过 Self-Attention 建立位置之间的联系,再把结果送入 Position-wise Feed-Forward Network。资料 把 FFN 描述为一个逐位置使用的前馈网络:每个位置单独经过同一个网络,最后得到新的位置表示。

注意力解决的是“当前位置需要从哪些位置读取信息”,FFN 解决的是“已经融合到当前位置的信息如何进一步变换”。它不直接负责跨位置查找,而是对每个位置的隐藏向量做更深的特征加工。

Transformer Self-Attention 输出进入逐位置 FFN 的结构示意图
注意力之后进入 FFN

Self-Attention 先融合上下文,FFN 再对每个位置的结果做非线性特征加工。

第一次线性变换为什么通常先扩大维度

假设模型宽度是 d_model,FFN 的第一层线性变换会把每个位置的向量映射到更宽的中间空间。文中的经典表达由两个线性变换组成,中间使用 ReLU 激活函数。扩大维度可以给模型提供更多中间特征通道。

这一步不是简单把信息复制得更大,而是通过可学习矩阵把原始特征重新组合。每个中间维度可以理解为一种潜在的响应方向,后面的激活函数会决定哪些响应被保留或抑制。

如果没有激活函数,两次线性层仍然只是一次线性变换

设第一层为 xW_1+b_1,第二层为 hW_2+b_2。如果中间没有激活函数,两个线性变换可以合并成一个更大的线性变换。无论中间空间多宽,整体仍然只能表达线性映射,增加一层并不会真正增加非线性表达能力。

激活函数打断了这种简单合并。它让中间特征经过非线性筛选后再进入第二层,模型因此可以表达更复杂的特征组合,而不是把输入做一次连续的矩阵变换后直接输出。

ReLU 在 FFN 中做了什么

这里介绍的经典 FFN 使用 ReLU 作为第一层和第二层之间的激活函数。ReLU 会把负值压到零,保留正值。它让不同中间通道出现选择性响应:某些特征在当前上下文下被激活,另一些特征暂时不参与后续组合。

这里的“压到零”不是把整个位置清空,而是逐特征处理中间向量的各个维度。一个位置仍然可以保留多个正向响应,第二个线性层再把这些响应组合回模型需要的宽度。现代模型也可能使用 GELU 等其他激活函数,但核心作用仍是引入非线性。

Transformer FFN 两次线性变换之间加入激活函数的流程图
FFN 两次线性变换之间的激活

输入先映射到中间特征空间,经激活函数筛选后,再投影回模型宽度。

第二次线性变换为什么要投影回 d_model

FFN 的中间空间可以比 d_model 更宽,但输出需要回到统一的模型宽度。这样,FFN 输出才能和子层输入通过残差连接相加,也才能继续进入下一层编码器或解码器。

第二层线性变换不是简单缩小维度,它会学习如何把多个中间通道重新组合成模型主干需要的表示。前一层负责展开特征,激活负责提供非线性,后一层负责压缩并综合,这三步共同构成 FFN 的基本工作方式。

逐位置使用同一组 FFN 参数

Position-wise 的意思是:每个序列位置独立完成同样的 FFN 计算,并共享同一组线性层参数。共享参数不代表每个位置得到相同结果,因为不同位置的输入表示不同,经过注意力后携带的上下文也不同。

这种设计让 FFN 专注于特征加工,而把跨位置关系交给注意力。无论句子有多少位置,FFN 都可以对每个位置并行应用同一套变换,输出形状保持为序列长度乘以模型宽度。

Transformer 同一组 FFN 参数对不同序列位置独立处理的示意图
同一组 FFN 逐位置并行使用

每个位置独立通过同一个 FFN 参数组,输入不同因此输出也不同。

FFN 不会替代注意力

FFN 能够增强每个位置的特征表达,但它不会直接读取其他位置。一个位置想要获得句子中其他词的信息,需要先通过 Self-Attention 或解码器中的交叉注意力完成信息聚合。

注意力和 FFN 的组合可以看成两个阶段:先把相关上下文搬到当前位置,再在当前位置内部做非线性加工。如果只使用 FFN,不同位置之间没有直接的信息交换;如果只有注意力,模型又缺少对每个位置进行深层特征变换的独立通道。

激活函数也影响梯度和训练行为

激活函数不仅决定前向计算的形状,也影响梯度如何通过 FFN。ReLU 在正区间保留梯度,在负区间输出为零;其他激活函数可能在更宽的范围内保持平滑变化。具体模型选择哪一种,需要结合架构和训练设置判断。

对于理解 Transformer 主线来说,最重要的是知道激活函数位于两次线性变换之间,并让 FFN 不再等价于一次线性层。它把中间特征从“加权组合”变成“经过条件筛选后的再组合”。

用四步记住 FFN

第一,接收某个位置经过注意力融合的隐藏向量;第二,通过第一层线性变换进入更宽的中间空间;第三,用激活函数对中间特征做非线性筛选;第四,通过第二层线性变换回到 d_model,接入残差和下一子层。

这四步说明了 FFN 为什么不是一个普通的全连接层:它既需要扩大和压缩特征空间,也需要在中间加入非线性,还要保持逐位置、统一维度和可并行计算的结构。

常见问题

FFN 的激活函数会在不同位置使用不同参数吗?

经典 Position-wise FFN 在所有位置共享同一组参数,但每个位置的输入不同,所以激活后的结果也不同。

没有激活函数时,两个线性层还有意义吗?

可以改变参数化方式和中间计算形状,但从整体表达能力看,连续线性层仍可合并成一个线性变换,缺少真正的非线性。

FFN 会不会像注意力一样读取其他位置?

经典逐位置 FFN 不直接读取其他位置,跨位置的信息主要由 Self-Attention 或交叉注意力提供。