自学内容网 自学内容网

LSTM的变体

一、GRU

1、什么是GRU

门控循环单元(GRU)是一种循环神经网络(RNN)的变体,它通过引入门控机制来控制信息的流动,从而有效地解决了传统RNN中的梯度消失问题。GRU由Cho等人在2014年提出,它简化了LSTM的结构,将遗忘门和输入门合并为一个更新门,并增加了一个重置门,同时合并了单元状态和隐藏状态,使得模型更加简洁,训练速度更快,且在性能上与LSTM相当。

2、GRU的核心

核心在于两个门:更新门(update gate)和重置门(reset gate)。更新门控制着从前一时刻的状态信息中保留多少到当前状态,而重置门决定着前一状态有多少信息被写入到当前的候选集中。这种结构使得GRU在处理长序列数据时能够更好地捕捉长期依赖关系,同时减少了模型参数,提高了计算效率。

3、GRU的应用

应用非常广泛,包括但不限于自然语言处理(NLP)、语音识别、图像处理等领域。在NLP领域,GRU可以用于语言建模、情感分析、机器翻译等任务;在语音识别领域,GRU可以用于语音信号的特征提取和识别;在图像处理领域,GRU可以用于图像分类、目标检测等任务。GRU的简洁性和效率使其在处理大规模序列数据时具有优势。

在选择GRU和LSTM时,通常考虑的因素包括任务的复杂性、数据集的大小以及训练资源。由于GRU参数更少,收敛速度更快,因此在需要快速迭代和实验时,GRU通常是首选。然而,在某些需要对复杂序列依赖关系进行建模的任务中,LSTM可能会表现得更好。

总的来说,GRU是一种强大的循环神经网络架构,它通过引入门控机制来控制信息流,有效地解决了传统RNN的梯度消失问题。GRU的简洁性和效率使其在多种序列建模任务中表现出色,成为了深度学习中处理时序数据的重要工具之一。

4、GRU的工作原理

5、手写代码实现

import numpy as np

class GRU():
    def __init__(self, input_size, hidden_size):
        self.input_size = input_size
        self.hidden_size = hidden_size

        # 初始化参数w和b
        self.W_z = np.random.randn(self.hidden_size, self.input_size + self.hidden_size)
        self.b_z = np.zeros(self.hidden_size)
        # 重置门
        self.W_r = np.random.randn(self.hidden_size, self.input_size + self.hidden_size)
        self.b_r = np.zeros(self.hidden_size)
        # 候选隐藏状态
        self.W_h = np.random.randn(self.hidden_size, self.input_size + self.hidden_size)
        self.b_h = np.zeros(self.hidden_size)

    def tanh(self, x):
        return np.tanh(x)

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def forward(self, x):
        h_prev = np.zeros((self.hidden_size,))
        concat_input = np.concatenate([x, h_prev], axis=0)

        z_t = self.sigmoid(np.dot(self.W_z, concat_input) + self.b_z)
        r_t = self.sigmoid(np.dot(self.W_r, concat_input) + self.b_r)

        concat_reset_input = np.concatenate([x, r_t * h_prev], axis=0)

        h_hat_t = self.tanh(np.dot(self.W_h, concat_reset_input) + self.b_h)

        h_t = (1 - z_t) * h_prev + z_t * h_hat_t
        return h_t

二、BiLSTM

1、什么是BiSTM

BiSTM,即双向门控循环单元(Bidirectional Gated Recurrent Unit),是一种循环神经网络(RNN)的变体。它结合了前向和后向的GRU,能够同时处理过去和未来的信息,从而更好地捕捉序列数据中的上下文关系。

在BiSTM中,数据通过两个GRU网络进行处理:一个从左到右(前向),另一个从右到左(后向)。这两个网络的输出然后被拼接或相加,形成最终的特征表示,这个特征表示包含了序列的双向信息。这种结构特别适合于需要理解序列中前后文信息的任务,如文本分类、语音识别、命名实体识别(NER)等。

2、BiSTM的关键特点包括:

  1. 双向信息捕捉:BiSTM能够同时考虑序列中每个元素之前的和之后的上下文信息,这使得它在处理像文本这样的序列数据时非常有效,因为文本中词汇的含义往往受到其前后词汇的影响。

  2. 门控机制:BiSTM继承了GRU的门控机制,包括更新门和重置门,这些门控单元可以控制信息的流动,从而减少无效或噪声信息的干扰,并增强模型对重要信息的记忆能力。

  3. 应用广泛:BiSTM因其强大的序列处理能力而被广泛应用于各种领域,包括自然语言处理(NLP)、语音识别、时间序列分析等。

  4. 模型性能:在某些任务中,BiSTM能够提供比单向GRU或LSTM更好的性能,尤其是在需要捕捉长期依赖关系的任务中。

  5. 模型复杂度:由于BiSTM包含两个GRU网络,其模型参数和计算复杂度相对于单向GRU或LSTM会有所增加,但在很多情况下,这种增加是值得的,因为它能带来更准确的预测结果

 3、手写BiLSTM代码

import torch
import torch.nn as nn
from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence

class LSTM(nn.Module):
    def __init__(self, vocab_size, target_size, input_size=512, hidden_size=512):
        super(LSTM, self).__init__()
        self.hidden_size = hidden_size
        self.embedding = nn.Embedding(vocab_size, input_size)
        self.mlp = nn.Sequential(
            nn.Linear(input_size, hidden_size),
            nn.GELU(),
            nn.Linear(hidden_size, hidden_size)
        )
        self.lstm = nn.LSTM(hidden_size, hidden_size * 2, num_layers=3, batch_first=True, dropout=0.5)
        self.avg_lstm = nn.AdaptiveAvgPool1d(1)
        self.avg_linear = nn.AdaptiveAvgPool1d(1)
        self.out_linear = nn.Sequential(
            nn.Linear(hidden_size * 2 + hidden_size, hidden_size),
            nn.GELU(),
            nn.LayerNorm(hidden_size),
            nn.Linear(hidden_size, target_size)
        )
        self.norm = nn.LayerNorm(hidden_size * 2)

    def forward(self, x, lengths):
        x = self.embedding(x)
        mlp = self.mlp(x)

        pached_embed = pack_padded_sequence(mlp, lengths, batch_first=True, enforce_sorted=False)
        lstm_out, _ = self.lstm(pached_embed)
        lstm_out, _ = pad_packed_sequence(lstm_out, batch_first=True)

        lstm_out = self.norm(lstm_out)
        avg_lstm = self.avg_lstm(lstm_out.permute(0, 2, 1)).squeeze(-1)
        avg_linear = self.avg_linear(mlp.permute(0, 2, 1)).squeeze(-1)

        out = torch.cat([avg_lstm, avg_linear], dim=-1)
        return self.out_linear(out)

class BiLSTM(nn.Module):
    def __init__(self, input_size=512, hidden_size=512, output_size=512):
        super(BiLSTM, self).__init__()
        self.hidden_size = hidden_size
        self.lstm_forward = nn.LSTM(input_size, hidden_size, num_layers=1, batch_first=True)
        self.lstm_backward = nn.LSTM(input_size, hidden_size, num_layers=1, batch_first=True)

    def forward(self, x):
        out_forward, _ = self.lstm_forward(x)
        out_backward, _ = self.lstm_backward(torch.flip(x, dims=[1]))
        out_backward = torch.flip(out_backward, dims=[1])
        combined_output = torch.cat([out_forward, out_backward], dim=-1)
        return combined_output


原文地址:https://blog.csdn.net/m0_64592880/article/details/142762971

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!