FFN 激活函数深度解析:从 ReLU 到 SwiGLU 的演进之路

FFN 激活函数深度解析:从 ReLU 到 SwiGLU 的演进之路

引言:为什么需要激活函数?

如果神经网络只有线性变换(矩阵乘法 + 偏置),无论堆多少层,最终都等价于一层线性变换:y = W₃(W₂(W₁x + b₁) + b₂) + b₃ = Wx + b。这意味着多层网络没有意义。

激活函数在每层之间引入非线性"弯折",让神经网络能够拟合复杂的非线性模式。在 Transformer 的 FFN(Feed-Forward Network)中,激活函数决定了模型的表达能力、训练稳定性和计算效率。

本文深入讲解 FFN 中主流激活函数(ReLU、GELU、SiLU、SwiGLU)的原理、演进和选择策略。


FFN 的基本结构:激活函数在哪里?

在深入激活函数之前,先理解 FFN 在 Transformer 中的位置。

Transformer 的整体架构

Transformer Block 包含两个核心组件:

  • Multi-Head Attention:建模序列关系
  • Feed-Forward Network (FFN):本文重点!每个位置独立进行非线性特征变换

每个组件后都有残差连接和层归一化(Add & Norm)。

标准 FFN 的计算流程

FFN 包含三个步骤:

  1. 第一层线性变换(W₁):将输入 x (d_model = 512) 扩展到更高维度 h (d_ff = 2048)
  2. 激活函数(σ):对 h 进行非线性变换 → 本文重点!
  3. 第二层线性变换(W₂):将激活后的向量压缩回原维度 y (d_model = 512)

数学表达式:

scss 复制代码
FFN(x) = W₂ · σ(W₁ · x + b₁) + b₂
                 ↑
            激活函数 σ

其中:

  • W₁ ∈ ℝ^(d_ff × d_model):第一层权重(扩展)
  • W₂ ∈ ℝ^(d_model × d_ff):第二层权重(压缩)
  • σ:激活函数(决定 FFN 的非线性特性)

关键洞察:

FFN 的结构很简单(两层全连接 + 激活函数),但它承担了 Transformer 中 70-80% 的参数量

  • Attention 负责"谁和谁相关"(序列建模)
  • FFN 负责"每个位置的特征变换"(非线性表达)

激活函数的选择,直接影响 FFN 的表达能力和训练效率。


激活函数的核心要求

在深入具体算法前,先理解一个好的激活函数需要满足什么条件。

1. 非线性(Nonlinearity)

要求: 必须是非线性函数,否则多层网络退化为单层。

反例:f(x) = ax + b(线性函数)

正例:f(x) = max(0, x)(ReLU,有折点)

2. 可微性(Differentiability)

要求: 至少几乎处处可微,否则无法用梯度下降训练。

部分可微的例子:ReLU 在 x=0 处不可微,但实际训练中可忽略(概率为 0)

完全可微的例子:GELU、SiLU(处处光滑)

3. 梯度友好(Gradient-Friendly)

要求: 避免梯度消失(gradient vanishing)或梯度爆炸(gradient exploding)。

问题示例:Sigmoid

scss 复制代码
σ(x) = 1 / (1 + e^(-x))

梯度:dσ/dx = σ(x) · (1 - σ(x))

当 x → +∞ 时,σ(x) → 1,梯度 → 0
当 x → -∞ 时,σ(x) → 0,梯度 → 0

结果:深层网络中,梯度会越乘越小(梯度消失)。

改进:ReLU 系列在 x > 0 时梯度恒为 1,避免了梯度消失。

4. 计算效率(Computational Efficiency)

要求: 计算快,占用 GPU 资源少。

对比:

激活函数 计算复杂度 原因
ReLU 极低 只需比较和取最大值
GELU 中等 需要计算误差函数 erf(x) 或 tanh 近似
SwiGLU 较高 需要额外的线性变换(参数量增加)
实际影响:

根据 Michael Brenndoerfer 的测试,激活函数的计算时间通常只占 FFN 总时间的 < 1%。但在超大规模模型(如 GPT-4 的 1.8T 参数)中,即使 1% 的差异也值得优化。

5. 数值稳定性(Numerical Stability)

要求: 在极端输入下不会溢出或下溢。

问题示例:Softmax

python 复制代码
softmax(x) = exp(x_i) / Σ exp(x_j)

当 x_i 很大(如 1000)时:
exp(1000) = 2.7 × 10^434  ← 数值溢出!

解决方案:Softmax 通常会减去 max(x) 来稳定。


第一代:ReLU - 简单粗暴的开拓者

ReLU(Rectified Linear Unit)定义为 ReLU(x) = max(0, x),即负数部分置零,正数部分保持不变。

ReLU 的核心优势是计算极快、梯度简单(x > 0 时梯度恒为 1),有效缓解了 Sigmoid/Tanh 的梯度消失问题,并且会产生稀疏激活(很多神经元输出 0)。

但 ReLU 有致命缺陷:死亡 ReLU 问题。如果神经元输入始终为负,则输出和梯度永远为 0,导致权重无法更新,神经元"死亡"。研究者提出了 Leaky ReLU、PReLU、ELU 等改进版本,在负数部分保留小的梯度,但增加了调参复杂度或计算成本。

现状(2026):主流 LLM 已不再使用 ReLU(GPT-3 之后),但在资源受限场景(边缘设备)和稀疏模型中仍有价值。


第二代:GELU - 引入概率的平滑曲线

GELU 的设计动机与定义

ReLU 的问题在于太"硬":在 x = 0 附近,微小的输入差异会导致截然不同的输出(-0.001 → 0,+0.001 → 0.001)。GELU 的思路是让激活函数"软"一点。

GELU(Gaussian Error Linear Unit)定义为 GELU(x) = x · Φ(x),其中 Φ(x) 是标准正态分布的累积分布函数(CDF)。直观理解:Φ(x) 表示"从 N(0,1) 采样的随机变量 ≤ x 的概率"。GELU 用概率来决定信号的激活程度:x 很大时 Φ(x) ≈ 1(几乎全部保留),x 很小时 Φ(x) ≈ 0(几乎全部抛弃),x 接近 0 时 Φ(x) ≈ 0.5(部分保留)。

GELU 的数学性质

GELU 处处可微(没有 ReLU 的折点),梯度为 dGELU/dx = Φ(x) + x · φ(x)(φ是概率密度函数)。梯度特点:x > 0 时梯度 > 1(略微放大),x ≈ 0 时梯度 ≈ 0.5,x < 0 时梯度 > 0(不会完全死亡)。

实践中,计算精确的 Φ(x) 需要误差函数 erf(x),可能较慢。常用近似方法包括 Tanh 近似(精度 99.9%)和 Sigmoid 近似(精度 98%)。PyTorch 默认使用 Tanh 近似作为精度和速度的平衡点。

GELU 的实际表现

对比实验(BERT 论文,2018):

激活函数 GLUE 分数 SQuAD F1
ReLU 80.1 88.2
GELU 82.3 90.1
Swish 81.7 89.5
关键结论:

GELU 在 BERT 上显著优于 ReLU(+2.2 GLUE 分数)。

为什么 GELU 更好?

  1. 平滑性 → 梯度更稳定,训练更顺畅
  2. 非零负值 → 不会像 ReLU 那样完全"死亡"
  3. 概率性质 → 类似于"软门控"(soft gating),比硬切换更灵活

GELU 的应用案例

BERT(2018)首次在 Transformer 中使用 GELU,此后 GPT-2、GPT-3、T5 等模型延续使用。现状(2026):GELU 仍是 Encoder-Only 模型(如 BERT)和 Encoder-Decoder 模型(如 T5)的主流选择,但在 Decoder-Only 模型(如 GPT 系列、LLaMA)中正在被 SwiGLU 取代。

第三代:SiLU/Swish - 自门控的激活函数

SiLU(Sigmoid Linear Unit)又称 Swish,是一个激活函数 ,定义为 SiLU(x) = x · sigmoid(x)

先理解 sigmoid(x):

sigmoid 函数 sigmoid(x) = 1 / (1 + e^(-x)) 的输出值永远在 0 到 1 之间:

  • x 很大时 → sigmoid ≈ 1(完全打开)
  • x 很小时 → sigmoid ≈ 0(完全关闭)
  • x = 0 时 → sigmoid = 0.5(半开半闭)

SiLU 的"自门控":

传统激活函数(如ReLU)只处理输入:ReLU(x) = max(0, x)

SiLU 不同:输入 x 既是"被处理的信号",又是"控制开关":

  • x=5 时:sigmoid(5)≈0.993,SiLU(5) = 5 × 0.993 ≈ 4.97(信号强,开关几乎全开,大部分通过)
  • x=-5 时:sigmoid(-5)≈0.007,SiLU(-5) = -5 × 0.007 ≈ -0.03(信号弱,开关几乎全关,几乎阻断)

这就是"自门控":输入控制自己能通过多少。

关键:SiLU 是单路径的,只有一个输入 x,经过 SiLU 激活后输出。它替代了 ReLU/GELU,作为传统 FFN 的激活函数。

SiLU 的实际性能

对比实验(LLaMA 论文,2023):

激活函数 困惑度(Perplexity) 训练速度
ReLU 10.8 基线
GELU 10.2 +5% 慢
SiLU 10.1 +2% 慢
关键结论:

SiLU 在性能上略优于 GELU,同时计算开销更小。


第四代:SwiGLU - 从单路径到双路径的革命

核心差异:SiLU 是激活函数,SwiGLU 是 FFN 架构。

传统 FFN(使用 SiLU)

scss 复制代码
输入 x (512维)
   ↓
  W₁ 升维到 2048维
   ↓
  SiLU 激活
   ↓
  W₂ 降维回 512维
   ↓
输出 (512维)
  • 2个权重矩阵:W₁(升维), W₂(降维)
  • 单路径:一个输入,一次激活,一个输出

SwiGLU FFN(双路径门控)

scss 复制代码
输入 x (512维)
   ├─→ W₁ 升维到 2048维 → SiLU → 门控 g (2048维)
   └─→ W₂ 升维到 2048维 ────→ 内容 v (2048维)
                ↓
           g ⊙ v 逐元素相乘 (2048维)
                ↓
           W₃ 降维回 512维
                ↓
           输出 (512维)
  • 3个权重矩阵:W₁(门控升维), W₂(内容升维), W₃(降维聚合)
  • 双路径:输入分两路,一路用SiLU激活作门控,一路作内容,最后相乘聚合

直观对比

SiLU(自门控):

  • 输入:x = 5.0
  • sigmoid(5) = 0.993(自己控制自己)
  • 输出:5.0 × 0.993 = 4.97

SwiGLU(分离门控):

  • 输入:x = [1.0, 2.0, 3.0]
  • 路径A(门控):W₁·x → SiLU → g = [0.9, 0.3, 0.8]
  • 路径B(内容):W₂·x → v = [5.0, 4.0, 6.0]
  • 输出:g ⊙ v = [4.5, 1.2, 4.8]

看到差别了吗?

  • SiLU:一个值控制自己(5.0 控制 5.0 能通过多少)
  • SwiGLU:一路控制另一路(g[0]=0.9 控制 v[0]=5.0 能通过多少)

为什么 SwiGLU 更强?

SiLU:x 再怎么复杂,也只能"自己决定自己的命运" SwiGLU:路径A 可以学会"识别重要性",路径B 专注"提取内容",两者分工合作,表达能力更强。

举例:假设 x 包含了"重要信息"和"噪声"混在一起,

  • SiLU:无法区分,只能整体缩放
  • SwiGLU:路径A学会屏蔽噪声(给噪声位置的门控信号=0.1),只激活重要信息(给重要位置的门控信号=0.9)

实验证明(GLU Variants Improve Transformer,2020):SwiGLU 比传统激活函数性能提升 +1.2 BLEU,代价是参数量增加 50%。

参数量权衡:PaLM 论文(2022)提出通过调整隐藏层维度保持参数量不变。关键公式:d_ff_swiglu = 2/3 × d_ff_standard。例如:

  • 传统 FFN:d_model=4096, d_ff=16384,参数量 134M
  • SwiGLU(直接替换):参数量 201M(+50%)
  • SwiGLU(2/3 调整):d_ff=10923,参数量 134M(持平)

性能表现:PaLM 实验显示,在相同参数量下,SwiGLU 比 GELU 困惑度降低 3-4%。

LoRA 微调时如何处理 SwiGLU?

LoRA(Low-Rank Adaptation)通过在原始权重旁添加低秩矩阵来微调模型。对于 SwiGLU 的三个矩阵:

理论上:三个矩阵都可以加 LoRA

  • W₁(门控路径):影响"什么重要"的判断
  • W₂(内容路径):影响特征的提取
  • W₃(输出投影):影响最终的输出表示

实践建议:

策略 LoRA 应用位置 参数量 适用场景
完整微调 W₁ + W₂ + W₃ 3 × rank × (d_model + d_ff) 数据充足,追求最佳效果
重点微调 W₁ + W₂ 2 × rank × (d_model + d_ff) 平衡效果和效率(推荐)
极简微调 W₁ 或 W₂ 1 × rank × (d_model + d_ff) 资源受限,快速实验

为什么 W₁ 和 W₂ 更重要?

W₃ 只是降维投影,相对通用;W₁ 和 W₂ 直接决定特征如何被提取和门控,对任务适应性影响更大。

对比传统 FFN 的 LoRA:

  • 传统 FFN(ReLU/GELU):只有 W₁ 和 W₂ 两个矩阵,通常都加 LoRA
  • SwiGLU FFN:多了一个 W₂,可以选择性应用

大多数开源实现(如 LLaMA 的 LoRA)默认对所有线性层(包括 W₁、W₂、W₃)应用 LoRA。

实际应用(2023-2026):LLaMA、Mistral、Gemma、Qwen 等主流大模型均采用 SwiGLU。现状(2026):SwiGLU 已成为 Decoder-Only 大模型的默认选择。


性能对比:如何选择激活函数?

综合性能对比表

激活函数 计算速度 参数量 性能(困惑度) 梯度稳定性 推荐场景
ReLU ★★★★★ 基线 ★★ ★★★ 资源受限、稀疏模型
GELU ★★★★ 基线 ★★★★ ★★★★ Encoder、小模型
SiLU ★★★★ 基线 ★★★★ ★★★★★ 通用 Decoder 模型
SwiGLU ★★★ 基线 × 1.5 ★★★★★ ★★★★★ 大规模 Decoder 模型

决策树:应该用哪个激活函数?

根据项目类型选择:

Encoder-Only(如 BERT)

  • 推荐:GELU

Encoder-Decoder(如 T5)

  • 推荐:GELU 或 SwiGLU

Decoder-Only(如 GPT、LLaMA)

  • 模型规模 < 1B → 推荐:GELU 或 SiLU
  • 模型规模 ≥ 1B → 推荐:SwiGLU(2/3 规则)

实际选择建议

场景 1:从零训练大模型(> 7B)

选择 SwiGLU

理由:

  • 性能最佳(困惑度降低 3-4%)
  • 业界验证充分(LLaMA、Mistral 等)
  • 参数量可控(2/3 规则)

场景 2:微调预训练模型

保持原模型的激活函数

理由:

  • 改变激活函数需要重新初始化 FFN
  • 微调时改动架构风险大

场景 3:资源受限(边缘设备、移动端)

选择 ReLU

理由:

  • 计算最快
  • 可以利用稀疏性优化

场景 4:研究新架构

尝试 GELU 或 SiLU

理由:

  • 实现简单
  • 调参容易
  • 性能稳定

前沿趋势:激活函数的未来方向

1. 自适应激活函数

让激活函数的形状可以学习。例如 Adaptive Piecewise Linear (APL) 将激活函数表示为可学习参数 aᵢ 和 bᵢ 的分段线性组合。优势是可以自动调整到最适合数据的形状,缺点是参数量增加、计算开销大。

2. 稀疏激活

2025 年的 Spark Transformer 论文显示:只激活 8% 的 FFN 神经元就能达到接近原始性能,推理速度提升 3.2 倍。实现方式是只保留 top-k 的激活值,其余置零。

3. 混合激活函数

在不同层使用不同的激活函数。理由是不同深度的层承担的任务不同,或许需要不同的非线性特性。例如底层用 SwiGLU(表达能力强)、中层用 GELU(计算快)、顶层用 ReLU(稀疏性好)。

4. 三层 FFN

Apple 的 One Wide FFN 论文(2025)提出使用三层 FFN(x → W₁ → σ₁ → W₂ → σ₂ → W₃ → y),在相同总参数量下,训练 loss 更低、参数效率更高、训练速度相当。


常见问题解答

Q1: 为什么不同论文的激活函数选择不一样?

激活函数的选择与模型架构(Encoder vs Decoder)、训练数据规模(小数据集上差异不大)、计算资源(SwiGLU 需要更多显存)、历史惯性(延续前代设计)等因素有关。建议:如果不确定,选择与参考模型相同的激活函数。

Q2: 能否在训练中途切换激活函数?

理论上可以,但实践中很少这么做。原因:激活函数是 FFN 的核心,切换相当于重新初始化,需要额外 warm-up 过程,可能导致训练不稳定。替代方案:从头开始用新激活函数重新训练一个分支对比性能。

Q3: SwiGLU 的 2/3 规则是怎么来的?

来自实验调优,不是理论推导。PaLM 论文尝试了多个比例:1/2(困惑度 10.5)、2/3(10.1)、3/4(10.0)、1.0(9.9)。结论:2/3 是性能和参数量的最佳平衡点。

Q4: 激活函数对模型大小有什么影响?

激活函数本身不占参数(只是计算逻辑),但 GLU 系列需要额外的权重矩阵。例如 d_model=4096, d_ff=16384 时:标准 FFN 参数量 134M,SwiGLU 原始版本 201M,2/3 调整后 134M。

Q5: 为什么 Transformer 不用 Sigmoid 或 Tanh?

梯度消失问题。在 x=10 时,Sigmoid 梯度 ≈ 0.00005,ReLU 梯度 = 1.0。在 24 层 Transformer 中,Sigmoid 梯度累乘后 ≈ 0(完全消失),ReLU 梯度保持 1.0(完美传递)。


总结:激活函数的演进路径

历史演进

2010-2015: ReLU 时代

  • 突破点:解决梯度消失
  • 局限:死亡 ReLU、硬切换

2016-2019: GELU 时代

  • 突破点:平滑激活、概率性质
  • 局限:计算略慢

2020-2023: SiLU 时代

  • 突破点:自门控、与 GELU 等效但更简单
  • 局限:仍是单路径设计

2023-至今: SwiGLU 时代

  • 突破点:双路径门控、选择性激活
  • 权衡:参数量增加(但可通过 2/3 规则平衡)

核心设计原则的演变

时代 核心思想 代表函数
第一代 简单有效 ReLU
第二代 平滑性 GELU
第三代 自门控 SiLU
第四代 选择性激活 SwiGLU

未来展望

三大方向:

  1. 自适应激活:让激活函数的形状可学习
  2. 稀疏激活:只激活部分神经元以提升效率
  3. 架构融合:激活函数与网络结构深度结合(如三层 FFN)

随着模型规模持续增长,激活函数的选择将更加注重:

  • 参数效率(同等性能下更少参数)
  • 计算效率(推理速度和吞吐量)
  • 可解释性(理解激活模式的含义)

激活函数看似是神经网络中的"小"组件,但它承载着引入非线性、控制信息流的核心功能。从 ReLU 到 SwiGLU 的演进,正是深度学习领域不断追求"更强表达能力"和"更高效计算"的缩影。


参考资料:

相关推荐
啊我不会诶2 小时前
最小生成树
c++·笔记·学习·算法
liuyao_xianhui2 小时前
优选算法_栈_删除字符中的所有相邻重复项_C++
开发语言·数据结构·c++·python·算法·leetcode·链表
WolfGang0073212 小时前
代码随想录算法训练营 Day22 | 回溯算法 part04
数据结构·算法
tankeven2 小时前
HJ154 kotori和素因子
c++·算法
Shirley~~2 小时前
力扣hot100:相交链表
前端·算法
会编程的土豆3 小时前
【leetcode hot 100】二叉树
算法·leetcode
罗湖老棍子3 小时前
花神游历各国(信息学奥赛一本通- P1550)(洛谷-P4145)
数据结构·算法·线段树·势能数·区间开平方根 区间查询
Mr_Xuhhh3 小时前
LeetCode 热题 100 刷题笔记:数组与排列的经典解法(续)
算法·leetcode·职场和发展
炽烈小老头3 小时前
【每天学习一点算法 2026/03/29】搜索二维矩阵 II
学习·算法·矩阵