PyTorch激活函数全攻略:从ReLU到GELU,一文看懂如何选型与使用
在深度学习中,激活函数是神经网络中不可或缺的部分。它们为模型引入非线性,使得神经网络能够学习复杂的模式和关系。如果没有激活函数,无论网络有多少层,最终都只能是输入的线性组合,表达能力极其有限。
本文将介绍PyTorch中常用的激活函数及其功能,帮助你在实际项目中做出合适的选择。
常用地址
官方文档(图层):https://docs.pytorch.org/docs/main/nn.html
官方文档(函数式):https://docs.pytorch.org/docs/main/nn.functional.html
使用方法
在PyTorch中,激活函数可以通过两种方式使用:
方式一:函数式调用(torch.*)
import torch
x = torch.randn(3, 2)
y = torch.sigmoid(x)
print("输入:", x)
print("Sigmoid输出:", y)
方式二:模块化调用(nn.*)
import torch
import torch.nn as nn
activate = nn.Sigmoid()
x = torch.randn(3, 2)
y = activate(x)
print(y)
两种方式本质相同,nn.*形式更适合在构建神经网络模型时使用。
常用激活函数
1. nn.ReLU(Rectified Linear Unit)
最常用的激活函数之一。当输入为正时输出等于输入,为负时输出0。
公式:ReLU(x) = max(0, x)
特点:
- 计算简单高效
- 缓解梯度消失问题
- 可能产生"神经元死亡"问题(负数区域梯度为0)
示例:
import torch
import torch.nn as nn
relu = nn.ReLU()
x = torch.tensor([-2.0, -1.0, 0.0, 1.0, 2.0])
y = relu(x)
print(y) # tensor([0., 0., 0., 1., 2.])
2. nn.Sigmoid
将输入压缩到(0, 1)区间,适合二分类问题的输出层。
公式:Sigmoid(x) = 1 / (1 + e^(-x))
特点:
- 输出有界,可作为概率解释
- 容易出现梯度消失(饱和区域梯度接近0)
- 输出非零中心化
示例:
sigmoid = nn.Sigmoid()
x = torch.tensor([-2.0, 0.0, 2.0])
y = sigmoid(x)
print(y) # tensor([0.1192, 0.5000, 0.8808])
3. nn.Tanh(双曲正切)
将输入压缩到(-1, 1)区间,输出零中心化。
公式:Tanh(x) = (e^x - e^(-x)) / (e^x + e^(-x))
特点:
- 输出关于0对称
- 相比Sigmoid梯度更强
- 仍存在饱和区域梯度消失问题
示例:
tanh = nn.Tanh()
x = torch.tensor([-2.0, 0.0, 2.0])
y = tanh(x)
print(y) # tensor([-0.9640, 0.0000, 0.9640])
4. nn.LeakyReLU
ReLU的改进版本,为负数区域赋予一个小的正斜率,避免神经元死亡。
公式:LeakyReLU(x) = max(0, x) + negative_slope * min(0, x)
特点:
- 负数区域有微小梯度
- 缓解神经元死亡问题
- 通常negative_slope默认为1e-2
示例:
leaky_relu = nn.LeakyReLU(negative_slope=0.01)
x = torch.tensor([-2.0, -1.0, 0.0, 1.0, 2.0])
y = leaky_relu(x)
print(y) # tensor([-0.0200, -0.0100, 0.0000, 1.0000, 2.0000])
5. nn.PReLU(Parametric ReLU)
LeakyReLU的可学习版本,负斜率作为可训练参数。
特点:
- 斜率参数在训练中自动学习
- 更强的灵活性
- 参数量较少(每个通道一个参数)
6. nn.RReLU(Randomized Leaky ReLU)
训练时负斜率从均匀分布中随机采样,测试时使用期望值。
特点:
- 具有一定的正则化效果
- 增加模型鲁棒性
7. nn.ELU(Exponential Linear Unit)
在负数区域使用指数函数,输出更接近零中心化。
公式:ELU(x) = x if x > 0 else alpha * (e^x - 1)
特点:
- 负数区域平滑饱和
- 输出均值接近0
- 计算稍复杂
8. nn.GELU(Gaussian Error Linear Unit)
Transformer模型中广泛使用的激活函数。
特点:
- 结合了Dropout和ReLU的思想
- 输入越小越可能被丢弃
- BERT、GPT等模型的首选
9. nn.SiLU / nn.Swish
SiLU(x) = x * sigmoid(x)
特点:
- 平滑、非单调
- 在某些任务上表现优于ReLU
- 计算量稍大
10. nn.Mish
Mish(x) = x * tanh(softplus(x)),其中softplus(x) = ln(1 + e^x)
特点:
- 平滑、非单调、有下界无上界
- 多个任务上表现优异
- YOLOv4等模型中使用
概率激活函数
这些函数通常用于多分类任务的输出层:
| 函数 | 用途 |
|---|---|
| nn.Softmax | 多分类,输出概率分布(和为1) |
| nn.LogSoftmax | Softmax后取对数,数值更稳定 |
| nn.Softmin | 与Softmax相反,小值获得高概率 |
| nn.Softmax2d | 图像特征图的空间Softmax |
示例
softmax = nn.Softmax(dim=1)
x = torch.tensor([[1.0, 2.0, 3.0], [1.0, 2.0, 3.0]])
y = softmax(x)
print(y)
# tensor([[0.0900, 0.2447, 0.6652],
# [0.0900, 0.2447, 0.6652]])
其他激活函数
| 函数 | 说明 |
|---|---|
| nn.Softplus | ReLU的平滑版本,Softplus(x) = ln(1 + e^x) |
| nn.Hardtanh | Tanh的分段线性近似,计算更快 |
| nn.Hardsigmoid | Sigmoid的分段线性近似 |
| nn.Hardswish | Swish的快速近似版本 |
| nn.SELU | 自归一化ELU,配合特定初始化可实现自归一化 |
| nn.CELU | ELU的连续可微版本 |
| nn.Softsign | `Softsign(x) = x / (1 + |
| nn.Tanhshrink | Tanhshrink(x) = x - tanh(x) |
| nn.GLU | 门控线性单元,输入通道被分为两部分 |
如何选择?
| 场景 | 推荐 |
|---|---|
| 隐藏层(通用) | ReLU |
| 缓解神经元死亡 | LeakyReLU / PReLU / ELU |
| Transformer模型 | GELU |
| 轻量级移动端 | Hardswish / Hardsigmoid |
| 二分类输出 | Sigmoid |
| 多分类输出 | Softmax |
| 回归输出 | 通常不用激活函数(线性输出) |
| 自归一化网络 | SELU |
总结
PyTorch提供了丰富的激活函数,覆盖了从经典到前沿的各种选择。理解每个函数的特性有助于根据具体任务和网络架构做出最优选择。在实践中,ReLU及其变体(LeakyReLU、ELU等)是最常用的隐藏层激活函数,而Softmax和Sigmoid则统治着分类任务的输出层。
建议从ReLU开始尝试,如果遇到神经元死亡问题再考虑LeakyReLU或ELU。对于特定的架构(如Transformer),遵循该领域的成熟实践会更为稳妥。