写给新人的深度学习扫盲贴:ReLu和梯度

发布于:2025-04-10 ⋅ 阅读:(51) ⋅ 点赞:(0)

一、ReLU(Rectified Linear Unit,修正线性单元)

梯度是深度学习中最常用的激活函数之一,因其简单、高效且能有效缓解梯度消失问题而被广泛使用。

1. 数学定义

  • 函数表达式

$$
\text{ReLU}(x) = \max(0, x) =
\begin{cases}
x & \text{if } x \geq 0 \
0 & \text{if } x < 0
\end{cases}

$$

  • 导数(梯度)

$$
\frac{d}{dx}\text{ReLU}(x) =
\begin{cases}
1 & \text{if } x \geq 0 \
0 & \text{if } x < 0
\end{cases}

$$


2. 核心特性

  • 非线性:虽然形式简单,但ReLU的非线性特性使神经网络能够学习复杂函数(多个ReLU组合可逼近任意连续函数)。
  • 稀疏激活:对负输入输出0,可让网络中的部分神经元“关闭”,产生稀疏性,提升计算效率。
  • 缓解梯度消失:对于正输入,梯度恒为1,避免了传统Sigmoid/Tanh函数在反向传播时因梯度连乘导致的梯度消失问题(尤其在深层网络中)。

3. 优缺点

  • 优点
    1. 计算高效:仅需比较和取最大值操作,比Sigmoid/Tanh的指数运算快得多。
    2. 生物学合理性:类似神经元的“全有或全无”激活模式。
    3. 实际效果优异:在CNN、MLP等结构中表现良好,加速模型收敛。
  • 缺点
    1. 死亡ReLU问题(Dying ReLU):若输入始终为负(如初始化不当或学习率过高),梯度为0,神经元永久失效。
    2. 非零中心化:输出均值大于0,可能影响梯度更新效率(但影响通常较小)。

4. ReLU的变体

为解决死亡ReLU问题,研究者提出了多种改进版本:

变体名称 公式 特性
Leaky ReLU max ⁡ ( 0.01 x , x ) \max(0.01x, x) max(0.01x,x) 负区间引入微小斜率(如0.01),避免神经元死亡。
Parametric ReLU (PReLU) max ⁡ ( α x , x ) \max(\alpha x, x) max(αx,x) 斜率 α \alpha α作为可学习参数,更灵活。
ELU
$$
\begin{cases} x & \text{if } x \geq 0 \ \alpha(e^x - 1) & \text{if } x < 0 \end{cases}
$$
负区间平滑过渡至负值,缓解死亡问题且接近零均值。
Swish x ⋅ σ ( β x ) x \cdot \sigma(\beta x) xσ(βx) 谷歌提出的平滑激活函数( σ \sigma σ为Sigmoid),可能优于ReLU。

5. 代码示例(PyTorch/TensorFlow)

1:在简单全连接网络中使用ReLU(PyTorch)

import torch
import torch.nn as nn

# 定义一个包含ReLU的三层全连接网络
class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(784, 256)  # 输入层→隐藏层1
        self.relu = nn.ReLU(inplace=True)  # inplace=True可节省内存
        self.fc2 = nn.Linear(256, 64)     # 隐藏层1→隐藏层2
        self.fc3 = nn.Linear(64, 10)      # 隐藏层2→输出层

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)    # 在隐藏层1后使用ReLU
        x = self.fc2(x)
        x = self.relu(x)    # 在隐藏层2后再次使用ReLU
        x = self.fc3(x)
        return x

# 使用示例
model = SimpleNet()
input_data = torch.randn(32, 784)  # 模拟批量数据(32样本,每个784维)
output = model(input_data)
print(output.shape)  # 输出形状:torch.Size([32, 10])

2:在卷积神经网络中使用ReLU(TensorFlow/Keras)

import tensorflow as tf
from tensorflow.keras import layers

# 定义一个CNN模型,包含ReLU激活函数
model = tf.keras.Sequential([
    layers.Conv2D(32, (3,3), activation='relu', input_shape=(28,28,1)),  # 卷积层+ReLU
    layers.MaxPooling2D((2,2)),
    layers.Conv2D(64, (3,3), activation='relu'),  # 第二个卷积层+ReLU
    layers.Flatten(),
    layers.Dense(64, activation='relu'),         # 全连接层+ReLU
    layers.Dense(10, activation='softmax')        # 输出层(分类任务用softmax)
])

# 编译模型
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 打印模型结构
model.summary()

二、梯度(Gradient)简介

1. 什么是梯度?

梯度是多元函数在某一点处变化率最大的方向及其大小,是导数的多维推广。

  • 数学定义:对函数 f ( x 1 , x 2 , . . . , x n ) f(x_1, x_2, ..., x_n) f(x1,x2,...,xn),其梯度为向量:
    ∇ f = ( ∂ f ∂ x 1 , ∂ f ∂ x 2 , . . . , ∂ f ∂ x n ) \nabla f = \left( \frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, ..., \frac{\partial f}{\partial x_n} \right) f=(x1f,x2f,...,xnf)
  • 物理意义:梯度指向函数值增长最快的方向,梯度大小表示变化速率。

2. 梯度在深度学习中的作用

在神经网络中,梯度用于优化模型参数(如权重和偏置),是反向传播(Backpropagation)的核心。

关键流程

  1. 前向传播:输入数据通过网络计算输出。
  2. 计算损失:输出与真实标签的差异(如交叉熵、均方误差)。
  3. 反向传播:从输出层向输入层逐层计算损失对每个参数的梯度。
  4. 参数更新:使用优化器(如SGD、Adam)沿梯度反方向更新参数,降低损失。

3. 梯度消失与梯度爆炸

问题定义

  • 梯度消失:深层网络中,梯度在反向传播时逐层减小,导致底层参数几乎不更新。
    • 常见原因:使用Sigmoid/Tanh激活函数(导数小于1,连乘后梯度指数级衰减)。
  • 梯度爆炸:梯度在反向传播时逐层增大,导致参数更新幅度过大,模型无法收敛。
    • 常见原因:权重初始化过大或网络过深。

解决方案

问题 解决方案
梯度消失 - 使用ReLU及其变体(LeakyReLU、PReLU)
- 残差连接(ResNet)
- 批归一化(BatchNorm)
梯度爆炸 - 梯度裁剪(Gradient Clipping)
- 权重正则化(L2正则化)
- 合理的权重初始化(如Xavier/He初始化)

4. 代码示例:梯度计算与监控

PyTorch中手动计算梯度

import torch

# 定义模型和输入
x = torch.tensor([2.0], requires_grad=True)
y = x ** 2 + 3 * x + 1  # 函数 y = x² + 3x + 1

# 计算梯度
y.backward()  # 自动计算y关于所有requires_grad=True的变量的梯度
print(x.grad)  # 输出: tensor([7.])

网站公告

今日签到

点亮在社区的每一天
去签到