PyTorch torch.nn.ReLU 函数
torch.nn.ReLU 是 PyTorch 中最常用的激活函数之一,它对输入张量逐元素执行修正线性单元(Rectified Linear Unit)运算。
ReLU 是深度学习中最成功的激活函数之一,因为它计算简单、收敛速度快,且能有效缓解梯度消失问题。
函数定义
torch.nn.ReLU(inplace=False)
参数说明:
inplace(bool): 如果设为True,将在原地直接修改输入张量,节省内存。默认为False。
数学原理
nn.ReLU 执行的计算公式如下:
f(x) = max(0, x)
即对于输入中的每个元素,如果值大于 0,则保持不变;如果值小于或等于 0,则输出为 0。
这个简单的非线性变换使得网络能够学习复杂的模式,同时保持梯度的流动。
使用示例
示例 1: 基本用法
创建一个 ReLU 激活层并对输入进行激活:
实例
import torch
import torch.nn as nn
# 创建 ReLU 激活层
relu = nn.ReLU()
# 创建包含负值的输入张量
input_tensor = torch.tensor([[-1.0, 2.0, -3.0], [4.0, -5.0, 6.0]])
# 前向传播
output = relu(input_tensor)
print("输入:n", input_tensor)
print("输出:n", output)
import torch.nn as nn
# 创建 ReLU 激活层
relu = nn.ReLU()
# 创建包含负值的输入张量
input_tensor = torch.tensor([[-1.0, 2.0, -3.0], [4.0, -5.0, 6.0]])
# 前向传播
output = relu(input_tensor)
print("输入:n", input_tensor)
print("输出:n", output)
输出结果为:
输入:
tensor([[-1., 2., -3.],
[ 4., -5., 6.]])
输出:
tensor([[0., 2., 0.],
[4., 0., 6.]])
可以看到,所有负值都被置为 0,正值保持不变。
示例 2: 原地操作
使用 inplace 参数可以节省内存:
实例
import torch
import torch.nn as nn
# 创建启用原地操作的 ReLU
relu_inplace = nn.ReLU(inplace=True)
# 创建输入张量
input_tensor = torch.randn(2, 4)
original_id = id(input_tensor)
# 原地修改
output = relu_inplace(input_tensor)
# 检查是否修改了原张量
print("是否修改了原张量:", id(output) == original_id)
print("输入/输出:n", input_tensor)
import torch.nn as nn
# 创建启用原地操作的 ReLU
relu_inplace = nn.ReLU(inplace=True)
# 创建输入张量
input_tensor = torch.randn(2, 4)
original_id = id(input_tensor)
# 原地修改
output = relu_inplace(input_tensor)
# 检查是否修改了原张量
print("是否修改了原张量:", id(output) == original_id)
print("输入/输出:n", input_tensor)
输出结果为:
是否修改了原张量: True
输入/输出:
tensor([[0.0000, 0.0000, 1.2345, 0.0000],
[0.5432, 0.0000, 0.0000, 2.3456]])
注意:原地操作可以节省内存,但在某些情况下可能影响梯度计算。在训练初期或需要保留中间激活值时,建议使用默认的
inplace=False。
示例 3: 在神经网络中使用
在卷积神经网络中,ReLU 通常跟在卷积层后面:
实例
import torch
import torch.nn as nn
# 定义一个简单的卷积神经网络
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
# 卷积层:输入3通道,输出32通道,卷积核3x3
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
# ReLU 激活
self.relu1 = nn.ReLU()
# 第二个卷积层
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.relu2 = nn.ReLU()
# 池化层
self.pool = nn.MaxPool2d(2, 2)
def forward(self, x):
x = self.conv1(x)
x = self.relu1(x)
x = self.pool(x)
x = self.conv2(x)
x = self.relu2(x)
x = self.pool(x)
return x
# 创建模型
model = SimpleCNN()
# 打印模型结构
print("模型结构:")
print(model)
# 测试前向传播
# 模拟一张 3x32x32 的彩色图片
input_image = torch.randn(1, 3, 32, 32)
output = model(input_image)
print("n输入形状:", input_image.shape)
print("输出形状:", output.shape)
import torch.nn as nn
# 定义一个简单的卷积神经网络
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
# 卷积层:输入3通道,输出32通道,卷积核3x3
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
# ReLU 激活
self.relu1 = nn.ReLU()
# 第二个卷积层
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.relu2 = nn.ReLU()
# 池化层
self.pool = nn.MaxPool2d(2, 2)
def forward(self, x):
x = self.conv1(x)
x = self.relu1(x)
x = self.pool(x)
x = self.conv2(x)
x = self.relu2(x)
x = self.pool(x)
return x
# 创建模型
model = SimpleCNN()
# 打印模型结构
print("模型结构:")
print(model)
# 测试前向传播
# 模拟一张 3x32x32 的彩色图片
input_image = torch.randn(1, 3, 32, 32)
output = model(input_image)
print("n输入形状:", input_image.shape)
print("输出形状:", output.shape)
输出结果为:
模型结构: SimpleCNN( (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (relu1): ReLU() (conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (relu2): ReLU() (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) 输入形状: torch.Size([1, 3, 32, 32]) 输出形状: torch.Size([1, 64, 8, 8])
示例 4: 使用 nn.functional.relu
PyTorch 还提供了函数式接口 torch.nn.functional.relu:
实例
import torch
import torch.nn.functional as F
# 使用函数式接口
input_tensor = torch.randn(1, 5, 5)
# 方法一:使用函数式接口
output1 = F.relu(input_tensor)
# 方法二:使用 inplace 版本的函数
F.relu_(input_tensor)
print("输出:n", output1)
import torch.nn.functional as F
# 使用函数式接口
input_tensor = torch.randn(1, 5, 5)
# 方法一:使用函数式接口
output1 = F.relu(input_tensor)
# 方法二:使用 inplace 版本的函数
F.relu_(input_tensor)
print("输出:n", output1)
两者的区别:
nn.ReLU是模块类,可在模型定义中使用,会保存参数。F.relu是函数式接口,常用于forward方法中或没有可学习参数的场合。F.relu_是原地版本的下划线函数。
与其他激活函数的对比
| 激活函数 | 公式 | 特点 | 适用场景 |
|---|---|---|---|
nn.ReLU |
max(0, x) | 计算简单,稀疏激活 | 通用深度学习(默认选择) |
nn.LeakyReLU |
x > 0 ? x : 0.01x | 负轴有小幅梯度 | 防止"死亡神经元" | nn.GELU |
x * Φ(x) | 平滑近似,Transformer 默认 | Transformer、BERT 等 |
nn.Sigmoid |
1/(1+e^(-x)) | 输出 0-1,梯度饱和 | 输出层、二分类 |
nn.Tanh |
(e^x - e^(-x))/(e^x + e^(-x)) | 输出 -1 到 1,零中心化 | RNN、LSTM |
常见问题
Q1: ReLU 为什么会产生"死亡神经元"问题?
当输入持续为负时,ReLU 的输出始终为 0,梯度也为 0,导致这些神经元无法再学习。
解决方法:
- 使用
nn.LeakyReLU或nn.ELU替代 - 使用较小的初始学习率
- 采用 Batch Normalization
Q2: ReLU 适合放在输出层吗?
通常不适合。输出层更常用 Sigmoid(分类)或恒等函数(回归),因为 ReLU 的输出无界。
使用场景
nn.ReLU 是深度学习中最常用的激活函数,主要应用场景包括:
- 卷积神经网络: 在卷积层或全连接层后引入非线性。
- 多层感知机: 作为隐藏层的激活函数。
- Transformer: 在 FFN(Feed-Forward Network)中作为激活函数(虽然现在更多使用 GELU)。
- 生成对抗网络: 作为生成器的激活函数。
提示:除非有特殊需求,否则在设计神经网络时,ReLU 是隐藏层激活函数的首选。

PyTorch torch.nn 参考手册