3.3-LSTM的改进

文章目录

  • 1改进点
    • 1.1多层化
    • 1.2 dropout
      • 1.2.1具体概念
      • 1.2.2应该插入到LSTM模型的哪里
    • 1.3权重共享
  • 2改进之后的LSTMLM的代码实现
    • 2.1初始化
    • 2.2前向计算
    • 2.3反向传播
  • 3相应的学习代码的实现
  • 4总结

1改进点

1.1多层化

  1. 加深神经网络的层数往往能够学习更复杂的模式;因此这里增加了LSTM层的数量;如下图所示:

    1. 第一个 LSTM 层的隐藏状态是第二个LSTM层的输入;
    2. 关于叠加几个层,这是超参数调优的范畴了;需要根据要解决的问题的复杂程度、能给到的训练数据的规模来确定;
    3. 在 PTB 数据集上学习语言模型的情况下,当 LSTM 的层数为 2 ~ 4 时,可以获得比较好的结果

    在这里插入图片描述

1.2 dropout

详细可以再看一下:https://1drv.ms/b/s!AvF6gzVaw0cNjqYc_hrdnGUeqyCXWg?e=hn5AoB;

1.2.1具体概念

  1. 通过加深层,可以创建表现力更强的模型,但是这样的模型往往会发生过拟合;过拟合即模型泛化能力差;

  2. RNN 比常规的前馈神经网络更容易发生过拟合,因此 RNN 的过拟合对策非常重要;

  3. 如何缓解过拟合:

    1. 优先考虑:一是增加训练数据;二是降低模型的复杂度
    2. 还有正则化的方法;即给予惩罚;
    3. dropout这种,在训练时随机忽略层的一部分(比如 50%)神经元,也可以被视为一种正则化;
  4. dropout的具体结构

    1. Dropout 随机选择一部分神经元,然后忽略它们,停止向前传递信号;具体而言,训练时,每传递一次数据,就会随机选择要删除的神经元。 然后,测试时,虽然会传递所有的神经元信号,但是对于各个神经元的输出, 要乘上训练时的删除比例后再输出

    2. 下图是概念图:

      在这里插入图片描述

  5. dropout的代码如下(直接看了书上的结果,没有自己做一遍):

    1. forward函数中,是一个判断;训练时需要按照设置的比例忽略一些神经元,忽略的方法就是将x中某些元素值设置为0;测试时传递所有的神经元信号,但是都要乘上删除比例;
    2. 正向传播时没有传递信号的神经元,反向传播时信号就停在那里;换句话说,这些神经元dout*self.mask的值为0,即这些神经元的梯度不会影响后续的反向传播;

    在这里插入图片描述

  6. 下图是书上的一个实验:

    1. 加了dropout之后,训练集和测试集上的表现更相近,说明缓解了过拟合;

    在这里插入图片描述

1.2.2应该插入到LSTM模型的哪里

  1. 不能在水平方向上插入

    1. 水平方向上是这样插入的:

      在这里插入图片描述

    2. 由于每次dropout都有神经元不进行前向计算,这存在信息丢失;

    3. 并且我们会设置stateful参数为true,即下一次Time LSTM前向计算时会继承上一次Time LSTM的最后一个LSTM层的隐藏状态;这样一来,这个信息丢失会随着时间的延续而不断累积;

    4. 信息丢失多了,那就是说有用的信息少了,噪声多了;

    5. 所以不建议在水平方向上加入dropout

  2. 因此可以在垂直方向上插入;如下图所示;这样水平方向上不存在信息丢失,因此至少输入的数据的信息都学到了;

    在这里插入图片描述

  3. 但是也有方法来实现水平方向上的dropout(正则化)

    1. “变分 Dropout”(variational dropout):同一层的 Dropout 使用相同的 mask。这里所说的 mask 是指决定是否传递数据的随机布尔值;这样每一层信息丢失的都是那一部分;那么在其它层的dropout信息丢失的又都是另外一部分,这样互相找补找补就会好很多;

      在这里插入图片描述

1.3权重共享

  1. 通过前面了解LSTM的结构,我们可以感受到,LSTM的参数量是RNN的好几倍;加上多层化的话,参数量更多;因此可以适当减少一下参数量,在能够保证模型效果的前提下;而且参数量减少了还能抑制过拟合;见论文;

  2. 权重共享前提是得两个层的权重确实是一样的;像本书中这里说的权重共享,是将Embedding 层和 Softmax 前的 Affine 层共享权重;这两个部分用的权重维度是一样的;

    1. 具体而言,Embedding层的权重维度为(V,H);Affine 层的权重维度为(H,V)
    2. 因此只需将 Embedding 层权重的转置设置为 Affine 层的权重即可;

    在这里插入图片描述

2改进之后的LSTMLM的代码实现

本书学习过程中的代码已全部搬运至gitee:https://gitee.com/gaoyan1518/basic-nlp;

代码位于:LSTM_model/better_LSTMLM.py

  1. 首先需要构建一下Time Dropout层;由于Dropout层只是单纯的给某些神经元遮蔽掉,多个时刻也是一样的处理,时刻与时刻之间的Dropout层是独立的;所以不需要像Time LSTM层那样在forward里面循环T次;

  2. 另外这里在实现的时候,是在训练阶段就进行了缩放,所以测试阶段直接就返回了x,代码如下;如果训练阶段没有进行缩放,则测试阶段就要对x乘上删除比例;1.0 - self.dropout_ratio是删除比例;【可以看这个博客】

    class TimeDropout:def __init__(self, dropout_ratio=0.5):self.params, self.grads = [], []self.dropout_ratio = dropout_ratioself.mask = Noneself.train_flg = Truedef forward(self, xs):if self.train_flg:flg = cupy.random.rand(*xs.shape) > self.dropout_ratioscale = 1 / (1.0 - self.dropout_ratio) # 删除比例的倒数;删除的越多,剩余神经元的权重就越小self.mask = flg.astype(cupy.float32) * scalereturn xs * self.maskelse:return xsdef backward(self, dout):return dout * self.mask

2.1初始化

  1. 与之前的LSTMLM相比,这里就是多层化了、权重共享了、加入了dropout,其他的都一样;代码如下:

    class BetterRnnlm:def __init__(self, vocab_size=10000, wordvec_size=650, hidden_size=650, dropout_ratio=0.5):V, D, H = vocab_size, wordvec_size, hidden_sizern = np.random.randnembed_W = (rn(V, D) / 100).astype('f') # 与affine_w权重共享lstm_Wx1 = (rn(D, 4 * H) / np.sqrt(D)).astype('f') # 同样是一个整合之后的权重矩阵lstm_Wh1 = (rn(H, 4 * H) / np.sqrt(H)).astype('f')lstm_b1 = np.zeros(4 * H).astype('f')lstm_Wx2 = (rn(H, 4 * H) / np.sqrt(H)).astype('f')lstm_Wh2 = (rn(H, 4 * H) / np.sqrt(H)).astype('f')lstm_b2 = np.zeros(4 * H).astype('f')affine_b = np.zeros(V).astype('f')if GPU:embed_W = to_gpu(embed_W)lstm_Wx1 = to_gpu(lstm_Wx1)lstm_Wx2 = to_gpu(lstm_Wx2)lstm_Wh1 = to_gpu(lstm_Wh1)lstm_Wh2 = to_gpu(lstm_Wh2)lstm_b1 = to_gpu(lstm_b1)lstm_b2 = to_gpu(lstm_b2)affine_b = to_gpu(affine_b)self.layers = [TimeEmbedding(embed_W),TimeDropout(dropout_ratio),TimeLSTM(lstm_Wx1, lstm_Wh1, lstm_b1, stateful=True),TimeDropout(dropout_ratio),TimeLSTM(lstm_Wx2, lstm_Wh2, lstm_b2, stateful=True),TimeDropout(dropout_ratio),TimeAffine(embed_W.T, affine_b)  # weight tying!!]self.loss_layer = TimeSoftmaxWithLoss()self.lstm_layers = [self.layers[2], self.layers[4]]self.drop_layers = [self.layers[1], self.layers[3], self.layers[5]]self.params, self.grads = [], []for layer in self.layers:self.params += layer.paramsself.grads += layer.grads
    

2.2前向计算

  1. 和之前一样,只不过这里需要先把dropout层设置为训练模式;如下图所示:

    在这里插入图片描述

  2. 代码如下:

        def predict(self, xs, train_flg=False):'''@param xs: (N, T);输入的数据;@param train_flg: 是否是训练阶段的标记;用于dropout层的计算方式选择;@return xs: (N,T,V);Time Affine层之后的输出,即得分;'''for layer in self.drop_layers:# 先将所有的dropout层都设置为训练模式layer.train_flg = train_flgfor layer in self.layers:xs = layer.forward(xs)return xsdef forward(self, xs, ts, train_flg=True):'''@param xs: (N, T);输入的数据;@param ts: (N, T);监督数据;(N,T)时不是独热编码形式;@param train_flg: 是否是训练阶段的标记;用于dropout层的计算方式选择;@return loss: 损失值;'''score = self.predict(xs, train_flg)loss = self.loss_layer.forward(score, ts)return loss
    

2.3反向传播

  1. 反向传播和LSTMLM一样;另外,重设状态的函数稍有区别;再就是还有加载和保存参数的函数;如下图所示;

    在这里插入图片描述

3相应的学习代码的实现

代码位于:LSTM_model/train_better_LSTMLM.py

  1. 由于这里将Embedding层和Affine层进行权重共享,因此在RNN_model/rnnTrainer.pyRnnlmTrainer.fit函数中,需要在梯度计算之后整合相同的权重对应的梯度值;即加入了remove_duplicate函数;如下图所示;

    在这里插入图片描述

  2. 在学习过程中,每学习一个epoch,就在验证集上计算困惑度,如果困惑度变大了,则降低学习率,让模型训练更加稳定;

    1. 所以这里还需要读取验证集数据;与读取测试集数据一样;同样考虑了GPU的运行;

    2. 我们只需要在调用RnnlmTrainer.fit函数时指定max_epoch=1就可以复用RnnlmTrainer.fit函数的同时,满足此处每个epoch都进行验证的需求;

    3. 验证前通过model.reset_state()重置模型的状态(即Time LSTM层的初始h和c置为空);验证完开启下一轮训练前也重置一次;

      1. 回忆改进前LSTMLM的学习过程,我们好像没有在每个epoch结束后重置状态;这里我自己试了一下在每个epoch开始前都重置初始的状态,结果和没有重置差不多
      2. 那这里重置的意义在于,因为要看在验证集上的表现,因此来自训练集训练好的状态当然不能要,否则就收到训练集影响了;
    4. 通过调用ppl = eval_perplexity(model, corpus_val)在测试集上走一遍前向计算的流程,获取模型在验证集上的困惑度值;读取数据的地方与RnnlmTrainer.fit函数中的有所不同,但本质上是一样的;eval_perplexity函数代码如下:

      def eval_perplexity(model, corpus, batch_size=10, time_size=35):print('evaluating perplexity ...')corpus_size = len(corpus)total_loss, loss_cnt = 0, 0max_iters = (corpus_size - 1) // (batch_size * time_size)jump = (corpus_size - 1) // batch_sizefor iters in range(max_iters):xs = np.zeros((batch_size, time_size), dtype=np.int32)ts = np.zeros((batch_size, time_size), dtype=np.int32)time_offset = iters * time_size # 每过一个iters就跳过每个句子的time_size个单词offsets = [time_offset + (i * jump) for i in range(batch_size)]for t in range(time_size):for i, offset in enumerate(offsets):# 这里xs和ts是都从corpus中获取;xs[i, t] = corpus[(offset + t) % corpus_size]ts[i, t] = corpus[(offset + t + 1) % corpus_size]try:xs = to_gpu(xs)ts = to_gpu(ts)loss = model.forward(xs, ts, train_flg=False) # 将dropout层设置为测试模式except TypeError:xs = to_gpu(xs)ts = to_gpu(ts)loss = model.forward(xs, ts)total_loss += loss# 实现了一个进度条sys.stdout.write('\r%d / %d' % (iters, max_iters))sys.stdout.flush()print('')ppl = np.exp(total_loss / max_iters) # 返回验证集上的困惑度return ppl
      
  3. 从生成模型开始的学习代码如下:

        # 生成模型model = BetterRnnlm(vocab_size, wordvec_size, hidden_size)optimizer = SGD(lr)trainer = RnnlmTrainer(model, optimizer)best_ppl = float('inf')for epoch in range(max_epoch):# 每次的fit都只训练一个epoch,所以传入的max_epoch=1trainer.fit(xs, ts, max_epoch=1, batch_size=batch_size, time_size=time_size, max_grad=max_grad)model.reset_state()ppl = eval_perplexity(model, corpus_val) # 在验证集上进行前向计算然后评价困惑度print('valid perplexity: ', ppl)if best_ppl > ppl:# 此时这一个epoch的模型效果更好best_ppl = pplmodel.save_params()else:# 否则困惑度更大,模型效果变差,则调整学习率lr /= 4.0optimizer.lr = lrmodel.reset_state() # 验证完了之后下个epoch训练前还要重置一下h和cprint('-' * 50)# 基于验证数据进行评价model.reset_state()ppl_test = eval_perplexity(model, corpus_test)print('test perplexity: ', ppl_test)
    
  4. 训练过程和结果如下:

    1. 由于堆叠了Time LSTM层,网络的参数量大幅增加,且相关超参数也增加了;可以看到显卡占用比原来增加了:

      在这里插入图片描述

    2. 每次训练完都会进行验证集上的困惑度的计算:

      在这里插入图片描述

    3. 下图是训练结果;训练集上最终的困惑度降低到了三四十;验证集上困惑度为79;测试集上的困惑度为76;如下图所示:

      在这里插入图片描述

4总结

  1. 本章我们用LSTM来代替RNN,从而缓解梯度消失的问题,能够控制梯度的流动;
  2. 本节咱们加深了神经网络的层数,为了防止过拟合,加入了dropout层;另外,对于能够权重共享的,我们进行权重共享;实现了效果的提升;
  3. 书上还有一部分是其他的一些研究,这里就不说了;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/381021.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5种梯度下降法的公式

5种梯度下降法的公式推演: 1. 梯度下降 (Gradient Descent) 梯度下降法的更新公式为: θ t 1 θ t − η ∇ θ J ( θ ) \theta_{t1} \theta_t - \eta \nabla_\theta J(\theta) θt1​θt​−η∇θ​J(θ) 其中, θ t \theta_t θt​…

Tomcat服务器

1.Tomcat定义以及作用 Web服务器是一个应用程序(软件),对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作。(不用程序员自己写代码去解析http协议规则,比如不用考虑响应码的问题,以及响应数据应该如何写),让…

ZK学习笔记

ZK 一.基本概念 Zookeeper是⼀个开源的分布式协调服务,其设计⽬标是将那些复杂的且容易出错的分布式⼀致性服务封装起来,构成⼀个⾼效可靠的原语集,并以⼀些简单的接⼝提供给⽤户使⽤。 zookeeper是⼀个典型的分布式数据⼀致性的解决⽅案&…

在 PostgreSQL 里如何实现数据的冷热数据分层存储的自动化策略调整?

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!📚领书:PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 里如何实现数据的冷热数据分层存储的自动化策略调整 在 PostgreSQL 里如何实现数据的冷…

ip地址是电脑还是网线决定的

在数字化时代的浪潮中,网络已经成为了我们日常生活和工作不可或缺的一部分。当我们谈论网络时,IP地址无疑是一个核心的概念。然而,关于IP地址的分配和决定因素,很多人可能存在误解。有些人认为IP地址是由电脑决定的,而…

mybatisPlus和mybatis的版本冲突问题、若依换成MP、解决git无法推送、使用若依框架的swagger、以后再遇到团队项目应该怎么做。

20240716 一. mybatisPlus和mybatis的版本冲突问题1. 使用前的准备2. 我遇到了一个很严重的问题。3. 解决问题,好吧也没解决,发现问题!! 二、该死的git!!!!1. 解决无法在idea中使用g…

CBSD bhyve Ubuntu 配置vnc登录管理

CBSD介绍 CBSD是为FreeBSD jail子系统、bhyve、QEMU/NVMM和Xen编写的管理层。该项目定位为一个综合解决方案的单一集成工具,用于使用预定义的软件集以最少的配置快速构建和部署计算机虚拟环境。 虽然CBSD没有提供额外的操作系统级功能,但它极大地简化了…

fatal: not a git repository (or any of the parent directories): .git

问题描述: 通过git pull 拉取代码提示: fatal: not a git repository (or any of the parent directories): .git 这个错误信息表明你当前所在的目录不是一个 Git 仓库,或者任何父目录中都没有 .git 目录。 问题解决: 确认当前目…

Windows 、Linux、MacOS 进程管理机制

本心、输入输出、结果 文章目录 Windows 、Linux、MacOS 进程管理机制前言Windows 进程管理机制Linux 进程管理macOS 进程管理内存不够了,几个操作系统如何处理Windows 、Linux、MacOS 进程管理机制 编辑 | 简简单单 Online zuozuo 地址 | https://blog.csdn.net/qq_15071263 …

<数据集>混凝土缺陷检测数据集<目标检测>

数据集格式:VOCYOLO格式 图片数量:7353张 标注数量(xml文件个数):7353 标注数量(txt文件个数):7353 标注类别数:6 标注类别名称:[exposed reinforcement, rust stain, Crack, Spalling, Efflorescence…

JavaSE从零开始到精通

1.前置知识 JVM:java virtrual machine, java虚拟机, 专门用于执行java代码的一款软件。可以将class文件,转换为机器认识的机器码,因为我们的计算机只认识010101的二进制语言。JRE:java runtime enviroment, java运行时环境, jav…

CMake生成Debug和Release目标程序时的一些配置

文章介绍 本文章将介绍在Windows和Linux平台,生成可执行程序时,如何设置Debug和Release的一些属性。主要介绍如何设置目标程序的生成路径,以及运行时库的设置和目标程序版本号的设置。 Debug和Release模式 -O,-O1: 这两个命令的效果是一样…

C++学习笔记-C++11中的智能指针

1.智能指针介绍 智能指针是C的特性用法,是一个类似指针功能的类对象,其目的是为了更好的管理动态分配的内存,避免出现内存泄漏、悬空指针等问题。C11的标准库里提供了三种智能指针模板类,分别是std::unique_ptr、std::shared_ptr…

深入解析HNSW:Faiss中的层次化可导航小世界图

层次化可导航小世界(HNSW)图是向量相似性搜索中表现最佳的索引之一。HNSW 技术以其超级快速的搜索速度和出色的召回率,在近似最近邻(ANN)搜索中表现卓越。尽管 HNSW 是近似最近邻搜索中强大且受欢迎的算法,…

Flutter动画详解第二篇之显式动画(Explicit Animations)

目录 前言 一、定义 1.AnimationController 1.常用属性 1. value 2. status 3. duration 2.常用方法 1.forward 2.reverse 3.repeat 4.stop 5. reset 6. animateTo(double target, {Duration? duration, Curve curve Curves.linear}) 7.animateBack(double ta…

大数据之写入Doris数据问题

1. 解决Key columns should be a ordered prefix of the schema. KeyColumns[1] (starts from zero) is xxx, but 背景 create table if not exists XXX ( fathercorp varchar(50), id decimalv3(38,0) ) ENGINEOLAP UNIQUE KEY(id) COMMENT xxxx DISTRIBUTED BY HASH(id) BUC…

C#实现数据采集系统-实现功能介绍

系统介绍 我们这里主要使用C#( .Net 6)来实现一个数据采集系统,从0到1搭建数据采集系统,从系统分析,功能拆解,到一一实现 数据采集 数据采集是企业信息化和数字化转型过程中的关键环节,它涉及到从生产设备、传感器…

数据结构之细说链表

1.1顺序表的问题以及思考 经过上一篇顺序表的学习,我们知道顺序表还是有很多缺点 顺序表的缺点: 1.中间/头部的插入删除,实际复杂度为O(N) 2.增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗 3.扩容一般…

实战打靶集锦-31-monitoring

文章目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 ssh服务4.2 smtp服务4.3 http/https服务 5. 系统提权5.1 枚举系统信息5.2 枚举passwd文件5.3 枚举定时任务5.4 linpeas提权 6. 获取flag 靶机地址:https://download.vulnhub.com/monitoring/Monitoring.o…

【BUG】已解决:python setup.py bdist_wheel did not run successfully.

已解决:python setup.py bdist_wheel did not run successfully. 目录 已解决:python setup.py bdist_wheel did not run successfully. 【常见模块错误】 解决办法: 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主…