LSTM理解与应用

2023-11-09

首先感谢https://www.jianshu.com/p/9dc9f41f0b29作者的文章,让我对LSTM有了初步的认识。

还有我要推荐李宏毅老师讲的LSTM课程,讲的实在是太容易理解了,https://www.youtube.com/watch?v=xCGidAeyS4M

理解RNN 

想要理解LSTM的前提是理解RNN,RNN(Recurrent Neural Network)是一类用于处理序列数据的神经网络。RNN的典型应用就是NLP,自然语言就是一个时间序列数据,上下文之间存在着一定的联系。RNN 是包含循环的网络,允许信息的持久化。

有时候当前预测位置与上下文中的相关信息间隔较远,当相关信息和当前预测位置之间的间隔不断增大时,RNN 会丧失学习到连接如此远的信息的能力,LSTM对于这种情况却有很好的效果。

 理解LSTM

Long Short Term 网络—— 一般就叫做 LSTM ——是一种 RNN 特殊的类型,可以学习长期依赖信息。

所有 RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中,这个重复的模块只有一个非常简单的结构,例如一个 tanh 层。

LSTM 同样是这样的结构,但是重复的模块拥有一个不同的结构。不同于 单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。 

门结构

LSTM 有通过“门”结构去除或增加信息到细胞状态的能力。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个按位的乘法操作。下图就是这个门

Sigmoid 层输出 0到 1 之间的数值,描述每个部分有多少量可以通过。0代表“不许任何量通过”,1就指“允许任意量通过”! 

第一步决定丢弃信息 

在我们 LSTM 中的第一步是决定我们会从细胞状态中丢弃什么信息。这个决定通过一个称为忘记门层完成。该门会读取 h_{t-1} 和 x_t,输出一个在 0 1之间的数值给每个在细胞状态 C_{t-1} 中的数字。1表示“完全保留”,0表示“完全舍弃”。 

例如在nlp中,当我们看到新的主语,我们希望忘记旧的主语

第二步决定更新的信息 

下一步是确定什么样的新信息被存放在细胞状态中。这里包含两个部分。第一,sigmoid 层称 “输入门层” 决定什么值我们将要更新。然后,一个 tanh 层创建一个新的候选值向量,\tilde{C}_t,会被加入到状态中。下一步,我们会讲这两个信息来产生对状态的更新。比如增加新的主语,来替代旧的需要忘记的主语。

 第三步更新细胞状态

C_{t-1} 更新为 C_t,把旧状态与 f_t 相乘,丢弃掉我们确定需要丢弃的信息。接着加上 i_t * \tilde{C}_t。这就是新的候选值,根据我们决定更新每个状态的程度进行变化。

 第四步确定输出信息

运行一个 sigmoid 层来确定细胞状态的哪个部分将输出出去。接着,把细胞状态通过 tanh 进行处理(得到一个在 -1 到 1 之间的值)并将它和 sigmoid 门的输出相乘,最终仅仅会输出我们确定输出的那部分。

 LSTM参数及其应用的简单解释

LSTM的参数

查找pytorch官方文档中的nn.LSTM可以看到,LSTM模型定义的时候有7个参数

  • input_size – The number of expected features in the input x

  • hidden_size – The number of features in the hidden state h

  • num_layers – Number of recurrent layers. E.g., setting num_layers=2 would mean stacking two LSTMs together to form a stacked LSTM, with the second LSTM taking in outputs of the first LSTM and computing the final results. Default: 1

  • bias – If False, then the layer does not use bias weights b_ih and b_hh. Default: True

  • batch_first – If True, then the input and output tensors are provided as (batch, seq, feature). Default: False

  • dropout – If non-zero, introduces a Dropout layer on the outputs of each LSTM layer except the last layer, with dropout probability equal to dropout. Default: 0

  • bidirectional – If True, becomes a bidirectional LSTM. Default: False

num_layers 为LSTM 堆叠的层数,默认值是1层,如果设置为2,第二个LSTM接收第一个LSTM的计算结果。也就是第一层输入 [ X0 X1 X2 ... Xt],计算出 [ h0 h1 h2 ... ht ],第二层将 [ h0 h1 h2 ... ht ] 作为 [ X0 X1 X2 ... Xt] 输入再次计算,输出最后的 [ h0 h1 h2 ... ht ]。

bias 是偏置值,或者偏移值。没有偏置值就是以0为中轴,或以0为起点。 

 batch_first: 输入输出的第一维是否为 batch_size,默认值 False。input 默认是(seq_len, batch, input_size), batch_first 设置为True,input变成(batch, seq, feature)。

bidirectional: 是否是双向 RNN,默认为:false,若为 true,则:num_directions=2,否则为1。

LSTM的输入

Inputs: input(seq_len, batch, input_size), (h_0, c_0)

h_0 of shape (num_layers * num_directions, batch, hidden_size)

c_0 of shape (num_layers * num_directions, batch, hidden_size)

 If (h_0, c_0) is not provided, both h_0 and c_0 default to zero.

LSTM的输出

Outputs: output(seq_len, batch, num_directions * hidden_size), (h_n, c_n)

h_n of shape (num_layers * num_directions, batch, hidden_size)

c_n of shape (num_layers * num_directions, batch, hidden_size)

例子

>>> rnn = nn.LSTM(10, 20, 2)

>>> input = torch.randn(5, 3, 10)

>>> h0 = torch.randn(2, 3, 20)

>>> c0 = torch.randn(2, 3, 20)

>>> output, (hn, cn) = rnn(input, (h0, c0))

下面我拿kaggle比赛用过的LSTM代码来对参数和应用来做一下 

声明LSTM的NeuralNet

class NeuralNet(nn.Module):
    def __init__(self, embedding_matrix, num_aux_targets):
        super(NeuralNet, self).__init__()
        embed_size = embedding_matrix.shape[1]
        
        self.embedding = nn.Embedding(max_features, embed_size)
        self.embedding.weight = nn.Parameter(torch.tensor(embedding_matrix, dtype=torch.float32))
        self.embedding.weight.requires_grad = False
        self.embedding_dropout = SpatialDropout(0.3)
        
        self.lstm1 = nn.LSTM(embed_size, LSTM_UNITS, bidirectional=True, batch_first=True)
        self.lstm2 = nn.LSTM(LSTM_UNITS * 2, LSTM_UNITS, bidirectional=True, batch_first=True)
    
        self.linear1 = nn.Linear(DENSE_HIDDEN_UNITS, DENSE_HIDDEN_UNITS)
        self.linear2 = nn.Linear(DENSE_HIDDEN_UNITS, DENSE_HIDDEN_UNITS)
        
        self.linear_out = nn.Linear(DENSE_HIDDEN_UNITS, 1)
        self.linear_aux_out = nn.Linear(DENSE_HIDDEN_UNITS, num_aux_targets)
        
    def forward(self, x, lengths=None):
        h_embedding = self.embedding(x.long())
        h_embedding = self.embedding_dropout(h_embedding)
        
        h_lstm1, _ = self.lstm1(h_embedding)
        h_lstm2, _ = self.lstm2(h_lstm1)
        
        # global average pooling
        avg_pool = torch.mean(h_lstm2, 1)
        # global max pooling
        max_pool, _ = torch.max(h_lstm2, 1)
        
        h_conc = torch.cat((max_pool, avg_pool), 1)
        h_conc_linear1  = F.relu(self.linear1(h_conc))
        h_conc_linear2  = F.relu(self.linear2(h_conc))
        
        hidden = h_conc + h_conc_linear1 + h_conc_linear2
        
        result = self.linear_out(hidden)
        aux_result = self.linear_aux_out(hidden)
        out = torch.cat([result, aux_result], 1)
        
        return out

self.lstm1 = nn.LSTM(embed_size, LSTM_UNITS, bidirectional=True, batch_first=True)
#input_size = embed_size   hidden_size = LSTM_UNITS
self.lstm2 = nn.LSTM(LSTM_UNITS * 2, LSTM_UNITS, bidirectional=True, batch_first=True)
#input_size = LSTM_UNITS * 2   hidden_size = LSTM_UNITS

h_lstm1, _ = self.lstm1(h_embedding)
#h_lstm1 的size为LSTM_UNITS * 2
h_lstm2, _ = self.lstm2(h_lstm1)
#h_lstm2 的size也为LSTM_UNITS * 2 

显然这个例子中是双层的LSTM,示意图如下所示

h_conc = torch.cat((max_pool, avg_pool), 1)
Concatenates the given sequence of seq tensors in the given dimension. All tensors must either have the same shape (except in the concatenating dimension) or be empty. 

h_conc_linear1  = F.relu(self.linear1(h_conc))
self.linear1 = nn.Linear(DENSE_HIDDEN_UNITS, DENSE_HIDDEN_UNITS) 输入为隐藏层size,输出也是隐藏层size

最终result输出为1,aux_result输出为7 

 

训练LSTM模型

def train_model(learn,test,output_dim,lr=0.001,
                batch_size=512, n_epochs=5,
                enable_checkpoint_ensemble=True):
    
    all_test_preds = []
    checkpoint_weights = [1,2,4,8,6]
    test_loader = torch.utils.data.DataLoader(test, batch_size=batch_size, shuffle=False)
    n = len(learn.data.train_dl)
    phases = [(TrainingPhase(n).schedule_hp('lr', lr * (0.6**(i)))) for i in range(n_epochs)]
    sched = GeneralScheduler(learn, phases)
    learn.callbacks.append(sched)
    for epoch in range(n_epochs):
        learn.fit(1)  # 表示epoch为1
        test_preds = np.zeros((len(test), output_dim))    
        for i, x_batch in enumerate(test_loader):
            X = x_batch[0].cuda()
            y_pred = sigmoid(learn.model(X).detach().cpu().numpy())
            test_preds[i * batch_size:(i+1) * batch_size, :] = y_pred

        all_test_preds.append(test_preds)


    if enable_checkpoint_ensemble:
        test_preds = np.average(all_test_preds, weights=checkpoint_weights, axis=0)    
    else:
        test_preds = all_test_preds[-1]
        
    return test_preds

主函数 

model = NeuralNet(embedding_matrix, y_aux_train.shape[-1])
#这里的model就是上述的双层LSTM模型
learn = Learner(databunch, model, loss_func=custom_loss)
#实例化Learner,Learner是fastai下面的类
test_preds = train_model(learn,test_dataset,output_dim=7)    
all_test_preds.append(test_preds)

Class Learner

Learner类在fastai的basic_train下,训练模型利用数据通过优化器最小化损失函数,可以自动获得最优模型。一个epoch后所有变量都会出输出,并且可以得到回调函数.

Learner(data:DataBunchmodel:Moduleopt_func:Callable='Adam'loss_func:Callable=Nonemetrics:Collection[Callable]=Nonetrue_wd:bool=Truebn_wd:bool=Truewd:Floats=0.01train_bn:bool=Truepath:str=Nonemodel_dir:PathOrStr='models'callback_fns:Collection[Callable]=Nonecallbacks:Collection[Callback]=<factory>layer_groups:ModuleList=Noneadd_time:bool=Truesilent:bool=None)

fit(epochs:intlr:Union[floatCollection[float], slice]=slice(None, 0.003, None)wd:Floats=Nonecallbacks:Collection[Callback]=None)

learn.recorder.plot() #画出loss与learning rate变化关系图

predict(item:ItemBasereturn_x:bool=Falsebatch_first:bool=Truewith_dropout:bool=False**kwargs)

class GeneralScheduler

GeneralScheduler(learn:Learnerphases:Collection[TrainingPhase], start_epoch:int=None) :: LearnerCallback 

class TrainingPhase[source][test]

TrainingPhase(length:int)

schedule_hp[source][test]
schedule_hp(name, vals, anneal=None)
Adds a schedule for name between vals using anneal.
The phase will make the hyper-parameter vary from the first value in vals to the second, following anneal. If an annealing function is specified but vals is a float, it will decay to 0. If no annealing function is specified, the default is a linear annealing for a tuple, a constant parameter if it's a float.

几个基础的超参数已经命名了,比如例子中的lr,同样也可以添加优化器中有的超参数,比如eps,如果在使用adam的话

  • 'lr' for learning rate
  • 'mom' for momentum (or beta1 in Adam)
  • 'beta' for the beta2 in Adam or the alpha in RMSprop
  • 'wd' for weight decay

代码举例

phases = [(TrainingPhase(n * (cycle_len * cycle_mult**i))
         .schedule_hp('lr', lr, anneal=annealing_cos)
         .schedule_hp('mom', mom)) for i in range(n_cycles)]
sched = GeneralScheduler(learn, phases)
learn.callbacks.append(sched)

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LSTM理解与应用 的相关文章

随机推荐

  • 开关电源纹波的产生、测量和抑制

    一 产生分析 1 随着SWITCH 的开关 电感L 中的电流也是在输出电流的有效值上下波动的 所以在输出端也会出现一个与SWITCH 同频率的纹波 一般所说的纹波就是指这个 它与输出电容的容量和ESR 有关系 这个纹波的频率与开关电源相同
  • Windows 下 sublime text3的安装及设置

    一 安装Sublime Text3 1 下载 官网下载 http www sublimetext com 3 百度云 https pan baidu com s 1X6hD7AH giyahkCK79ZKqw 提取码 e3ai 2 安装 S
  • android recovery 升级和分区

    1 华为手机分区信息 1 shell android df df Filesystem Size Used Free Blksize dev 196M 64K 196M 4096 mnt asec 196M 0K 196M 4096 mnt
  • DBCP连接池配置参数说明

  • 【注意】C++基类的构造函数中,参数与类中已有变量同名,要加上作用域来表示类内变量

    定义一个类 class Text1 public Text1 构造函数 Text1 int pub int pri int pro 重载的构造函数 Text1 int pub void OutputValue 打印类内变量 private
  • java实现一台电脑控制多台手机_涨姿势:教你用电脑远程控制多台手机!终于可以挂手机了!...

    是不是每次坐到电脑前 你的桌面上总会摆好手机 时不时低头瞅瞅 不管是看视频 资讯都会时不时摆弄两下手机 如果你是上班族 是不是因为这个被领导骂过或者斜眼过 好吧 难道你不感觉这样很烦么 小编今天就介绍一个方法让你能用电脑挂手机 关键是过程超
  • iOS死灰复燃SDK

    iOS死灰复燃SDK功能 令iOS APP进入后台或手机锁屏下常也能常驻后台活动 定位 即使杀死APP进程也会适时自动复活APP 让APP能够在后台或进程被杀死之后也能照常发送网络请求 定位 更新数据等操作 具备自动复活功能 SDK版本 V
  • 华为OD机试真题- 找数字【2023Q2】【JAVA、Python、C++】

    题目描述 给一个二维数组nums 对于每一个元素num i 找出距离最近的且值相等的元素 输出横纵坐标差值的绝对值之和 如果没有等值元素 则输出 1 例如 输入数组nums为 0 3 5 4 2 2 5 7 8 3 2 5 4 2 4 对于
  • 2023待学习&待填的坑

    代码cherry pick时解决代码冲突 一 gdb调试 二 git教程实践部分 done 20230805 学习笔记链接 git相关 张杰萌萌哒的博客 CSDN博客 三 编译原理及makefile编写 四 C 课程 60 学习笔记链接 C
  • TOB企业如何借助生态力,实现可持续增长

    近年来 随着经济社会的高速发展 数字化转型已成为企业高质量发展 必答题 企业开始通过购买产品 解决方案或者自研的方式来进行本企业的数字化建设 但是由于内部部门墙或者是系统之间的隔阂 难以做到以整个公司为视角的全面数字化建设 就容易在企业内部
  • 分布式ID生成方案

    分布式ID生成方案 在业务系统中很多场景下需要生成不重复的 ID 比如订单编号 支付流水单号 优惠券编号等都需要使用到 在我们业务数据量不大的时候 单库单表完全可以支撑现有业务 数据再大一点搞个MySQL主从同步读写分离也能对付 但随着数据
  • JAVA环境变量path配置及其作用

    1 环境变量的作用是为了在dos的任意目录 可以去使用Java和javac 命令 2 先配置JAVA HOME 指向jdk安装的主目录 3 编辑path环境变量 增加 JAVA HOME bin 其中 代表引用 这样写的好处就是将来的jdk
  • springboot WxJava 收发企业微信 应用消息

    在Spring Boot中 同样可以使用WxJava来实现企业微信应用消息的收发功能 WxJava是一款基于微信公众号 小程序 企业号的Java SDK 提供了丰富的功能 包括消息收发 菜单管理 用户管理等 以下是简单的WxJava实现企业
  • HTML加js实现计算文件哈希值,前端使用js计算文件的MD5值

    在前端开发时有时需要计算文件的 MD5 值传给后端用作比较文件的准确性和完整性 还应用到了现代浏览器中都实现了的类 FileReader 它的实例的 readAsBinaryString 方法 用来读取文件的原始二进制数据 创建HTML部分
  • eclipse的下载及安装

    目录 1 eclipse的下载 2 2 eclipse的安装 4 1 eclipse的下载 eclipse官网地址 https www eclipse org 进入eclipse官网选择Download 选择Download Package
  • 300. 最长上升子序列

    300 最长上升子序列 给定一个无序的整数数组 找到其中最长上升子序列的长度 示例 输入 10 9 2 5 3 7 101 18 输出 4 解释 最长的上升子序列是 2 3 7 101 它的长度是 4 package com wangyg
  • 为什么LTE PA用GaAs工艺而GSM PA用CMOS工艺?

    为什么LTE PA用GaAs工艺而GSM PA用CMOS工艺 2017 09 14 00 00 小编参加了Qorvo公司发布会 会上了解到Qorvo的主要产品包括GaAS和CMOS 的PA 会后小编提问到这两种PA的区别以及CMOS PA在
  • 对象池(连接池):commons-pool2源码解析:GenericObjectPool的borrowObject方法

    为什么会有对象池 在实际的应用工程当中 存在一些被频繁使用的 创建或者销毁比较耗时 持有的资源也比较昂贵的一些对象 比如 数据库连接对象 线程对象 所以如果能够通过一种方式 把这类对象统一管理 让这类对象可以被循环利用的话 就可以减少很多系
  • 均值已知检验方差_SAS读书笔记:方差分析

    方差分析 Analysis of Variance ANOVA 就是用于检验两组或两组以上的均值是否具有显著性差异的数理统计方法 有单因素方差分析和多因素方差分析 1 基本原理 在方差分析中 把要分析的变量称为响应变量 对响应变量取值有影响
  • LSTM理解与应用

    首先感谢https www jianshu com p 9dc9f41f0b29作者的文章 让我对LSTM有了初步的认识 还有我要推荐李宏毅老师讲的LSTM课程 讲的实在是太容易理解了 https www youtube com watch