RNN的理解与实践
对于RNN和CNN的区别,最感性的认识就是CNN适用于做网格计算,所以经常被应用于图像处理的问题;而RNN更适用于处理序列,所以经常被应用于文本的处理。而对RNN的兴趣源于寒小阳&龙心尘的一篇博文,可以利用神经网络模仿人类写作,可以跑出来具有小四风格的文章段落。正好有师妹推荐了新晋机器学习Python神库Keras,那就理论加实践一起认识一下神奇的循环神经网络吧。
RNN结构及原理浅析
首先,需要说明的是,RNN依然是一个神经网络,其基本结构与普通的神经网络基本一致,如下图所示Ref:
但所不同的是,传统的神经网络(包括CNN)假定所有输入和输出都是相互独立的。而RNN的基本假设是输入序列之间是存在相互影响的。RNN之所以被称为循环,就是它会按照序列的输入时间不断重复训练该网络,并利用后向传播算法不断迭代更新权重$(U, V, W)$,这也就是为什么可以将RNN一层网络“展开”为$n$层,而$n$是序列输入的长度,也是时间总步长。同时,不难理解为什么一个RNN层“展开”的结点都共用一套参数。这里的“展开”是虚拟的。
其中,$U$是从输入层到隐藏层$S$的参数,$W$是$t$时刻到$t+1$时刻的参数,$V$是隐藏层到输出层的参数。图片来源于Bengio的Deep Learning一书中第二部分第10章Sequence Modeling: Recurrent and Recursive Nets。
RNN的基本算法如下:
- $x_t$是$t$时刻的输入,可以是单词或者句子的One-hot编码;
- 隐藏层$s_t=f(Ux_t+Ws_{t-1})$,通常函数$f$会选择tanh或者ReLU,$s_{t-1}$是前一时刻的隐藏状态,当$t=0$时,$s_{-1}$通常被初始化为0向量;
- 输出$o_t=\mathrm{Softmax}(Vs_t)$。
值得注意的是,虽然隐藏层状态的更新经历了全输入序列,但由于神经网络参数训练的机制,只有当前时刻前近段时间内输入对其有影响,这也是符合人类记忆的基本规律。
最简单的RNN介绍到这,在此基础之上还有双向RNN和LSTM,暂时不做展开。我们直接介绍将要用到的character-level RNN。
Character-Level RNN
大神Karpathy在其一篇博客上面提到了Character-level RNN(以下简称char-RNN)最初的想法便是扔给RNN一堆文本,让其从字母级别进行学习,让RNN写出以某字母或者某单词开始,最可能的字符序列,组织成词或者句子。
例如有四个字母h, e, l, o。将其映射成k维的向量,用hello
作为训练样本对网络进行训练。完成训练后,以h为首字母,让网络自动输出最有可能的字母接在后面,组成一个单词。
例子很简单,最终肯定会生成单词hello
,而举这个例子的目的是理解char_RNN的工作原理。第一步先扔给RNN一个字母h,后面接“h”的置信度是1.0,接e是2.2,接“l”是-3.0,接“o”4.1. 因为我们的训练数据是“hello”,所以对于下一个字母“e”我们想要提高其的置信度(绿色)并降低其他字母的置信度(红色). 同样地,我们每走一步都要提高绿色字母的置信度。因为RNN组成均可微,所以可以采用backpropagation算法调整权重。然后,我们可以执行参数更新。如果我们持续喂给RNN同样的输入后,会发现正确的字符 (如第一步中的”e”) 的置信度便会稍高,而不正确的字符的置信度将会稍低。我们然后重复这个过程多次,直到网络收敛和其预测就是最终符合训练数据,下一步就总是正确的字符。
更具体的细节,例如会同时用标准的Softmax分类器同步更新输出变量。RNN用mini-batch随机梯度下降算法更新参数(mini-batch Stochastic Gradient Descent),或者也可以用RMSProp或Adam (per-parameter adaptive learning rate methods)更新参数。需要注意的是,训练数据中有两个“l”,而两个“l”出现的置信度是不一样的,这是因为RNN依赖于上下文,而不仅仅是前一个字母。
在测试时,我们会得到下一个可能的字母的概率分布,依据这个概率分布可以得到下一下最有可能出现的字母,重复这个过程,来看看出现什么奇迹吧!
出于教学的目的,作者Karpathy用Python/numpy写了一个小的character-level RNN语言模型的Demo(需翻墙)。只有100行代码,这里贴出来与大家分享,希望可以给大家一些直观的具体的理解。现在作者Karpathy及其团队更专注于更快更强的Lua/Torch代码库。
1 | """ |
Keras
Keras的作者不是希腊人就是对文学很感兴趣,因为Keras在希腊语中意指号角。其文学形象来源于古希腊和拉丁文学,最初出现于Odyssey。梦境被分为被幻像欺骗的人,通过象牙门到达凡间的人,预言家和从号角门中来的人。最近越来越热的深度学习上层封装库,简单列一下优缺点吧,因为使用的话看文档三分钟就可以搭出一个深度学习的模型原型,支持可插拔的神经网络层,不能更赞。但调试不易,且不利于对于原理的理解。
项目地址:https://github.com/fchollet/keras
文档地址:http://keras.io/
优点:
- 文档非常全且细致。
- 提供较为上层的框架,搞个深度学习的原型非常方便。
- 更新很快,且基于Python,支持CPU、GPU运算。
- 现在已经可以切换backend了,可以选择用
theano
还是用tensorflow
缺点:
- 原理上理解还是建议动手去搭
- 运行效率较低
- 调试不易
- 更新太快,Github上面的基于
Keras
的代码基本要根据最新的文档改一遍才能用。
Char-RNN Using Keras
由于是小试牛刀,所以直接从Github上面扒了一段Keras的char-RNN代码,修改一下,跑沙士比亚《凯撒大帝(The Tragedy of Julius Ceasar)》的剧本。
1 | # -*- coding: utf-8 -*- |
结果是我的小mba风扇呜呜直转,跑了两天多,RNN像一个小孩子从刚刚咿呀学语,到最后能出完整的单词和句子,简直不能神奇更多。
- epoch:0, batch:1000, loss:2.13260865211
LSTM based fo?
OUREOTIN:
Why rom hames ane ttwe woe, wheu menerk.
SeDIS:
Ay, by shue le art feramt your of
Thin hen a soating lener ti vis
The to mime
Bo rinh. oliwhew of: she hiant,
Anles woer deie hizh theew on wore,
The te dwyialt im sishor' va.
- epoch:40, batch:1000, loss:1.24812698364
LSTM based sight:
This splits agurated with your cheek to wor,
Even and more perjection of thy life,
You should not visit such aljufper'd up:
And you will did my deft, to know the bases:
Our sweet Worwing thrafts to such convey'd his
own's boar weakness. Take i
- epoch:99, batch:1000, loss:1.11117362976
LSTM based Norfaxen!
GREMIO:
Fight, they know it.
CATESBY:
My Lord of York, here he not appear'd toice.
Widow:
Fetch them well: is thy son was from me all:
Were my behind the earth rabes through himself.
PROSPERO:
I will confess him with your infroch
扯些闲篇
用char-RNN学习写汉字的一篇文章。
以及黑镜第三季中有一集可以学习男友的通信及聊天记录,可以模拟男友与自己聊天,栩栩如生。如今看来完全可以用RNN来进行训练。