Activation & Initialization —— 激活函数与权重初始化 - Clear Eyes, Full Heart
LOADING
3117 words
16 minutes
Activation & Initialization —— 激活函数与权重初始化

Activation & Initialization —— 激活函数与权重初始化

一、引言:激活函数与初始化的「共生关系」

在上一篇文章中,我们推导了多层感知机的反向传播过程。细心的读者可能已经注意到一个关键问题:反向传播时,梯度在每一层都会乘以激活函数的导数。如果这个导数很小,多层累积之后梯度就会指数级衰减——这就是著名的梯度消失(Vanishing Gradient) 问题。

梯度消失几乎让深度学习在2010年前后陷入绝境。直到ReLU激活函数和Kaiming初始化的出现,才真正让训练数十层甚至上百层的深度网络成为可能。

本文将从梯度饱和这一核心问题出发,系统梳理激活函数的演进历程,并深入推导Xavier和Kaiming两种初始化方法的数学原理。


二、饱和激活函数:Sigmoid与Tanh的「甜蜜陷阱」

2.1 Sigmoid:优雅但致命

Sigmoid函数的定义为:

σ(x)=11+ex\sigma(x) = \frac{1}{1 + e^{-x}}

值域为 (0,1)(0, 1),在零点处取最大值 σ(0)=0.5\sigma(0) = 0.5

Sigmoid有一个非常优美的导数公式:

σ(x)=σ(x)(1σ(x))\sigma'(x) = \sigma(x)(1 - \sigma(x))

证明:用商法则,

σ(x)=ex(1+ex)2\sigma'(x) = \frac{e^{-x}}{(1+e^{-x})^2}

σ(x)(1σ(x))=11+exex1+ex=ex(1+ex)2\sigma(x)(1-\sigma(x)) = \frac{1}{1+e^{-x}} \cdot \frac{e^{-x}}{1+e^{-x}} = \frac{e^{-x}}{(1+e^{-x})^2}

因此 σ(x)=σ(x)(1σ(x))\sigma'(x) = \sigma(x)(1-\sigma(x))。这个公式的优雅之处在于:只要知道函数值,就能直接算出导数值

然而,致命的缺陷隐藏在这个导数公式中

x+x \to +\infty 时,σ(x)1\sigma(x) \to 1σ(x)0\sigma'(x) \to 0; 当 xx \to -\infty 时,σ(x)0\sigma(x) \to 0σ(x)0\sigma'(x) \to 0

x=0x=0 处导数取最大值:

σ(0)=σ(0)(1σ(0))=1212=14\sigma'(0) = \sigma(0)(1-\sigma(0)) = \frac{1}{2} \cdot \frac{1}{2} = \frac{1}{4}

也就是说,Sigmoid的导数最大也只有0.25

这意味着什么?假设一个10层的网络,每层都使用Sigmoid激活函数,在最优情况下(每层输入都在0附近),反向传播的梯度每经过一层就乘以0.25。10层之后:

0.25109.5×1070.25^{10} \approx 9.5 \times 10^{-7}

梯度衰减了一百万倍!这就是梯度消失的数学根源。

📌 实验数据:当输入绝对值大于5时,Sigmoid输出已接近饱和区,梯度接近零。在10层以上的网络中,反向传播时梯度会以指数级衰减。

2.2 Tanh:零中心的改进,但饱和依旧

Tanh函数的定义为:

tanh(x)=exexex+ex\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}

它与Sigmoid的关系为:tanh(x)=2σ(2x)1\tanh(x) = 2\sigma(2x) - 1

Tanh的导数公式为:

tanh(x)=1tanh2(x)\tanh'(x) = 1 - \tanh^2(x)

Tanh相比Sigmoid的改进:输出是零中心(zero-centered) 的,值域为 (1,1)(-1, 1)。这缓解了Sigmoid非零中心导致的”锯齿形”(zigzag)梯度更新问题。

但Tanh仍然存在梯度饱和问题:当输入绝对值较大时,tanh(x)±1\tanh(x) \to \pm 1,导数 tanh(x)0\tanh'(x) \to 0。虽然Tanh在零点处的导数最大值为1(比Sigmoid的0.25大),但在饱和区的梯度同样趋近于零。

2.3 饱和激活函数的三大缺陷总结

缺陷SigmoidTanh
梯度饱和最大导数仅0.25,极易梯度消失仍存在饱和区,梯度趋近于零
非零中心输出恒为正,导致zigzag更新✅ 已解决,输出零中心
计算开销需要exp运算,较慢需要exp运算,较慢

三、ReLU及其变体:非饱和时代的开启

3.1 ReLU:简单粗暴的解决方案

ReLU(Rectified Linear Unit)的定义极为简单:

ReLU(x)=max(0,x)\text{ReLU}(x) = \max(0, x)

其导数为:

ReLU(x)={1,x>00,x0\text{ReLU}'(x) = \begin{cases} 1, & x > 0 \\ 0, & x \leq 0 \end{cases}

ReLU的革命性优势

  1. 正区间无梯度饱和:当 x>0x > 0 时,导数为1,梯度可以完整地向前传播。这意味着在正区间,梯度不会衰减

  2. 计算简单:不需要指数运算,只是简单的比较和取零。

  3. 稀疏激活:负值被置零,产生稀疏表示,有助于特征选择。

3.2 死亡ReLU(Dying ReLU):ReLU的「阿喀琉斯之踵」

然而,ReLU并非完美。当神经元的输入持续为负时,该神经元的输出恒为0,梯度也为0,权重再也无法更新——这个神经元就”死”了。

数学上,若对于某神经元,在训练过程中 wx+b<0\mathbf{w}^{\top}\mathbf{x} + b < 0 始终成立,则:

Lw=LReLUReLU(wx+b)=0\frac{\partial L}{\partial \mathbf{w}} = \frac{\partial L}{\partial \text{ReLU}} \cdot \text{ReLU}'(\mathbf{w}^{\top}\mathbf{x}+b) = 0

权重永远无法更新。

死亡ReLU的严重后果:在深度超过20层的网络中,未经特殊处理的ReLU可能导致30%-50%的神经元死亡,显著降低模型的有效容量。

3.3 ReLU变体:给负区间留一条「活路」

LeakyReLU

LeakyReLU在负区间引入一个小的斜率 α\alpha(通常取0.01):

LeakyReLU(x)={x,x>0αx,x0\text{LeakyReLU}(x) = \begin{cases} x, & x > 0 \\ \alpha x, & x \leq 0 \end{cases}

导数为:

LeakyReLU(x)={1,x>0α,x0\text{LeakyReLU}'(x) = \begin{cases} 1, & x > 0 \\ \alpha, & x \leq 0 \end{cases}

负区间梯度不再是0,神经元不会”死亡”。实验表明,α=0.01\alpha=0.01 时神经元死亡率可降低至5%以下。

PReLU(Parametric ReLU)

PReLU将负区间的斜率 α\alpha 变为可学习的参数

f(x)=max(x,αx)f(x) = \max(x, \alpha x)

其中 α\alpha 通过反向传播与权重一起更新。在ImageNet分类任务中,PReLU较ReLU可提升约1.2%的Top-1准确率。

ELU(Exponential Linear Unit)

ELU在负区间使用指数函数:

ELU(x)={x,x>0α(ex1),x0\text{ELU}(x) = \begin{cases} x, & x > 0 \\ \alpha(e^x - 1), & x \leq 0 \end{cases}

ELU具有ReLU的优势,且输出均值接近零,同时对噪声有一定鲁棒性。但需要计算exp,计算量稍大。

GELU(Gaussian Error Linear Unit)

GELU是Transformer等现代架构的首选激活函数。其定义为:

GELU(x)=xΦ(x)\text{GELU}(x) = x \cdot \Phi(x)

其中 Φ(x)\Phi(x) 是标准正态分布的累积分布函数。

实际计算中常用近似公式:

GELU(x)0.5x(1+tanh(2π(x+0.044715x3)))\text{GELU}(x) \approx 0.5x \left(1 + \tanh\left(\sqrt{\frac{2}{\pi}}(x + 0.044715x^3)\right)\right)

GELU的核心思想是:根据输入的大小”软性”地决定激活程度——输入值大时接近完全激活,输入值小时部分激活,负值大时接近零但不完全为零。

GELU的平滑性和非零曲率提供了更丰富的梯度信息,使深度网络的训练更加稳定。

Swish

Swish由Google Brain团队通过自动搜索发现,定义为:

Swish(x)=xσ(βx)=x1+eβx\text{Swish}(x) = x \cdot \sigma(\beta x) = \frac{x}{1 + e^{-\beta x}}

其中 β\beta 可以是常数(通常为1)或可训练参数。

Swish被称为**“自门控”(self-gated)激活函数**:输入 xx 乘以其自身的Sigmoid函数 σ(x)\sigma(x),Sigmoid充当一个”门”,控制有多少输入能够通过。

xx 很大时,σ(x)1\sigma(x) \approx 1,Swish x\approx x(近似线性); 当 xx 很小时,σ(x)0\sigma(x) \approx 0,Swish 0\approx 0(但梯度非零)。

Swish在负区间保持非零梯度,同时保留正区间的线性特性,避免了死亡ReLU问题。

3.4 激活函数对比总结

激活函数梯度饱和零中心计算开销死亡神经元适用场景
Sigmoid✅ 严重-二分类输出层
Tanh✅ 存在-传统RNN
ReLU❌ 正区间无✅ 有CNN通用
LeakyReLU⚠️ 极少防止死亡ReLU
PReLU⚠️ 极少可学习负斜率
ELU需零中心输出
GELUTransformer
Swish深层网络

四、权重初始化:让网络赢在「起跑线」

选择合适的激活函数只是解决梯度问题的一半。即使使用了ReLU,如果权重初始化不当,梯度仍然可能爆炸或消失

4.1 为什么初始化如此重要?

考虑一个全连接层:z=i=1nwixiz = \sum_{i=1}^{n} w_i x_i

如果权重 wiw_i 初始值太大,zz 会很大,可能将激活函数推入饱和区(对Sigmoid/Tanh而言)。

如果权重 wiw_i 初始值太小,zz 会很小,梯度在反向传播时会逐层衰减。

理想情况是:每一层输出的方差保持稳定,既不放大也不衰减

4.2 Xavier初始化(Glorot初始化)

Xavier初始化由Glorot & Bengio在2010年提出,主要适用于 Sigmoid和Tanh 等饱和激活函数。

核心假设

  1. 权重 wiw_i 独立同分布,均值为0,方差为 Var(w)\text{Var}(w)
  2. 输入 xix_i 独立同分布,均值为0,方差为 Var(x)\text{Var}(x)
  3. 激活函数在0附近近似线性(即 f(z)zf(z) \approx z

前向传播的方差约束

对于线性层 z=i=1ninwixiz = \sum_{i=1}^{n_{in}} w_i x_i,根据方差的性质(独立变量和的方差等于方差之和):

Var(z)=i=1ninVar(wixi)=ninVar(w)Var(x)\text{Var}(z) = \sum_{i=1}^{n_{in}} \text{Var}(w_i x_i) = n_{in} \cdot \text{Var}(w) \cdot \text{Var}(x)

为了保持方差一致(Var(z)=Var(x)\text{Var}(z) = \text{Var}(x)),需要:

ninVar(w)=1Var(w)=1ninn_{in} \cdot \text{Var}(w) = 1 \quad \Longrightarrow \quad \text{Var}(w) = \frac{1}{n_{in}}

反向传播的方差约束

反向传播时,梯度 Lxi\frac{\partial L}{\partial x_i} 与权重的转置相关:

Lxi=j=1noutwijLzj\frac{\partial L}{\partial x_i} = \sum_{j=1}^{n_{out}} w_{ij} \cdot \frac{\partial L}{\partial z_j}

同理,为保持梯度方差一致,需要:

noutVar(w)=1Var(w)=1noutn_{out} \cdot \text{Var}(w) = 1 \quad \Longrightarrow \quad \text{Var}(w) = \frac{1}{n_{out}}

最终的方差选择

前向和反向传播对方差的要求不同(1/nin1/n_{in} vs 1/nout1/n_{out}),Xavier取两者的调和平均

Var(w)=2nin+nout\text{Var}(w) = \frac{2}{n_{in} + n_{out}}

实现方式

正态分布wN(0,2nin+nout)w \sim \mathcal{N}\left(0, \frac{2}{n_{in} + n_{out}}\right)

均匀分布:若 wU(a,a)w \sim U(-a, a),则 Var(w)=a23\text{Var}(w) = \frac{a^2}{3}。令其等于 2nin+nout\frac{2}{n_{in}+n_{out}},得:

a=6nin+nouta = \sqrt{\frac{6}{n_{in} + n_{out}}}

wU(6nin+nout,6nin+nout)w \sim U\left(-\sqrt{\frac{6}{n_{in}+n_{out}}}, \sqrt{\frac{6}{n_{in}+n_{out}}}\right)

4.3 Kaiming初始化(He初始化)

Xavier初始化在ReLU上表现不佳,因为ReLU会将大约一半的神经元输出置为零,相当于砍掉了一半的信号

何恺明在2015年的论文《Delving Deep into Rectifiers》中提出了专门针对ReLU的Kaiming初始化。

核心洞察

ReLU的负值全部被截断为零,导致输出的方差大约只有输入方差的一半。为了补偿这个损失,权重的方差需要翻倍

前向传播的推导

设第 ll 层的输入为 xx(已经过ReLU激活),输出为 y=i=1nwixiy = \sum_{i=1}^{n} w_i x_i(线性变换后,尚未激活)。

由于 xx 是ReLU的输出,x0x \geq 0 且均值为0(假设权重均值为0,输入在0附近对称分布)。

关键步骤:ReLU将输入方差减半

对于零均值的对称分布 uu,经过ReLU后:

E[x2]=E[(ReLU(u))2]=12E[u2]\mathbb{E}[x^2] = \mathbb{E}[(\text{ReLU}(u))^2] = \frac{1}{2}\mathbb{E}[u^2]

Var(x)=12Var(u)\text{Var}(x) = \frac{1}{2}\text{Var}(u)

因此:

Var(y)=nVar(w)Var(x)=nVar(w)12Var(u)\text{Var}(y) = n \cdot \text{Var}(w) \cdot \text{Var}(x) = n \cdot \text{Var}(w) \cdot \frac{1}{2}\text{Var}(u)

为了保持方差一致(Var(y)=Var(u)\text{Var}(y) = \text{Var}(u)):

nVar(w)12=1Var(w)=2nn \cdot \text{Var}(w) \cdot \frac{1}{2} = 1 \quad \Longrightarrow \quad \text{Var}(w) = \frac{2}{n}

最终结果

Kaiming初始化的权重方差为:

Var(w)=2nin\text{Var}(w) = \frac{2}{n_{in}}

正态分布wN(0,2nin)w \sim \mathcal{N}\left(0, \frac{2}{n_{in}}\right)

均匀分布wU(6nin,6nin)w \sim U\left(-\sqrt{\frac{6}{n_{in}}}, \sqrt{\frac{6}{n_{in}}}\right)

💡 关键区别:Xavier用的是 2nin+nout\frac{2}{n_{in}+n_{out}},Kaiming用的是 2nin\frac{2}{n_{in}}。对于ReLU,Kaiming初始化保证每层方差守恒。

4.4 Python实现

import numpy as np
def xavier_uniform(input_dim, output_dim):
"""Xavier均匀初始化,适用于Sigmoid/Tanh"""
limit = np.sqrt(6 / (input_dim + output_dim))
return np.random.uniform(-limit, limit, (output_dim, input_dim))
def xavier_normal(input_dim, output_dim):
"""Xavier正态初始化,适用于Sigmoid/Tanh"""
std = np.sqrt(2 / (input_dim + output_dim))
return np.random.normal(0, std, (output_dim, input_dim))
def kaiming_uniform(input_dim, output_dim):
"""Kaiming均匀初始化,适用于ReLU"""
limit = np.sqrt(6 / input_dim)
return np.random.uniform(-limit, limit, (output_dim, input_dim))
def kaiming_normal(input_dim, output_dim):
"""Kaiming正态初始化,适用于ReLU"""
std = np.sqrt(2 / input_dim)
return np.random.normal(0, std, (output_dim, input_dim))
# 示例:创建一个3层MLP的权重
d, h1, h2, q = 784, 256, 128, 10
# 使用Kaiming初始化(ReLU网络)
W1 = kaiming_normal(d, h1) # 方差 = 2/784 ≈ 0.00255
W2 = kaiming_normal(h1, h2) # 方差 = 2/256 ≈ 0.00781
W3 = kaiming_normal(h2, q) # 方差 = 2/128 ≈ 0.01563

4.5 初始化方法选择指南

激活函数推荐初始化方差公式
SigmoidXavier2/(nin+nout)2/(n_{in}+n_{out})
TanhXavier2/(nin+nout)2/(n_{in}+n_{out})
ReLUKaiming2/nin2/n_{in}
LeakyReLUKaiming(Leaky版)2/(1+α2)nin2/(1+\alpha^2)n_{in}
GELU近似Kaiming2/nin2/n_{in}
Swish近似Kaiming2/nin2/n_{in}

五、总结:激活函数与初始化的「协同进化」

回顾整个发展历程,我们可以看到一条清晰的脉络:

第一代(Sigmoid) :提出了可微的非线性激活,但梯度饱和严重,最大导数仅0.25,深层网络几乎无法训练。

第二代(Tanh) :解决了零中心问题,但饱和问题依然存在。

第三代(ReLU) :正区间导数为1,彻底解决了正区间的梯度消失问题,使训练深层网络成为可能。但引入了死亡ReLU的新问题。

第四代(LeakyReLU/PReLU/ELU/GELU/Swish) :在保留ReLU优势的同时,通过给负区间赋予非零梯度来解决死亡ReLU问题。

权重初始化与激活函数相辅相成

  • Xavier初始化为Sigmoid/Tanh提供了方差守恒的保障
  • Kaiming初始化为ReLU家族补偿了”砍掉一半信号”的损失

一个经验法则

使用ReLU及其变体 → 用Kaiming初始化 使用Sigmoid或Tanh → 用Xavier初始化

理解这些原理,你就掌握了深度学习训练稳定性的两个关键杠杆。下一篇文章,我们将深入探讨卷积神经网络(CNN) 的数学原理与反向传播。


延伸阅读:

Activation & Initialization —— 激活函数与权重初始化
/posts/deep_learning/activation_initialization/
Author
Zhang Haoyi
Published at
2025-08-12
License
CC BY-NC-SA 4.0
分享:

Some information may be outdated

Directory
Albums
Diary
Posts
Projects
Skills
Timeline
Categories
Tags
Table of Contents