RNN简介

来源:互联网 发布:2017网络市场专项行动 编辑:程序博客网 时间:2024/06/05 06:54

1. RNN的提出背景

对于序列类型的数据,比如翻译问题,时间序列预测问题,由于前后样本之间有顺序之间的先后关系,而传统的神经网络无法体现这一关系,因此出现了RNN(Recurrent Neural Network)。RNN会记住之前的输入值,因此对于RNN而言,即时后面有相同的输入,输出值也会不同,这是与传统的NN不同的地方。序列数据的类型有:
这里写图片描述

  • one to one: Vanilla Neural Networks,最简单的BP网络
  • one to many: Image Captioning,可将图像转换成文字
  • many to one:Sentiment Classification,情感分类
  • many to many-1: Machine Translation,机器翻译
  • many to many-2:Video classification,视频分类

2. RNN的基本结构

对于RNN神经元,其输出结果考虑的东西除了输入值之外,还会考虑存在内存当中的其他值,这些值是先前计算的结果:
这里写图片描述
首先在初始的时候,会给Memory单元的a1a2一个初始值。下一步,绿色的神经元的输入既有x1x2的贡献,又有a1a2的贡献。然后据此计算出y1y2。一轮计算完成之后,会将绿色的神经元的输出保存到memory的a1a2单元中。因此整个计算过程当中a1a2的值会不断变化。
例如: 令所有的权值都是1,a1a2初始都为0,则对应的输入输出和memory分别为:

x1 x2 a1 a2 y1 y2 1 1 0 0 4 4 1 1 2 2 12 12 2 2 6 6 32 32

因此输出样本的顺序会对结果产生影响。因此下一时刻的输出值会受到前面所有时刻的输入值的影响:

ht=fW(ht1,xt)

如果令fW(x)=tanh(x),则:
htyt=tanh(Whhht1+Wxhxt)=Whyht

例如对于词汇来将,每个单词都是一个输入的x,对于其他时间序列数据,每个时间点的输入都是一个输入样本:
这里写图片描述
更一般的情况,会将输出值存入memory中:
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

3. Bidirectional RNN(双向RNN)

将输入的数字,从前到后训练一个RNN,从后往前训练一个RNN。对于单向的RNN,由于只能看到前面已经输入的样本数据,因此无法看到全局。而对于双向RNN,既能看到全面的样本数据,又能看到后面的样本数据,准确性更好。
这里写图片描述

4. RNN中的梯度爆炸(gradient explode)和梯度消失(gradient vanishing)

先看下面一个简单的例子:
这里写图片描述
假设S0为给定值,则最简单的前向传播为:

S1S2S3=WxX1+WsS0+b1O1=W0S1+b2=WxX2+WsS1+b1O2=W0S2+b2=WxX3+WsS2+b1O3=W0S3+b2

假设t=3时刻,损失为:L3=12(Y3O3)2,则总的损失为:
L=t=0TLt

即每一时刻的损失之和。RNN的训练过程其实就是对Wx,Ws,Wob1,b2求偏导,并不断调整它们使得L达到最小。
t=3时刻对Wx,Ws,Wo求偏导,得:
这里写图片描述
因此对于W0求偏导没有长期以来,但是对于WxWs求偏导数则会产生长期依赖。St会随着时间序列向前传播,而StWxWs的函数。
因此任意时刻损失对于WxWs的偏导为:
LtWx=k=0tLtOtOtSt(j=k+1tSjSj1)SkWx

对于Ws同理。加上激活函数之后,有:
Sj=activate(WxXj+WsSj1+b1)

因此:
j=k+1tSjSj1=j=k+1t=activate(Sj)×Ws

如果激活函数为y=tanh(x),图像为:
这里写图片描述
如果激活函数为y=sigmod(x),则图像为:
这里写图片描述
由上图可以看出activate1,对于训练中大部分都是activate都是小于1的。因此tj=k+1=activate(Sj)×Ws就会趋近0。同理,如果存在activate>1tj=k+1=activate(Sj)×Ws会趋近无穷,这就是梯度消失(vanishing gradient)和梯度爆炸(explode gradient)现象。要解决这一现象,就要使得tj=k+1=activate(Sj)×Ws趋近1或者趋近0,这就是LSTM出现的原因。

5 LSTM的基本结构

每个LSTM神经元有4个input,3个gate,1个output
这里写图片描述
对于传统的RNN神经元,t时刻会立刻把t1时刻存储在memory中的值冲刷掉,因此只能做到短期记忆,即ShortShortTermMemory。LSTM的cell为:
)
Z是外界的input,其中哦那个的3个gate分别为input gate, forget gate, output gate,控制参数分别为Zi,Zf,Zo,都是通过Z学习产生,注意Zi,Zf,Zo都是数值(标量)。然后Z,Zi,Zf,Zo分别通过激活函数(通常是sigmod函数)分别得到g(z),f(Zi),f(Zf),f(Zo),代表相应gate的打开程度,如果f(Z)为1,表示完全打开,若为0则为完全关闭。设原来存储的值为c,则经过一个Z之后,memory里面的值变为:

c=g(Z)f(Zi)+cf(zf)

f(Zi)表示是否允许Z的输入, f(Zf)表示是否要将存在memory里面的值c冲洗掉。
LSTM与传统的神经网络相同,只需将传统的网络中的神经元换成LSTMCell即可:
这里写图片描述
因此对于一个序列x1,x2,需要乘以几个权值分别得到Z,Zi,Zf,Zo,然后分别控制3个gate
通常情况下LSTM的神经网络图为
)
假设该网络有n个LSTM的cell,其中c(t1)是一个n维的vector,表示t1时刻存放在LSTM的Cell中的值组成的向量。Xt也是一个向量,是由n个输入的x组成的向量,作为LSTM的输入值。xt乘以分别乘以权值WfWiWo得到n维向量ZfZiZo,分别用来控制n个LSTM的3个gate。注意:每个LSTM Cell的gate控制值都只是一个标量。
单个Cell的计算过程为:
这里写图片描述
整个LSTM的计算过程为:
这里写图片描述
以上只是最简单的LSTM,实际使用过程中会将ctyt拿过来和xt+1同时作为控制LSTM的输入:
这里写图片描述
多层的LSTM结构为:
这里写图片描述

6. 为何LSTM能解决Gradient Vanishing问题

实际工作过程当中,RNN的训练Loss变化为:
这里写图片描述

即图中绿线所示,蓝线为理想状态下Loss变化图。

训练过程中,Loss与参数变化示意图为:
这里写图片描述
可以看出,图中的Loss会剧烈震荡,因此在通过Gradient Descent参数参数的过程当中,由于learning rate的原因,导致参数跳动太大。因此一般采用clip的方法,即当Gradient大于某个阈值的时候,就以该阈值作为此时的Gradient。
RNN能产生Gradient Vanishing主要是由于RNN本身的特征产生的。对于传统的RNN来讲,假设有以下的一个简单的例子:
这里写图片描述
如果输入序列为(1,0,,0),则得到的输出y1000y1000=w999。当w=1时,y1000=1。当w=1.01时,y100020000。当w=0.99时,y10000。当w=0.01时,y10000。因此w11.01的时候Lw特别大,此时应该用一个比较小的learningrate。但从10.99和从0.990.01,此时Lw特别小,此时需要一个大一点的learningrate。因此以上两种情况会矛盾。这主要是因为RNN有着一个比较长的sequence,同样的weight在不同的时间点会被不断被反复使用。

而对于LSTM来讲,在处理memory里面的值的时候,采用的方法是不同的。在RNN里面,每一个新的时间点,memory里面的值都会被冲洗掉。而在LSTM里面,ct=ct1×Zf+f(Z),因此和原来的值是相加关系。虽然在训练过程中有forgetgate,但通常会给forgetgate一个较大的biases,这样forgetgate在多数情况下会开启,此时只需要调整learningrate到一个比较小的值即可。因此LSTM可以解决GradientVanishing问题,但是无法解决GradientExplode问题。

另一方面,RNN无法解决长期记忆问题,假设我们试着去预测“I grew up in France… I speak fluent French”最后的词。当前的信息建议下一个词可能是一种语言的名字,但是如果我们需要弄清楚是什么语言,我们是需要先前提到的离当前位置很远的 France 的上下文的。这说明相关信息和当前预测位置之间的间隔就肯定变得相当的大。不幸的是,在这个间隔不断增大时,RNN 会丧失学习到连接如此远的信息的能力。但是LSTM因为拥有forgategate,是可以解决长期记忆问题的。

其他的解释LSTM解决GradientVanishing问题:
1. LSTM如何来避免梯度弥散和梯度爆炸?
2. 为什么相比于RNN,LSTM在梯度消失上表现更好?
3. LSTM如何解决梯度消失问题

7. LSTM解决问题举例:

7.1. 机器翻译

这里写图片描述
但此时翻译会一直继续下去,因此需要定义一个终止符号:
这里写图片描述
其余都是通过AutoEncoder来实现:
这里写图片描述

7.2. 语音辨识:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述
训练结果为:
这里写图片描述

7.3. 聊天机器人:

这里写图片描述
通过不断收集对话的Data,然后丢入RNN中不断训练。

7.4. visual question answer

这里写图片描述

这里写图片描述

7.4. 英语听力测试:

这里写图片描述

6 LSTM的TensorFlow简单实现

import tensorflow as tffrom tensorflow.examples.tutorials.mnist import input_datafrom tensorflow.contrib import rnnmnist = input_data.read_data_sets("/tmp/data/", one_hot = True)hm_epochs = 3n_classes = 10batch_size = 128chunk_size = 28n_chunks = 28rnn_size = 128x = tf.placeholder('float', [None, n_chunks,chunk_size])y = tf.placeholder('float')def recurrent_neural_network(x):    layer = {'weights':tf.Variable(tf.random_normal([rnn_size,n_classes])),             'biases':tf.Variable(tf.random_normal([n_classes]))}    x = tf.transpose(x, [1,0,2])    x = tf.reshape(x, [-1, chunk_size])    x = tf.split(x, axis=0, num_or_size_splits = n_chunks)    lstm_cell = rnn.BasicLSTMCell(rnn_size,state_is_tuple=True)    outputs, states = rnn.static_rnn(lstm_cell, x, dtype=tf.float32)    output = tf.matmul(outputs[-1],layer['weights']) + layer['biases']    return outputdef train_neural_network(x):    prediction = recurrent_neural_network(x)    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=y))    optimizer = tf.train.AdamOptimizer().minimize(cost)    with tf.Session() as sess:        sess.run(tf.global_variables_initializer())        for epoch in range(hm_epochs):            epoch_loss = 0            for _ in range(int(mnist.train.num_examples / batch_size)):                epoch_x, epoch_y = mnist.train.next_batch(batch_size)                epoch_x = epoch_x.reshape((batch_size, n_chunks, chunk_size))                _, c = sess.run([optimizer, cost], feed_dict={x: epoch_x, y: epoch_y})                epoch_loss += c            print('Epoch', epoch, 'completed out of', hm_epochs, 'loss:', epoch_loss)        correct = tf.equal(tf.argmax(prediction, 1), tf.argmax(y, 1))        accuracy = tf.reduce_mean(tf.cast(correct, 'float'))        print('Accuracy:',              accuracy.eval({x: mnist.test.images.reshape((-1, n_chunks, chunk_size)), y: mnist.test.labels}))train_neural_network(x)
原创粉丝点击