NLP TASK8 循环和递归神经网络

49 篇文章 1 订阅
6 篇文章 0 订阅

学习任务

RNN的结构。循环神经网络的提出背景、优缺点。着重学习RNN的反向传播、RNN出现的问题(梯度问题、长期依赖问题)、BPTT算法。
双向RNN
递归神经网络
LSTM、GRU的结构、提出背景、优缺点。
针对梯度消失(LSTM等其他门控RNN)、梯度爆炸(梯度截断)的解决方案。
Memory Network(自选)
Text-RNN的原理。
利用Text-RNN模型来进行文本分类。
Recurrent Convolutional Neural Networks(RCNN)原理。
利用RCNN模型来进行文本分类。

内容笔记

RNN

RNN的结构

在这里插入图片描述

循环神经网络

    循环神经网络,故名思义,就是可以循环的神经网络。所谓的“循环”,指的是隐藏层中每一个神经元的循环使用。
    人类并不是每时每刻都从一片空白的大脑开始他们的思考。在你阅读这篇文章时候,你都是基于自己已经拥有的对先前所见词的理解来推断当前词的真实含义。我们不会将所有的东西都全部丢弃,然后用空白的大脑进行思考。我们的思想拥有持久性。
    传统的神经网络并不能做到这点,看起来也像是一种巨大的弊端。例如,假设你希望对电影中的每个时间点的时间类型进行分类。传统的神经网络应该很难来处理这个问题——使用电影中先前的事件推断后续的事件。RNN 解决了这个问题。RNN 是包含循环的网络,允许信息的持久化。

BPTT

循环神网络的训练算法是Backpropagation Through Time,BPTT算法,其基本原理和反向传播算法是一样的,只不过反向传播算法是按照层进行反向传播,BPTT是按照时间t进行反向传播。
在这里插入图片描述

梯度消失

传统RNN的一个问题是在训练过程中,反向传播会出现gradient explode/vanish的问题,用中文来理解就是梯度消失或者梯度爆炸。具体看:
在这里插入图片描述
如上图所示,这里是一个RNN的cell,灰色箭头是正向传播,红色箭头是反向传播。以这个cell的反向传播为例,根据复合梯度的乘法原理,在计算反向传播时会对d(h)乘以W。那么对于整个RNN来说:
在这里插入图片描述
如图所示,对于有四个node的网络来说,从h_4到h_0的反向传播过程中会有 D(h_0) x W x W x W,也就是乘以W的四次方。这样就会产生梯度爆炸或者梯度消失的问题。因为RNN中的一个常用机制是权值共享机制,也就是说W是一样的;那么如果W矩阵的最大特征值 > 1, 就会产生题都爆炸的情况,也就是梯度传到比较靠前的状态节点比如t = 0的时候,因为乘了W的n次方,梯度此时会非常大;反之,如果W的最大特征值 < 1,就会使得梯度近似于0。(试想一下W是一个标量,如果W大于1,那梯度是不断增加的过程;如果W小于1,梯度会越来越小最终趋于0)
当然,对于gradient explod我们可以采用clipping的方法,即如果梯度值 G > max_value(eg: 50)时,我们可以令G = 50。但是对于gradient vanishing的问题,并没有很好的解决方法。

长度依赖

什么是长期依赖

长期依赖是指当前系统的状态,可能受很长时间之前系统状态的影响,是RNN中无法解决的一个问题。

如果从“这块冰糖味道真?”来预测下一个词,是很容易得出“甜”结果的。但是如果有这么一句话,“他吃了一口菜,被辣的流出了眼泪,满脸通红。旁边的人赶紧给他倒了一杯凉水,他咕咚咕咚喝了两口,才逐渐恢复正常。他气愤地说道:这个菜味道真?”,让你从这句话来预测下一个词,确实很难预测的。因为出现了长期依赖,预测结果要依赖于很长时间之前的信息。
在这里插入图片描述
理论上,通过调整参数,RNN是可以学习到时间久远的信息的。但是,实践中的结论是,RNN很难学习到这种信息的。RNN 会丧失学习时间价格较大的信息的能力,导致长期记忆失效。

双向RNN

RNN和LSTM都只能依据之前时刻的时序信息来预测下一时刻的输出,但在有些问题中,当前时刻的输出不仅和之前的状态有关,还可能和未来的状态有关系。比如预测一句话中缺失的单词不仅需要根据前文来判断,还需要考虑它后面的内容,真正做到基于上下文判断。BRNN有两个RNN上下叠加在一起组成的,输出由这两个RNN的状态共同决定。
在这里插入图片描述
对于每个时刻t,输入会同时提供给两个方向相反的RNN,输出由这两个单向RNN共同决定。

递归神经网络

循环神经网络,它可以用来处理包含序列结构的信息。然而,除此之外,信息往往还存在着诸如树结构、图结构等更复杂的结构。对于这种复杂的结构,循环神经网络就无能为力了。本文介绍一种更为强大、复杂的神经网络:递归神经网络 (Recursive Neural Network, RNN),以及它的训练算法BPTS (Back Propagation Through Structure)。顾名思义,递归神经网络(巧合的是,它的缩写和循环神经网络一样,也是RNN)可以处理诸如树、图这样的递归结构。比如
在这里插入图片描述

LSTM

长短期记忆(Long short-term memory, LSTM)是一种特殊的RNN,主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说,就是相比普通的RNN,LSTM能够在更长的序列中有更好的表现。LSTM结构:
在这里插入图片描述

GRU

GRU(Gate Recurrent Unit)是循环神经网络(Recurrent Neural Network, RNN)的一种。和LSTM(Long-Short Term Memory)一样,也是为了解决长期记忆和反向传播中的梯度等问题而提出来的。GRU和LSTM在很多情况下实际表现上相差无几,但是更易于计算。GRU结构:
在这里插入图片描述

Text-RNN的原理

论文:Recurrent Neural Network for Text Classification with Multi-Task Learning 利用CNN进行文本分类,说到底还是利用卷积核寻找n-gram特征。卷积核的大小是超参。而RNN基本是处理文本信息的标配了,因为RNN先天就是为处理时间序列而设计的,它通过前后时刻的输出链接保证了“记忆”的留存。但RNN循环机制过于简单,前后时刻的链接采用了最简单的 f = a c t i v a t e ( w s + b ) f=activate(ws+b) f=activate(ws+b)的形式,这样在梯度反向传播时出现了时间上的连乘操作,从而导致了梯度消失和梯度爆炸的问题。RNN的 变种LSTM/GRU在一定程度上减缓了梯度消失和梯度爆炸问题,因此现在使用的其实要比RNN更多。
利用RNN做文本分类也比较好理解。对于英文,都是基于词的。对于中文,首先要确定是基于字的还是基于词的。如果是基于词,要先对句子进行分词。之后,每个字/词对应RNN的一个时刻,隐层输出作为下一时刻的输入。最后时刻的隐层输出h_ThT​catch住整个句子的抽象特征,再接一个softmax进行分类。
在这里插入图片描述

RCNN的原理

RCNN模型来源于论文 Recurrent Convolutional Neural Networks for Text Classification

RCNN原理图
在这里插入图片描述

Text-RNN文本分类范例
#模型结构代码
#!/usr/bin/python
# -*- coding: utf-8 -*-

import tensorflow as tf

class TRNNConfig(object):
    """RNN配置参数"""

    # 模型参数
    embedding_dim = 64      # 词向量维度
    seq_length = 600        # 序列长度
    num_classes = 10        # 类别数
    vocab_size = 5000       # 词汇表达小

    num_layers= 2           # 隐藏层层数
    hidden_dim = 128        # 隐藏层神经元
    rnn = 'gru'             # lstm 或 gru

    dropout_keep_prob = 0.8 # dropout保留比例
    learning_rate = 1e-3    # 学习率

    batch_size = 128         # 每批训练大小
    num_epochs = 10          # 总迭代轮次

    print_per_batch = 100    # 每多少轮输出一次结果
    save_per_batch = 10      # 每多少轮存入tensorboard


class TextRNN(object):
    """文本分类,RNN模型"""
    def __init__(self, config):
        self.config = config

        # 三个待输入的数据
        self.input_x = tf.placeholder(tf.int32, [None, self.config.seq_length], name='input_x')
        self.input_y = tf.placeholder(tf.float32, [None, self.config.num_classes], name='input_y')
        self.keep_prob = tf.placeholder(tf.float32, name='keep_prob')

        self.rnn()

    def rnn(self):
        """rnn模型"""

        def lstm_cell():   # lstm核
            return tf.contrib.rnn.BasicLSTMCell(self.config.hidden_dim, state_is_tuple=True)

        def gru_cell():  # gru核
            return tf.contrib.rnn.GRUCell(self.config.hidden_dim)

        def dropout(): # 为每一个rnn核后面加一个dropout层
            if (self.config.rnn == 'lstm'):
                cell = lstm_cell()
            else:
                cell = gru_cell()
            return tf.contrib.rnn.DropoutWrapper(cell, output_keep_prob=self.keep_prob)

        # 词向量映射
        with tf.device('/cpu:0'):
            embedding = tf.get_variable('embedding', [self.config.vocab_size, self.config.embedding_dim])
            embedding_inputs = tf.nn.embedding_lookup(embedding, self.input_x)

        with tf.name_scope("rnn"):
            # 多层rnn网络
            cells = [dropout() for _ in range(self.config.num_layers)]
            rnn_cell = tf.contrib.rnn.MultiRNNCell(cells, state_is_tuple=True)

            _outputs, _ = tf.nn.dynamic_rnn(cell=rnn_cell, inputs=embedding_inputs, dtype=tf.float32)
            last = _outputs[:, -1, :]  # 取最后一个时序输出作为结果

        with tf.name_scope("score"):
            # 全连接层,后面接dropout以及relu激活
            fc = tf.layers.dense(last, self.config.hidden_dim, name='fc1')
            fc = tf.contrib.layers.dropout(fc, self.keep_prob)
            fc = tf.nn.relu(fc)

            # 分类器
            self.logits = tf.layers.dense(fc, self.config.num_classes, name='fc2')
            self.y_pred_cls = tf.argmax(tf.nn.softmax(self.logits), 1)  # 预测类别

        with tf.name_scope("optimize"):
            # 损失函数,交叉熵
            cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=self.input_y)
            self.loss = tf.reduce_mean(cross_entropy)
            # 优化器
            self.optim = tf.train.AdamOptimizer(learning_rate=self.config.learning_rate).minimize(self.loss)

        with tf.name_scope("accuracy"):
            # 准确率
            correct_pred = tf.equal(tf.argmax(self.input_y, 1), self.y_pred_cls)
            self.acc = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
#输出结果
Test Loss:    0.2, Test Acc:  94.17%
Precision, Recall and F1-Score...
              precision    recall  f1-score   support

          体育       1.00      0.98      0.99      1000
          财经       0.94      0.97      0.96      1000
          房产       0.99      1.00      0.99      1000
          家居       0.92      0.76      0.84      1000
          教育       0.91      0.94      0.92      1000
          科技       0.93      0.97      0.95      1000
          时尚       0.96      0.93      0.95      1000
          时政       0.86      0.94      0.90      1000
          游戏       0.96      0.97      0.96      1000
          娱乐       0.96      0.96      0.96      1000

   micro avg       0.94      0.94      0.94     10000
   macro avg       0.94      0.94      0.94     10000
weighted avg       0.94      0.94      0.94     10000

Confusion Matrix...
[[979   0   0   0   9   4   1   0   2   5]
 [  0 975   0   1   1   0   0  18   5   0]
 [  0   0 996   0   2   2   0   0   0   0]
 [  0  11  11 762  26  42  19 101  13  15]
 [  1  10   0   5 935  18   3  19   6   3]
 [  0   1   0   6   6 973   0   3   8   3]
 [  3   0   0  38  13   2 928   1   6   9]
 [  0  21   0   8  24   5   0 939   1   2]
 [  0   7   0   0   6   1   8   2 969   7]
 [  0  13   0   4   4   4   5   6   3 961]]
Time usage: 0:02:58
参考资料

https://ilewseu.github.io/2017/12/30/RNN简单推导/
https://www.cnblogs.com/wacc/p/5341670.html
https://zhuanlan.zhihu.com/p/47780305
https://zhuanlan.zhihu.com/p/40119926
https://zhuanlan.zhihu.com/p/40182925
https://blog.csdn.net/Kaiyuan_sjtu/article/details/84536256

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值