跳转至

03 - 激活函数详解

常用激活函数

激活函数对比

图注:激活函数对比 - 展示了Sigmoid、Tanh、ReLU、Leaky ReLU、ELU和GELU六种常用激活函数的函数曲线

重要性: ⭐⭐⭐⭐⭐ 实用度: ⭐⭐⭐⭐⭐ 学习时间: 4小时 必须掌握: 是


为什么学这一章?

激活函数是神经网络的"灵魂",它赋予网络非线性表达能力。理解激活函数能帮助你: - 理解为什么神经网络能拟合任意复杂函数 - 选择合适的激活函数解决梯度消失/爆炸问题 - 调试训练过程中的异常行为 - 优化网络性能和收敛速度

学完这一章,你将能够: - ✅ 解释为什么需要非线性激活函数 - ✅ 掌握常用激活函数的特点和适用场景 - ✅ 理解激活函数的演化历史 - ✅ 深入分析Dead ReLU问题及其解决方案 - ✅ 理解梯度消失/爆炸问题及其解决方案 - ✅ 根据任务选择合适的激活函数 - ✅ 实现和可视化各种激活函数


📖 为什么需要激活函数?

线性变换的局限

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    没有激活函数的问题                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  假设我们有一个多层网络,但没有激活函数(只有线性变换):                │
│                                                                     │
│  第1层: h₁ = x · W₁ + b₁                                            │
│  第2层: h₂ = h₁ · W₂ + b₂                                           │
│  第3层: y  = h₂ · W₃ + b₃                                           │
│                                                                     │
│  展开看看:                                                          │
│  y = (x · W₁ + b₁) · W₂ + b₂) · W₃ + b₃                             │
│  y = x · (W₁ · W₂ · W₃) + (b₁ · W₂ · W₃ + b₂ · W₃ + b₃)             │
│  y = x · W' + b'                                                    │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  惊人发现:多层线性网络 = 单层线性网络!                       │   │
│  │                                                              │   │
│  │  无论多少层,最终都是: y = x · W + b                          │   │
│  │  只能学习线性映射,无法解决非线性问题!                        │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  图示:                                                              │
│                                                                     │
│  多层线性网络              等价于              单层网络               │
│  ┌─────┐    ┌─────┐    ┌─────┐              ┌─────┐                │
│  │ 输入 │───→│线性 │───→│线性 │───→ 输出  =   │线性 │───→ 输出        │
│  └─────┘    │变换 │    │变换 │              │变换 │                │
│             └─────┘    └─────┘              └─────┘                │
│                                                                     │
│  结论:没有非线性激活函数,深层网络毫无意义!                          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

激活函数的作用

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    激活函数的核心作用                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  激活函数 = 非线性变换 = 网络的表达能力                               │
│                                                                     │
│  加入激活函数后:                                                    │
│                                                                     │
│  第1层: h₁ = f(x · W₁ + b₁)   ← 非线性激活                          │
│  第2层: h₂ = f(h₁ · W₂ + b₂)  ← 非线性激活                          │
│  第3层: y  = h₂ · W₃ + b₃                                           │
│                                                                     │
│  现在无法合并!每一层都在做非线性变换,网络可以学习复杂模式            │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  万能逼近定理(Universal Approximation Theorem)              │   │
│  │                                                              │   │
│  │  一个具有单隐藏层和非线性激活函数的前馈神经网络,                 │   │
│  │  只要有足够多的隐藏单元,就可以以任意精度逼近任意连续函数!        │   │
│  │                                                              │   │
│  │  这就是深度学习的理论基础!                                    │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  图示对比:                                                          │
│                                                                     │
│  线性网络(无激活)          非线性网络(有激活)                      │
│  ┌─────────────────┐        ┌─────────────────┐                     │
│  │ 只能拟合直线     │        │ 可以拟合任意曲线  │                     │
│  │        ╱        │        │    ╭──╮         │                     │
│  │       ╱         │        │   ╱    ╲        │                     │
│  │      ╱          │        │  ╱      ╲       │                     │
│  │     ╱           │        │ ╱        ╲      │                     │
│  └─────────────────┘        └─────────────────┘                     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🧬 激活函数演化史

激活函数演化时间线

图注:激活函数演化时间线 - 从1986年的Sigmoid/Tanh时代到2020年的多样化发展

从Sigmoid到ReLU的演进

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    激活函数演化时间线                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  1986 ───┐                                                          │
│          │  Sigmoid/Tanh 时代                                        │
│          │  • 反向传播算法提出                                       │
│          │  • Sigmoid作为默认选择                                     │
│          │  • 问题:梯度消失逐渐显现                                  │
│          ↓                                                          │
│  1998 ───┐                                                          │
│          │  LeNet-5 使用 Sigmoid                                     │
│          │  • 网络较浅(5层),梯度消失不严重                         │
│          │  • 奠定了CNN基础                                          │
│          ↓                                                          │
│  2012 ───┐                                                          │
│          │  AlexNet 使用 ReLU ⭐ 转折点                               │
│          │  • 首次在大规模网络上使用ReLU                              │
│          │  • 训练速度提升6倍                                        │
│          │  • 缓解梯度消失问题                                       │
│          ↓                                                          │
│  2015 ───┐                                                          │
│          │  ResNet + BatchNorm                                       │
│          │  • 可以训练100+层网络                                      │
│          │  • ReLU成为隐藏层标准                                      │
│          ↓                                                          │
│  2017 ───┐                                                          │
│          │  Transformer + GELU                                       │
│          │  • BERT、GPT使用GELU                                       │
│          │  • 平滑激活函数重新受到关注                                │
│          ↓                                                          │
│  2020+ ───┐                                                         │
│           │  多样化发展                                               │
│           │  • Swish、Mish等新激活函数                                 │
│           │  • 根据任务和架构选择最优激活函数                          │
│           │  • 神经架构搜索(NAS)探索激活函数组合                       │
│                                                                     │
│  关键洞察:                                                          │
│  • 激活函数选择直接影响网络可训练深度                                  │
│  • ReLU的出现使深度学习成为可能                                        │
│  • 不同架构(CNN、RNN、Transformer)有各自的最优选择                    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

演化驱动力

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    激活函数演化的核心驱动力                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  1. 梯度流动问题                                                     │
│     ┌─────────────────────────────────────────┐                     │
│     │ Sigmoid: 两端饱和,梯度消失            │                     │
│     │    ↓                                    │                     │
│     │ ReLU: 正区间梯度恒为1,缓解梯度消失    │                     │
│     │    ↓                                    │                     │
│     │ ResNet: 残差连接,梯度直接回传         │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  2. 计算效率问题                                                     │
│     ┌─────────────────────────────────────────┐                     │
│     │ Sigmoid: 需要指数运算,计算昂贵        │                     │
│     │    ↓                                    │                     │
│     │ ReLU: 只需比较操作,计算极快           │                     │
│     │    ↓                                    │                     │
│     │ 硬件优化:ReLU易于GPU并行化            │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  3. 网络深度增加                                                     │
│     ┌─────────────────────────────────────────┐                     │
│     │ 浅层网络(5层):Sigmoid尚可           │                     │
│     │    ↓                                    │                     │
│     │ 深层网络(50层):必须ReLU             │                     │
│     │    ↓                                    │                     │
│     │ 超深网络(1000层):ReLU+残差连接      │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  4. 任务特性需求                                                     │
│     ┌─────────────────────────────────────────┐                     │
│     │ CNN: ReLU(稀疏性有利于特征学习)      │                     │
│     │    ↓                                    │                     │
│     │ RNN: Tanh(输出范围适合记忆单元)      │                     │
│     │    ↓                                    │                     │
│     │ Transformer: GELU(平滑有利于优化)    │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🔧 常用激活函数详解

1. Sigmoid 函数

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    Sigmoid 函数                                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  数学公式:                                                          │
│  σ(x) = 1 / (1 + e^(-x))                                            │
│                                                                     │
│  函数图像:                                                          │
│                                                                     │
│       σ(x)                                                          │
│       1 │        ╭──────╮                                           │
│         │       ╱        ╲                                          │
│     0.5 │──────╱          ╲────────                                 │
│         │     ╱            ╲                                        │
│       0 │────╱              ╲──────                                 │
│         └────────────────────────→ x                                │
│            -6  -3   0   3   6                                       │
│                                                                     │
│  导数:                                                              │
│  σ'(x) = σ(x) · (1 - σ(x))                                          │
│                                                                     │
│  导数图像:                                                          │
│                                                                     │
│     σ'(x)                                                           │
│    0.25 │        ╭──╮                                               │
│         │       ╱    ╲                                              │
│       0 │──────╱      ╲────────                                     │
│         └────────────────────────→ x                                │
│            -6  -3   0   3   6                                       │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  特点:                                                       │   │
│  │  • 输出范围 (0, 1),可解释为概率                              │   │
│  │  • 平滑可导,适合梯度下降                                     │   │
│  │  • 输出不是0中心化(都是正数)                                │   │
│  │                                                              │   │
│  │  问题:梯度消失(Vanishing Gradient)                         │   │
│  │  • 当 |x| > 5 时,σ(x) ≈ 0 或 1                               │   │
│  │  • 此时 σ'(x) ≈ 0,梯度几乎为0                                │   │
│  │  • 深层网络中梯度逐层衰减,前几层几乎学不到东西                 │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  适用场景:                                                          │
│  • 二分类问题的输出层(输出概率)                                     │
│  • 浅层网络(1-2层)                                                 │
│  • 不推荐用于隐藏层!                                                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2. Tanh 函数

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    Tanh 函数(双曲正切)                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  数学公式:                                                          │
│  tanh(x) = (e^x - e^(-x)) / (e^x + e^(-x))                          │
│         = 2 · σ(2x) - 1                                             │
│                                                                     │
│  函数图像:                                                          │
│                                                                     │
│      tanh(x)                                                        │
│       1 │        ╭──────╮                                           │
│         │       ╱        ╲                                          │
│       0 │──────╱          ╲────────                                 │
│         │     ╱            ╲                                        │
│      -1 │────╱              ╲──────                                 │
│         └────────────────────────→ x                                │
│            -6  -3   0   3   6                                       │
│                                                                     │
│  导数:                                                              │
│  tanh'(x) = 1 - tanh²(x)                                            │
│                                                                     │
│  导数最大值:1(在x=0处)                                            │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  特点:                                                       │   │
│  │  • 输出范围 (-1, 1),0中心化                                  │   │
│  │  • 相比Sigmoid,收敛更快(数据中心化有助于优化)               │   │
│  │  • 仍然存在梯度消失问题                                       │   │
│  │                                                              │   │
│  │  Sigmoid vs Tanh:                                           │   │
│  │  • Sigmoid: 输出 (0, 1),用于概率                             │   │
│  │  • Tanh: 输出 (-1, 1),用于特征(0中心化更好)                 │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  适用场景:                                                          │
│  • 隐藏层(比Sigmoid更好)                                           │
│  • RNN中的某些变体                                                   │
│  • 不推荐用于深层网络(仍有梯度消失)                                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

3. ReLU 函数 ⭐ 最常用

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    ReLU(Rectified Linear Unit)                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  数学公式:                                                          │
│  ReLU(x) = max(0, x)                                                │
│                                                                     │
│  函数图像:                                                          │
│                                                                     │
│      ReLU(x)                                                        │
│         │        ╱                                                  │
│       5 │       ╱                                                   │
│         │      ╱                                                    │
│       0 │─────╱────────────────                                     │
│         │    ╱                                                      │
│      -5 │   ╱                                                       │
│         └────────────────────────→ x                                │
│            -6  -3   0   3   6                                       │
│                                                                     │
│  导数:                                                              │
│  ReLU'(x) = 1 if x > 0                                              │
│             0 if x < 0                                              │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  优点:                                                       │   │
│  │  • 计算简单(只需要比较和取max)                               │   │
│  │  • 缓解梯度消失(正区间梯度恒为1)                             │   │
│  │  • 收敛速度快(比Sigmoid/Tanh快6倍)                          │   │
│  │  • 引入稀疏性(负数输出为0,部分神经元不激活)                  │   │
│  │                                                              │   │
│  │  缺点:Dead ReLU问题                                          │   │
│  │  • 负数区域梯度为0,神经元可能"死亡"                          │   │
│  │  • 如果初始化不当或学习率太大,很多神经元可能永远不被激活        │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  适用场景:                                                          │
│  • 隐藏层的默认选择 ⭐                                               │
│  • CNN、MLP的标准激活函数                                             │
│  • 深层网络的首选                                                     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

4. Leaky ReLU

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    Leaky ReLU                                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  数学公式:                                                          │
│  LeakyReLU(x) = x       if x > 0                                    │
│                 α·x     if x ≤ 0   (α 通常取 0.01)                  │
│                                                                     │
│  函数图像:                                                          │
│                                                                     │
│   LeakyReLU(x)                                                      │
│         │        ╱                                                  │
│       5 │       ╱                                                   │
│         │      ╱                                                    │
│       0 │─────╱────────────────                                     │
│         │    ╱                                                      │
│    -0.1 │   ╱   ← 小的负斜率                                        │
│         └────────────────────────→ x                                │
│            -6  -3   0   3   6                                       │
│                                                                     │
│  导数:                                                              │
│  LeakyReLU'(x) = 1   if x > 0                                       │
│                  α   if x < 0                                       │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  改进:解决Dead ReLU问题                                       │   │
│  │  • 负数区域有小的梯度(α),神经元不会完全"死亡"               │   │
│  │  • 保留了ReLU的优点(计算简单、收敛快)                        │   │
│  │                                                              │   │
│  │  变体:                                                        │   │
│  │  • PReLU: α 是可学习的参数                                    │   │
│  │  • RReLU: α 在训练中随机采样                                  │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  适用场景:                                                          │
│  • 当发现很多Dead ReLU时使用                                         │
│  • 生成模型(GAN)中常用                                             │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

5. ELU(Exponential Linear Unit)

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    ELU                                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  数学公式:                                                          │
│  ELU(x) = x              if x > 0                                   │
│           α·(e^x - 1)    if x ≤ 0   (α 通常取 1)                    │
│                                                                     │
│  函数图像:                                                          │
│                                                                     │
│       ELU(x)                                                        │
│         │        ╱                                                  │
│       5 │       ╱                                                   │
│         │      ╱                                                    │
│       0 │─────╱────────────────                                     │
│    -0.5 │    ╱╲                                                     │
│      -1 │   ╱  ╲  ← 平滑的负值                                      │
│         └────────────────────────→ x                                │
│            -6  -3   0   3   6                                       │
│                                                                     │
│  特点:                                                              │
│  • 负数区域平滑,均值更接近0                                         │
│  • 缓解Dead ReLU问题                                                │
│  • 计算比ReLU稍复杂(需要指数运算)                                   │
│                                                                     │
│  适用场景:                                                          │
│  • 需要更平滑的激活函数时                                            │
│  • 对收敛速度要求较高的场景                                          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

6. GELU(Gaussian Error Linear Unit)

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    GELU ⭐ Transformer标配                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  数学公式:                                                          │
│  GELU(x) = x · Φ(x)                                                 │
│  其中 Φ(x) 是标准正态分布的CDF                                       │
│                                                                     │
│  近似公式(Hendrycks & Gimpel, 2016):                              │
│  GELU(x) ≈ 0.5 · x · (1 + tanh[√(2/π) · (x + 0.044715 · x³)])       │
│                                                                     │
│  函数图像:                                                          │
│                                                                     │
│       GELU(x)                                                       │
│         │        ╱                                                  │
│       5 │       ╱                                                   │
│         │      ╱                                                    │
│       0 │─────╱────────────────                                     │
│    -0.5 │    ╱╲                                                     │
│         │   ╱  ╲  ← 平滑曲线                                        │
│         └────────────────────────→ x                                │
│            -6  -3   0   3   6                                       │
│                                                                     │
│  特点:                                                              │
│  • 平滑非单调(在负数区域有小的负值)                                 │
│  • 在Transformer中表现优异(BERT、GPT都用它)                         │
│  • 有概率解释(随机dropout的期望)                                    │
│                                                                     │
│  适用场景:                                                          │
│  • Transformer模型的默认选择                                         │
│  • 自然语言处理任务                                                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

⚠️ 深入分析:Dead ReLU问题

Dead ReLU问题可视化

图注:Dead ReLU问题可视化 - 左侧显示正常ReLU神经元,右侧显示Dead ReLU神经元(所有输入都是负数)

什么是Dead ReLU?

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    Dead ReLU问题详解                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  问题描述:                                                          │
│                                                                     │
│  当一个ReLU神经元在训练过程中始终接收到负输入时:                      │
│  • 输出始终为0                                                       │
│  • 梯度始终为0(因为ReLU在负数区域导数为0)                           │
│  • 该神经元及其权重永远不会更新                                       │
│  • 这个神经元"死亡"了                                                │
│                                                                     │
│  图示:                                                              │
│                                                                     │
│  正常ReLU神经元              Dead ReLU神经元                         │
│                                                                     │
│  输入分布                    输入分布                                 │
│    │    ╱╲                    │                                      │
│    │   ╱  ╲                   │    ╱╲                                │
│    │  ╱    ╲                  │   ╱  ╲                               │
│    │ ╱      ╲                 │  ╱    ╲                              │
│    └──────────→               │ ╱      ╲                             │
│       0                       └──────────→                           │
│                              所有输入都是负数!                        │
│                              输出永远为0                               │
│                                                                     │
│  后果:                                                              │
│  • 网络表达能力下降(有效神经元减少)                                  │
│  • 如果大量神经元死亡,模型性能严重下降                                │
│  • 特别是在网络的前几层发生时影响更大                                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Dead ReLU的原因

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    Dead ReLU的常见原因                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  1. 权重初始化不当                                                   │
│     ┌─────────────────────────────────────────┐                     │
│     │ 初始化权重过大 → 加权和大 → 负数 → ReLU输出0 │                     │
│     │ 例:He初始化使用不当                   │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  2. 学习率过大                                                       │
│     ┌─────────────────────────────────────────┐                     │
│     │ 大学习率 → 权重更新过大 → 跳到负区域   │                     │
│     │ 一旦进入负区域,梯度为0,无法恢复      │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  3. 数据预处理问题                                                   │
│     ┌─────────────────────────────────────────┐                     │
│     │ 输入数据没有归一化                     │                     │
│     │ 输入值过大或过小,导致加权和偏向负值   │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  4. 网络设计问题                                                     │
│     ┌─────────────────────────────────────────┐                     │
│     │ 某一层神经元过多,竞争激烈              │                     │
│     │ 部分神经元无法获得正输入               │                     │
│     └─────────────────────────────────────────┘                     │
│                                                                     │
│  检测方法:                                                          │
│  • 统计每层死亡神经元的比例                                           │
│  • 监控激活值的分布                                                   │
│  • 检查梯度是否在某些层为0                                            │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Dead ReLU的解决方案

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    Dead ReLU的解决方案                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  方案1:使用Leaky ReLU / PReLU / ELU                                  │
│  ┌─────────────────────────────────────────┐                        │
│  │ 负数区域有小的梯度,神经元不会完全死亡  │                        │
│  │ LeakyReLU: f(x) = max(αx, x), α=0.01   │                        │
│  │ PReLU: α是可学习的参数                 │                        │
│  └─────────────────────────────────────────┘                        │
│                                                                     │
│  方案2:使用较小的学习率                                             │
│  ┌─────────────────────────────────────────┐                        │
│  │ 避免权重更新过大跳到负区域             │                        │
│  │ 配合学习率衰减策略                     │                        │
│  └─────────────────────────────────────────┘                        │
│                                                                     │
│  方案3:使用Batch Normalization                                      │
│  ┌─────────────────────────────────────────┐                        │
│  │ 归一化输入,使其分布更稳定             │                        │
│  │ 减少进入负区域的概率                   │                        │
│  │ 现代深度网络的标准配置                 │                        │
│  └─────────────────────────────────────────┘                        │
│                                                                     │
│  方案4:更好的权重初始化                                             │
│  ┌─────────────────────────────────────────┐                        │
│  │ He初始化(专为ReLU设计)               │                        │
│  │ W ~ N(0, √(2/n_in))                    │                        │
│  │ 保持前向传播的方差稳定                 │                        │
│  └─────────────────────────────────────────┘                        │
│                                                                     │
│  方案5:使用GELU或Swish                                              │
│  ┌─────────────────────────────────────────┐                        │
│  │ 平滑激活函数,负数区域也有梯度         │                        │
│  │ Transformer中的成功应用                │                        │
│  └─────────────────────────────────────────┘                        │
│                                                                     │
│  推荐组合:                                                          │
│  • 简单任务:ReLU + 好的初始化                                       │
│  • 深层网络:ReLU + BatchNorm + He初始化                             │
│  • 生成模型:LeakyReLU                                               │
│  • Transformer:GELU                                                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

📊 激活函数对比总结

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    激活函数对比表                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  函数      │ 公式              │ 输出范围  │ 梯度消失 │ 计算成本 │ 推荐度 │
│  ──────────┼───────────────────┼───────────┼─────────┼─────────┼───────│
│  Sigmoid   │ 1/(1+e^(-x))      │ (0, 1)    │ 严重    │ 中      │ ⭐    │
│  Tanh      │ (e^x-e^(-x))/(...)│ (-1, 1)   │ 严重    │ 中      │ ⭐⭐   │
│  ReLU      │ max(0, x)         │ [0, +∞)   │ 无      │ 低      │ ⭐⭐⭐⭐⭐│
│  LeakyReLU │ max(αx, x)        │ (-∞, +∞)  │ 无      │ 低      │ ⭐⭐⭐⭐ │
│  ELU       │ x or α(e^x-1)     │ (-α, +∞)  │ 无      │ 中      │ ⭐⭐⭐  │
│  GELU      │ x·Φ(x)            │ (-∞, +∞)  │ 无      │ 高      │ ⭐⭐⭐⭐ │
│  Softmax   │ e^x/Σe^x          │ (0, 1)    │ -       │ 中      │ 输出层 │
│                                                                     │
│  推荐选择:                                                          │
│  • 隐藏层默认: ReLU                                                  │
│  • 深层网络: ReLU / LeakyReLU                                        │
│  • Transformer: GELU                                                 │
│  • 二分类输出: Sigmoid                                               │
│  • 多分类输出: Softmax                                               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

⚠️ 梯度消失与梯度爆炸

梯度消失与梯度爆炸可视化

图注:梯度消失与梯度爆炸可视化 - 左侧展示Sigmoid导致的梯度消失问题,右侧展示梯度爆炸问题

问题描述

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    梯度消失与梯度爆炸问题                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  深层网络中的梯度传播:                                               │
│                                                                     │
│  输入 → [层1] → [层2] → [层3] → ... → [层N] → 输出                   │
│         ↑      ↑      ↑            ↑                               │
│       梯度    梯度    梯度         梯度                             │
│                                                                     │
│  梯度计算(链式法则):                                               │
│  ∂L/∂W₁ = ∂L/∂Wₙ · ∂Wₙ/∂Wₙ₋₁ · ... · ∂W₂/∂W₁                      │
│                                                                     │
│  问题:多个小数相乘 → 梯度消失                                        │
│       多个大数相乘 → 梯度爆炸                                         │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  梯度消失(Vanishing Gradient)                               │   │
│  │                                                              │   │
│  │  现象:前面层的梯度几乎为0,参数不更新                         │   │
│  │  原因:Sigmoid/Tanh在饱和区梯度接近0                          │   │
│  │  解决:                                                        │   │
│  │  • 使用ReLU等激活函数                                          │   │
│  │  • 残差连接(ResNet)                                          │   │
│  │  • 批归一化(BatchNorm)                                       │   │
│  │  • 更好的初始化(He/Xavier)                                   │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  梯度爆炸(Exploding Gradient)                               │   │
│  │                                                              │   │
│  │  现象:梯度变得极大,参数更新失控(NaN)                       │   │
│  │  原因:权重初始化过大,或学习率过大                            │   │
│  │  解决:                                                        │   │
│  │  • 梯度裁剪(Gradient Clipping)                               │   │
│  │  • 更小的学习率                                                │   │
│  │  • 权重正则化                                                  │   │
│  │  • 批归一化                                                    │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🧪 动手实验:激活函数可视化

实验代码

Python
import numpy as np
import matplotlib.pyplot as plt

# 定义激活函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def tanh(x):
    return np.tanh(x)

def relu(x):
    return np.maximum(0, x)

def leaky_relu(x, alpha=0.01):
    return np.where(x > 0, x, alpha * x)

def elu(x, alpha=1.0):
    return np.where(x > 0, x, alpha * (np.exp(x) - 1))

def gelu(x):
    """
    GELU近似实现

    精确公式:GELU(x) = x * Φ(x),其中Φ(x)是标准正态分布的CDF
    近似公式(Hendrycks & Gimpel, 2016):
    GELU(x) ≈ 0.5 * x * (1 + tanh[√(2/π) * (x + 0.044715 * x³)])
    """
    return 0.5 * x * (1 + np.tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * x**3)))

# 生成输入
x = np.linspace(-5, 5, 1000)

# 创建图形
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
fig.suptitle('Activation Functions Comparison', fontsize=16)

# 绘制每个激活函数
functions = [
    ('Sigmoid', sigmoid(x)),
    ('Tanh', tanh(x)),
    ('ReLU', relu(x)),
    ('Leaky ReLU', leaky_relu(x)),
    ('ELU', elu(x)),
    ('GELU', gelu(x))
]

for ax, (name, y) in zip(axes.flat, functions):  # zip按位置配对多个可迭代对象
    ax.plot(x, y, linewidth=2)
    ax.set_title(name, fontsize=12)
    ax.set_xlabel('x')
    ax.set_ylabel('f(x)')
    ax.grid(True, alpha=0.3)
    ax.axhline(y=0, color='k', linewidth=0.5)
    ax.axvline(x=0, color='k', linewidth=0.5)

plt.tight_layout()
plt.savefig('activation_functions.png', dpi=150)
plt.show()

print("激活函数可视化完成!")

实验结果分析

运行代码后,你将看到: - Sigmoid/Tanh 的饱和特性 - ReLU 的简单高效 - Leaky ReLU/ELU/GELU 的负值处理


💡 核心要点总结

激活函数演化历史

时期 代表激活函数 特点
1986-2011 Sigmoid/Tanh 早期标准,但有梯度消失问题,网络难以做深
2012-2016 ReLU 深度学习转折点,计算简单,缓解梯度消失,网络可以做深
2017-2020 GELU/Swish Transformer时代,平滑激活函数,优化更稳定
2020+ 多样化 根据任务和架构选择最优激活函数

激活函数选择指南

场景 推荐激活函数 原因
隐藏层(默认) ReLU 简单、快速、缓解梯度消失
深层网络 ReLU/LeakyReLU 避免梯度消失
Transformer GELU 平滑、概率解释
生成模型(GAN) LeakyReLU 避免Dead ReLU
二分类输出 Sigmoid 输出概率 (0,1)
多分类输出 Softmax 输出概率分布
回归输出 线性(无激活) 输出任意实数

Dead ReLU问题

  • 原因:神经元始终接收负输入,梯度为0
  • 检测:监控每层死亡神经元比例
  • 解决:LeakyReLU、BatchNorm、小学习率、He初始化

关键洞察

  1. 非线性是必需的:没有激活函数,多层网络退化为单层
  2. ReLU是默认选择:简单高效,适合大多数场景
  3. 注意梯度问题:Sigmoid/Tanh在深层网络中容易导致梯度消失
  4. 没有完美的激活函数:根据任务特点选择
  5. 激活函数演化推动了深度学习发展:ReLU的出现使训练深层网络成为可能

❓ 常见问题

Q1:为什么ReLU比Sigmoid收敛快?

A: - ReLU计算简单(只需要max操作) - ReLU在正区间梯度恒为1,不会饱和 - Sigmoid在两端梯度接近0,导致梯度消失

Q2:什么是Dead ReLU?如何解决?

A: - Dead ReLU:神经元永远输出0(输入总是负数) - 解决: - 使用Leaky ReLU/ELU/GELU - 更小的学习率 - 更好的初始化(He初始化) - Batch Normalization

Q3:为什么Transformer用GELU而不是ReLU?

A: - GELU更平滑,有利于优化 - GELU有概率解释(dropout的期望) - 实验表明GELU在NLP任务上表现更好

Q4:可以同时使用不同的激活函数吗?

A:可以!不同层可以使用不同激活函数,例如: - 隐藏层:ReLU - 输出层:Softmax(分类)或线性(回归)

Q5:如何检测梯度消失/爆炸?

A: - 打印每层的梯度范数 - 观察损失曲线(不下降可能是梯度消失) - 检查参数更新量(太小→消失,太大→爆炸) - 使用梯度裁剪防止爆炸

Q6:激活函数的选择对模型性能影响有多大?

A: - 非常大!激活函数直接影响: - 网络能否训练(梯度流动) - 收敛速度 - 最终性能 - 在深层网络中,错误的激活函数选择可能导致完全无法训练


📝 自测问题

  1. 为什么神经网络需要非线性激活函数?
  2. Sigmoid和Tanh的主要区别是什么?为什么Tanh通常更好?
  3. ReLU的优点和缺点分别是什么?
  4. 什么是Dead ReLU问题?有哪些解决方案?
  5. 什么是梯度消失问题?哪些激活函数容易导致这个问题?
  6. 激活函数的选择如何影响网络的可训练深度?
  7. 为以下场景选择合适的激活函数:
  8. CNN的卷积层
  9. Transformer的FFN层
  10. 二分类问题的输出层
  11. 多分类问题的输出层

📚 扩展阅读

  1. 《Delving Deep into Rectifiers》 - He et al. (2015) - PReLU和He初始化
  2. 《Gaussian Error Linear Units》 - Hendrycks & Gimpel (2016) - GELU
  3. 《Fast and Accurate Deep Network Learning》 - Clevert et al. (2015) - ELU
  4. 《Searching for Activation Functions》 - Ramachandran et al. (2017) - Swish

🎯 下一步

继续学习 04-损失函数与优化,了解如何衡量模型性能并优化参数。