【NLP】LSTM结构,原理,代码实现,序列池化

LSTM 长短期记忆网络

由于长序列的长期依赖问题,当序列很长,RNN难以学习并保持序列早期时间步的信息。

LSTM(Long Short-Term Memory) 引入了细胞状态的概念,通过门控机制,控制信息保留的程度。

LSTM结构

在这里插入图片描述

LSTM的关键是细胞状态c,也就是图中最上方的一条贯穿整个链式结构的水平线,每个隐藏状态的输出,由细胞中的几个门共同控制。同时,这几个门也作用于细胞状态的更新。

门控机制

  1. 遗忘门

遗忘门(Forget Gate) 决定了要保留多少上一个细胞状态的信息

在这里插入图片描述

通过输入当前时间步的x和上一隐藏状态,对其进行拼接,乘上对应的权重加上偏置,最后使用sigmoid进行激活,得到遗忘门的值

  1. 输出门

**输入门(Input Gate)**决定要从当前时间步得到多少信息来更新细胞状态

在这里插入图片描述

同遗忘门得到输入门的 i t i_t it,相同的公式,但是权重不同,可以得到不同的值

同时,对输入的 x t , h t − 1 x_t,h_{t-1} xt,ht1 计算得到细胞候选状态,通过输入门得到的保留程度,以此跟新细胞状态

  1. 细胞状态更新

C t = f t ∗ C t − 1 + i t ∗ C ~ t C_t = f_t * C_{t-1} + i_t * \tilde{C}_t Ct=ftCt1+itC~t

通过遗忘门和输入门得到对应的保存信息的权重$ f_t和i_t ,以及细胞候选状态 ,以及细胞候选状态 ,以及细胞候选状态\tilde{C}_t$,计算更新细胞状态

在这里插入图片描述

通过这样的细胞状态的更新传递,可以保留每个时间步的信息,也能记忆之前的时间步。每次的更新,得到不同的保留比例,从而实现长短期记忆

  1. 输出门

在特定的时间步的输出,同样的计算权重,而后使用当前细胞状态用tanh激活,乘上这个权重,得到当前时间步的输出,同时也是隐藏状态

在这里插入图片描述

总结

对比可知,所有的门控权重计算都相同,但是其输入的权重不同,所以可以保留不同的信息

在这里插入图片描述

注:这里最后的输出 h t h_t ht 应该是tanh而不是sigmoid

基于Numpy实现

import torch
import torch.nn as nn
import numpy as np


class LSTM(nn.Module):
    def __init__(self,input_size,hidden_size,output_size):
        super().__init__()

        """
        :pram input_size  输入的词向量的维度
        :param hidden_size  隐藏状态的维度  
        :pram output_size 输出的维度
        """

        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size

        # 初始化权重
        self.w_f = np.random.rand(hidden_size,input_size+hidden_size)
        self.b_f = np.random.rand(hidden_size)

        self.w_i = np.random.rand(hidden_size,input_size+hidden_size)
        self.b_i = np.random.rand(hidden_size)

        self.w_c = np.random.rand(hidden_size,input_size+hidden_size)
        self.b_c = np.random.rand(hidden_size)

        self.w_o = np.random.rand(hidden_size,input_size+hidden_size)
        self.b_o = np.random.rand(hidden_size)

        # 输出层
        self.w_y = np.random.rand(output_size, hidden_size)
        self.b_y = np.random.rand(output_size)

    # 激活函数
    def tanh(self,x):
        return  np.tanh(x)

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

    def forward(self,x):
        # 初始化隐藏状态
        h_t = np.zeros((self.hidden_size,))
        # cell
        c_t = np.zeros((self.hidden_size,))

        # 存储 时间步的隐藏和细胞状态
        h_state = []
        c_state = []

        for t in range(x.shape[0]):
            x_t = x[t] # 拿到当前时间步的输入

            # 垂直方向凭借  列不变 增加行
            x_t = np.concatenate([x_t,h_t])  # 拼接时间步和隐藏

            # 遗忘门
            f_t = self.sigmoid(np.dot(self.w_f,x_t)+self.b_f)

            # 候选细胞状态
            c_hat_t = self.tanh(np.dot(self.w_c,x_t)+self.b_c)

            # 输入门
            i_t = self.sigmoid(np.dot(self.w_i,x_t)+self.b_i)

            # 细胞状态更新
            c_t = f_t * c_t + i_t * c_hat_t

            # 输出门
            o_t = self.sigmoid(np.dot(self.w_o,x_t)+self.b_o)

            # 更新隐藏状态
            h_t = o_t * self.tanh(c_t)

            # 保存隐藏状态和细胞状态
            h_state.append(h_t)
            c_state.append(c_t)

        y_t = np.dot(self.w_y,h_t) + self.b_y

        # 转化为张量 dim 行的维度
        output = torch.softmax(torch.tensor(y_t),dim=0)

        return np.array(h_state),np.array(c_state),output
# 数据输入
x = np.random.rand(3,2) # 三个词 词向量维度2 
# 这里只是以输入一个数据为例,如果是多个批次,还需要对维度进行转换,以符合矩阵相乘
hidden_size = 5

# 实例化模型
mdoel = LSTM(2,hidden_size,6)

h_state,c_state,output = mdoel(x)

print('class:' ,output)
print('hidden:' ,h_state)
print('hidden size :' ,h_state.shape)
print('cell:' ,c_state)
print('cell size:' ,c_state.shape)

基于PyTorch API实现

import torch
import torch.nn as nn


class LSTM(nn.Module):
    def __init__(self,input_size,hidden_size,output_size):
        """
        :param input_size:  词向量
        :param hidden_size:  隐藏层
        :param output_size:  输出类别
        """

        super().__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size
        self.lstm = nn.LSTM(input_size,hidden_size)
        self.fc = nn.Linear(hidden_size,output_size)

    def forward(self,x):
        # 初始化隐藏状态和细胞状态
        h0 = torch.zeros(1,x.size()[1],self.hidden_size)
        c0 = torch.zeros(1,x.size()[1],self.hidden_size)

        # 前向传播
        out,state = self.lstm(x,(c0,h0)) 
        # out所有时间步的输出  state最后一个时间步的状态  隐藏状态和细胞状态

        out = self.fc(out[-1,:,:]) # 取最后一个时间步的输出

        return out

# 定义参数
seq_size,batch_size,input_size = 5,4,2 # 5批次 4个词  向量维度2
hidden_size,output_size = 6,7

x = torch.randn(seq_size,batch_size,input_size )
model = LSTM(input_size,hidden_size,output_size)

out = model(x)
print(out)
print(out.shape)

序列池化

序列池化,把变长序列转换为固定长度的表示方法。如一个序列有多个词向量组成,每个向量的求和平均,合并为一个向量

主要有最大池化(突出序列特定的最大激活值)平均池化(保留序列总体的信息)注意力池化(注意力机制池化,对每个时间步分配权重)

import torch
import torch.nn as nn


input_data = torch.randn(2,3,4) # 批次  词数, 词向量维度

avg_pool = nn.AdaptiveAvgPool1d(1)  
# max_pool = nn.AdaptiveMaxPool1d(1)

# 调整维度
input_data = input_data.permute(0,2,1) # b.s.d >> b.d.s #

output = avg_pool(input_data) # 转化为句向量
# output = max_pool(input_data) # 转化为句向量

print(output.shape) # torch.Size([2, 4, 1])
LSTM-CNN网络是一种融合了长短期记忆网络(LSTM)和卷积神经网络(CNN)的深度学习模型。该模型在自然语言处理和计算机视觉领域中具有广泛的应用。 为了实现LSTM-CNN网络结构,我们可以采用TensorFlow 2框架。具体步骤如下: 1. 导入所需的TensorFlow模块和其他必要的Python模块。 ``` import tensorflow as tf from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Dense, Dropout, LSTM, Conv1D, MaxPooling1D, Flatten, concatenate ``` 2. 定义模型的输入层。 ``` input_layer = Input(shape=(sequence_length, input_size)) ``` 其中,sequence_length表示序列的长度,input_size表示每个时间步输入的特征数。 3. 定义LSTM层。 ``` lstm_layer = LSTM(lstm_units, return_sequences=True)(input_layer) ``` 其中,lstm_units表示LSTM单元的数量,return_sequences=True表示返回所有时间步的输出结果。 4. 定义卷积层和池化层。 ``` cnn_layer = Conv1D(cnn_filters, cnn_kernel_size, activation='relu')(input_layer) cnn_layer = MaxPooling1D(pool_size=cnn_pool_size)(cnn_layer) ``` 其中,cnn_filters表示卷积核的数量,cnn_kernel_size表示卷积核的尺寸,cnn_pool_size表示池化层的尺寸。 5. 将LSTM层和卷积层合并。 ``` merge_layer = concatenate([lstm_layer, cnn_layer]) ``` 6. 定义全连接层和输出层。 ``` dense_layer = Dense(dense_units, activation='relu')(merge_layer) output_layer = Dense(output_size, activation='softmax')(dense_layer) ``` 其中,dense_units表示全连接层的神经元数量,output_size表示输出层的大小。 7. 定义模型并编译。 ``` model = Model(inputs=input_layer, outputs=output_layer) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) ``` 其中,loss表示损失函数,optimizer表示优化器,metrics表示评估指标。 8. 训练模型。 ``` model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=num_epochs, batch_size=batch_size) ``` 其中,x_train和y_train表示训练数据集,x_test和y_test表示测试数据集,num_epochs表示训练轮数,batch_size表示批量大小。 通过以上步骤,我们可以使用TensorFlow 2框架轻松地实现LSTM-CNN网络结构,并在自然语言处理和计算机视觉领域中应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值