RECURRENT NEURAL NETWORK TUTORIAL, PART 4 – IMPLEMENTING A GRU/LSTM RNN WITH PYTHON AND THEANO

本文中,我们将学习关于LSTM (Long Short Term Memory)网络和 GRUs (Gated Recurrent Units)的知识。LSTM最初由Sepp Hochreiter and Jürgen Schmidhuber于1997年提出,如今是深度学习自然语言处理领域最流行的模型。GRU,出现于2014年,是LSTM的简化版,与LSTM有许多相似的特性。##LSTM 网络在第三部分我们提到了梯度消失问题妨碍了标准的RNN学习长期依赖问题。LSTM被设计于用gate结构解决梯度消失问题。为了理解这个机制,我们来看看LSTM如何计算隐藏状态$$s_t$$(其中小圆圈代表Hadamard product,即同型矩阵各元素对应相乘,不同于矩阵点乘)。式子看起来复杂,一步一步来理解实则简单。首先,LSTM的一层代表的只是另一种计算隐藏层的方法。之前我们计算了隐藏状态$$s_t = tanh(Ux_t + WS_{s-1})$$。对于当前的单元,输入是$$t$$时刻的$$x_t$$,而$$s_{t-1}$$是之前的隐藏状态,输出是新的隐藏状态$$s_t$$。其实,LSTM做的事情是完全一样的,只不过换了种方式,这也是理解LSTM的核心。我们可以把LSTM单元看作是黑盒子,给予其当前输入和之前的隐藏状态,它可以输出下一个隐藏状态。把这个牢记于心,我们开始来阐述LSTM如何计算隐藏状态。关于这一点,详细可看这篇文章,这里我们只作简短描述:$$i,f,o$$分别被称为输入门、遗忘门和输出门。注意到,它们具有相同的等式,只是参数矩阵不同。它们之所以被称为“门”,是因为sigmoid函数将向量值压缩到0和1之间,再与另一个向量相乘,我们因此决定向量的多少“通过”。输入门决定当前输入计算出来的状态的多少成分被通过,遗忘门决定之前的状态有多少可以被保留到之后,输出门决定当前的状态有多少被传送到外层的网络(高层网络和下一时刻)。这些门的维度都是$$d_s$$,即隐藏层的大小。$$g$$是一个候选的隐藏状态,基于当前的输入和之前的隐藏状态计算而出。其与vanilla RNN的计算等式相同,只是把参数$$U,W$$改名为$$U^g,W^g$$。和RNN的直接将$$g$$作为心的隐藏状态不同,我们将其通过一个输入门来决定保留它的多少成分。$$c_t$$是单元的内部的记忆,它由之前的记忆$$c_{t-1}$$通过遗忘门再加上新计算出来的隐藏状态$$g$$通过输入门计算得出。因此,它代表了旧的记忆与新的输入的结合。我们可以选择全部忽略旧的记忆(遗忘门全部置零),或者忽略全部的计算出的新状态(输入门全部置零),但是通常来说,我们可能更希望介于两者之间。给定记忆$$c_t$$,我们最终通过让记忆和输出门相乘计算出输出隐藏层状态$$s_t$$。在网络内,不是所有的内部记忆都与其他单元使用的隐藏状态有关。换一种说法,我们可以将标准的RNN看作是特殊的LSTM,如果我们将遗忘门全部置零,输入门全部置一,输出门全部置一,我们就几乎得到一个标准的RNN。通过门机制,LSTM可以操作记忆从而解决长期依赖问题。注意到,还有许多的LSTM变种,一种添加上“猫眼”结构,它的门同时取决于之前的隐藏状态$$s_{t-1}$$和之前的内部状态$$c_{t-1}$$。 LSTM: A Search Space Odyssey 实验观察了许多不同的LSTM机制。##GRU网络GRU的理念类似于LSTM,其等式如下:GRU拥有两个门,称为重置门$$r$$和更新门$$z$$。直观来说,重置门决定如何联合新的输入和之前的记忆,而更新门决定留下多少之前的记忆。如果将重置门全部置一并且更新门全部置零,那么我们又得到了我们原始的RNN了。GRU的解决长期依赖的理念和LSTM基本类似,以下是一些不同之处:两个门VS三个门GRU不处理内层记忆$$c_t$$输入门和遗忘门被组合成更新门$$z$$,重置门$$r$$直接连接之前的隐藏状态。因此,计算输出是不加上第二个非线性变换##GRU VS LSTM如今你认识了两个对抗梯度消失的模型  

0 Comments

在Windows上安装并加速拉取Docker镜像的方法

Docker容器服务近来可谓是一日千里爆炸式的发展,但是在国内安装Docker或者拉取庞大的Docker镜像都不可避免的遇到蜗牛式速度的问题,本文主要关于加速下载DockerWindows客户端和镜像的方法。   下载Docker Windows客户端 使用Daocloud提供的下载地址,基本上几分钟即可下载完100Mb左右的Docker Windows客户端,而用Docker官网的下载地址可谓几乎没有速度。 加速拉取Docker镜像 不挂VPN直接拉取Docker镜像绝对是灾难性的体验,不仅慢如狗而且极容易中断连接。这里我们同样使用Daocloud提供的镜像站如这里,使用方法为在Docker右键菜单的设置选项内的DockerDaemon里面,加上一段地址改为如下形式, 1 2 3 4 5 6 { "registry-mirrors": [ "http://59dcc468.m.daocloud.io" ], "insecure-registries": [] } 之后Docker会自动重启,之后再Pool镜像即可享受火箭加速般的提升!  

0 Comments

RECURRENT NEURAL NETWORKS TUTORIAL, PART 3 – BACKPROPAGATION THROUGH TIME AND VANISHING GRADIENTS

在之前的部分我们实现了RNN,但是并未深入探究时间反向传播算法,本文将对这一点作详细说明。我们将了解关于梯度消失问题的知识,它促使了LSTM和GRU的出现,而这两者都是NLP领域非常常见的模型。##BACKPROPAGATION THROUGH TIME (BPTT)首先我们回顾一下RNN的基本等式:我们也定义了损失函数(交叉熵):在这里,$$y_t$$是 $$t$$时刻的正确的词语, $$tilde{y_t}$$ 是我们的预测。因为我们把一整个序列(句子)当做是输入,那么错误等同于每个时间step(词语)的错误的和。![](/images/2016/06/rnn-bptt1.png)需要注意,我们的目标是计算基于参数$$U, V, W$$错误的梯度,并且通过SGD来学习到好的参数。类似于我们将错误相加的做法,对于一个训练样本,我们将各个时间点的梯度相加。$$frac{partial{E}}{partial{W}} = sum_{t} frac{partial{E_t}}{partial{W}}$$我们使用链式求导法则来计算这些梯度,这就是反向传播算法:从错误处反向计算。以下我们使用$$E_3$$作为例子。其中,$$z_3 = V s_3$$,并且$$otimes$$指的是向量外积。在这里我们需要注意到,$$frac{partial{E_3}}{partial{V}}$$只取决于当前时刻的值$$tilde{y_3}, y_3, s_3$$。如果你明确了这一点,那么计算$$V$$的梯度只是矩阵计算罢了。但是,对于$$frac{partial{E_3}}{partial{W}}$$和$$V$$就不一样了。我们写出链式法则:可以看到,$$s_3 = tanh(U x_t + W s_2)$$取决于$$s_2$$,而$$s_2$$又取决于$$W$$和$$s_1$$,以此类推。所以我们计算$$W$$的偏导,我们不能把$$s_2$$当做一个常量,相反我们需要一遍遍的应用链式法则:我们把每个时间点对于梯度贡献综合起来。换句话说,因为$$W$$在直到我们需要输出的时刻都被用到,所以我们需要计算$$t=3$$时刻直到$$t=0$$时刻:这其实和深度前馈神经网络里的标准的反向传播算法是类似的。主要的不同点在于我们把每个时间点的$$W$$的梯度综合起来。传统的神经网络的不同层之间不共享参数,于是我们也不需要综合什么。但是在我看来,BPTT只不过是在没有展开的RNN上的标准BP算法的别名罢了。类似于标准的BP算法,你也可以定义一个徳塔项来表示反向传播的内容。例如:$$delta_{2}^{(3)} = frac{partial{E_3}}{partial{z_2}} = frac{partial{E_3}}{partial{s_3}} frac{partial{s_3}}{partial{s_2}} frac{partial{s_2}}{partial{z_2}}$$,其中$$z_2 =…

0 Comments

Learn More,Study Less

关于learn more study less 的思维导图 ![](/images/2017/03/learn more study less 15.45.08.png)holistic learning 的流程Acquire 获取准确、精炼地得到信息 简化 提取精华、略去无用信息 容量 知道的信息越多越好 速度 尽快完成获取阶段 Understand 理解了解信息的基本意思,并联系上下文来理解 理解信息的第一阶段:理解信息的表层含义 当遇到不明白之处,应该分解问题,找到真正不明白之处 Explore 扩展形成高速公路、模型及内部联系良好的结构 深度扩展 知识的由来、背景的探究 横向扩展 构造模型:寻找类似的知识的联系 纵向扩展…

0 Comments

Vim 练级攻略一

你想以最快的速度学习人类史上最好的文本编辑器VIM吗?你先得懂得如何在VIM幸存下来,然后一点一点地学习各种戏法。Vim: the Six Billion Dollar editorBetter, Stronger, Faster.学习Vim并且其会成为你最后一个使用的文本编辑器。没有比这个更好的文本编辑器了,非常地难学,但是却不可思议地好用。我建议下面这四个步骤:存活感觉良好觉得更好,更强,更快使用VIM的超能力当你走完这篇文章,你会成为一个vim的 superstar。在开始学习以前,我需要给你一些警告:学习vim在开始时是痛苦的。需要时间需要不断地练习,就像你学习一个乐器一样。不要期望你能在3天内把vim练得比别的编辑器更有效率。事实上,你需要2周时间的苦练,而不是3天。##第一级 – 存活安装Vim启动Vim什么也不干!请先阅读当你安装好一个编辑器后,你一定会想在其中输入点什么东西,然后看看这个编辑器是什么样子。但vim不是这样的,请按照下面的命令操作:启动Vim后,vim在 Normal 模式下。让我们进入 Insert 模式,请按下键 i 。(你会看到vim左下角有一个–insert–字样,表示,你可以以插入的方式输入了)此时,你可以输入文本了,就像你用“记事本”一样。如果你想返回 Normal 模式,请按 ESC 键。现在,你知道如何在 Insert 和 Normal 模式下切换了。下面是一些命令,可以让你在 Normal 模式下幸存下来(箭头不代表按键):i → Insert 模式,按…

0 Comments

Vim 练级攻略二

第三级 – 更好,更强,更快先恭喜你!你干的很不错。我们可以开始一些更为有趣的事了。在第三级,我们只谈那些和vi可以兼容的命令。更好下面,让我们看一下vim是怎么重复自己的:. → (小数点) 可以重复上一次的命令N → 重复某个命令N次下面是一个示例,找开一个文件你可以试试下面的命令:2dd → 删除2行3p → 粘贴文本3次100idesu [ESC] → 会写下 “desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu…

0 Comments

RECURRENT NEURAL NETWORKS TUTORIAL, PART 2 – IMPLEMENTING A RNN WITH PYTHON, NUMPY AND THEANO

本文将用Python实现完整的RNN,并且用Theano来优化。语言模型我们的目标是使用RNN建立一个语言模型。以下我们举例说明什么是语言模型。例如,你说了一句包括$$m$$个词语的句子,语言模型可以为这句话出现的概率打分:$$P(w_1,cdots,w_m) = prod_{i=1}^m P(w_i mid w_1,cdots,w_{i-1})$$ 每一个词语的概率都取决于它之前的所有的词的概率。这样的模型有什么用处呢?可以用于机器翻译或者语音识别中的正确句子打分以概率生成新的句子注意到在上面的公式内,我们使用了所有的之前的词的概率,实际上这在计算和存储时的耗费都是巨大的,通常而言只会取2~4个词左右。预处理并训练数据1.标记化原始的文本需要被标记化,例如需要把文本标记为句子,句子标记为词语,并且还需要处理标点符号。我们将使用NLTK的word_tokenizesent_tokenize方法。2.移除低频词移除低频词不管是对于训练和预测都是有帮助的。这里我们设置一个上限vocabulary_size为8000,出现次数少于它的词都会被替换为UNKNOWN_TOKEN输入,而当输出是UNKNOWN_TOKEN时,它将被随机替换为一个不在词表内的词,亦或者持续预测直到不出现UNKNOWN_TOKEN为止。3.放置句子开始和结束标记为了解句子的开始和结束,我们把SENTENCE_START放置在句子开头,并且把SENTENCE_END放置在句子结尾。4.建立训练数据的矩阵RNN的输入和输出都是向量而不是字符串,我们需要把词与向量一一对应,通过index_to_word和word_to_index。比如一个训练的例子$$x$$为[0, 179, 341, 416](注意到其中每个元素都是长度为vocabulary_size的one-hot向量,所以$$x$$实际上是一个矩阵),那么其label-$$y$$为[179, 341, 416, 1],注意到我们的目标是预测下一个词,所以$$y$$就是$$x$$移动一位,并添加上最后的一个元素(预测词)的结果,其中SENTENCE_START和SENTENCE_END分别为0和1.123456789101112131415161718192021222324252627282930313233343536373839404142vocabulary_size = 8000unknown_token = "UNKNOWN_TOKEN"sentence_start_token = "SENTENCE_START"sentence_end_token = "SENTENCE_END"# Read the data and append SENTENCE_START and SENTENCE_END tokensprint…

0 Comments