_ 我的博客标题

RNN梯度爆炸问题

在深度学习中,循环神经网络 (Recurrent Neural Networks, RNNs) 被广泛应用于处理序列数据。然而,当 RNN 中的梯度值变得非常大时,就会出现梯度爆炸的问题。在本文中,我们将探讨 RNN 梯度爆炸的原因以及如何解决这个问题。

什么是梯度爆炸

在 RNN 中,我们需要计算每个时间步的梯度值,然后通过反向传播算法将这些梯度值传播到之前的时间步。如果在传播过程中,梯度值变得非常大,那么就会出现梯度爆炸的问题。梯度爆炸指的是在反向传播过程中,梯度值变得非常大,以至于无法更新网络的权重。在极端情况下,梯度值可能会变得非常大,导致网络的权重溢出,从而使网络无法收敛。

什么是梯度消失

除了梯度爆炸,另一个常见的问题是梯度消失。在 RNN 中,梯度消失指的是在反向传播过程中,梯度值变得非常小,以至于无法更新网络的权重。这可能会导致网络无法学习长时间依赖关系。

RNN的问题

1.深层网络

深层网络由许多非线性层堆叠而来,每一层网络激活后的输出为fi(x),其中i为第i层,x是第i层的输入,即第i-1层的输出,f是激活函数,整个深层网络可视为一个复合的非线性多元函数:

Xt
Ht-1
Zt
Ht
Ht-1
Zt-1
Ht-2
Zt-2
Ht-3
Zt-3
Ht-4
Zt-4
M
Ht
Zt+1
Ht+1
Zt+2
Ht+2
Zt+3
Ht+3
Zt+4
Ht+4

目的是多元函数F ( x ) F(x)F(x)完成输入到输出的映射,假设不同的输入,输出的最优解是g(x),则优化深层网络就是为了找到合适的权值,满足L o s s = L ( g ( x ) , F ( x ) ) Loss=L(g(x),F(x))Loss=L(g(x),F(x))取得极小值。

对激活函数求导,如果此部分大于1,随着层数增加,梯度更新将以指数形式增加,即发生梯度爆炸;如果此部分小于1,随着层数增加,梯度更新将以指数形式衰减,即发生梯度消失。

梯度消失、爆炸,其根本原因在于反向传播训练法则,链式求导次数太多。

2.激活函数

计算权值更新信息,需要计算前层偏导信息,因此激活函数选择不合适,比如Sigmoid,梯度消失会更明显。

如果使用sigmoid作为损失函数,其梯度是不可能超过0.25的,这样经过链式求导之后,很容易发生梯度消失。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mG9kVQ4g-1678246311577)(…/…/_resources/ebf6dcac8b3bf03894d5efa4766436e5.png)]

tanh作为损失函数,它的导数图如下,可以看出,tanh比sigmoid要好一些,但是它的导数仍然是小于1的。

由于sigmoid和tanh存在上述的缺点,因此relu激活函数成为了大多数神经网络的默认选择。relu函数的导数在正数部分是恒等于1,因此在深层网络中就不存在梯度消失/爆炸的问题,每层网络都可以得到相同的更新速度。另外计算方便,计算速度快,加速网络的训练。

但是relu也存在缺点:即在x xx小于0时,导数为0,导致一些神经元无法激活。输出不是以0为中心的。因此引申出下面的leaky relu函数,但是实际上leaky relu使用的并不多。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7F0bOqdO-1678246311577)(…/…/_resources/1bbedc8f9d2f9ed0d6669e1506ba17cc.png)]

3.RNN中的梯度消失和CNN的梯度消失有区别

RNN中的梯度消失/爆炸和MLP/CNN中的梯度消失/爆炸含义不同:MLP/CNN中不同的层有不同的参数,各是各的梯度;而 RNN 中同样的权重在各个时间步共享,最终的梯度 g 等于各个时间步的梯度gt的和。

RNN中的总的梯度不会消失。即便梯度越传越弱,那也只是远距离的梯度消失,由于近距离的梯度不会消失,所有梯度之和并不会消失。RNN 所谓梯度消失的真正含义是,梯度被近距离梯度主导,导致模型难以学到远距离的依赖关系。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g2WDnXgo-1678246311578)(…/…/_resources/bfc5139e557db0715be80e66d199f8d4.png)]

如何解决

RNN在处理长序列时,容易出现梯度消失和梯度爆炸的问题。梯度消失的原因是在反向传播过程中,由于乘积链规则,长序列中每一步的梯度都需要相乘,当梯度小于1时,随着序列长度的增加,梯度会指数级地逼近0,从而无法更新网络参数。梯度爆炸则是在反向传播时,由于乘积链规则,梯度可以指数级地增长,从而导致网络无法更新参数。

  • 梯度裁剪
    梯度裁剪是一种常见的解决梯度爆炸的方法。它的基本思想是在计算梯度之后,将其裁剪到一个固定的范围内。这可以通过以下代码实现:

以下是一些可以在Python中使用的方法来解决这些问题:

import torch.nn as nn
import torch.nn.utils as utils

# 定义RNN模型
class RNN(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, output_size):
        super(RNN, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x, h):
        out, h = self.rnn(x, h)
        out = self.fc(out[:, -1, :])
        return out, h

# 梯度裁剪函数
def clip_gradient(model, clip_value):
    parameters = list(filter(lambda p: p.grad is not None, model.parameters()))
    for p in parameters:
        p.grad.data.clamp_(-clip_value, clip_value)

# 训练函数
def train(model, train_loader, criterion, optimizer, clip):
    model.train()
    running_loss = 0.0
    for inputs, labels in train_loader:
        optimizer.zero_grad()
        h = torch.zeros(model.num_layers, inputs.size(0), model.hidden_size)
        output, h = model(inputs, h)
        loss = criterion(output, labels)
        loss.backward()
        clip_gradient(model, clip)
        optimizer.step()
        running_loss += loss.item()
    return running_loss / len(train_loader)

长短期记忆网络(LSTM)
LSTM是一种常用的RNN变体,可以解决梯度消失的问题。它的基本思想是引入一个门控机制,可以控制信息的流动。具体来说,它有三个门:输入门、遗忘门和输出门。这些门可以学习调整信息的流动,从而避免信息在处理过程中丢失。以下是使用LSTM的代码示例:

————————————————
版权声明:本文为CSDN博主「kwg126」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42676396/article/details/126121277

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值