0%

LSTM模型

LSTM模型

LSTM

  • LSTM(Long Short-Term Memory)也称长短时记忆结构,它是传统RNN的变体,与经典RNN相比,能够有效捕捉长序列之间的语义关联,缓解梯度消失或爆炸现象,同时LSTM的结构更复杂,它的核心结构可以分为四个部分去解析:

    • 遗忘门
    • 输入门
    • 细胞状态
    • 输出门

LSTM的内部结构图

结构解释图

遗忘门

遗忘门部分结构图与计算公式

\(f_t=\sigma(W_f\cdot [h_{t-1}, x_t] + b_f)\)

遗忘门结构分析

  • 与传统RNN的内部结构计算非常相似,首先将当前时间步输入x(t)与上一时间步隐含状态h(t-1)拼接,得到[x(t), h(t-1)],然后通过一个全连接层做变换,最后通过sigmoid函数进行激活得到f(t),可以将f(t)看做是门值 ,好比一扇门开合的大小程度,门值都将作用在通过该扇门的张量,遗忘门门值将作用的上一层的细胞状态上,代表遗忘过去的多少信息,又因为遗忘门门值是由x(t),h(t-1)计算得来的,因此整个公式意味着根据当前时间步输入和上一个时间步隐含状态h(t-1)来决定遗忘多少上一层的细胞状态所携带的过往信息

遗忘门内部结构过程演示

激活函数sigmoid的作用

  • 用于帮助调节流经网络的值 ,sigmoid函数将值压缩在0和1之间

输入门

输入门部分结构图与计算公式

\(i_t = \sigma(W_i\cdot [h_{t-1}, x_t]+b_i)\)

\(\widetilde C_t = \tanh(W_C\cdot[h_{t-1}, x_t] + b_C)\)

输入门结构分析

  • 输入门的计算公式有两个
  • 第一个是产生输入门门值的公式,它和遗忘门公式几乎相同,区别只是在于它们之后要作用的目标上。这个公式意味着输入信息有多少需要进行过滤。
  • 第二个公式是与传统RNN的内部结构计算相同,对于LSTM来说,它得到的是当前的细胞状态,而不是像经典RNN一样得到的是隐含状态。

输入门内部结构过程演示

细胞状态

细胞状态更新图与计算公式

\(C_t = f_t*C_{t-1}+i_t*\widetilde C_t\)

细胞状态更新分析

  • 细胞更新的结构与计算公式非常容易理解,没有全连接层,只是将刚才得到的遗忘门门值与上一个时间步得到的C(t-1)相乘,再加上输入门门值与当前时间步得到的未更新C(t)相乘的结果。最终得到更新后的C(t)作为下一个时间步输入的一部分。整个细胞状态更新过程就是对遗忘门和输入的门的应用。

细胞状态更新过程演示

输出门

输出门部分结构图与计算公式

\(o_t = \sigma(W_o[h_{t-1}, x_t]+b_o)\)

\(h_t=o_t*\tanh(C_t)\)

输出门结构分析

  • 输出门部分的公式也是两个
  • 第一个是计算输出门的门值,和遗忘门、输入门计算方式相同
  • 第二个是使用这个门值产生隐含状态h(t),它将作用在更新后的细胞状态C(t)上,并做tanh激活,最终得到h(t)作为下一时间步输入的一部分
  • 整个输出门的过程,就是为了产生隐含状态h(t)

输出门内部结构过程演示

Bi-LSTM

什么是Bi-LSTM

  • Bi-LSTM即双向LSTM,它没有改变LSTM本身任何的内部结构,只是将LSTM应用两次且方向不同,再将再次得到的LSTM结果进行拼接作为最终输出。

Bi-LSTM结构分析

  • 可以看到图中对“我爱中国”这句话(或输入序列),进行了从左到右和从右到左两次LSTM处理,将得到的结构张量进行了拼接作为最终 输出。这种结构能够捕捉语言语法中一些特定的前置或后置特征,增强语义关联,但是模型参数和计算复杂度也随之增加了一倍,一般需要对语料和计算资源进行评估后决定是否使用该结构。

Pytorch中LSTM工具的使用

  • 位置:在torch.nn工具包中,通过torch.nn.LSTM可调用

nn.LSTM类初始化主要参数解释

  • input_size:输入张量x中特征维度的大小
  • hidden_size:隐层张量h中的特征维度的大小
  • num_layers:隐含层的数量
  • bidirectional:是否选择使用双向LSTM,如果为True,则使用,默认不使用

nn.LSTM类实例化对象主要参数解释

  • input:输入张量x
  • h0:初始化的隐层张量h
  • c0:初始化的细胞状态张量c

nn.LSTM使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 定义LSTM的参数含义:(input_size, hidden_size, num_layers)
# 定义输入张量的参数含义:(sequence_length, batch_size, input_size)
# 定义隐藏层初始张量和细胞初始状态张量的参数含义:(num_layers * num_directions, batch_size, hidden_size)
import torch.nn as nn
import torch
# 5:输入维度;6:隐层维度;2:隐层数量
rnn = nn.LSTM(5, 6, 2)
# 1:序列长度;3:批次大小;5:输入维度
input = torch.randn(1, 3, 5)
# 2:隐层数量*单向/双向;3:批次大小;隐层维度:6
h0 = torch.randn(2, 3, 6)
c0 = torch.randn(2, 3, 6)
output, (hn, cn) = rnn(input, (h0, c0))
print(output)
print(hn)
print(cn)

tensor([[[ 0.1640, -0.1755, -0.2231, 0.2956, -0.1259, 0.0481], [-0.0310, 0.0456, -0.0640, -0.2073, -0.2792, -0.0446], [-0.0691, 0.0526, -0.3319, 0.3188, -0.1701, 0.3165]]], grad_fn=)

tensor([[[-0.1792, 0.1443, -0.1400, -0.0487, 0.1453, -0.0225], [ 0.0436, 0.5360, -0.0183, 0.2408, -0.3201, -0.0759], [ 0.1945, 0.2964, -0.1649, 0.1836, 0.2909, -0.0121]], [[ 0.1640, -0.1755, -0.2231, 0.2956, -0.1259, 0.0481], [-0.0310, 0.0456, -0.0640, -0.2073, -0.2792, -0.0446], [-0.0691, 0.0526, -0.3319, 0.3188, -0.1701, 0.3165]]], grad_fn=)

tensor([[[-0.3156, 0.3427, -1.0010, -0.1101, 0.2818, -0.0554], [ 0.1355, 0.8116, -0.1146, 0.5970, -0.5943, -0.1559], [ 0.3381, 0.4068, -1.1335, 0.5564, 0.5162, -0.1545]], [[ 0.4358, -0.3849, -0.3493, 1.8045, -0.2975, 0.0737], [-0.0490, 0.0953, -0.1204, -0.4137, -0.5312, -0.0848], [-0.0952, 0.1141, -0.7335, 0.5470, -0.4002, 0.5907]]], grad_fn=)