精华内容
下载资源
问答
  • 基于keras的双层LSTM网络和双向LSTM网络中,都会用到 LSTM层,主要参数如下: LSTM(units,input_shape,return_sequences=False) units:隐藏层神经元个数 input_shape=(time_step, input_feature):time_step是...

    1 前言

    基于keras的双层LSTM网络双向LSTM网络中,都会用到 LSTM层,主要参数如下:

    LSTM(units,input_shape,return_sequences=False)
    
    • units:隐藏层神经元个数
    • input_shape=(time_step, input_feature):time_step是序列递归的步数,input_feature是输入特征维数
    • return_sequences: 取值为True,表示每个时间步的值都返回;取值为False,表示只返回最后一个时间步的取值

    本文以MNIST手写数字分类为例,讲解双层LSTM网络和双向LSTM网络的实现。关于MNIST数据集的说明,见使用TensorFlow实现MNIST数据集分类

    笔者工作空间如下:

    代码资源见--> 双隐层LSTM和双向LSTM

    2 双层LSTM网络

    双层LSTM网络结构

     DoubleLSTM.py

    from tensorflow.examples.tutorials.mnist import input_data
    from keras.models import Sequential
    from keras.layers import Dense,LSTM
    
    #载入数据
    def read_data(path):
        mnist=input_data.read_data_sets(path,one_hot=True)
        train_x,train_y=mnist.train.images.reshape(-1,28,28),mnist.train.labels,
        valid_x,valid_y=mnist.validation.images.reshape(-1,28,28),mnist.validation.labels,
        test_x,test_y=mnist.test.images.reshape(-1,28,28),mnist.test.labels
        return train_x,train_y,valid_x,valid_y,test_x,test_y
    
    #双层LSTM模型
    def DoubleLSTM(train_x,train_y,valid_x,valid_y,test_x,test_y):
        #创建模型
        model=Sequential()
        model.add(LSTM(64,input_shape=(28,28),return_sequences=True))  #返回所有节点的输出
        model.add(LSTM(32,return_sequences=False))  #返回最后一个节点的输出
        model.add(Dense(10,activation='softmax'))
        #查看网络结构
        model.summary()
        #编译模型
        model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])
        #训练模型
        model.fit(train_x,train_y,batch_size=500,nb_epoch=15,verbose=2,validation_data=(valid_x,valid_y))
        #评估模型
        pre=model.evaluate(test_x,test_y,batch_size=500,verbose=2)
        print('test_loss:',pre[0],'- test_acc:',pre[1])
       
    train_x,train_y,valid_x,valid_y,test_x,test_y=read_data('MNIST_data')
    DoubleLSTM(train_x,train_y,valid_x,valid_y,test_x,test_y)

    每层网络输出尺寸:

    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    lstm_5 (LSTM)                (None, 28, 64)            23808     
    _________________________________________________________________
    lstm_6 (LSTM)                (None, 32)                12416     
    _________________________________________________________________
    dense_5 (Dense)              (None, 10)                330       
    =================================================================
    Total params: 36,554
    Trainable params: 36,554
    Non-trainable params: 0

    由于第一个LSTM层设置了 return_sequences=True,每个节点的输出值都会返回,因此输出尺寸为 (None, 28, 64) 

    由于第二个LSTM层设置了 return_sequences=False,只有最后一个节点的输出值会返回,因此输出尺寸为 (None, 32) 

     训练结果:

    Epoch 13/15
     - 17s - loss: 0.0684 - acc: 0.9796 - val_loss: 0.0723 - val_acc: 0.9792
    Epoch 14/15
     - 18s - loss: 0.0633 - acc: 0.9811 - val_loss: 0.0659 - val_acc: 0.9822
    Epoch 15/15
     - 17s - loss: 0.0597 - acc: 0.9821 - val_loss: 0.0670 - val_acc: 0.9812
    test_loss: 0.0714278114028275 - test_acc: 0.9789000034332276

    3 双向LSTM网络

    双向LSTM网络结构
    from tensorflow.examples.tutorials.mnist import input_data
    from keras.models import Sequential
    from keras.layers import Dense,LSTM,Bidirectional
    
    #载入数据
    def read_data(path):
        mnist=input_data.read_data_sets(path,one_hot=True)
        train_x,train_y=mnist.train.images.reshape(-1,28,28),mnist.train.labels,
        valid_x,valid_y=mnist.validation.images.reshape(-1,28,28),mnist.validation.labels,
        test_x,test_y=mnist.test.images.reshape(-1,28,28),mnist.test.labels
        return train_x,train_y,valid_x,valid_y,test_x,test_y
    
    #双向LSTM模型
    def BiLSTM(train_x,train_y,valid_x,valid_y,test_x,test_y):
        #创建模型
        model=Sequential()
        lstm=LSTM(64,input_shape=(28,28),return_sequences=False)  #返回最后一个节点的输出
        model.add(Bidirectional(lstm))  #双向LSTM
        model.add(Dense(10,activation='softmax'))
        #编译模型
        model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])
        #训练模型
        model.fit(train_x,train_y,batch_size=500,nb_epoch=15,verbose=2,validation_data=(valid_x,valid_y))
        #查看网络结构
        model.summary()
        #评估模型
        pre=model.evaluate(test_x,test_y,batch_size=500,verbose=2)
        print('test_loss:',pre[0],'- test_acc:',pre[1])
       
    train_x,train_y,valid_x,valid_y,test_x,test_y=read_data('MNIST_data')
    BiLSTM(train_x,train_y,valid_x,valid_y,test_x,test_y)

     每层网络输出尺寸:

    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    bidirectional_5 (Bidirection (None, 128)               47616     
    _________________________________________________________________
    dense_6 (Dense)              (None, 10)                1290      
    =================================================================
    Total params: 48,906
    Trainable params: 48,906
    Non-trainable params: 0

    由于LSTM层设置了 return_sequences=False,只有最后一个节点的输出值会返回,每层LSTM返回64维向量,两层合并共128维,因此输出尺寸为 (None, 128) 

    训练结果: 

    Epoch 13/15
     - 22s - loss: 0.0512 - acc: 0.9839 - val_loss: 0.0632 - val_acc: 0.9790
    Epoch 14/15
     - 22s - loss: 0.0453 - acc: 0.9865 - val_loss: 0.0534 - val_acc: 0.9832
    Epoch 15/15
     - 22s - loss: 0.0418 - acc: 0.9869 - val_loss: 0.0527 - val_acc: 0.9830
    test_loss: 0.06457789749838412 - test_acc: 0.9795000076293945

     

    展开全文
  • 双层LSTM】IMDB文本情感分析完整代码 基于tensorflow(含数据+词向量) 基于tensorflow的IMDB文本情感分析完整代码(包含数据和词向量可直接运行),网络结构采用双层LSTM
  • 基于tensorflow的IMDB文本情感分析完整代码(包含数据和词向量可直接运行),网络结构采用双层LSTM
  • 想搭建一个循环神经网络的双向双层LSTM神经网络,用于行为识别,数据集已有
  • BiLSTM+CRF: 如果看了之后还看不懂,我自罚三杯!!! 参考的是国外一个很好的博客,原文链接:https://createmomo.github.io/2017/12/06/CRF-Layer-on-the-Top-of-BiLSTM-7/ 现在抽空学习一下知识图谱方面的知识...

    BiLSTM+CRF:

    如果看了之后还看不懂,我自罚三杯!!!

    参考的是国外一个很好的博客,原文链接:https://createmomo.github.io/2017/12/06/CRF-Layer-on-the-Top-of-BiLSTM-7/

    现在抽空学习一下知识图谱方面的知识

    1、Introduction

    1.1 开始之前:

           假设我们有两个实体类别:person+location。在我们的数据集中,我们有五个标签,B-person、I-person、B-location、I-  location以及标签O。在一个句子x(小明生活在北京)中,小明是一个person实体,北京是一个location实体。其他的元素如“生”“活”“在”都属于O。

    1.2 BiLSTM-CRF模型:

                                  

             BilSTM-CRF模型输入:wi是句子中每一个元素,转换成字向量之后作为输入。

             BilSTM-CRF模型输出:每一个元素相对应的标签。

             BiLSTM模型输出:每一个元素对每个标签的概率,下图中黄色部分。这些会作为CRF的输入。

                                        

    1.3 如果没有CRF层

    如果没有CRF层,我们貌似也可以BiLSTM层每个元素输出的最大概率标签当做最后结果,如下图所示,w0的最大概率输出标签是B-person,那么直接把这个元素最后结果当做B-person,相应的w1是I-person,等等。

                                        

    上面说的貌似是正确的,但这种情况下元素之间的标签不存在约束关系,即B-person之后绝对不能跟B-person,I-person之前绝对不能是I-organization,所以就会出现下面的错误。

                                     

    1.4 CRF层能够学习到上面所说的限制关系

    CRF层能够对最后的结果加上一些限制来确保结果是正确的,这些限制可以在训练过程中通过训练集自动学习得到。这些限制可能有:

    1. 句子中的第一个字可能是B-或者O,不能是I-
    2. B-label I-label2 I-label3中,label1、label2、label3应该是相同的实体label。也就是B-person后面不能跟I-location
    3. O后面不能跟I-label,这是明显的。

    2 、CRF层:

          在CRF层,存在两种类型的scores,这个两种scores是crf层重要部分。

    2.1 Emission score

          Emission scores主要来自于BiLSTM层,如下图所示,第一个元素对于B-person的得分是1.5。

                              

          为了方便观察,给每个label加 一个index。

    我们使用xiyj来代表emission score,其中i表示第几个元素,yj表示label的index。例如上上个图中,xi=1,yj=2= xw1,B-organization=0.1,代表的是第二个元素是B-organization的得分。

    2.2 Transition score

           tyiyj表示transition score,例如,tB-person,I-person=0.9意味着B-person到下一个字是I-person的概率是0.9,因此,transition包含所有标签之间的转移概率。为了是transition矩阵更鲁棒,我们新加两个label,start和end,start表示一个句子的开始,并不是第一个字,end表示句子的结束。样例如下图所示:

    显然上述矩阵是存在一些限制关系的,如:transition矩阵从start到I-person和I-organization的概率是很低的,因为第一个字应该以B-或者O-开始,而不是I-;B-person到I-organization的概率很低,因为不能从一个label的开始到另一个标签的中间;O-到I-的概率很低,因为不可能呀!!!!那么如何获得这个矩阵呢?

    实际上,transition矩阵是整个模型的一个参数,训练之前,你可以随机初始化这个矩阵,在训练过程中,这个矩阵会不断的更新,换言之,CRF层能够学习到这个矩阵。

    2.3 CRF lossfunction

            这一层的损失包含真实路径和所有路径的得分和,真实路径应该是最高得分。(真实路径也就是每个元素的真是标签,举个例子,一个句子有5个元素,标签数量是7个,那么路径个数是7^5,如下图所示,每条路径都有一个得分,也可以说是一个概率,真实路径只有一个,使其最大就好了)

          

    那么总得分就是Ptotal=P1+ P2+……+ Pn=eS1+ eS2+……+ eSn,e是自然对数,下一节会介绍如何计算Si。损失计算公式如下:

    LossFunction=PRealPath/( P1+ P2+……+ Pn)

    在训练期间,参数的更新使这个比重越来越大。

    1. 如何计算每个路径的得分
    2. 如何计算所有路径的总得分
    3. 计算总得分的时候,有必要列出来所有路径吗(显然是NO)

    2.4 真实路径

           在训练过程中,lossFunction只需要两个得分,真实路径score+全部路径的score。

    真实路径score的计算:句子有5个元素,7个label,真实路径是START B-Person I-Person O B-Organization O END

    Si=EmissionScore+TransitionScore

    EmissionScore=(x0,START)+(x1,BPerson)+(x2,IPerson)+(x3,O)+(x4,BOrganization)+(x5,O)+(x6,END)     

    x1,BPerson是第一个字是B-person的概率,这就是BiLSTM这一层的输出呀

    x0,STARTx6,END我们赋值为0

    TransitionScore=tSTART−>BPerson + tBPerson−>IPerson + tIPerson−>O + t0−>BOrganization + tBOrganization−>O + tO−>END

    tBPerson−>IPersonCRFtransition的参数,表示B-personI-person的转移概率

    2.5 全路径score

          可以计算出所有路径的score然后相加得到全路径的得分,但这样的话计算量是相当大的,训练是很耗时的。

          下面的例子会让你了解如何快速计算全路径的score,一步一步来,不着急,你会明白其中的奥妙。

    Step1LossFunction=PRealPath/( P1+ P2+……+ Pn)

                 LogLossFunction=log(PRealPath/( P1+ P2+……+ Pn))

                 最小化

                             

    Step2为了更好的描述,我们假设我们的句子长度只有3。  X=[w0, w1, w2];两个label={ l1, l2}

                 假设emission score情况如下:xij表示wi是lj的概率,即BiLSTM层的输出

                      

                 Transition矩阵如下:tij表示label从i到j的概率

                 

    Step3: 我们的目标是计算log(eS1+ eS1+ ...+eSN)

                整个计算过程和动态规划想类似。所有可能路径的总得分w0是已经计算好的,然后我们计算w0->w1的总得分,再计算                w0->w1->w2。在下面的步骤中,你会看到两个变量,obsprevious。previous储存了前一步的结果,obs表示当前字的              信息。

    w0

             obs=[x01, x02]

             previous=None

              如果我们句子只有一个字,我们就不需要从previous中获取结果了,因此previous是None。那么很显然,所有路径的得分            就是log(ex01+ ex02)。

    w0->w1

             obs=[ x11, x12]

             previous=[x01, x02]

             1.把previous和obs扩展成矩阵:

                                              

                为什么要扩展呢?因为扩展之后才能有效计算所有路径的总得分呀。

              2.计算previous、obs和transition score的和:

                                           

                                               

                 举个简单的例子你就理解了,假设只有两个元素,两个label,那么路径是不是有4条,即上面scores里面的东西,                         scores  里面每个元素的得分就是一个路径的得分,包括emission score和transition score,这也是为什么要把previous                 和obs扩展成矩阵了,因为这样元素之间的相加可以罗列出所有的矩阵呀。那么下一次迭代的previous是什么呢,就是我               们的scores呀,只不过样式需要变换一下:

                                   

                  为什么要这种样式呢?我们分步计算一下就知道了:

                    

                   最后这个结果和直接求e求和再求log的效果是一样的。看着previous是两个元素,实际上还有四条路径。

    w0->w1->w2

                   接下来的迭代和上面的几乎是一样的了。

                   obs=[ x21, x22]

                    previous=[log(ex01+x11+t11+ ex02+x11+t21), log(ex01+x12+t12+ ex02+x12+t22)]

                    1.把previous和obs扩展成矩阵:

                                                                        

                                   

                     2.计算previous、obs和transition score的和:

                      

                       下一次迭代的previous就是:看着复杂,实际很简单。

                      

                       分步计算可以知道,三个元素时,一共有8条路径,

                      

                       发现没?完整的8条路径,就是全路径的得分了!!!

    2.6 如果预测一个句子的label

          Step1emission score和transition score

                       假设句子还是三个字:X=[w0, w1, w2],且已经得到相应的emission score和transition score。

          Step2如果你了解Viterbi算法(之前了解过,貌似忘了,之前的博客有介绍HMM算法,和Viterbi差不多)。α0是历史最好                        得分 。α1是相应标签的indexs。

          w0

                 obs=[x01, x02]

                 previous=None

                 现在我们只观察到第一个字w0,如果obs=[ x01=0.2, x02=0.8],显然,w0最好的结果就是l2。

          w0->w1

                 obs=[ x11, x12]

                 previous=[x01, x02]

                (1)老规矩,把previous和obs扩展成矩阵:、

                                          

                                                       

                 (2)计算previous、obs和transition矩阵的和:

                               

                       到这里你会不会觉得这和之前求总得分的步骤是一样呀,不要着急,慢慢看。

                       previous=[max(scores[00], scores[10]), max(scores[01], scores[11])]

                       例如,如果我的得分是

                                       

                        那么我们下一次迭代的previous就会变成

                         previous=[max(scores[00], scores[10]), max(scores[01], scores[11])] = [0.5, 0.4]

                         这里previous存储的是前一个字的每一个label的最大得分,和HMM很像啊啊啊啊啊!

                        Example Start

                               上述例子中,我们只有两个label,这两个label的index是0和1,。previous[0]表示到达前一个字是label1的最大                                值,同理,previous[1]表示到达前一个字是label2的最大值。每一次迭代中,变量previous存储到达每一个                                    label的最大得分值。换言之,每一次迭代中,我们都存储了到达每一个label的最优路径。

                        Example End

                                 我们上面提到过,我们还有两个变量去存储历史信息α0和α1。

                                迭代时,我们把最优得分信息放入α0:

                                α0 = [(scores[10], scores[11])] = [(0.5, 0.4)]

                                α1中存入相应的列坐标:

                                α1 = [(ColumnIndex(scores[10]), ColumnIndex(scores[11]))] = [(1, 1)]

                                如何解释呢,l1的下标是0,l2的下标是1,所以(1, 1)=(l2, l2)表示当前字wi和li。具体来说就是对于w1                                    时,到达l1(这个l1是(l2, l2)中第一个元素l2所以在位置是0)的最大值的上一个标签是l2,即到达0.5的路                                  径是l(i-1) = l2 –> l(i) = l1。

                                到达l2(这个l2是(l2, l2)中第二个元素l2所以在位置是1)的最大值的上一个标签是l2,即到达0.4的路径是

                                 l(i-1) = l2 –> l(i) = l2。

                                 l(i-1)指的是字w(i-1)的标签。相当于保存了路径。

             w0->w1->w2

                          接下来的迭代和上面的几乎是一样的了。

                          obs=[ x21, x22]

                          previous=[0.5, 0.4]

                          1.把previous、obs扩展成矩阵:

                            

    1.                然后还是求和:

                                                              

    1.                然后计算找到最大值,更新previous:

                                                  previous=[max(scores[00], scores[10]), max(scores[01], scores[11])]

                            假设这个得分是:

                                                         

                            那么previous=[0.8, 0.9],实际上previous[0]和previous[1]中最大的一个就是最优路径的得分

                            同时,我们需要更新α0和α1:

                            α0 = [(0,5, 0.4), (scores[10], scores[01])] = [(0,5, 0.4), (0,8 0.9)]

                            α1 = [(1, 1), (1, 0)]

                            我觉得我有必要再强调一下α1,现在到达w2的l1和l2的最优路径分别是l2 –>l1 ->l2和l2 –>l2 ->l1

              Step3找到最高得分的最优路径:

                           实际上面已经说过了,α1中保存的就是最优路径,只要复现出来就ok了。算了,还是再说一遍吧。

                           w1->w2

                               α0 = [(0,5, 0.4), (0,8 0.9)]

                               α1 = [(1, 1), (1, 0)]

                               最大得分是0.9呀,相当于w2的 标签是l2;再看α1,到达l2的上一个字w1的标签是l1,所以最后一条连线就是                               l1- l2

                          w0->w1

                                上一个w1的标签是l1,那么到达l1的上一个字w0的标签是l2,所以整个路径就是l2 –>l1 ->l2。

    3、Chainer Implementation

                    终于到代码实现了,但作者使用chainer实现的,所以不写了吧,毕竟没用过,改天贴上自己的代码,整个算法过程肯定理解了吧。

     

     

     

     

    展开全文
  • Tensorflow 2 实战(kears)- 双层RNN/LSTM/GRU一、背景介绍1.1、数据集简介1.2、模型简介1.2.1、本次实战模型采用Encoder-Decoder的结构,Encoder采用 “双层RNN/LSTM/GRU", Decoder采用 “一个全连接层1.2.2、本次...

    一、背景介绍

    1.1、数据集简介

    本次实战使用数据集为 “IMDB” , 数据集内容为 “两极分化的评论”;该数据集共50000条,其中训练集25000条、测试集25000条;数据集分为两个类别(正面评价为1、负面评价为0),训练集和测试集都包含50%的正面评价和50%的负面评价。该数据集已经经过预处理:评论(单词序列)已经被转换为整数序列,其中每个整数代表字典中的某个单词。

    1.2、模型简介

    RNN解决了普通模型不适合处理序列数据的问题(例如:序列数据样本长度不一、参数过多、不能分享从序列不同位置学到的特征等问题)。
    LSTM(长短期记忆网络)解决了由于梯度消失引起的RNN记忆力不好的问题。
    GRU与LSTM类似,但GRU计算量要小一些,有助于构建更加庞大的项目。
    在这里插入图片描述

    1.2.1、实战模型(共三层)由一个“双层RNN/LSTM/GRU"及 “一个全连接层”构成

    • 双层RNN/LSTM/GRU输入为经过数据预处理的 “词向量” ,输出为“最后一层“中”最后一个时间步“的结果向量(句子编译的结果)。
    • 全连接层输入为“双层RNN/LSTM/GRU的输出”,输出为类别的概率。

    1.2.2、实战模型使用两种方式编写“双层RNN/LSTM/GRU”中的层

    • 一种为:“每一层” 中使用 “RNN/LSTM/GRU单个时间步” 串联的方式实现,如下:

    在这里插入图片描述

    • 另一种为: “每一层” 中直接使用tf.kears中“layers.SimpleRNN/LSTM/GRU” 实现,如下:
      在这里插入图片描述

    二、双层RNN/LSTM/GRU实战代码

    2.1、双层RNN/LSTM/GRU-单个时间步

    import  os
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
    
    import  tensorflow as tf
    import  numpy as np
    from    tensorflow import keras
    from    tensorflow.keras import layers
    
    
    tf.random.set_seed(22)
    np.random.seed(22)
    assert tf.__version__.startswith('2.')
    
    batchsz = 128
    
    # total_words为常见单词数量,此处仅保留训练数据的前10000个最常见出现的单词,低频单词将被舍弃(0不代表任何特定的词,而是用来编码任何未知单词)
    total_words = 10000
    #max_review_len为句子的最大长度
    max_review_len = 80
    #词向量的长度
    embedding_len = 100
    #加载数据集
    (x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=total_words)
    # x_train:[b, 80]
    # x_test: [b, 80]
    #pad_sequences对句子进行padding(maxlen:任何大于此值的句子将被截断,小于则补0)
    x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_len)
    x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=max_review_len)
    
    #构造数据集
    db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
    #drop_remainder=True如果最后一个 “batch的大小” 小于 “batchsz的大小” 则丢弃掉(它的shape与我们固定的shape不一致,不利于训练)
    db_train = db_train.shuffle(1000).batch(batchsz, drop_remainder=True)
    db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
    db_test = db_test.batch(batchsz, drop_remainder=True)
    print('x_train shape:', x_train.shape, tf.reduce_max(y_train), tf.reduce_min(y_train))
    print('x_test shape:', x_test.shape)
    
    
    
    class MyRNN(keras.Model):
        #定义层的实现
        def __init__(self, units):
            super(MyRNN, self).__init__()
    
            # [b, 64]
            #初始化c,a(LSTM)
            self.state0 = [tf.zeros([batchsz, units]),tf.zeros([batchsz, units])]
            self.state1 = [tf.zeros([batchsz, units]),tf.zeros([batchsz, units])]
            # #初始化c(GRU)
            # self.state0 = [tf.zeros([batchsz, units])]
            # self.state1 = [tf.zeros([batchsz, units])]
    
            # [b, 80] => [b, 80, 100]
            #将词转为词向量(total_words:单词表大小, embedding_len:词向量长度,input_length:句子的最大长度)
            self.embedding = layers.Embedding(total_words, embedding_len,
                                              input_length=max_review_len)
    
            # [b, 80, 100] , units:输出空间的维度(正整数),即隐藏层神经元数量(这里是64)
            # RNN: cell0 ,cell1
    
            # #SimpleRNNcell  RNN中的一个时间步
            # self.rnn_cell0 = layers.SimpleRNNCell(units, dropout=0.5)
            # self.rnn_cell1 = layers.SimpleRNNCell(units, dropout=0.5)
            #LSTMcell   LSTM中的一个时间步
            self.rnn_cell0 = layers.LSTMCell(units, dropout=0.5)
            self.rnn_cell1 = layers.LSTMCell(units, dropout=0.5)
            # #GRUcell   GRU中的一个时间步
            # self.rnn_cell0 = layers.LSTMCell(units, dropout=0.5)
            # self.rnn_cell1 = layers.LSTMCell(units, dropout=0.5)
    
    
            # fc全连接层,用于分类, [b, 80, 100] => [b, 64] => [b, 1]
            self.outlayer = layers.Dense(1)
    
        #实现前向过程
        def call(self, inputs, training=None):
            """
            net(x) net(x, training=True) :train mode 表示为train的计算过程(train阶段dropout会运行)
            net(x, training=False): test   表示为test的计算过程(test阶段dropout不会运行)
            :param inputs: [b, 80]
            :param training:
            :return:
            """
            # [b, 80]
            x = inputs
            # embedding: [b, 80] => [b, 80, 100]
            x = self.embedding(x)
            # rnn cell compute
            # [b, 80, 100] => [b, 64]
            state0 = self.state0
            state1 = self.state1
    
            # 创建双层RNN(按照“单词维度展开”串联时间步)
            for word in tf.unstack(x, axis=1): # word: [b, 100]
                # h1 = x*wxh+h0*whh
                # out0: [b, 64]
                out0, state0 = self.rnn_cell0(word, state0, training)
                # out1: [b, 64]
                out1, state1 = self.rnn_cell1(out0, state1, training)
    
            # out: [b, 64] => [b, 1]
            #“最后一层“中”最后一个时间步“的结果作为句子编译的结果
            x = self.outlayer(out1)
            # p(y is pos|x)
            #对输出结果进行分类
            prob = tf.sigmoid(x)
    
            return prob
    #训练模型
    def main():
        units = 64
        epochs = 4
    
        import time
    
        t0 = time.time()
        # MyRNN:网络的实例化,compile:网络的装载,fit:网络的训练,evaluate:网络的测试
        model = MyRNN(units)
        model.compile(optimizer = keras.optimizers.Adam(0.001),
                      loss = tf.losses.BinaryCrossentropy(),
                      metrics=['accuracy'])
        model.fit(db_train, epochs=epochs, validation_data=db_test)
    
        model.evaluate(db_test)
    
        t1 = time.time()
        print('total time cost:', t1-t0)
    
    
    if __name__ == '__main__':
        main()
    
    

    2.1、双层RNN/LSTM/GRU-layers.SimpleRNN/LSTM/GRU

    import  os
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
    
    import  tensorflow as tf
    import  numpy as np
    from    tensorflow import keras
    from    tensorflow.keras import layers
    
    
    tf.random.set_seed(22)
    np.random.seed(22)
    assert tf.__version__.startswith('2.')
    
    batchsz = 128
    
    #加载数据及数据预处理
    # the most frequest words
    total_words = 10000
    max_review_len = 80
    embedding_len = 100
    (x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=total_words)
    # x_train:[b, 80]
    # x_test: [b, 80]
    x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=max_review_len)
    x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=max_review_len)
    
    db_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
    db_train = db_train.shuffle(1000).batch(batchsz, drop_remainder=True)
    db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
    db_test = db_test.batch(batchsz, drop_remainder=True)
    print('x_train shape:', x_train.shape, tf.reduce_max(y_train), tf.reduce_min(y_train))
    print('x_test shape:', x_test.shape)
    
    
    
    class MyRNN(keras.Model):
        #定义层的实现
        def __init__(self, units):
            super(MyRNN, self).__init__()
    
    
            # 将词转为词向量(total_words:单词表大小, embedding_len:词向量长度,input_length:句子的最大长度)
            # [b, 80] => [b, 80, 100]
            self.embedding = layers.Embedding(total_words, embedding_len,
                                              input_length=max_review_len)
    
    
            # [b, 80, 100],units:输出空间的维度(正整数),即隐藏层神经元数量(这里是64)
            self.rnn = keras.Sequential([
                # #创建双层RNN
                # layers.SimpleRNN(units, dropout=0.5, return_sequences=True, unroll=True),
                # layers.SimpleRNN(units, dropout=0.5, unroll=True)
    
                #创建双层LSTM
                #unroll:默认为False,为True可以加速RNN(占用大量内存),为True仅适用于短序列。
                layers.LSTM(units, dropout=0.5, return_sequences=True, unroll=True),
                layers.LSTM(units, dropout=0.5, unroll=True)
    
                # #创建双层GRU
                # layers.GRU(units, dropout=0.5, return_sequences=True, unroll=True),
                # layers.GRU(units, dropout=0.5, unroll=True)
            ])
    
    
            # fc全连接层,用于分类,[b, 80, 100] => [b, 64] => [b, 1]
            self.outlayer = layers.Dense(1)
    
        # 实现前向过程
        def call(self, inputs, training=None):
            """
            net(x) net(x, training=True) :train mode
            net(x, training=False): test
            :param inputs: [b, 80]
            :param training:
            :return:
            """
            # [b, 80]
            x = inputs
            # embedding: [b, 80] => [b, 80, 100]
            x = self.embedding(x)
            # rnn cell compute
            # x: [b, 80, 100] => [b, 64]
            x = self.rnn(x)
    
            # out: [b, 64] => [b, 1]
            x = self.outlayer(x)
            # p(y is pos|x)
            prob = tf.sigmoid(x)
    
            return prob
    
    #训练模型
    def main():
        units = 64
        epochs = 4
    
        import time
    
        t0 = time.time()
    
        # MyRNN:网络的实例化,compile:网络的装载,fit:网络的训练,evaluate:网络的测试
        model = MyRNN(units)
        model.compile(optimizer = keras.optimizers.Adam(0.001),
                      loss = tf.losses.BinaryCrossentropy(),
                      metrics=['accuracy'])
        model.fit(db_train, epochs=epochs, validation_data=db_test)
    
        model.evaluate(db_test)
    
    
        t1 = time.time()
        print('total time cost:', t1-t0)
    
    
    if __name__ == '__main__':
        main()
    
    展开全文
  • 基于双层Bi-LSTM神经网络的情感分析LSTM介绍 LSTM介绍 长短期记忆网络(Long Short-Term Memory NetWork,LSTM)是循环神经网络的一个变体,可以有效地解决简单循环神经网络的梯度爆炸或消失问题。将其按照时序展开...

    基于双层Bi-LSTM神经网络的情感分析

    LSTM介绍

    长短期记忆网络(Long Short-Term Memory NetWork,LSTM)是循环神经网络的一个变体,可以有效地解决简单循环神经网络的梯度爆炸或消失问题。将其按照时序展开如下图所示。
    在这里插入图片描述
    其中, x 1 , x 2 , x 3 . . . x t x_{1},x_{2},x_{3}...x_{t} x1,x2,x3...xt为每个时刻的输入, c 1 , c 2 , c 3 . . . c t c_{1},c_{2},c_{3}...c_{t} c1,c2,c3...ct为每个时刻的内部状态, h 1 , h 2 , h 3 . . . h t h_{1},h_{2},h_{3}...h_{t} h1,h2,h3...ht为每个时刻的外部状态。
    循环单元结构如下图所示:
    在这里插入图片描述

    图片引自邱锡鹏教授所著《神经网络与深度学习》,本节内容参考此书。

    在简单循环神经网络的基础上,LSTM主要改进在以下两个方面:

    1.新的内部状态

    LSTM引入一个新的内部状态c t _t tR D ^D D,专门进行线性的循环信息传递,同时输出信息给隐藏层的外部状态h t _t tR D ^D D,内部状态通过下面的公式计算:
    在这里插入图片描述其中,f t _t t∈[0,1] D ^D Di t _t t∈[0,1] D ^D Do t _t t∈[0,1] D ^D D为三个门来控制信息传递的路径;⊙为向量元素乘积;c t − 1 _{t-1} t1为上一时刻的记忆单元; c ~ t ∈ \tilde{c}_t ∈ c~tR D ^D D是通过非线性函数得到的候选状态:。         (3-3)在每个时刻t,LSTM网络的内部状态ct记录了到当前时刻为止的历史信息。

    2.门控机制

    LSTM网络引入门控机制来控制信息传递的路径。三个“门”分别为遗忘门f t _t t、输入门i t _t t和输出门o t _t t。这三个门的作用分别为:
    (1)遗忘门f t _t t控制上一个时刻的内部状态c t − 1 _{t-1} t1需要遗忘多少信息。
    (2)输入门i t _t t控制当前时刻的候选状态 c ~ t ∈ \tilde{c}_t ∈ c~t有多少信息需要保存。
    (3)输出门o t _t t控制当前时刻的内部状态c t _t t有多少信息需要输出给外部状态h t _t t
    LSTM网络中的“门”取值在(0,1)之间,表示以一定的比例允许信息通过。三个门的计算方式为:
    在这里插入图片描述其中, σ \sigma σ(·)为Logistic函数,x t _{t} t为当前时刻输入,h t − 1 _{t-1} t1为上一时刻的外部状态。
    通过LSTM循环单元,整个网络可以建立较长距离的时序依赖关系。上述可以简洁的描述为:
    在这里插入图片描述其中,x t _t tR M ^M M为当前时刻的输入,W ∈R 4 D ∗ ( D + M ) ^{4D*(D+M)} 4D(D+M)和b∈R 4 D ^{4D} 4D为网络参数。

    LSTM实验

    本文采用的是双层双向的LSTM,其按时序展开如下图所示。(图中省略了内部状态c t _t t,⊕为向量拼接操作)。本实验中,将y t _t t作为模型的输出,送入到全连接层,并最终得到分类结果。

    在这里插入图片描述

    实验步骤:

    1.不断调整模型中的超参数以提高模型性能,最终将模型的超参数设置为:max_seq_len:50,hidden-dim:200,batch-size:64,learning rate:0.002 ,dropout rate:0.5。
    2.损失函数采用交叉熵,使用Adam优化器进行最多200个epochs训练,当验证集损失连续20个epochs没有下降时,停止训练,将训练过程验证集损失最小的模型作为测试集输入的模型,得到最终测试集的准确率。
    3.进行步骤2中的10次实验,得到最终的准确率均值±标准差为:0.8926±0.0027。

    核心代码展示

    import numpy as np
    import pickle
    import torch
    import torch.nn as nn
    import time
    import random
    import os
    import torch.utils.data as data
    import torch.nn.utils.rnn as rnn
    import copy
    from sklearn import metrics
    #random.seed(53112)
    #np.random.seed(53112)
    #torch.manual_seed(53113)
    #torch.cuda.manual_seed(53113)
    max_seq_len=50
    with open("DATA/x_train.txt", "rb") as f:
        x_train = pickle.load(f)
    with open("DATA/x_valid.txt", "rb") as f:
        x_valid = pickle.load(f)
    with open("DATA/x_test.txt","rb") as f:
        x_test = pickle.load(f)
    y_train=np.loadtxt("DATA/y_train.txt",dtype=int)
    y_valid=np.loadtxt("DATA/y_valid.txt",dtype=int)
    y_test=np.loadtxt("DATA/y_test.txt",dtype=int)
    y_train=torch.LongTensor(y_train)
    y_valid=torch.LongTensor(y_valid)
    y_test=torch.LongTensor(y_test)
    embeddings=np.loadtxt("DATA/embeddings.txt",dtype=float)
    embeddings=torch.from_numpy(embeddings)
    class mydataset(data.Dataset):
        def __init__(self,data,label):
            self.data=data
            self.label=label
        def __len__(self):
            return len(self.data)
        def __getitem__(self,index):
            data=self.data[index]
            label=self.label[index]
            seq_len=len(self.data[index])
            pd_data=copy.deepcopy(data)
    
            if seq_len>max_seq_len:
                for i in range(seq_len-max_seq_len):
                    pd_data.pop()
            else:
                pd_data.extend([0]*(max_seq_len-seq_len))
            if seq_len>max_seq_len:
                seq_len=max_seq_len
            pd_data=np.array(pd_data)
            pd_data=torch.LongTensor(pd_data)
    
            sample={'data':pd_data,'label':label,'seq_len':seq_len}
            return sample
    train_dataset=mydataset(x_train,y_train)
    valid_dataset=mydataset(x_valid,y_valid)
    test_dataset=mydataset(x_test,y_test)
    train_loader=torch.utils.data.DataLoader(
        dataset=train_dataset,
        batch_size=64,
        shuffle=True,
        pin_memory=True,
    )
    valid_loader=torch.utils.data.DataLoader(
        dataset=valid_dataset,
        batch_size=1024,
        #shuffle=True,
        pin_memory=False,
    )
    test_loader=torch.utils.data.DataLoader(
        dataset=test_dataset,
        batch_size=1024,
        #shuffle=True,
        pin_memory=False,
    
    )
    
    
    
    
    
    
    class LSTMModel(nn.Module):
        def __init__(self,embeddings,embedding_dim,hidden_dim,output_dim):
            super(LSTMModel,self).__init__()
            self.hidden_dim=hidden_dim
            self.embedding=nn.Embedding(len(embeddings),embedding_dim)
            self.embedding.weight.data.copy_(embeddings)
            self.embedding.weight.requires_grad = False
            self.lstm=nn.LSTM(embedding_dim,hidden_dim,num_layers=2,batch_first=True,bidirectional=True)
            self.linear=nn.Linear(2*hidden_dim,output_dim)
            self.dropout1=nn.Dropout(0.5)
            self.dropout2=nn.Dropout(0.5)
        def forward(self,data,seq_len,hidden=None):
    
            batch_size,max_seq_len=data.size()
            if hidden is None:
                h_0=data.new(4,batch_size,self.hidden_dim).fill_(0).float()
                c_0=data.new(4,batch_size,self.hidden_dim).fill_(0).float()
            else:
                h_0,c_0=hidden
    
            embedded= self.embedding(data)
            embedded= self.dropout1(embedded)
            embedded_packed=rnn.pack_padded_sequence(embedded,seq_len,enforce_sorted=False,batch_first=True)
            output,(hidden,cell)=self.lstm(embedded_packed)
            print(hidden.shape)
            hidden=torch.cat((hidden[-2,:,:],hidden[-1,:,:]),1)
            hidden=self.dropout2(hidden)
            return self.linear(hidden)
    
    
    
    
    
    def accuracy(preds,y):
        correct=(preds.max(1)[1]==y).float()
        acc=correct.sum()/len(correct)
        return acc
    
    
    def epoch_time(start_time,end_time):
        elapsed_time=end_time-start_time
        elapsed_mins=int(elapsed_time/60)
        elapsed_secs=int(elapsed_time-(elapsed_mins*60))
        return elapsed_mins,elapsed_secs
    
    def train(model,train_loader,optimizer,loss_fn):
            epoch_loss,epoch_acc=0.,0.
            model.train()
            for input in train_loader:
                input['data']=input['data'].cuda()
                input['label']=input['label'].cuda()
                input['seq_len']=input['seq_len'].cuda()
                preds=model(input['data'],input['seq_len'])
                loss=loss_fn(preds,input['label'])
                acc=accuracy(preds,input['label'])
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
                epoch_loss+=loss.item()
                epoch_acc+=acc.item()
            return epoch_loss/len(train_loader),epoch_acc/len(train_loader)
    
    def evaluate(model,valid_loader,loss_fn):
        epoch_loss,epoch_acc=0.,0.
        model.eval()
        with torch.no_grad():
            for input in valid_loader:
                input['data']=input['data'].cuda()
                input['label']=input['label'].cuda()
                input['seq_len']=input['seq_len'].cuda()
                preds=model(input['data'],input['seq_len'])
                loss=loss_fn(preds,input['label'])
                acc=accuracy(preds,input['label'])
                epoch_loss+=loss.item()
                epoch_acc+=acc.item()
        return epoch_loss/len(valid_loader),epoch_acc/len(valid_loader)
    
    test_preds=[]
    test_labels=[]
    def test(model,valid_loader,loss_fn):
        epoch_loss=0.
        epoch_acc=0.
        model.eval()
        with torch.no_grad():
            for input in valid_loader:
                input['data']=input['data'].cuda()
                input['label']=input['label'].cuda()
    
                input['seq_len']=input['seq_len'].cuda()
                preds=model(input['data'],input['seq_len'])
                loss=loss_fn(preds,input['label'])
                acc=accuracy(preds,input['label'])
                epoch_loss+=loss.item()
                epoch_acc+=acc.item()
    
                for y in input['label']:
                    y=y.cpu()
                    y=y.numpy()
                    test_labels.append(y)
                for pred in preds.max(1)[1]:
                    test_preds.append(pred.cpu().numpy())
        return epoch_loss/len(valid_loader),epoch_acc/len(valid_loader)
    
    
    
    
    
    lr=0.002
    embedding_dim=200
    hidden_dim=200
    device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    output_dim=2
    epochs=200
    model=LSTMModel(embeddings,embedding_dim,hidden_dim,output_dim)
    loss_fn=torch.nn.CrossEntropyLoss()
    optimizer=torch.optim.Adam(model.parameters(),lr=lr,weight_decay=0)
    model=model.to(device)
    loss_fn=loss_fn.to(device)
    
    early_stopping=20
    valid_losses=[]
    best_valid_loss=1.
    for epoch in range(epochs):
        start_time=time.time()
        train_loss,train_acc=train(model,train_loader,optimizer,loss_fn)
        valid_loss,valid_acc=evaluate(model,valid_loader,loss_fn)
        valid_losses.append(valid_loss)
        end_time=time.time()
        epoch_mins,epoch_secs=epoch_time(start_time,end_time)
    
        if valid_loss<best_valid_loss:
            best_valid_loss=valid_loss
            torch.save(model.state_dict(),'BiLSTMModel.pt')
    
    
        print(f'Epoch:{epoch+1:02}|Epoch Time:{epoch_mins}m {epoch_secs}s')
        print(f'\tTrain Loss:{train_loss:.3f}|Train Acc:{train_acc*100:.2f}%  Valid Loss:{valid_loss:.3f}|Valid Acc:{valid_acc*100:.2f}%')
        if epoch>early_stopping and valid_losses[-1]>np.mean(valid_losses[-early_stopping-1:-1]):
            print("Early stopping...")
            break
    print("Optimization Finished!")
    
    model.load_state_dict(torch.load('BiLSTMModel.pt'))
    model.to(device)
    
    test_loss,test_acc=evaluate(model,test_loader,loss_fn)
    print('Test set results:')
    print(f'\tTest Loss:{test_loss:.3f}|Test Acc:{test_acc*100:.2f}%')
    
    test_loss,test_acc=test(model,test_loader,loss_fn)
    print("Macro average Test Precision, Recall and F1-Score...")
    print(metrics.classification_report(test_labels, test_preds, digits=4))
    

    笔者将在后续章节将持续介绍CNN、GCN、Bert等以及在微博评论数据集上的应用,持续关注哟~
    关注公众号获取数据集以及项目完整代码~感激不尽!!!景柯的学习笔记

    展开全文
  • 本文使用双层LSTM网络,实现对MNIST数据集的分类。 理解LSTM网络的传送门:https://blog.csdn.net/jerr__y/article/details/58598296 参考:https://blog.csdn.net/jerr__y/article/details/61195257 # -*- ...
  • 在pytorch下,以数万首唐诗为素材,训练双层LSTM神经网络,使其能够以唐诗的方式写诗。 代码结构分为四部分,分别为 1.model.py,定义了双层LSTM模型 2.data.py,定义了从网上得到的唐诗数据的处理方法 3.utlis.py ...
  • 使用GRU模型实现文本生成任务的步骤 第一步:使用TFDS下载IMDB数据集,并划分训练集和测试集 第二步:按batch划分数据并训练单层biLSTM模型 第三步:训练双层bi-LSTM模型,对比效果 第一步: 使用TFDS下载IMDB数据集...
  • Lstm输入参数详细解释

    千次阅读 2021-03-19 10:02:56
    比如建立双层lstm,以mnist数据集来进行叙述: 我们知道mnist数据集,是28*28;用lstm训练mnist数据集过程; def DoubleLSTM(train_x,train_y,valid_x,valid_y,test_x,test_y): #创建模型 model=Sequential() ...
  • pytorch下使用LSTM神经网络写诗

    千次阅读 2018-04-23 00:33:30
    在pytorch下,以数万首唐诗为素材,训练双层LSTM神经网络,使其能够以唐诗的方式写诗。代码结构分为四部分,分别为1.model.py,定义了双层LSTM模型2.data.py,定义了从网上得到的唐诗数据的处理方法3.utlis.py 定义...
  • 在pytorch下,以数万首唐诗为素材,训练双层LSTM神经网络,使其能够以唐诗的方式写诗。代码结构分为四部分,分别为1.model.py,定义了双层LSTM模型2.data.py,定义了从网上得到的唐诗数据的处理方法3.utlis.py 定义...
  • 朋友们好,时隔很久我又开始写时间序列相关的博客啦。...模型使用双层LSTM加一个全连接层实现预测 具体结构如下 def trainModel(trainX,trainY,config): ''' trainX,trainY: 训练LSTM模型所需要的数据 p
  • 基于TensorFlow的双层BiDirection_Attention_LSTM的北京PM2.5数据集预测 预测北京PM2.5数据集你会学到: 传统的线性模型难以解决多变量或多输入问题,而神经网络如LSTM则擅长于处理多个变量的问题,该特性使其有助于...
  • 双隐层LSTM和双向LSTM

    2020-03-21 13:01:15
    使用双隐层LSTM模型(DHLSTM)和双向LSTM(Bi-LSTM)模型两种方法,实现MNIST数据集分类
  • 使用的RNN中的LSTM进行对28个英文字母的简单文本预测
  • 目录 1. 区别 2. 例子 3. 疑问解答 4. 实战 1. 实例1:官方的example——lstm_stateful.py ... 2. 实例2:用Keras实现有状态LSTM——电量消费预测 ... 3. 实例3:用Keras实现有状态LSTM序列预测 ...双层stacked ...
  • LSTM: nn.LSTM(input_size, hidden_size, num_layers=1, nonlinearity=tanh, bias=True, batch_first=False, dropout=0, bidirectional=False)   input_size:表示输入 xt 的特征维度 ...
  • 本文不是RNN系列入门,而是对RNN、LSTM、BiLSTM的内部结构和输入输出做透彻的剖析。 RNN:循环神经网络 LSTM:长短期记忆网络 BiLSTM:双向长短期记忆网络 重要的先验知识: 本质上单个RNN cell是在多个时间步上...
  • 单层LSTM和多层LSTM的输入与输出

    千次阅读 多人点赞 2020-06-10 11:44:09
    单层LSTM的输入与输出 上图是单层LSTM的输入输出结构图。其实它是由一个LSTM单元的一个展开,如下图所示: 所以从左到右的每个LSTM Block只是对应一个时序中的不同的步。 在第一个图中,输入的时序特征有S个,长度...
  • Pytorch — LSTM

    2020-05-22 14:56:46
    nn.LSTMLSTM中,c和h的size是一样的 import torch from torch import nn import numpy as np lstm = nn.LSTM(input_size=100, hidden_size=20, num_layers=4) print(lstm) x = torch.randn(10,3,100) #3...
  • LSTM RNN

    2018-04-14 16:24:32
    LSTM是神经网络一个相当简单的延伸扩展,而且在过去几年里取得了很多惊人成就。我第一次了解到LSTM时,简直有点目瞪口呆。不知道你能不能从下图中发现LSTM之美。OK,咱们这就开始切入正题。先简单介绍一下神经网络和...
  • 图解LSTM结构

    千次阅读 2019-06-26 22:39:47
    这是我见到比较清楚的对LSTM网络结构比较清晰的解释,故摘抄方面大家理解

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,277
精华内容 510
关键字:

双层lstm