美文网首页
LSTM内部结构-我彻底明白了

LSTM内部结构-我彻底明白了

作者: 笑傲NLP江湖 | 来源:发表于2022-01-14 10:40 被阅读0次

原创:李孟启

1、背景

LSTM(Long Short-term Memory,LSTM)长短期记忆[1],是一种用于处理序列数据的神经网络。相比一般的神经网络来说,他能够处理序列变化的数据。比如某个单词的意思会因为上文提到的内容不同而有不同的含义,LSTM就能够很好地解决这类问题。

本教程适合入门深度学习的小白,大神请绕行,你要是即将参加面试,那么这篇文章也会对你产生帮助。

2、LSTM结构

如图1所示,这是一个时刻的LSTM的内部结构图,多个时刻就是下图在横向上拼接组成。

图1 LSTM单元结构图

(1)从图中我们可以看到有三个门,即输⼊门(input gate)、遗忘门(forget gate)和输出门(output gate),以及记忆细胞(某些⽂献把记忆细胞当成⼀种特殊的隐藏状态),从⽽记录额外的信息。这里你可能不懂隐藏状态,但是没关系,你只需要理解下面的计算过程即可。一提到LSTM,我们就不得不面对下面的公式,这些公式也是面试中常被问及的地方,也有一定的重复性,突出两个字“好记”。

\boldsymbol{I}_{t}=\sigma\left(\boldsymbol{X}_{t} \boldsymbol{W}_{x i}+\boldsymbol{H}_{t-1} \boldsymbol{W}_{h i}+\boldsymbol{b}_{i}\right) 式1

\boldsymbol{F}_{t}=\sigma\left(\boldsymbol{X}_{t} \boldsymbol{W}_{x f}+\boldsymbol{H}_{t-1} \boldsymbol{W}_{h f}+\boldsymbol{b}_{f}\right) 式2

\boldsymbol{O}_{t}=\sigma\left(\boldsymbol{X}_{t} \boldsymbol{W}_{x o}+\boldsymbol{H}_{t-1} \boldsymbol{W}_{h o}+\boldsymbol{b}_{o}\right) 式3

这里从数学运算的角度上讲解,所以不会涉及太多深度学习的名词,我们先来明确公式中每个参数的含义,这些参数是以矩阵的形式存在的,X_{t}t 时刻的输入,尺寸为 [n,d](可以理解为一个样本数量为n每个样本特征数为d的一个矩阵),H_{t-1}是上一个时刻传过来的状态信息,它的尺寸是 [n,h]W_{xi}W_{xf}W_{xo}$$\in$$[d,h]W_{hi}W_{hf}W_{ho}$$\in$$[h,h]是权重参数, \boldsymbol{b}_{i}, \boldsymbol{b}_{f}, \boldsymbol{b}_{o}的尺寸是[1,h](其实就是偏差参数),公示中“+”是元素的对位相加,相乘是矩阵乘法。\sigmasigmoid 激活函数如公式4所示,就是把括号中运算得到的矩阵每一个元素都带入sigmoid 函数求值,运算前后矩阵的形状不变。

S(x)=\frac{1}{1+e^{-x}} 式4

最终我们可以得到I_{t}F_{t}O_{t}$$\in$$[n,h]

(2)下面是候选记忆细胞的计算公式:

\tilde{\boldsymbol{C}}_{t}=\tanh \left(\boldsymbol{X}_{t} \boldsymbol{W}_{x c}+\boldsymbol{H}_{t-1} \boldsymbol{W}_{h c}+\boldsymbol{b}_{c}\right) 式5

其中W_{xc}\in [d,h]W_{hc}\in[h,h] 是权重参数,b_{c}\in[1,h] 偏差参数 ,这里括号里面的计算方式同上三个门的计算过程一致,只不过这里使用了tanh激活函数,tanh如式6所示。最终\tilde{\boldsymbol{C}}_{t}\in[n,h]

\tanh x=\frac{\sinh x}{\cosh x}=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}} 式6

那么,剩余的计算就简单多了,现在我门已知I_{t}、F_{t}、O_{t}\in[n,h]\tilde{\boldsymbol{C}}_{t}\in[n,h] ,那么C_{t}的计算如式7所示。

\boldsymbol{C}_{t}=\boldsymbol{F}_{t} \odot \boldsymbol{C}_{t-1}+\boldsymbol{I}_{t} \odot \tilde{\boldsymbol{C}}_{t} 式7

其中,C_{t-1}C_{t}的形状一致同为[n,h],只不过是上一个时刻的输出,\odot是两个矩阵对位元素的相乘,“+”就是两个矩阵对位元素相加。

(3)有了记忆细胞以后,接下来我们还可以通过输出⻔来控制从记忆细胞到隐藏状态H_{t}的信息的

流动:

\boldsymbol{H}_{t}=\boldsymbol{O}_{t} \odot \tanh \left(\boldsymbol{C}_{t}\right) 式8

这里的计算过程类比式7即可,就不再赘述。

上述过程就是LSTM一个单元细胞的数据流动。

3、pytorch实现LSTM

下面我们再从代码的角度理解LSTM内部结构。

(1)导入必要的包

import torch
import numpy as np
from torch import nn

(2)这里生成LSTM内部的权重参数

def get_params():
    def _one(shape):
        ts = torch.tensor(np.random.normal(0, 0.01, size=shape), device=device, dtype=torch.float32)
        return torch.nn.Parameter(ts, requires_grad=True)
    def _three():
        return (_one((num_inputs, num_hiddens)),
                _one((num_hiddens, num_hiddens)),
                torch.nn.Parameter(torch.zeros(num_hiddens, device=device, dtype=torch.float32), requires_grad=True))
    W_xi, W_hi, b_i = _three()  # 输⼊⻔参数
    W_xf, W_hf, b_f = _three()  # 遗忘⻔参数
    W_xo, W_ho, b_o = _three()  # 输出⻔参数
    W_xc, W_hc, b_c = _three()  # 候选记忆细胞参数
    # 输出层参数 (下面的两行代码新建的权重不属于LSTM,属于输出层;意思是LSTM每个时刻的输出又乘了一个矩阵)
    W_hq = _one((num_hiddens, num_outputs))
    b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device, dtype=torch.float32), requires_grad=True)
    return nn.ParameterList([W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c, W_hq, b_q])

(3)这里用代码实现LSTM内部的计算公式

def lstm(inputs, state, params):
    # 这里获取上面代码初始化的参数
    [W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc,b_c, W_hq, b_q] = params
    (H, C) = state  # 接受初始化的H和C,这里未给出相关的代码,大家知道即可
    outputs = []  # 用来存储每个时间步的输出信息
    for X in inputs:  # 在这里inputs的形状是[t, n, d],通过for循环,可以逐一的拿出每个时刻的输入信息X(X的shape是[n,d])
        # 输入门的计算,公式1
        I = torch.sigmoid(torch.matmul(X, W_xi) + torch.matmul(H, W_hi) + b_i)
        # 遗忘门计算,公式2
        F = torch.sigmoid(torch.matmul(X, W_xf) + torch.matmul(H, W_hf) + b_f)
        # 输出门计算,公式3
        O = torch.sigmoid(torch.matmul(X, W_xo) + torch.matmul(H, W_ho) + b_o)
        # 候选记忆细胞计算,公式5
        C_tilda = torch.tanh(torch.matmul(X, W_xc) + torch.matmul(H, W_hc) + b_c)
        # C的计算,公式7
        C = F * C + I * C_tilda
        # 输出隐藏状计算,公式8
        H = O * C.tanh()
        # 输出层的计算,该过程不包括在LSTM中
        Y = torch.matmul(H, W_hq) + b_q
        # 记录每个时刻的输出信息
        outputs.append(Y)  # 把每个时刻的输出Y追加到列表中
    return outputs, (H, C)  # 返回所有时刻的输出outputs,最终时刻的隐藏状态H、记忆细胞C

(4)生成初始时刻的需要输入的记忆细胞和隐藏状态

def init_lstm_state(batch_size, num_hiddens, device):
    return (torch.zeros((batch_size, num_hiddens), device=device), torch.zeros((batch_size, num_hiddens), device=device))

(5)开始运行程序

if __name__ == '__main__':
    device = torch.device('gpu' if torch.cuda.is_available() else 'cpu')  # 指定运算使用的设备(gpu or cpu)
    batch_size, num_inputs, num_hiddens, num_outputs = 32, 512, 256, 512  # 定义公式中参数的维度
    print('将会使用:', device)
    C, H = init_lstm_state(batch_size, num_hiddens, device)  # 这里生成LSTM初始时刻需要的C和H
    print('开始时刻记忆细胞的输入设置为全0', C)
    print('开始时刻隐藏状态的输入设置为全0', H)
    # 在这里随机生成每个时刻的输入inputs(inputs的shape是[t, n, d])
    shape = (56, 32, 512)  # t=56;n=32;d=512
    inputs = torch.tensor(np.random.normal(0, 0.01, size=shape), device=device, dtype=torch.float32)
    # 通过事先定义好的函数get_params获取LSTM中使用的参数
    params = get_params()
    state = (H, C)
    outputs, (H, C) = lstm(inputs, state, params)
    print(outputs[0].shape)  # 取出第一个时刻的输出,它的shape是[32, 512]

4、总结

从代码中可以看到LSTM每个时刻的单元是共享同一组参数的。

这里列举了LSTM网络中涉及的公式和代码的详细实现,但是在实际应用中,我们只需要做好调包侠即可。

参考文献

[1] Hochreiter, S., & Schmidhuber, J. (1997). Long short-term memory. Neural computation,9(8), 1735-1780.

相关文章

  • LSTM内部结构-我彻底明白了

    原创:李孟启 1、背景 LSTM(Long Short-term Memory,LSTM)长短期记忆[1],是一种...

  • 彻底明白了

    我现在彻底明白了一个事实。 讨厌就是讨厌。不可挽回。 之前的心血付之东流。 就当是在接济一个弱者,做做善事吧。 何...

  • 【一旸的面试流水账】搜狗

    【实习】桌面事业部 一面 1.项目 包括毕设课题、切分等; 细节:LSTM,单元内部结构 2.算法 1)快排:...

  • pytorch1.0 搭建LSTM网络

    torch.nn包下实现了LSTM函数,实现LSTM层。多个LSTMcell组合起来是LSTM。 LSTM自动实现...

  • AWD-LSTM为什么这么棒?

    摘要:AWD-LSTM为什么这么棒,看完你就明白啦! AWD-LSTM是目前最优秀的语言模型之一。在众多的顶会论文...

  • 深度学习——RNN(2)

    前言:前面介绍了LSTM,下面介绍LSTM的几种变种 双向RNN Bidirectional RNN(双向RNN)...

  • keras lstm 杂记

    1、例子 情感分析 情感分析(苏剑林) lstm多曲线预测 lstm多曲线预测(原文) 2、lstm参数 lstm...

  • 详解 LSTM

    今天的内容有: LSTM 思路 LSTM 的前向计算 LSTM 的反向传播 关于调参 LSTM 长短时记忆网络(L...

  • struct和typedef struct彻底明白了

    参看struct和typedef struct彻底明白了 typedef struct和struct的区别: ty...

  • Tensorflow[基础篇]——LSTM的理解与实现

    前言 本文参考了tensorflow github里面的实现的lstm的教程代码6_lstm.ipynb。因为这代...

网友评论

      本文标题:LSTM内部结构-我彻底明白了

      本文链接:https://www.haomeiwen.com/subject/vqracrtx.html