激活函数
作用
激活函数通常需满足以下条件:
- 非线性:允许网络逼近任意函数,避免线性叠加的限制。
- 可微性:支持梯度下降和反向传播,便于优化。
- 输出范围有限:控制输出值域,防止梯度爆炸或数值不稳定。
主要作用包括:
- 引入非线性变换,使多层网络具有表达能力。
- 控制输出范围:将神经元的输出压缩在特定区间(如 [ 0 , 1 ] [0, 1] [0,1] 或 [ − 1 , 1 ] [-1, 1] [−1,1]),有利于数值稳定性和后续层的输入对齐。控制梯度流动,影响训练速度和稳定性。
- 在输出层适应特定任务,如分类或回归。
- 稀疏激活(Sparse Activation):通过让部分神经元输出为 0,模拟生物神经元的抑制机制,减少计算冗余并缓解过拟合。
基础经典组:
sigmod
早期神经网络(如 Logistic 回归)的标准选择。数学表达: σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+e−x1
- 优点:输出平滑,值域在 ( 0 , 1 ) (0, 1) (0,1) 之间,非常适合表示概率。
- 缺点:
- 梯度消失(Gradient Vanishing):在 x x x 很大或很小时,导数趋近于 0,导致反向传播时参数无法更新。
- 非零中心(Non-zero centered):输出均大于 0,会导致后一层神经元的梯度方向出现“锯齿协同”变化,减缓收敛。(所有参数的更新(梯度)方向相同,要么同为正,要么同为负)
softmax
Softmax 是神经网络中常用的多分类激活函数,将实数向量转换为概率分布。数学表达: σ ( x ) i = e x i ∑ j = 1 k e x j \sigma(x)_{i}=\frac{e^{x_{i}}}{\sum_{j=1}^{k}e^{x_{j}}} σ(x)i=∑j=1kexjexi
- 优点:输出平滑,每个输出可解释为类别概率,且所有类别概率之和为 1。
- 缺点:
- 梯度消失(Gradient Vanishing):当某个类别的 logit 值远大于其他类别时,主导类别和其他类别的梯度都趋近于 0,导致反向传播时参数无法更新。
- 非零中心(Non-zero centered):输出均大于 0
tanh
数学表达: tanh ( x ) = e x − e − x e x + e − x \tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} tanh(x)=ex+e−xex−e−x
- 优点:输出范围在 ( − 1 , 1 ) (-1, 1) (−1,1),解决了零中心化问题,收敛速度通常快于 Sigmoid。
- 缺点:依然无法逃脱梯度消失的困境。
ReLU 变体与平滑组:
ReLu
由 AlexNet 推向主流,彻底改变了深层网络的训练难度。数学表达: f ( x ) = max ( 0 , x ) f(x) = \max(0, x) f(x)=max(0,x)
- 优点:
- 计算极其简单:只需一个阈值判断。
- 缓解梯度消失:在 x > 0 x > 0 x>0 区域,导数恒为 1,支持训练极深的网络。
- 稀疏性:使部分神经元失活,模型更具鲁棒性。
- 缺点:Dead ReLU 问题:如果一个很大的梯度流过,导致权重更新到让 x x x 始终小于 0,该神经元将永久“死亡”,不再更新。
LeakyRelu&PRelu
旨在修复“Dead ReLU”问题。数学表达: f ( x ) = max ( α x , x ) f(x) = \max(\alpha x, x) f(x)=max(αx,x)(其中 α \alpha α 是一个很小的常数,如 0.01)。
- 优点:在 x < 0 x < 0 x<0 时保留了一个微小的梯度,保证所有神经元都能持续学习。
- PReLU (Parametric ReLU):将 α \alpha α 设为可学习参数,让模型自适应调整负半轴斜率。
RRelu
在训练过程中随机化负半轴的斜率,以增强模型的鲁棒性和泛化能力。其数学表达式为:
f
(
x
)
=
max
(
α
x
,
x
)
f(x) = \max(\alpha x, x)
f(x)=max(αx,x) 其中
α
\alpha
α 是一个随机变量,服从特定分布(如均匀分布或高斯分布),而非固定值或可学习参数。例如:
f
(
x
)
=
{
x
if
x
≥
0
α
x
if
x
<
0
,
α
∼
U
(
a
,
b
)
f(x) = \begin{cases} x & \text{if } x \geq 0 \ \alpha x & \text{if } x < 0 \end{cases}, \quad \alpha \sim \mathcal{U}(a,b)
f(x)={xif x≥0 αxif x<0,α∼U(a,b) 其中
U
(
a
,
b
)
\mathcal{U}(a,b)
U(a,b) 表示均匀分布,
a
a
a 和
b
b
b 为超参数(例如
a
=
0.1
a=0.1
a=0.1,
b
=
0.3
b=0.3
b=0.3)。
- 优点:引入随机性,RRELU能够动态调整负半轴的梯度传递强度,既避免了Dead ReLU问题,又增强了模型对噪声和输入变化的适应能力
Dice
Dice 是在阿里巴巴的 DIN (Deep Interest Network) 模型中提出的,专门为推荐系统设计。
- 设计目的:ReLU 的硬截断(在 0 处断开)忽略了数据分布。Dice 认为,激活的“开关”不应固定在 0,而应根据输入数据的均值和方差动态调整。数学表达: f ( s ) = p ( s ) ⋅ s + ( 1 − p ( s ) ) ⋅ α s f(s) = p(s) \cdot s + (1 - p(s)) \cdot \alpha s f(s)=p(s)⋅s+(1−p(s))⋅αs其中 p ( s ) = 1 1 + e − s − E [ s ] V a r [ s ] + ϵ p(s) = \frac{1}{1 + e^{-\frac{s - E[s]}{\sqrt{Var[s] + \epsilon}}}} p(s)=1+e−Var[s]+ϵs−E[s]1。
- 优点:
- 平滑性:在分布中心附近平滑过渡。
- 数据自适应:根据当前 Batch 的数据分布自动调整校正点。
- 缺点:计算开销比 ReLU 大,且高度依赖 Batch 统计信息(受 Batch Size 影响)。
GELU
GeLU (Gaussian Error Linear Unit):Transformer 的标配当前 GPT、BERT 等大语言模型最常用的激活函数。数学表达: G E L U ( x ) = x ⋅ Φ ( x ) GELU(x) = x \cdot \Phi(x) GELU(x)=x⋅Φ(x)其中 Φ ( x ) \Phi(x) Φ(x) 是标准正态分布的累积分布函数。
- 设计逻辑:它结合了 ReLU 的非线性和 Dropout 的随机性思想。在 x x x 较小时,以更高概率被“丢弃(归零)”。
- 优点:在 0 附近更加平滑,实验证明其在高性能 NLP 模型中表现优于 ReLU。
GeLU近似实现: GeLU ( x ) ≈ x σ ( 1.702 x ) \text{GeLU}(x) \approx x\sigma(1.702x) GeLU(x)≈xσ(1.702x) 通过调整sigmoid系数平衡线性与非线性特性。
Swish
由 Google 团队通过自动搜索发现,目前广泛应用于 EfficientNet 和 Llama 2/3。数学表达: f ( x ) = x ⋅ σ ( β x ) = x 1 + e − β x f(x) = x \cdot \sigma(\beta x) = \frac{x}{1 + e^{-\beta x}} f(x)=x⋅σ(βx)=1+e−βxx(当 β = 1 \beta=1 β=1 时,常被称为 SiLU)。
- 优点:
- 无上界但有下界:有助于防止梯度饱和。
- 非单调性(Non-monotonic):在 x < 0 x < 0 x<0 附近有一个小的“凹陷”,这被认为有助于捕捉更复杂的底层特征。
- 平滑性:导数连续,比 ReLU 更容易通过梯度下降优化。
门控组
GLU
GLU(Gated Linear Unit)是一种门控激活函数,通过线性变换和门控机制结合,增强模型对信息的筛选能力。
- 核心思想是使用sigmoid门控控制信息流动,保留重要特征,抑制无关信息。数学表达:
GLU
(
x
)
=
(
x
W
+
b
)
⊗
σ
(
x
V
+
c
)
\text{GLU}(x) = (xW + b) \otimes \sigma(xV + c)
GLU(x)=(xW+b)⊗σ(xV+c)
其中: x x x 是输入向量, W , V W, V W,V是可学习的权重矩阵, b , c b, c b,c是偏置项, σ \sigma σ 是sigmoid函数, ⊗ \otimes ⊗ 表示逐元素乘法 - 工作原理:输入向量通过两条并行路径处理:
- 线性变换路径: x W + b xW + b xW+b 对输入做线性投影
- 门控路径: σ ( x V + c ) \sigma(xV + c) σ(xV+c) 生成0到1之间的门控值
- 优点:
- 门控机制实现动态特征选择
- 缓解梯度消失问题(线性变换允许梯度部分传播)
变体:(替换门控sigmoid函数)
- ReGLU:用ReLU替换sigmoid门控 ReGLU ( x ) = ( x W + b ) ⊗ max ( 0 , x V + c ) \text{ReGLU}(x) = (xW + b) \otimes \max(0, xV + c) ReGLU(x)=(xW+b)⊗max(0,xV+c)
- GEGLU:采用GELU作为门控函数 GEGLU ( x ) = ( x W + b ) ⊗ GELU ( x V + c ) \text{GEGLU}(x) = (xW + b) \otimes \text{GELU}(xV + c) GEGLU(x)=(xW+b)⊗GELU(xV+c)
SwiGLU
Llama 系列、PaLM 等主流大模型的核心组件。数学表达: S w i G L U ( x , W , V , b , c ) = S w i s h β ( x W + b ) ⊗ ( x V + c ) SwiGLU(x, W, V, b, c) = Swish_{\beta}(xW + b) \otimes (xV + c) SwiGLU(x,W,V,b,c)=Swishβ(xW+b)⊗(xV+c)其中 ⊗ \otimes ⊗ 是逐元素相乘(Hadamard product)。
- 设计目的:利用“门控机制”。一个分支负责提取特征 ( x V xV xV),另一个分支通过 Swish 产生权重控制信息流。
- 为什么 LLM 都用它?计算效率与表达力的平衡:虽然参数量增加了(需要两个权重矩阵 W W W 和 V V V),但它显著提升了模型在处理复杂逻辑推理时的收敛速度和最终精度。
GeGLU
PaLM 和部分 BERT 变体中使用,是 GeLU 的门控版本。数学表达: G e G L U ( x , W , V ) = G e L U ( x W ) ⊗ ( x V ) GeGLU(x, W, V) = GeLU(xW) \otimes (xV) GeGLU(x,W,V)=GeLU(xW)⊗(xV)
- 特点:与 SwiGLU 类似,但将门控分支替换为 GeLU。在处理多模态数据时表现出极强的稳定性。
总结对比表
| 函数 | 核心应用场景 | 关键特性 | 建议 |
|---|---|---|---|
| ReLU | CNN / 工业级 | baseline,简单、快、易死掉 | 适合快速实验 |
| GeLU | BERT / Transformer | 平滑、考虑随机性 | NLP 任务的首选单函数 |
| Dice | 推荐系统 (CTR) | 数据自适应偏移 | 仅推荐在 DS 场景尝试 |
| SwiGLU | Llama / 大模型 FFN | 门控机制、推理能力强 | 当前 SOTA 模型的最强选择 |
激活函数可视化:

1. 组 1:基础经典组
- Sigmoid vs Tanh:直观地看到 Tanh 是零中心的(过原点),而 Sigmoid 全部在 y > 0 y > 0 y>0 区域。这解释了为什么 Tanh 在深层网络中通常比 Sigmoid 收敛更快。
- ReLU 的硬截断:注意 ReLU 在 x = 0 x=0 x=0 处的突变,这导致了“Dead ReLU”问题。
2. 组 2:ReLU 变体与平滑组(最重要的一组)
- SiLU (Swish) vs GeLU:两者非常相似,但在 0 附近,GeLU 的负向凹陷比 SiLU 更深一些,且在正负轴过渡时更加平滑。这微小的差别在超大规模参数的 Transformer 训练中可能会产生累积的影响。
- 局部放大图:清晰地展示了“非单调性”——当输入 x x x 在 − 2 -2 −2 到 0 0 0 之间变大时,输出 y y y 反而变小。这种特性被认为有助于模型在优化初期跳出局部最优。
3. 组 3:数据自适应组 (Dice)
- 核心区别:ReLU 坚决地将负数全部归零。而 Dice 函数的“开关点”随着数据分布的均值(E[s])移动。在我们的模拟中,数据中心在 1.0,Dice 在 1.0 附近平滑地实现了从“抑制(斜率为 α \alpha α)”到“激活(斜率为 1)”的转换。
4. 组 4:大模型门控组
- 表达力对比:SiLU (Swish) 只是一个简单的非线性映射。而 SwiGLU(我们这里做了一维的抽象表示)通过门控机制,在正轴方向产生了一个更复杂的、具有更强非线性截断特征的曲线。这种结构赋予了大模型更强的逻辑推理和参数拟合能力。
Python 代码实现
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
#设置中文字体 (根据你的系统调整,常用有 SimHei, Arial Unicode MS)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# --- 1. 定义激活函数 ---
# 经典组
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.1): # 稍微增大 alpha 以便观察
return np.where(x > 0, x, alpha * x)
def silu(x): # 即 Swish with beta=1
return x * sigmoid(x)
from scipy.stats import norm
def gelu(x):
# 使用标准正态分布的累积分布函数
return x * norm.cdf(x)
# 数据自适应组 (Dice)
def dice_simulation(s, alpha=0.2):
"""
模拟 Dice 函数。
在真实场景中,E[s] 和 Var[s] 来自 Batch 统计。
这里我们模拟一个均值为 1.0,方差为 0.5 的分布。
"""
E_s = 1.0
Var_s = 0.5
epsilon = 1e-8
# 计算 p(s)
p_s = 1 / (1 + np.exp(-(s - E_s) / np.sqrt(Var_s + epsilon)))
return p_s * s + (1 - p_s) * (alpha * s)
# 大模型门控组 (抽象展示 Swish vs SwiGLU 的门控效果)
def swiglu_abstract_show(x):
"""
SwiGLU 是一个双分支结构:Swish(xW) * (xV)。
为了在一维图像中展示其非线性特性,我们抽象地假设 W=1, V=0.5 (简化表示)。
这仅用于展示其相比 SiLU 更加复杂的非线性截断特征。
"""
gate_branch = silu(x * 1.0)
linear_branch = x * 0.5
return gate_branch * linear_branch
# --- 2. 准备数据 ---
x = np.linspace(-5, 5, 500) # 生成 -5 到 5 的 500 个点
# --- 3. 开始绘图 ---
fig = plt.figure(figsize=(16, 12), dpi=100)
gs = gridspec.GridSpec(2, 2, height_ratios=[1, 1], width_ratios=[1, 1])
# --- 子图 1: 基础经典组 ---
ax1 = fig.add_subplot(gs[0, 0])
ax1.plot(x, sigmoid(x), label='Sigmoid', color='#1f77b4', lw=2.5)
ax1.plot(x, tanh(x), label='Tanh', color='#ff7f0e', lw=2.5)
ax1.plot(x, relu(x), label='ReLU', color='#2ca02c', lw=2.5, linestyle='--')
ax1.set_title('组 1: 基础经典激活函数', fontsize=14)
ax1.set_ylim(-1.2, 1.2) # Tanh 范围
ax1.axhline(0, color='black',linewidth=0.5)
ax1.axvline(0, color='black',linewidth=0.5)
ax1.grid(True, linestyle='--', alpha=0.5)
ax1.legend(fontsize=12)
# --- 子图 2: ReLU 变体与平滑组 (最常用) ---
ax2 = fig.add_subplot(gs[0, 1])
ax2.plot(x, relu(x), label='ReLU (硬截断)', color='#2ca02c', lw=3, alpha=0.6)
ax2.plot(x, leaky_relu(x), label='Leaky ReLU ($\\alpha=0.1$)', color='#d62728', lw=2)
ax2.plot(x, silu(x), label='SiLU/Swish (Llama/EfficientNet)', color='#9467bd', lw=2.5)
ax2.plot(x, gelu(x), label='GeLU (Transformer/GPT)', color='#8c564b', lw=2.5, linestyle=':')
ax2.set_title('组 2: ReLU 变体与平滑非单调函数', fontsize=14)
ax2.set_ylim(-1.0, 5.0) # 聚焦负半轴死区
ax2.set_xlim(-4, 4)
ax2.axhline(0, color='black',linewidth=0.5)
ax2.axvline(0, color='black',linewidth=0.5)
ax2.grid(True, linestyle='--', alpha=0.5)
ax2.legend(fontsize=12)
# 在负半轴放大局部,展示 SiLU/GeLU 的非单调性 (凹陷)
ax2_ins = ax2.inset_axes([0.1, 0.5, 0.35, 0.35])
ax2_ins.plot(x, silu(x), color='#9467bd', lw=2)
ax2_ins.plot(x, gelu(x), color='#8c564b', lw=2, linestyle=':')
ax2_ins.set_xlim(-2.5, 0.5)
ax2_ins.set_ylim(-0.3, 0.1)
ax2_ins.grid(True, linestyle='--', alpha=0.3)
ax2_ins.set_title('负半轴非单调性放大', fontsize=10)
# --- 子图 3: 数据自适应组 (Dice) ---
ax3 = fig.add_subplot(gs[1, 0])
s = np.linspace(-3, 6, 500) # 扩大范围以容纳模拟分布
# 模拟的数据分布直方图 (辅助理解)
data_dist = np.random.normal(1.0, np.sqrt(0.5), 10000)
ax3.hist(data_dist, bins=50, density=True, alpha=0.15, color='gray', label='模拟数据分布 ($\\mu=1, \\sigma^2=0.5$)')
ax3.plot(s, relu(s), label='ReLU (固定 0 点截断)', color='#2ca02c', lw=2, alpha=0.5)
ax3.plot(s, dice_simulation(s), label='Dice (自适应分布中心)', color='#e377c2', lw=3)
# 标出数据分布中心 E[s]
ax3.axvline(1.0, color='#e377c2', linestyle=':', label='数据均值 E[s]')
ax3.set_title('组 3: 数据自适应激活函数 (推荐系统)', fontsize=14)
ax3.set_xlabel('神经元输入 $s$', fontsize=12)
ax3.set_ylim(-0.5, 4.0)
ax3.grid(True, linestyle='--', alpha=0.5)
ax3.legend(fontsize=11, loc='upper left')
# --- 子图 4: 大模型门控组 (SiLU vs SwiGLU 抽象效果) ---
ax4 = fig.add_subplot(gs[1, 1])
ax4.plot(x, silu(x), label='SiLU (单分支非线性)', color='#9467bd', lw=2.5)
# 抽象展示 SwiGLU 的门控效果
ax4.plot(x, swiglu_abstract_show(x), label='SwiGLU (门控线性单元 - 抽象展示)', color='#17becf', lw=3, linestyle='-.')
ax4.set_title('组 4: 大模型前馈网络 (FFN) 演进', fontsize=14)
ax4.set_xlabel('输入 $x$', fontsize=12)
ax4.set_ylim(-1.0, 5.0)
ax4.axhline(0, color='black',linewidth=0.5)
ax4.axvline(0, color='black',linewidth=0.5)
ax4.grid(True, linestyle='--', alpha=0.5)
ax4.legend(fontsize=12)
plt.tight_layout()
plt.show()
&spm=1001.2101.3001.5002&articleId=157330201&d=1&t=3&u=3e00759f1eea4a5bb94b601093c26c25)
1万+

被折叠的 条评论
为什么被折叠?



