现在位置: 首页 > PyTorch 教程 > 正文

PyTorch torch.nn.ReLU 函数

PyTorch torch.nn 参考手册 PyTorch torch.nn 参考手册


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)

输出结果为:

输入:
 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)

输出结果为:

是否修改了原张量: 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)

输出结果为:

模型结构:
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)

两者的区别:

  • 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.LeakyReLUnn.ELU 替代
  • 使用较小的初始学习率
  • 采用 Batch Normalization

Q2: ReLU 适合放在输出层吗?

通常不适合。输出层更常用 Sigmoid(分类)或恒等函数(回归),因为 ReLU 的输出无界。


使用场景

nn.ReLU 是深度学习中最常用的激活函数,主要应用场景包括:

  • 卷积神经网络: 在卷积层或全连接层后引入非线性。
  • 多层感知机: 作为隐藏层的激活函数。
  • Transformer: 在 FFN(Feed-Forward Network)中作为激活函数(虽然现在更多使用 GELU)。
  • 生成对抗网络: 作为生成器的激活函数。

提示:除非有特殊需求,否则在设计神经网络时,ReLU 是隐藏层激活函数的首选。


PyTorch torch.nn 参考手册 PyTorch torch.nn 参考手册