RNN以及变体LSTM,GRU,以及Tensorflow代码

本文详细介绍了RNN的原理,包括单个RNN单元、多步前向传播及反向传播,探讨了RNN的问题,如无法利用未来信息和梯度消失。接着,文章讨论了LSTM和GRU作为RNN的变体,以解决这些问题。此外,还展示了如何在TensorFlow中实现RNN,包括动态RNN的使用和多层RNN的堆叠。最后,给出了几个使用LSTM和双向LSTM的实践任务,如预测sin函数、MNIST手写数字分类和Char-RNN项目。
摘要由CSDN通过智能技术生成

1.RNN

  • 原因很简单,无论是卷积神经网络,还是人工神经网络,他们的前提假设都是:元素之间是相互独立的,输入与输出也是独立的,比如猫和狗。

  • CNN是专门处理网格化数据(例如图像),而RNN是专门处理序列的神经网络。

  • 但现实世界中,很多元素都是相互连接的,比如股票随时间的变化,

  • 一个人说了:我喜欢旅游,其中最喜欢的地方是云南,以后有机会一定要去()
    
  • 这里填空,人应该都知道是填“云南“。因为我们是根据上下文的内容推断出来的,但机会要做到这一步就相当得难了。因此,就有了现在的循环神经网络,他的本质是**:像人一样拥有记忆的能力。**因此,他的输出就依赖于当前的输入和记忆

这里写图片描述

  • 其中每个圆圈可以看作是一个单元,而且每个单元做的事情也是一样的,因此可以折叠呈左半图的样子。用一句话解释RNN,就是一个单元结构重复使用

1.1 单个RNN单元

  • 循环神经网络可以看作是单元的重复,首先要实现单个时间步的计算,下图描述了RNN单元的单个时间步的操作。

rnn_step_forward.png

​ Xt:表示t时刻的输入,y^t:表示t时刻的输出,at:表示t时刻的记忆

  • 每个时间步隐藏层的计算:

  • 输入分为两个部分,一个是当前时间步的输入Xt 和上一个时间步的输出at-1.

  • 将两个输入部分分别乘以各自的权重Wax和Waa然后加上偏置b,再进行激活函数tanh的计算得到当前时间步的隐藏层输出at

  • 再将输出 at乘以权重Wya ,加上偏置by,送入softmax函数,得到当前时间步的预测值y

1.2 多个RNN单元的前向传播

cell_rnn.png

模型的结构如下:

  • 初始化参数
  • 循环:
    • 前向传播计算损失
    • 反向传播计算关于损失的梯度
    • 修剪梯度以免梯度爆炸
    • 用梯度下降更新规则更新参数。
  • 返回学习后了的参数

1.3 RNN的反向传播(单个RNN单元)

rnn_cell_backprop.png

1.4 RNN存在的问题1:无法运用未来的信息

1.4.1 RNN的改进:双向RNN
  • 假设当前t的输出不仅仅和之前的序列有关,并且 还与之后的序列有关img

1.5 RNN存在的问题2:梯度爆炸和梯度消失

  • 梯度消失:反向传播时,当梯度从后往前传时,梯度不断减小,最后变为零,此时,浅层的神经网络权重得不到更新,这种现象称为“饱和”,整个网络学习速度非常慢。梯度消失导致后层的权重更新的快,而前层网络由于梯度传递不过去而得不到更新。这样在网络很深的时候,学习的速度很慢或者无法学习。

  • 梯度爆炸:这是一种与梯度消失相反的情况,当进行反向传播时,梯度从后往前传时,梯度不断增大,导致权重更新太大,以致不断波动,使网络在最优点之间波动。

  • **原因:**前面层上的梯度是来自于后面层上梯度的乘乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景,如梯度消失和梯度爆炸。

  • 解决方案:

    • 方案1:梯度剪切:这个方案主要是针对梯度爆炸提出的,其思想是设置一个梯度剪切阈值,然后更新梯度的时候,如果梯度超过这个阈值,那么就将其强制限制在这个范围之内。这可以防止梯度爆炸。
    • 方案2-relu、leakrelu、elu等激活函数:思想也很简单,如果激活函数的导数为1,那么就不存在梯度消失爆炸的问题了,每层的网络都可以得到相同的更新速度,relu就这样应运而生。
    • 方案3:LSTM

2 RNN的变体

2.1 LSTM (Long Short-Term Memory)长短时记忆网络

LSTM.png

  • ct :代表哪些信息应该被遗忘以及哪些信息应该被记住
  • at: 代表这个lstm单元最终的输出
  • 遗忘门(forget gate),所谓的“遗忘”,也就是“记忆的残缺”。它决定了上一时刻的单元状态有多少“记忆”可以保留到当前时刻;
  • 输入门(input gate),它决定了当前时刻的输入有多少保存到单元状态。
  • 候选门(Candidate gate),它控制着以多大比例融合“历史”信息和“当下”刺激。

2.2 BI-LSTM

img

2.3 GRU(Gated Recurrent Unit)

GRU

  • GRU中将LSTM中的决定哪些遗忘哪些记住的ct 以及 最终输出的at 合并成了一个 ht

  • **更新门zt:**将遗忘门 输入门 合并成了一个更新门。更新门用于控制前一时刻的状态信息被带入到当前状态中的程度,更新门的值越大说明前一时刻的状态信息带入越多。

  • 重置门rt:重置门用于控制忽略前一时刻的状态信息的程度,重置门的值越小说明忽略得越多。


3 TensorFlow中的RNN

3.1 RNN单元:

3.1.1 RNN 基类

定义RNN单元和调用Call()

  • class tf.contrib.rnn.BasicRNNCell(num_units, activation=None, reuse=None, name=None)
    

输入参数

  • num_units: int, the number of units in the RNN cell.
  • activation: Nonlinearity to use. Default: tanh.
  • reuse: (optional) Python boolean describing whether to reuse variables in an existing scope. If not True, and the existing scope already has the given variables, an error is raised.
  • name: String, the name of the layer. Layers with the same name will share weights, but to avoid mistakes we require reuse=True in such cases.

输出

  • 一个隐层神经元数量为 num_units 的 RNN 基本单元(实例化的 cell)

常用属性

函数返回属性:

  • state:size(s) of state(s) used by this cell,等于隐层神经元数量
  • output: size of outputs produced by this cell
    注意在此函数中,state_size 永远等于 output_size
  • 比如我们通常是将一个batch送入模型计算,设输入数据的形状为(batch_size, input_size),那么计算时得到的隐层状态就是(batch_size, state_size),输出就是(batch_size, output_size)。

常用方法

  • call(inputs, state): (output, next_state) = Cell.call(input, state)。

    返回两个一模一样的隐层状态值.每调用一次RNNCell的call方法,就相当于在时间上“推进了一步”,这就是RNNCell的基本功能。在新版本中改成了直接调用:(Cell.(input,state))

  • zero_state(batch_size, dtype): 返回一个形状为 [batch_size, state_size] 的全零tensor.一般用来定义RNN单元的初始状态。

  • 代码示例

  • import tensorflow as tf
    import numpy as np
    #state_size = 128
    #cell =tf.nn.rnn_cell.BasicRNNCell(num_units=128)
    cell =tf.contrib.rnn.BasicRNNCell(num_units = 128)
    #128
    print(cell.state_size)
    #batch_size 32
    inputs = tf.placeholder(np.float32,shape=(32,128))
    #通过zero_state 得到一个全0的初始状态
    h0 = cell.zero_state(32,np.float32)
    output , h1 = cell(inputs,h0)
    print("h1.shape: " ,h1.shape)#32 128
    print("output.shape: ",output.shape)
    

3.1.2 LSTM基类

class tf.contrib.rnn.BasicLSTMCell(num_units, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None, name=None)

输入参数

  • num_units: int, the number of units in the RNN cell.
  • forget_bias: float, Biases of the forget gate are initialized by default to 1 in order to reduce the scale of forgetting at the beginning of the training.
  • state_is_tuple: If True, accepted and returned states are 2-tuples of the c_state and m_state
  • activation: Nonlinearity to use. Default: tanh.
  • reuse: (optional) Python boolean describing whether to reuse variables in an existing scope. If not True, and the existing scope already has the given variables, an error is raised.
  • name: String, the name of the layer. Layers with the same name will share weights, but to avoid mistakes we require reuse=True in such cases.

输出

  • 一个隐层神经元数量为 num_units 的 LSTM 基本单元(实例化的 lstm_cell)
  • state_size:size(s) of state(s) used by this cell,等于隐层神经元数量
  • output_size: size of outputs produced by this cell.

注意:

  • 在此函数中,state_size 永远等于 output_size

常用方法

  • call(inputs, state): 返回一个是 new_h,一个是 new_state(LSTMStateTuple:包含 ct 和 ht)

ct 和 ht 对应我们上面的LSTM示意图中的ct 和at(ct代表哪些信息应该被记住哪些应该被遗忘,ht代表这个cell最终的输出)

  • BasicLSTMCell 的 call 函数定义

  • 返回的隐状态new_cnew_h 的组合,而 output 就是单独的 new_h

  • 如果我们处理的是分类问题,那么我们还需要对 new_h 添加单独的 Softmax 层才能得到最后的分类概率输出

代码示例

import tensorflow as tf

lstm_cell = tf.contrib.rnn.BasicLSTMCell(num_units=128, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None, name=None)
print(lstm_cell.output_size)  # 128
print(lstm_cell.state_size)   # LSTMStateTuple(c=128, h=128)

inputs = tf.placeholder(shape=[32, 100], dtype=tf.float32)  # 32 是 batch_size
h0 = lstm_cell.zero_state(batch_size=32, dtype=tf.float32)
print(h0)
# LSTMStateTuple(c=<tf.Tensor 'BasicLSTMCellZeroState/zeros:0' shape=(32, 128) dt
  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值