- 什么是激活函数? (核心概念)
- 为什么需要激活函数? (它的作用)
- 常用的激活函数及其特点 (重点介绍)
- 如何在 Python (PyTorch/TensorFlow) 中使用激活函数? (代码实践)
- 如何选择激活函数? (实践指南)
什么是激活函数?
激活函数是人工神经网络中神经元的一个核心组件,它的作用是接收神经元的输入(通常是上一层所有神经元的加权和),然后通过一个特定的数学函数进行非线性变换,最终产生神经元的输出。

可以把它想象成一个“决策开关”或“信号放大器”:
- 输入:
z = (w₁x₁ + w₂x₂ + ... + wₙxₙ) + b(权重加权和 + 偏置) - 输出:
a = Activation(z)(经过激活函数处理后的最终输出)
这个输出 a 会作为下一层神经元的输入。
为什么需要激活函数?
这是初学者最常问的问题,也是理解深度学习的关键。
一句话总结:为了引入非线性,让神经网络能够学习复杂的模式。

-
如果没有激活函数:
- 神经网络的每一层,无论有多少层,其计算都可以简化为
output = W * input + b。 - 多层叠加后,整个网络仍然只是一个线性变换
output = W_total * input + b_total。 - 这样的网络能力非常有限,本质上就是一个线性回归模型,连解决 XOR 这样的简单非线性问题都做不到。
- 神经网络的每一层,无论有多少层,其计算都可以简化为
-
有了激活函数:
- 每一层引入了一个非线性变换,即使每一层都很简单,多层叠加后,网络的表达能力(或称“容量”)会呈指数级增长。
- 这使得神经网络能够拟合任意复杂的函数,从而解决图像识别、自然语言处理等高度复杂的任务。
核心要点:激活函数为网络带来了“非线性”,这是深度学习有效性的基石。
常用的激活函数及其特点
下面是几种最主流的激活函数,我们来看它们的数学公式、图像和优缺点。
a) Sigmoid (S型函数)
- 公式:
σ(z) = 1 / (1 + e⁻ᶻ) - 输出范围:
(0, 1) - 特点:
- 优点: 输出在 (0, 1) 之间,可以很好地表示一个“概率”。
- 缺点:
- 梯度消失: 当输入
z极大或极小时(如z > 5或z < -5),函数曲线会变得非常平缓,导致梯度(导数)接近于0,在反向传播时,梯度会不断衰减,导致靠近输入层的权重几乎无法更新,网络难以训练。 - 输出非零中心化: 输出均值不是0,这可能会影响下一层梯度的更新,导致梯度下降的“之”字形路径,收敛速度变慢。
- 梯度消失: 当输入
- 应用场景: 现在已不常用作为隐藏层的激活函数,主要用于二分类问题的输出层,表示类别概率。
b) Tanh (双曲正切函数)
- 公式:
tanh(z) = (eᶻ - e⁻ᶻ) / (eᶻ + e⁻ᶻ) - 输出范围:
(-1, 1) - 特点:
- 优点: 输出范围是零中心的 (-1, 1),这通常比 Sigmoid 更好,因为下一层得到的输入均值为0,有助于梯度更新。
- 缺点: 同样存在梯度消失问题,当输入
z极大或极小时,梯度趋近于0。
- 应用场景: 在某些循环神经网络中仍有使用,现在也较少作为首选的隐藏层激活函数。
c) ReLU (Rectified Linear Unit, 修正线性单元)
- 公式:
f(z) = max(0, z) - 输出范围:
[0, +∞) - 特点:
- 优点:
- 解决梯度消失: 对于正输入,梯度恒为1,不存在梯度消失问题,使得网络可以训练得更深。
- 计算简单: 公式简单,计算速度快,没有复杂的指数运算。
- 引入稀疏性: 当输入为负时,输出为0,使得网络中的一部分神经元“失活”,起到了类似稀疏自动编码器的作用,有助于减轻过拟合。
- 缺点:
- Dying ReLU Problem: 如果一个神经元的权重更新导致其输入在任何样本下都为负,那么该神经元的梯度将永远为0,导致它再也无法被激活(“死亡”),学习率过高时容易发生。
- 优点:
- 应用场景: 目前最主流、最常用的隐藏层激活函数,在绝大多数CNN和深度前馈网络中作为首选。
d) Leaky ReLU / PReLU (带泄漏的 ReLU)
- 公式:
f(z) = max(αz, z), 是一个很小的正数(如 0.01)。 - 特点:
- 优点: 为了解决 Dying ReLU 问题,当输入为负时,不再输出0,而是输出一个很小的线性值
αz,这样,即使输入为负,梯度也不为0,神经元就不会“死亡”。 - 缺点: 需要额外调整超参数 (虽然实践中
α=0.01通常效果不错)。
- 优点: 为了解决 Dying ReLU 问题,当输入为负时,不再输出0,而是输出一个很小的线性值
- 应用场景: ReLU 的一个优秀替代品,当 ReLU 表现不佳(如神经元大量死亡)时可以尝试。
e) ELU (Exponential Linear Unit)
- 公式:
f(z) = z if z > 0 else α(eᶻ - 1) - 特点:
- 优点: 结合了 ReLU 和 Leaky ReLU 的优点,同时其负值部分是平滑的,这有助于让神经元的激活均值更接近于0,有助于收敛。
- 缺点: 计算比 ReLU 稍复杂,因为有指数运算。
- 应用场景: ReLU 的又一个强力竞争者,在某些任务上表现优于 ReLU。
f) Softmax
- 公式:
σ(zᵢ) = eᶻⁱ / Σⱼ eᶻʲ - 输出范围:
(0, 1),并且所有类别的输出之和为1。 - 特点:
- 作用: 它不是一个简单的逐元素激活函数,而是对一个向量进行操作,它会将一个实数向量转换为一个概率分布,每个元素代表对应类别的概率。
- 应用场景: 多分类问题的输出层。
如何在 Python 中使用激活函数?
在主流的深度学习框架中,激活函数通常作为层来使用,或者作为函数直接调用,下面以 PyTorch 和 TensorFlow 为例。
PyTorch 示例
在 PyTorch 中,激活函数通常在 torch.nn 模块中定义,作为 nn.Module 的子类。
import torch
import torch.nn as nn
# 创建一个模拟输入 (一个批次,一个样本,一个特征)
x = torch.tensor([-2.0, -1.0, 0.0, 1.0, 2.0])
# 1. 定义激活函数层
sigmoid_layer = nn.Sigmoid()
relu_layer = nn.ReLU()
leaky_relu_layer = nn.LeakyReLU(negative_slope=0.01) # negative_slope alpha
# 2. 前向传播
x_sigmoid = sigmoid_layer(x)
x_relu = relu_layer(x)
x_leaky_relu = leaky_relu_layer(x)
print("原始输入:", x)
print("Sigmoid 输出:", x_sigmoid)
print("ReLU 输出:", x_relu)
print("LeakyReLU 输出:", x_leaky_relu)
# 在网络模型中定义
class MyNet(nn.Module):
def __init__(self):
super(MyNet, self).__init__()
self.layer1 = nn.Linear(10, 5) # 一个线性层
self.activation = nn.ReLU() # 激活层
def forward(self, x):
x = self.layer1(x)
x = self.activation(x)
return x
# 也可以使用函数式接口 (更简洁)
output = torch.relu(x)
print("函数式 ReLU 输出:", output)
TensorFlow/Keras 示例
在 Keras 中,使用起来非常方便,可以直接在 Dense 层中指定 activation 参数,或者单独使用激活层。
import tensorflow as tf
# 创建一个模拟输入 (一个批次,一个样本,一个特征)
x = tf.constant([-2.0, -1.0, 0.0, 1.0, 2.0])
# 1. 在 Keras 层中直接指定
# 注意:Keras 的 ReLU 默认没有负斜率,即 f(x)=max(0,x)
# 如果要带泄漏,使用 tf.keras.layers.LeakyReLU
model = tf.keras.Sequential([
tf.keras.layers.Dense(1, activation='relu', input_shape=[1])
])
# 单独使用激活函数
x_sigmoid = tf.keras.activations.sigmoid(x)
x_relu = tf.keras.activations.relu(x)
x_leaky_relu = tf.keras.layers.LeakyReLU(alpha=0.01)(x)
print("原始输入:", x)
print("Sigmoid 输出:", x_sigmoid)
print("ReLU 输出:", x_relu)
print("LeakyReLU 输出:", x_leaky_relu)
# 在模型定义中
model = tf.keras.Sequential([
tf.keras.layers.Dense(64, activation='relu', input_shape=(784,)),
tf.keras.layers.Dense(64, activation='leaky_relu'), # 或者用 tf.keras.layers.LeakyReLU() 层
tf.keras.layers.Dense(10, activation='softmax') # 多分类输出层
])
如何选择激活函数?
这是一个经验性的问题,但也有一些公认的指导原则:
| 场景 | 推荐激活函数 | 原因 |
|---|---|---|
| 隐藏层 | ReLU | 首选,计算简单,有效缓解梯度消失,是目前最通用、效果最好的选择。 |
| 隐藏层 (ReLU 效果不佳时) | Leaky ReLU / ELU | 当使用 ReLU 出现大量“死亡”神经元时,可以尝试带泄漏的版本。 |
| 二分类输出层 | Sigmoid | 输出在 (0, 1) 之间,可以解释为“属于正类的概率”。 |
| 多分类输出层 | Softmax | 将输出转换为一个概率分布,所有类别概率之和为1,适合多分类任务。 |
| 回归问题输出层 | Linear (无激活函数) | 直接输出一个实数值,不需要进行非线性变换。 |
| RNN/LSTM/GRU | Tanh / Sigmoid | 传统循环网络中常用,因为它们的输出范围有界,适合处理序列数据。 |
总结建议:
- 对于初学者和大多数任务:隐藏层用 ReLU,输出层根据任务类型选择 Sigmoid 或 Softmax,这是一个不会出错的起点。
- 如果遇到训练困难:可以尝试用 Leaky ReLU 或 ELU 替换 ReLU。
- 避免在隐藏层使用 Sigmoid:除非有非常特殊的需求,否则应尽量避免,因为梯度消失问题太严重了。
