零基础入门深度学习(5) - 循环神经网络

往期回顾

在前面的文章系列文章中,咱们介绍了全链接神经网络和卷积神经网络,以及它们的训练和使用。他们都只能单独的取处理一个个的输入,前一个输入和后一个输入是彻底没有关系的。可是,某些任务须要可以更好的处理序列的信息,即前面的输入和后面的输入是有关系的。好比,当咱们在理解一句话意思时,孤立的理解这句话的每一个词是不够的,咱们须要处理这些词链接起来的整个序列;当咱们处理视频的时候,咱们也不能只单独的去分析每一帧,而要分析这些帧链接起来的整个序列。这时,就须要用到深度学习领域中另外一类很是重要神经网络:循环神经网络(Recurrent Neural Network)。RNN种类不少,也比较绕脑子。不过读者不用担忧,本文将一如既往的对复杂的东西剥茧抽丝,帮助您理解RNNs以及它的训练算法,并动手实现一个循环神经网络。python

 

语言模型

RNN是在天然语言处理领域中最早被用起来的,好比,RNN能够为语言模型来建模。那么,什么是语言模型呢?git

咱们能够和电脑玩一个游戏,咱们写出一个句子前面的一些词,而后,让电脑帮咱们写下接下来的一个词。好比下面这句:github

我昨天上学迟到了,老师批评了____。算法

咱们给电脑展现了这句话前面这些词,而后,让电脑写下接下来的一个词。在这个例子中,接下来的这个词最有多是『我』,而不太多是『小明』,甚至是『吃饭』。数组

语言模型就是这样的东西:给定一个一句话前面的部分,预测接下来最有可能的一个词是什么。网络

语言模型是对一种语言的特征进行建模,它有不少不少用处。好比在语音转文本(STT)的应用中,声学模型输出的结果,每每是若干个可能的候选词,这时候就须要语言模型来从这些候选词中选择一个最可能的。固然,它一样也能够用在图像到文本的识别中(OCR)。app

使用RNN以前,语言模型主要是采用N-Gram。N能够是一个天然数,好比2或者3。它的含义是,假设一个词出现的几率只与前面N个词相关。咱们以2-Gram为例。首先,对前面的一句话进行切词:dom

我 昨天 上学 迟到 了 ,老师 批评 了 ____。python2.7

若是用2-Gram进行建模,那么电脑在预测的时候,只会看到前面的『了』,而后,电脑会在语料库中,搜索『了』后面最可能的一个词。无论最后电脑选的是否是『我』,咱们都知道这个模型是不靠谱的,由于『了』前面说了那么一大堆其实是没有用到的。若是是3-Gram模型呢,会搜索『批评了』后面最可能的词,感受上比2-Gram靠谱了很多,但仍是远远不够的。由于这句话最关键的信息『我』,远在9个词以前!ide

如今读者可能会想,能够提高继续提高N的值呀,好比4-Gram、5-Gram.......。实际上,这个想法是没有实用性的。由于咱们想处理任意长度的句子,N设为多少都不合适;另外,模型的大小和N的关系是指数级的,4-Gram模型就会占用海量的存储空间。

因此,该轮到RNN出场了,RNN理论上能够往前看(日后看)任意多个词。

 

循环神经网络是啥

循环神经网络种类繁多,咱们先从最简单的基本循环神经网络开始吧。

 

基本循环神经网络

下图是一个简单的循环神经网络如,它由输入层、一个隐藏层和一个输出层组成:

纳尼?!相信第一次看到这个玩意的读者心里和我同样是崩溃的。由于循环神经网络实在是太难画出来了,网上全部大神们都不得不用了这种抽象艺术手法。不过,静下心来仔细看看的话,其实也是很好理解的。若是把上面有W的那个带箭头的圈去掉,它就变成了最普通的全链接神经网络。x是一个向量,它表示输入层的值(这里面没有画出来表示神经元节点的圆圈);s是一个向量,它表示隐藏层的值(这里隐藏层面画了一个节点,你也能够想象这一层实际上是多个节点,节点数与向量s的维度相同);U是输入层到隐藏层的权重矩阵(读者能够回到第三篇文章零基础入门深度学习(3) - 神经网络和反向传播算法,看看咱们是怎样用矩阵来表示全链接神经网络的计算的);o也是一个向量,它表示输出层的值;V是隐藏层到输出层的权重矩阵。那么,如今咱们来看看W是什么。循环神经网络的隐藏层的值s不只仅取决于当前此次的输入x,还取决于上一次隐藏层的值s。权重矩阵 W就是隐藏层上一次的值做为这一次的输入的权重。

若是咱们把上面的图展开,循环神经网络也能够画成下面这个样子:

如今看上去就比较清楚了,这个网络在t时刻接收到输入以后,隐藏层的值是,输出值是。关键一点是,的值不只仅取决于,还取决于。咱们能够用下面的公式来表示循环神经网络的计算方法:

 

 

式式

 

式1是输出层的计算公式,输出层是一个全链接层,也就是它的每一个节点都和隐藏层的每一个节点相连。V是输出层的权重矩阵,g是激活函数。式2是隐藏层的计算公式,它是循环层。U是输入x的权重矩阵,W是上一次的值做为这一次的输入的权重矩阵,f是激活函数。

从上面的公式咱们能够看出,循环层和全链接层的区别就是循环层多了一个权重矩阵 W。

若是反复把式2带入到式1,咱们将获得:

 

 

 

 

从上面能够看出,循环神经网络的输出值,是受前面历次输入值、...影响的,这就是为何循环神经网络能够往前看任意多个输入值的缘由。

 

双向循环神经网络

对于语言模型来讲,不少时候光看前面的词是不够的,好比下面这句话:

个人手机坏了,我打算____一部新手机。

能够想象,若是咱们只看横线前面的词,手机坏了,那么我是打算修一修?换一部新的?仍是大哭一场?这些都是没法肯定的。但若是咱们也看到了横线后面的词是『一部新手机』,那么,横线上的词填『买』的几率就大得多了。

在上一小节中的基本循环神经网络是没法对此进行建模的,所以,咱们须要双向循环神经网络,以下图所示:

当遇到这种从将来穿越回来的场景时,不免处于懵逼的状态。不过咱们仍是能够用屡试不爽的老办法:先分析一个特殊场景,而后再总结通常规律。咱们先考虑上图中,的计算。

从上图能够看出,双向卷积神经网络的隐藏层要保存两个值,一个A参与正向计算,另外一个值A'参与反向计算。最终的输出值取决于。其计算方法为:

 

 

 

 

则分别计算:

 

 

 

 

如今,咱们已经能够看出通常的规律:正向计算时,隐藏层的值有关;反向计算时,隐藏层的值有关;最终的输出取决于正向和反向计算的加和。如今,咱们仿照式1和式2,写出双向循环神经网络的计算方法:

 

 

 

 

从上面三个公式咱们能够看到,正向计算和反向计算不共享权重,也就是说U和U'、W和W'、V和V'都是不一样的权重矩阵。

 

深度循环神经网络

前面咱们介绍的循环神经网络只有一个隐藏层,咱们固然也能够堆叠两个以上的隐藏层,这样就获得了深度循环神经网络。以下图所示:

咱们把第i个隐藏层的值表示为,则深度循环神经网络的计算方式能够表示为:

 

 

 

 

 

循环神经网络的训练

 

循环神经网络的训练算法:BPTT

BPTT算法是针对循环层的训练算法,它的基本原理和BP算法是同样的,也包含一样的三个步骤:

  1. 前向计算每一个神经元的输出值;
  2. 反向计算每一个神经元的偏差项值,它是偏差函数E对神经元j的加权输入的偏导数;
  3. 计算每一个权重的梯度。

最后再用随机梯度降低算法更新权重。

循环层以下图所示:

 

前向计算

使用前面的式2对循环层进行前向计算:

 

 

 

 

注意,上面的都是向量,用黑体字母表示;而U、V是矩阵,用大写字母表示。向量的下标表示时刻,例如,表示在t时刻向量s的值。

咱们假设输入向量x的维度是m,输出向量s的维度是n,则矩阵U的维度是,矩阵W的维度是。下面是上式展开成矩阵的样子,看起来更直观一些:

 

 

 

 

在这里咱们用手写体字母表示向量的一个元素,它的下标表示它是这个向量的第几个元素,它的上标表示第几个时刻。例如,表示向量s的第j个元素在t时刻的值。表示输入层第i个神经元到循环层第j个神经元的权重。表示循环层第t-1时刻的第i个神经元到循环层第t个时刻的第j个神经元的权重。

 

偏差项的计算

BTPP算法将第l层t时刻的偏差项值沿两个方向传播,一个方向是其传递到上一层网络,获得,这部分只和权重矩阵U有关;另外一个是方向是将其沿时间线传递到初始时刻,获得,这部分只和权重矩阵W有关。

咱们用向量表示神经元在t时刻的加权输入,由于:

 

 

 

 

所以:

 

 

 

 

咱们用a表示列向量,用表示行向量。上式的第一项是向量函数对向量求导,其结果为Jacobian矩阵:

 

 

 

 

同理,上式第二项也是一个Jacobian矩阵:

 

 

 

 

其中,diag[a]表示根据向量a建立一个对角矩阵,即

 

 

 

 

最后,将两项合在一块儿,可得:

 

 

 

 

上式描述了将沿时间往前传递一个时刻的规律,有了这个规律,咱们就能够求得任意时刻k的偏差项

 

 

 

式3就是将偏差项沿时间反向传播的算法。

循环层将偏差项反向传递到上一层网络,与普通的全链接层是彻底同样的,这在前面的文章零基础入门深度学习(3) - 神经网络和反向传播算法中已经详细讲过了,在此仅简要描述一下。

循环层的加权输入与上一层的加权输入关系以下:

 

 

 

 

上式中是第l层神经元的加权输入(假设第l层是循环层);是第l-1层神经元的加权输入;是第l-1层神经元的输出;是第l-1层的激活函数。

 

 

 

 

因此,

 

 

 

式4就是将偏差项传递到上一层算法。

 

权重梯度的计算

如今,咱们终于来到了BPTT算法的最后一步:计算每一个权重的梯度。

首先,咱们计算偏差函数E对权重矩阵W的梯度

上图展现了咱们到目前为止,在前两步中已经计算获得的量,包括每一个时刻t 循环层的输出值,以及偏差项

回忆一下咱们在文章零基础入门深度学习(3) - 神经网络和反向传播算法介绍的全链接网络的权重梯度计算算法:只要知道了任意一个时刻的偏差项,以及上一个时刻循环层的输出值,就能够按照下面的公式求出权重矩阵在t时刻的梯度

 

 

 

在式5中,表示t时刻偏差项向量的第i个份量;表示t-1时刻循环层第i个神经元的输出值。

咱们下面能够简单推导一下式5。

咱们知道:

 

 

 

 

由于对W求导与无关,咱们再也不考虑。如今,咱们考虑对权重项求导。经过观察上式咱们能够看到只与有关,因此:

 

 

 

 

按照上面的规律就能够生成式5里面的矩阵。

咱们已经求得了权重矩阵W在t时刻的梯度,最终的梯度是各个时刻的梯度之和:

 

 

 

式6就是计算循环层权重矩阵W的梯度的公式。

----------数学公式超高能预警----------

前面已经介绍了的计算方法,看上去仍是比较直观的。然而,读者也许会困惑,为何最终的梯度是各个时刻的梯度之和呢?咱们前面只是直接用了这个结论,实际上这里面是有道理的,只是这个数学推导比较绕脑子。感兴趣的同窗能够仔细阅读接下来这一段,它用到了矩阵对矩阵求导、张量与向量相乘运算的一些法则。

咱们仍是从这个式子开始:

 

 

 

 

由于与W彻底无关,咱们把它看作常量。如今,考虑第一个式子加号右边的部分,由于W和都是W的函数,所以咱们要用到大学里面都学过的导数乘法运算:

 

 

 

 

所以,上面第一个式子写成:

 

 

 

 

咱们最终须要计算的是

 

 

 

咱们先计算式7加号左边的部分。是矩阵对矩阵求导,其结果是一个四维张量(tensor),以下所示:

 

 

 

 

接下来,咱们知道,它是一个列向量。咱们让上面的四维张量与这个向量相乘,获得了一个三维张量,再左乘行向量,最终获得一个矩阵:

 

 

 

 

接下来,咱们计算式7加号右边的部分:

 

 

 

 

因而,咱们获得了以下递推公式:

 

 

 

 

这样,咱们就证实了:最终的梯度是各个时刻的梯度之和。

----------数学公式超高能预警解除----------

同权重矩阵W相似,咱们能够获得权重矩阵U的计算方法。

 

 

 

式8是偏差函数在t时刻对权重矩阵U的梯度。和权重矩阵W同样,最终的梯度也是各个时刻的梯度之和:

 

 

 

 

具体的证实这里就再也不赘述了,感兴趣的读者能够练习推导一下。

 

RNN的梯度爆炸和消失问题

不幸的是,实践中前面介绍的几种RNNs并不能很好的处理较长的序列。一个主要的缘由是,RNN在训练中很容易发生梯度爆炸和梯度消失,这致使训练时梯度不能在较长序列中一直传递下去,从而使RNN没法捕捉到长距离的影响。

为何RNN会产生梯度爆炸和消失问题呢?咱们接下来将详细分析一下缘由。咱们根据式3可得:

 

 

 

 

上式的定义为矩阵的模的上界。由于上式是一个指数函数,若是t-k很大的话(也就是向前看很远的时候),会致使对应的偏差项的值增加或缩小的很是快,这样就会致使相应的梯度爆炸和梯度消失问题(取决于大于1仍是小于1)。

一般来讲,梯度爆炸更容易处理一些。由于梯度爆炸的时候,咱们的程序会收到NaN错误。咱们也能够设置一个梯度阈值,当梯度超过这个阈值的时候能够直接截取。

梯度消失更难检测,并且也更难处理一些。总的来讲,咱们有三种方法应对梯度消失问题:

  1. 合理的初始化权重值。初始化权重,使每一个神经元尽量不要取极大或极小值,以躲开梯度消失的区域。
  2. 使用relu代替sigmoid和tanh做为激活函数。原理请参考上一篇文章零基础入门深度学习(4) - 卷积神经网络的激活函数一节。
  3. 使用其余结构的RNNs,好比长短时记忆网络(LTSM)和Gated Recurrent Unit(GRU),这是最流行的作法。咱们将在之后的文章中介绍这两种网络。
 

RNN的应用举例——基于RNN的语言模型

如今,咱们介绍一下基于RNN语言模型。咱们首先把词依次输入到循环神经网络中,每输入一个词,循环神经网络就输出截止到目前为止,下一个最可能的词。例如,当咱们依次输入:

我 昨天 上学 迟到 了

神经网络的输出以下图所示:

其中,s和e是两个特殊的词,分别表示一个序列的开始和结束。

 

向量化

咱们知道,神经网络的输入和输出都是向量,为了让语言模型可以被神经网络处理,咱们必须把词表达为向量的形式,这样神经网络才能处理它。

神经网络的输入是词,咱们能够用下面的步骤对输入进行向量化:

  1. 创建一个包含全部词的词典,每一个词在词典里面有一个惟一的编号。
  2. 任意一个词均可以用一个N维的one-hot向量来表示。其中,N是词典中包含的词的个数。假设一个词在词典中的编号是i,v是表示这个词的向量,是向量的第j个元素,则:
 

 

 

 

上面这个公式的含义,能够用下面的图来直观的表示:

使用这种向量化方法,咱们就获得了一个高维、稀疏的向量(稀疏是指绝大部分元素的值都是0)。处理这样的向量会致使咱们的神经网络有不少的参数,带来庞大的计算量。所以,每每会须要使用一些降维方法,将高维的稀疏向量转变为低维的稠密向量。不过这个话题咱们就再也不这篇文章中讨论了。

语言模型要求的输出是下一个最可能的词,咱们可让循环神经网络计算计算词典中每一个词是下一个词的几率,这样,几率最大的词就是下一个最可能的词。所以,神经网络的输出向量也是一个N维向量,向量中的每一个元素对应着词典中相应的词是下一个词的几率。以下图所示:

 

Softmax层

前面提到,语言模型是对下一个词出现的几率进行建模。那么,怎样让神经网络输出几率呢?方法就是用softmax层做为神经网络的输出层。

咱们先来看一下softmax函数的定义:

 

 

 

 

这个公式看起来可能很晕,咱们举一个例子。Softmax层以下图所示:

从上图咱们能够看到,softmax layer的输入是一个向量,输出也是一个向量,两个向量的维度是同样的(在这个例子里面是4)。输入向量x=[1 2 3 4]通过softmax层以后,通过上面的softmax函数计算,转变为输出向量y=[0.03 0.09 0.24 0.64]。计算过程为:

 

 

 

 

咱们来看看输出向量y的特征:

  1. 每一项为取值为0-1之间的正数;
  2. 全部项的总和是1。

咱们不难发现,这些特征和几率的特征是同样的,所以咱们能够把它们看作是几率。对于语言模型来讲,咱们能够认为模型预测下一个词是词典中第一个词的几率是0.03,是词典中第二个词的几率是0.09,以此类推。

 

语言模型的训练

可使用监督学习的方法对语言模型进行训练,首先,须要准备训练数据集。接下来,咱们介绍怎样把语料

我 昨天 上学 迟到 了

转换成语言模型的训练数据集。

首先,咱们获取输入-标签对:

输入 标签
s
昨天
昨天 上学
上学 迟到
迟到
e

而后,使用前面介绍过的向量化方法,对输入x和标签y进行向量化。这里面有意思的是,对标签y进行向量化,其结果也是一个one-hot向量。例如,咱们对标签『我』进行向量化,获得的向量中,只有第2019个元素的值是1,其余位置的元素的值都是0。它的含义就是下一个词是『我』的几率是1,是其它词的几率都是0。

最后,咱们使用交叉熵偏差函数做为优化目标,对模型进行优化。

在实际工程中,咱们可使用大量的语料来对模型进行训练,获取训练数据和训练的方法都是相同的。

 

交叉熵偏差

通常来讲,当神经网络的输出层是softmax层时,对应的偏差函数E一般选择交叉熵偏差函数,其定义以下:

 

 

 

 

在上式中,N是训练样本的个数,向量是样本的标记,向量是网络的输出。标记是一个one-hot向量,例如,若是网络的输出,那么,交叉熵偏差是(假设只有一个训练样本,即N=1):

 

 

 

 

咱们固然能够选择其余函数做为咱们的偏差函数,好比最小平方偏差函数(MSE)。不过对几率进行建模时,选择交叉熵偏差函数更make sense。具体缘由,感兴趣的读者请阅读参考文献7

 

RNN的实现

完整代码请参考GitHub: https://github.com/hanbt/learn_dl/blob/master/rnn.py (python2.7)

为了加深咱们对前面介绍的知识的理解,咱们来动手实现一个RNN层。咱们复用了上一篇文章零基础入门深度学习(4) - 卷积神经网络中的一些代码,因此先把它们导入进来。

 
  1. import numpy as np
  2. from cnn import ReluActivator, IdentityActivator, element_wise_op

咱们用RecurrentLayer类来实现一个循环层。下面的代码是初始化一个循环层,能够在构造函数中设置卷积层的超参数。咱们注意到,循环层有两个权重数组,U和W。

 
  1. class RecurrentLayer(object):
  2. def __init__(self, input_width, state_width,
  3. activator, learning_rate):
  4. self.input_width = input_width
  5. self.state_width = state_width
  6. self.activator = activator
  7. self.learning_rate = learning_rate
  8. self.times = 0 # 当前时刻初始化为t0
  9. self.state_list = [] # 保存各个时刻的state
  10. self.state_list.append(np.zeros(
  11. (state_width, 1))) # 初始化s0
  12. self.U = np.random.uniform(-1e-4, 1e-4,
  13. (state_width, input_width)) # 初始化U
  14. self.W = np.random.uniform(-1e-4, 1e-4,
  15. (state_width, state_width)) # 初始化W

在forward方法中,实现循环层的前向计算,这部分比较简单。

 
  1. def forward(self, input_array):
  2. '''
  3. 根据『式2』进行前向计算
  4. '''
  5. self.times += 1
  6. state = (np.dot(self.U, input_array) +
  7. np.dot(self.W, self.state_list[-1]))
  8. element_wise_op(state, self.activator.forward)
  9. self.state_list.append(state)

在backword方法中,实现BPTT算法。

 
  1. def backward(self, sensitivity_array,
  2. activator):
  3. '''
  4. 实现BPTT算法
  5. '''
  6. self.calc_delta(sensitivity_array, activator)
  7. self.calc_gradient()
  8. def calc_delta(self, sensitivity_array, activator):
  9. self.delta_list = [] # 用来保存各个时刻的偏差项
  10. for i in range(self.times):
  11. self.delta_list.append(np.zeros(
  12. (self.state_width, 1)))
  13. self.delta_list.append(sensitivity_array)
  14. # 迭代计算每一个时刻的偏差项
  15. for k in range(self.times - 1, 0, -1):
  16. self.calc_delta_k(k, activator)
  17. def calc_delta_k(self, k, activator):
  18. '''
  19. 根据k+1时刻的delta计算k时刻的delta
  20. '''
  21. state = self.state_list[k+1].copy()
  22. element_wise_op(self.state_list[k+1],
  23. activator.backward)
  24. self.delta_list[k] = np.dot(
  25. np.dot(self.delta_list[k+1].T, self.W),
  26. np.diag(state[:,0])).T
  27. def calc_gradient(self):
  28. self.gradient_list = [] # 保存各个时刻的权重梯度
  29. for t in range(self.times + 1):
  30. self.gradient_list.append(np.zeros(
  31. (self.state_width, self.state_width)))
  32. for t in range(self.times, 0, -1):
  33. self.calc_gradient_t(t)
  34. # 实际的梯度是各个时刻梯度之和
  35. self.gradient = reduce(
  36. lambda a, b: a + b, self.gradient_list,
  37. self.gradient_list[0]) # [0]被初始化为0且没有被修改过
  38. def calc_gradient_t(self, t):
  39. '''
  40. 计算每一个时刻t权重的梯度
  41. '''
  42. gradient = np.dot(self.delta_list[t],
  43. self.state_list[t-1].T)
  44. self.gradient_list[t] = gradient

有意思的是,BPTT算法虽然数学推导的过程很麻烦,可是写成代码却并不复杂。

在update方法中,实现梯度降低算法。

 
  1. def update(self):
  2. '''
  3. 按照梯度降低,更新权重
  4. '''
  5. self.W -= self.learning_rate * self.gradient

上面的代码不包含权重U的更新。这部分实际上和全链接神经网络是同样的,留给感兴趣的读者本身来完成吧。

循环层是一个带状态的层,每次forword都会改变循环层的内部状态,这给梯度检查带来了麻烦。所以,咱们须要一个reset_state方法,来重置循环层的内部状态。

 
  1. def reset_state(self):
  2. self.times = 0 # 当前时刻初始化为t0
  3. self.state_list = [] # 保存各个时刻的state
  4. self.state_list.append(np.zeros(
  5. (self.state_width, 1))) # 初始化s0

最后,是梯度检查的代码。

 
  1. def gradient_check():
  2. '''
  3. 梯度检查
  4. '''
  5. # 设计一个偏差函数,取全部节点输出项之和
  6. error_function = lambda o: o.sum()
  7. rl = RecurrentLayer(3, 2, IdentityActivator(), 1e-3)
  8. # 计算forward值
  9. x, d = data_set()
  10. rl.forward(x[0])
  11. rl.forward(x[1])
  12. # 求取sensitivity map
  13. sensitivity_array = np.ones(rl.state_list[-1].shape,
  14. dtype=np.float64)
  15. # 计算梯度
  16. rl.backward(sensitivity_array, IdentityActivator())
  17. # 检查梯度
  18. epsilon = 10e-4
  19. for i in range(rl.W.shape[0]):
  20. for j in range(rl.W.shape[1]):
  21. rl.W[i,j] += epsilon
  22. rl.reset_state()
  23. rl.forward(x[0])
  24. rl.forward(x[1])
  25. err1 = error_function(rl.state_list[-1])
  26. rl.W[i,j] -= 2*epsilon
  27. rl.reset_state()
  28. rl.forward(x[0])
  29. rl.forward(x[1])
  30. err2 = error_function(rl.state_list[-1])
  31. expect_grad = (err1 - err2) / (2 * epsilon)
  32. rl.W[i,j] += epsilon
  33. print 'weights(%d,%d): expected - actural %f - %f' % (
  34. i, j, expect_grad, rl.gradient[i,j])

须要注意,每次计算error以前,都要调用reset_state方法重置循环层的内部状态。下面是梯度检查的结果,没问题!

 

小节

至此,咱们讲完了基本的循环神经网络、它的训练算法:BPTT,以及在语言模型上的应用。RNN比较烧脑,相信拿下前几篇文章的读者们搞定这篇文章也不在话下吧!然而,循环神经网络这个话题并无完结。咱们在前面说到过,基本的循环神经网络存在梯度爆炸和梯度消失问题,并不能真正的处理好长距离的依赖(虽然有一些技巧能够减轻这些问题)。事实上,真正获得普遍的应用的是循环神经网络的一个变体:长短时记忆网络。它内部有一些特殊的结构,能够很好的处理长距离的依赖,咱们将在下一篇文章中详细的介绍它。如今,让咱们稍事休息,准备挑战更为烧脑的长短时记忆网络吧。

 

参考资料

  1. RECURRENT NEURAL NETWORKS TUTORIAL
  2. Understanding LSTM Networks
  3. The Unreasonable Effectiveness of Recurrent Neural Networks
  4. Attention and Augmented Recurrent Neural Networks
  5. On the difficulty of training recurrent neural networks, Bengio et al.
  6. Recurrent neural network based language model, Mikolov et al.
  7. Neural Network Classification, Categorical Data, Softmax Activation, and Cross Entropy Error, McCaffrey
  8. 转载自:https://zybuluo.com/hanbingtao/note/541458
相关文章
相关标签/搜索