1 引入
一个input的属性 会受到其前后文的影响——>神经网络需要记忆
这里“Taipei”的属性(destination还是source)受到前面的动词“arrive”和“leave”的影响。所以为了更好地预测"Taipei",神经网络必须记住前面的动词时arrive还是leave。
2 图示RNN
每一次隐藏层的输出将被保存起来,作为下一时间片的另外一个输入。
2.1 实例
假设图上所有的箭头表示的运算都是求和运算。一开始我们没有历史记忆,隐藏层状态为0。那么隐藏层的两个输出都是1+1=2(这个2被储存起来),然后输出层的输出都是2+2=4。
我们将此时的input(1,1)和上一时刻的隐藏层输出(2,2)一起作为本轮的输入,那么隐藏层状态分别为2+2+1+1=6(存起来),输出的内容为6+6=12
之后的同理。RNN的输出结果和顺序有关,顺序不同,最终的output也会不同
RNN相当于同样的一个network,被不断地使用。隐藏层状态h在各个时间片内传递。
虽然画了这么多模型的部分,模型其实只是下图紫色框的部分。只是输入(灰色的部分)在随着时间的推移在变化。
本质上RNN的模型参数是共享的
2.2 RNN计算图
2.2.1 many to many
2.2.2 many to one
只有最有一个有输出
2.2.3 one to many
只有第一个输入是x+hidden state,之后的都是只有hidden state作为输入
2.2.4 seq2seq
many to one + one to many
2.3 RNN的优劣
2.3.1 优势
- 可以处理任意长度的input
- 模型参数的大小不会随着input尺寸而增加
- 时刻t的计算可以使用很多时间片之前的信息
2.3.2 劣势
- 计算较慢
- 无法并行操作
- 很难处理很多很多步之前的信息
2.4 RNN language model的训练
2.4.1 损失函数
比如我们对每个时间步t,计算输出分布
我们用交叉熵来计算损失函数‘
(因为实际的是one-hot 编码,所以只会有ground truth的的预测概率)
整个训练集的损失函数是整体平均:
2.4.2 语言模型的perplexity
2.4.3 图示
但是,如果sequence很长的话,我们计算整个预料的loss是很昂贵的,所以在实际问题中,我们一般固定一个大小的sequence length(类似于mini-batch SGD)
2.5 RNN的反向传播(BPTT)
这里是因为RNN中参数共享,所以链式法则中的一项为1(紫色框起来的部分),可以去掉
3 word2vector
3.1 one hot encoding
由于词汇很多,所以我们需要一个表示“other”这一层意思的one hot encoding。
3.2 n-gram
将每个单词分为多个小的连续块,如果单词里面出现了这个连续块,对应的这一位设置为1。
上面这个例子为3-gram,就是因为apple里面出现了"app","ppl","ple",所以这三个3-gram对应的位为1,其他的为0。
那么这样就只需要一个26^3的一维向量,比one-hot节省空间。
4 Elman Network & Jordan Network
二者的区别在于,传递给下一时间片的memory是隐藏层还是输出层的output。
5 Bidirectional RNN
两个方向隐藏层的信息合并起来,喂给下一个时间片,然后得到输出。
双向 RNN 仅适用于可以访问整个输入序列的情况。 它们不适用于语言建模,因为未来的单词不可访问。
6 RNN Gradient Flow
我们看一下,如果要反向传播的话,误差是一个什么样的流向
但如果RNN对应的这个W矩阵设置不当的话,可能会出现梯度爆炸/梯度消失的问题:
对于梯度爆炸的情况,我们可以设置一个梯度的上界:
而对于梯度消失,我们则需要改变RNN的结构了(模型并没有看到足够的信息,并没有充分学习数据的特征)
下面的LSTM,就是一种改进:
7 LSTM
lstm有四个输入(神经网络的输入,输入门信号,遗忘门信号,输出门信号)
注:LSTM不能保证它一定没有梯度下降/梯度消失,但是它确实提供了一个更好地学习长距离关联性的方法
7.1 原理
z是神经网络的输入,zi是输入门信号(z经过线性变换而来)。zi通过激活函数(比如sigmoid)得到一个0~1的值f(zi),表示我们的输入信号保留多少比例g(z)*f(zi)
同理,zf是遗忘门的信号,他表示我们的memory保留的比例c*f(zf)
将这一轮的输入和之前的memory加总:c'=g(z)*f(zi)+c*f(zf)
对c'进行一层线性变换,得到h(c')
zo是输出门,控制我们输出的比例
7.2 举例
假设参数【weight+bias】已经学习完毕
1,先考虑第一个输入(3,1,0,1)[最后一个对应的是wx+b的b]。因为输入和三个门的权重已经有了,我们就通过权重计算各个门的比例,得到输入门和遗忘门为1,输出们为0。又输入为3,所以按下图方式更新权重:
然后是(4,1,0,1)
(2,0,0,1),此时输入门关闭,那么记忆部分本轮不更新。
(1,0,1,1),此时输出门打开,记忆存储的7被输出
(3,-1,0,1)
7.3 几点补充
李宏毅教授之后的可见又补充了一些细节
7.3.1 传递状态
相比RNN只有一个传递状态 ,LSTM有两个传输状态,一个 (cell state),和一个 (hidden state)。(Tips:RNN中的 对于LSTM中的 )
其中对于传递下去的改变得很慢,通常输出的 是上一个状态传过来的 加上一些数值。
而则在不同节点下往往会有很大的区别。
7.3.2 门信号的处理
使用LSTM的当前输入和上一个状态传递下来的 拼接,然后得到三个门信号+输入信号z
8 RNN的缺陷
8.1 RNN不太容易训练
8.2 rnn的loss function会很曲折
假设图中最右方的橙色点表示初始值,由于刚开始error surface比较flat,gradient也比较小,learning rate比较大;经过多次的训练后,如果这时候刚好到达悬崖和平原的交接处,这一次的gradient就超级大,再加上之前很大的learning rate,loss可能就会直接‘飞’出去了。
改进措施是clipping,当gradient大于15的时候,就看做是15,不再继续增加,这时gradient的移动方向就是上图中的蓝色虚线部分,就不会再飞出去了,仍然可以继续做RNN training。
8.2.1 可能的原因?
8.2.2 解决方案
LSTM可以把一些很平坦的地方拿掉,使error surface不再有那么平坦的地方;可以解决gradient vanishing问题,但并不能解决gradient exploding的问题,有的地方还是会特别崎岖,因此在使用LSTM时,需要设置很小的learning rate。
LSTM可以解决gradient vanishing的原因:如果forget gate是打开的状态,一旦weight可以影响memory里面的值,这个影响就会永远存在,每次都会有新的东西加进来,不会被直接覆盖掉,除非forget gate打算把memory cell的值忘掉;但RNN是直接覆盖,前面的影响就消失了。(换句话说,RNN是直接把本轮hidden_layer的输出作为memory的,但是LSTM在此基础上,还融合了之前的memory,相当于一个“惯性”)
9 RNN应用
9.1 情感分析 sentiment analysis
输入一些vector组成的sequence,输出情感。
这个sequence最后一个vector的隐藏层接上输出,因为这时候整个句子都看到了。
9.2 语音识别 speech recognition
给一段语音,每隔一段时间采一个样,辨识它听到的声音。
9.3 机器翻译 machine translation
首先先读入这个完整的sequence,然后读完sequence之后,输出第一个翻译的word“机”。
根据上一个时间点的memory和上一个时间点的输出“机”,RNN就可以学习到输出为“器”。
如果不停止的话,rnn可能会一直生成下去,因此要加入一个“断“字,停止生成。
9.4 attention-based model
首先机器会读取一堆sequence,作为它的memory。
然后我们输入一些东西(比如一句问句什么的),input经过一些神经网路后,生成一个reading head controller,告诉我们应该去machine memory的哪里寻找到我们的答案,我们把reading head对应的memory提取出来,再经过神经网路,生成output。
机器阅读理解machine reading comprehension就是这个原理。
当然可以多次生成reading head controller,提取多次信息。
蓝色表示每一个hop,我们reading head controller指向的是谁。