本文将从以下几个方面介绍RNN
1.RNN的产生背景
RNN是循环序列神经网络的简称,它是为了模拟人类的推理能力而提出的,例如,人类可以根据一个故事的开头猜测到一个故事的结尾;可以根据对方说的话,揣测他背后的意图,这就说人类的分析能力,根据前因后果、语言的规则等等,我们可以得到很多重要的信息。智者往往处理事情有理有据,逻辑推理缜密,我们期待计算机也有这样的分析推理能力,所以学者们设计了神奇的循环神经网络。
2.RNN的特点
2.1. 序列化
RNN引入时间序列,一个RNN网络运行过程中,输入数据进来后,就会被网络记住,然后把这个被记住的数据表达为一个向量,下一次再输入数据,就继续填充到这个向量中,这样反复循环,这个向量就记住了数据的先后顺序,这个向量叫做隐状态,所以RNN的输入包括两部分,一部分是当前的输入数据,一部分是上一时刻的隐状态。
2.2. 自动提取特征
RNN可以根据知识库的已有知识来推断新知识,这点和人类的认识事物的过程类似,根据已有的推断未知的,根据大脑中已有的存量知识推断新事物,推理过程是根据事物之间的相似性。借用抖音上看到的认知学中,我们会根据已知的东西来了解未知,比如墨西哥有一种食物叫做 Burrito,第一次看到它可能不知道它是什么,就会问:这里面有什么,哦,这是一块饼,上面放一点肉,再放一点蔬菜,然后卷起来,哦,我知道了,这就是卷饼嘛,墨西哥的卷饼。用已知来了解未知,用记忆来诠释这个世界。借用心理学家乔丹.彼得森的话来说,当你看到这个世界时,你看到了什么,一个回答是,你看到了你的回忆(记忆),通过记忆建立起了这些认知(参照物)。当你认识这个世界时,使用的是这些认知(参照物),为什么不呢?要看清这个世界太难了。
2.3 共享参数
RNN通过共享参数变量,减少运算过程的复杂性。
3. RNN的网络模型
上图为盗图,表示成数学公式为:
上图依旧为盗图,但是感觉不太对,s1,s2...隐藏层应该是随时间t的流逝序列化的传递,而不是全连接。
4.实际用途
RNN加速了神经网络的智能化,在知识推理方面有着重要的作用,具体包括如下:
4.1 语言翻译
4.2 情感分类
4.3. 语音识别
4.4 视频动作识别
4.5 名命实体识别
5.RNN的算法
5.1 RNN的基础算法
从3 网络结构图可以看到,当前的隐层 = 参数W*上一层的隐层 + 参数U*当前的输入元素;
5.2 RNN的算法缺陷
从5.1式子可以看到,在使用梯度下降法反向求解参数W和参数U时,因为参数W和参数U是在整个循环链中共享的,所以使用链式法则求导会存在当链条过长时,会使得梯度爆炸或梯度消失的问题。理论推导过程如下:
具体参考blog:https://zhuanlan.zhihu.com/p/76772734
5.3 RNN的算法优化
为了解决5.2存在的缺陷,有关学者针对基础的算法模型提出了几种优化算法。
5.3.1. LSTM算法
LSTM是另一种更强大的解决梯度消失问题的方法。它对应的RNN隐藏层单元结构如下图所示:
LSTM包含三个gates:Γu,Γf,Γo,分别对应update gate,forget gate和output gate。
如果考虑c^<t−1>对Γu,Γf,Γo的影响,可加入peephole connection,对LSTM的表达式进行修改:
GRU可以看成是简化的LSTM,两种方法都具有各自的优势。
5.3.2. GRU算法
RNN的隐藏层单元结构如下图所示:
上图依旧为盗图
为了解决梯度消失问题,对上述单元进行修改,添加了记忆单元,构建GRU,如下图所示:
相应的表达式为:
上图可以理解为:
当前隐层的算法思想为: 为试算的“类隐层结果值”,当为0时,选择遗忘门 1 - 中的上一层的隐层结果,当为1时,选择
向前计算一步,常规计算;这样就可以根据隐层的值动态调整选择遗忘门还是更新门。
6.源码
tensorflow库已经封装了RNN的相关方法库,我们只需要根据实际情况调用即可。
这里简单介绍下tensorflow库中的重要方法:
6.1. BasicRNNCell( num ):构建基础的RNN结构单元,参数为单元个数。
6.2 placeholder(batch_size,input_size) :shape = (batch_size, input_size)
6.3. call(inputs, h0)
用例代码如下:
import tensorflow as tf
import numpy as np
cell = tf.nn.rnn_cell.BasicRNNCell(num_units=128) # state_size = 128
print(cell.state_size) # 128
inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_size,100是input_size shape = (batch_size, input_size)
h0 = cell.zero_state(32, np.float32) # 通过zero_state得到一个全0的初始状态,形状为(batch_size, state_size)
output, h1 = cell.call(inputs, h0) #调用call函数
print(h1.shape) # (32, 128)
7.参考文献
https://zhuanlan.zhihu.com/p/76772734
网友评论