实际上RNN有两种神经网络模型的缩写
一种是递归神经网络(Recursive Neural Network)----针对树状结构
一种是循环神经网络(Recurrent Neural Network)----针对时间序列
虽然这两种神经网络有着千丝万缕的联系,但是大部分情况下主要讨论的是第二种神经网络模型——循环神经网络(Recurrent Neural Network)。
从应用方面上来看,CNN用到做图像识别比较多,而RNN在做到语言处理多一点,如果拿来比喻的话,CNN如同眼睛一样,正是目前机器用来识别对象的图像处理器。相应地,RNN则是用于解析语言模式的数学引擎,就像耳朵和嘴巴。
CNN神经网络:有一个基础的假设——人类的视觉总是会关注视线内特征最明显的点。所以CNN没有时序性的概念,输入直接和输出挂钩。
RNN神经网络,它的假设则是——事物的发展是按照时间序列展开的,即前一刻发生的事物会对未来的事情的发展产生影响。因此需要RNN具有时序性,当前决策跟前一次决策有关。
语言模型可以对一段文本的概率进行估计,对信息检索,机器翻译,语音识别等任务有着重要的作用。
语言模型分为统计语言模型和神经网络语言模型。
(1)统计语言模型
经典的统计语言模型就是N-gram语言模型。
核心就是:当前词只和它前面的n个词有关,与更前面的词无关
n-gram语言模型解决了用普通的条件概率计算句子概率参数太多难以训练的问题,理论上来说n取得越大保留的词序信息就越多,生成的句子越合理,但如果n取得比较大,同样会面临数据稀疏的问题,n-gram 模型解决了参数太多难以训练的问题,但没有解决数据稀疏的问题。
之所以存在数据稀疏的问题,是因为我们想把n取得大一点来更多的保留词序信息,但n太大会导致w1,w2,w3,…wn这个序列在语料中很少出现或者根本不出现,(根据经验也知道太长的一句话在语料中出现的次数不是那么多,要远远小于2,3个词出现的次数)造成计算出的条件概率接近于0,那算出的句子的概率也是接近于0,这个语言模型就没法用了,这是数据稀疏导致的训练出的语言模型无法用的原因。
现在问题来了,我们既想把n取的大一点以保留更多的词序信息,又想避免数据稀疏的问题,事实上,确实有这样的模型,那就是神经网络语言模型。
(2)神经网络语言模型
神经网络语言模型的提出解决了n-gram模型当n较大时会发生数据稀疏的问题。
与N-gram语言模型相同,神经网络语言模型(NNLM)也是对n元语言模型进行建模,估计P(wi|wi−n+1,wi−n+2,…wi−1)的概率,与统计语言模型不同的是,NNLM不通过计数的方法对n 元条件概率进行估计,而是直接通过一个神经网络对其建模求解。
现在常用的是循环神经网络语言模型(RNNLM)。
首先看一个简单的循环神经网络如,它由输入层、一个隐藏层和一个输出层组成:
接下来依次分析出现的结点:
(1)X是一个向量,它表示输入层的值(这里面没有画出来表示神经元节点的圆圈)
(2)S是一个向量,它表示隐藏层的值(这里隐藏层面画了一个节点,你也可以想象这一层其实是多个节点,节点数与向量s的维度相同);
(3)O也是一个向量,它表示输出层的值
(4)U是输入层到隐藏层的权重矩阵,
(5)V是隐藏层到输出层的权重矩阵。
到此,如果把上面有W的那个带箭头的圈去掉,它就变成了最普通的全连接神经网络(CNN)。
那么W是什么?----循环神经网络的隐藏层的值s不仅仅取决于当前这次的输入x,还取决于上一次隐藏层的值s。所以权重矩阵 W就是隐藏层上一次的值作为这一次的输入的权重。
接下来进一步地,公式化 RNN 的结构:
现在看上去就比较清楚了,这个网络在t时刻接收到输入Xt 之后,隐藏层的值是 St ,输出值是Ot 。关键一点是,St的值不仅仅取决于 Xt,还取决于 St-1 。我们可以用下面的公式来表示:
带上偏置项和具体激活函数就是如下所示:
最后总结一下RNN的网络结构
注意下图中的x1,x2…并不是时序下的输入,而是一个时刻的输入。别和Xt和Xt-1混淆了。
带入参数去看一个RNN的示例,如下所示,希望output层中绿色的数字足够大,而红色的数字足够小, 这样经过softmax后,才能输出正确的内容。
对于RNN来说有一个时间概念,需要把梯度沿时间通道传播的 BP 算法,所以称为Back Propagation Through Time-BPTT
首先明确反向传播的计算目标是什么?
由前向传递公式:
可知我们的目标是计算误差关于参数U、V和W以及两个偏置bx,by的梯度,然后使用梯度下降法学习这几项参数。
计算过程总体说明
具体推导见两帖:
学习笔记-循环神经网络(RNN)及沿时反向传播BPTT
时序反向传播算法(BPTT)
简单介绍一下过程:
BPTT算法是针对循环层的训练算法,它的基本原理和BP算法是一样的,也包含同样的三个步骤:
(1)前向计算每个神经元的输出值
(3)计算每个权重的梯度。
BPTT的问题:
t时刻的梯度是前t-1时刻所有梯度的累积,时间越长,梯度消失越严重
RNN最主要的问题是梯度消失与梯度爆炸,至于RNN梯度消失和爆炸的原因可以见这个帖子(RNN梯度消失和爆炸的原因),简单的说RNN梯度爆炸与梯度消失是由于连乘项导致隐藏层权重V不断增大然后结合tanh的导数性质造成的,所以要解决这个问题主要是去掉连乘项。
而长短期记忆(Long short-term memory, LSTM)是一种特殊的RNN,主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说,就是相比普通的RNN,LSTM能够在更长的序列中有更好的表现。
而且由上面两幅图可以观察到,LSTM结构更为复杂,在RNN中,将过去的输出(隐状态 ht−1)和当前的输入(xt)连接(concatenate)到一起,通过tanh来控制两者的输出,它只考虑最近时刻的状态。在RNN中有两个输入和一个输出。
而LSTM为了能记住长期的状态,在RNN的基础上增加了一路输入和一路输出,增加的这一路就是细胞状态ct−1 cell,也就是途中最上面的一条通路。在LSTM中有三个输入和两个输出。其中,多出的cell实际上更多地与RNN中的 ht−1比较像,保存的是历史状态的信息,而LSTM中的 ht−1更多的保存上一时刻的输出信息。
如上图所示为LSTM的基础结构,事实上整个LSTM分成了三个部分:
遗忘门,输入门和输出门
在讲这三个部分之前,先对结构中两个细节进行描述
Ct是什么?
记忆状态(cell state) →信息
• 存储之前时刻的信息
• 避免长时记忆问题的核心
什么是控制门?
控制门(gate):选择性控制信息流入
• 由元素乘操作实现
• 配有sigmoid激活函数的神经层
• 值域[0,1]: 0=不通过任何信息 1=通过所有信息,通过对权重的控制来控制输入的信息内容。
接下来具体展开三个部分的介绍
1)遗忘门—哪些细胞状态应该被遗忘
这部分功能是通过sigmoid函数实现的,也就是最左边的通路,如下图所示。根据输入xt和上一时刻的输出ht-1来决定当前细胞状态是否有需要被遗忘的内容。举个例子,如果之前细胞状态Ct-1中有主语,而输入xt-1中又有了主语,那么原来存在的主语就应该被遗忘。输入和上一时刻的输出concatenate后,再经过sigmoid函数后得到 ft,ft中每一个值的范围都是 [0, 1],越接近于0被遗忘的越多,越接近于1被遗忘的越少。
这一段的公式形式为:
其中C’t-1表示这一段的上端的输出。
2)输入门----哪些新的状态应该被加入
继续上面的例子,遗忘掉原来存在的主语后,那么新进来的主语自然就是应该被加入到细胞状态Ct的内容,同理也是靠sigmoid函数来决定应该记住哪些内容。
但是值得一提的是,需要被记住的内容有两部分:
一是输入xt和上一时刻的输出ht-1经过concatenate的内容,经过tanh处理以后的内容,这部分表示得到新的输入信息
二是输入xt和上一时刻的输出ht-1经过concatenate的内容,经过sigmoid激活以后得到的it,这部分表示哪些新信息有用。这点也是和RNN保持一致的。但是需要注意的是此处的sigmoid和前一步的sigmoid层的w和b不同,是需要分别训练的层。
然后把这两部分内容再向量相乘,加入到C’t-1,最后得到Ct( t 时刻的 cell 状态)的内容。
公式表达为:
至此,经过前面两部分以后,如下图所示,细胞状态在忘记了该忘记的,记住了该记住的之后,就可以作为下一时刻的细胞状态输入了。
3)输出门----根据当前的状态和现在的输入,输出应该是什么
这是最右侧的通路,简单的说输出门主要是用来判断哪些信息会到 ht中去的。
首先第一部分是细胞状态Ct经过 tanh 函数(tanh其实起到一定的过滤作用)得到可以输出的信息
然后第二部分输入xt和上一时刻的输出ht-1经过concatenate的内容经过 sigmoid 函数后得到一个向量 ot, ot 的每一维的范围都是 [0, 1],表示哪些位置的输出应该去掉,哪些应该保留。
最终这两部分的向量相乘后的结果就是最终的预测结果ht。
其实一系列结构看下来不难发现:事实上,LSTM就是在RNN的基础上,增加了对过去状态的过滤,从而可以选择哪些状态对当前更有影响,而不是简单的选择最近的状态。
2个改动
(1)合并输入门和忘记门
(2)合并记忆状态和隐藏状态
2个控制门:
• 重置门(Reset gate) • 更新门(Update gate)
这两个门控机制的特殊之处在于,它们能够保存长期序列中的信息,且不会随时间而清除或因为与预测不相关而移除。
从直观上来说,重置门决定了如何将新的输入信息与前面的记忆相结合。重置门其实强制隐藏状态遗忘一些历史信息,并利用当前输入的信息。这可以令隐藏状态遗忘任何在未来发现与预测不相关的信息,同时也允许构建更加紧致的表征。
更新门定义了前面记忆保存到当前时间步的量。更新门将控制前面隐藏状态的信息有多少会传递到当前隐藏状态,这与 LSTM 网络中的记忆单元非常相似,它可以帮助 RNN 记住长期信息。
如果我们将重置门设置为 1,更新门设置为 0,那么我们将再次获得标准 RNN 模型。
GRU作为LSTM的一种变体,将忘记门和输入门合成了一个单一的更新门。同样还混合了细胞状态和隐藏状态,加诸其他一些改动。最终的模型比标准的 LSTM 模型要简单,也是非常流行的变体。
图说模型实现的目标是:为图片生成描述语言,即输入是图片,输出是客观描述图片内容的句子。可以理解为一种特殊的机器翻译:视觉→语言
图说模型深度神经网络(DNN)组成部分:
(1)CNN: 图片理解VGG,ResNet,GoogLeNet
(2)RNN:语言理解及生成Multimodal-RNN, LSTM,GRU
(3)特殊功能模块:Attention
NIC模型的结构就是利用encoder-decoder框架,主要分为以下几个部分:
(1)首先利用CNN(这里是GoogLeNet)作为encoder,将 Softmax 之前的那一层固定维数的向量作为图像特征.
(2)再使用LSTM作为decoder,其中图像特征输入decoder(CNN得到的图像特征只在LSTM的开始时刻被使用,后面时刻不会被应用)。
(3)模型的训练使用最大化对数似然来训练,然后在测试阶段采用beam search来减小搜索空间。
理解encoder-decoder框架:
Encoder-Decoder框架可以看作是一种深度学习领域的研究模式,应用场景异常广泛。如下图所示是文本处理领域里常用的Encoder-Decoder框架最抽象的一种表示。
可以把encoder-decoder看作适合处理由一个句子(或篇章)生成另外一个句子(或篇章)的通用处理模型。我们的目标是给定输入句子: Source sequence,期待通过Encoder-Decoder框架来生成目标句子Target sequence。其中Source和Target可以是同一种语言,也可以是两种不同的语言。而Source和Target分别由各自的单词序列构成,如上图所示的(x1,x2,x3,x4,…)就是Source,(y1,y2,y3,…)就是Target。
Encoder顾名思义就是对输入句子Source进行编码,将输入句子通过非线性变换转化为中间语义表示C,即把Source(x1,x2,x3,x4,…)转化为一个固定长度的context vector即中间语义表示C,整个句子的中间语义C就是Encoder的最后一个时间步的状态:
对于解码器Decoder来说,其任务是根据句子Source的中间语义表示C和之前已经生成的历史信息来生成i时刻要生成的单词:
每个yi都依次这么产生,那么看起来就是整个系统根据输入句子Source生成了目标句子Target。如果Source是一张图片,Target是概括性的几句描述语句,那么这就是图说模型的Encoder-Decoder框架。而在NIC模型和之后介绍的SAT模型中都是这种框架的产物。
我们可以看到经过CNN以后得到的特征,通过特征映射矩阵We,将图片特征空间文本映射到文本,然后开启LSTM。
特别要注意一点,NIC 模型仅在decoder的开始时刻输入了图像特征,而不是在每个解码时刻都输入了图像特征。
所谓的Beam Search,其实就是每次保留TOP-Beam Search的概率的词作为备选
如假设beam size为2;词典大小为3,内容为(a,b,c)。生成第1个词的时候,选择概率最大的2个词,假设为a,c,则当前保留的预测序列就是a,c。然后生成第2个词的时候,将当前序列a和c,分别与词表中的所有词进
行组合,得到新的6个序列aa ab ac ca cb cc,然后再从其中选择2个得分最高的,作为当前序列,后面会不断重复这个过程,直到遇到结束符为止。最终输出2个得分最高的序列。也就是每次从预测所有序列中只保留TOP2。如下图所示:
在3.2.1里面介绍了encoder-decoder的框架,那种框架是不带注意力机制的,那么可以把它看作是注意力不集中的分心模型。
为什么说它注意力不集中呢?
请观察下在不带注意力机制的encoder-decoder的框架中目标句子Target中每个单词的生成过程如下:
其中f是Decoder的非线性变换函数。从这里可以看出,在生成目标句子的单词时,不论生成哪个单词,它们使用的输入句子Source的中间语义编码C都是一样的,没有任何区别。而语义编码C是由句子Source的每个单词经过Encoder 编码产生的,这意味着不论是生成哪个单词,y1,y2还是y3,其实句子Source中任意单词对生成某个目标单词yi来说影响力都是相同的
这就导致了这类框架存在非常大的局限性,局限性就来自于于编码和解码之间的唯一联系就是一个固定长度的中间语义编码C。也就是说,编码器要将整个序列的信息压缩进一个固定长度的编码向量C中去。但是这样做有两个弊端:
1.语义向量无法完全表示整个序列的信息,
2.先输入的内容携带的信息会被后输入的信息稀释掉,或者说,被覆盖了。当输入序列越长,这个现象就越严重。这就使得在解码的时候一开始就没有获得输入序列足够的信息, 那么解码的准确度自然也就要打个折扣了
用一个例子表示这个过程:
比如输入的Source是英文句子:Tom chase Jerry
我们需要Encoder-Decoder框架逐步生成中文单词:“汤姆”,“追逐”,“杰瑞”。
在翻译“杰瑞”这个中文单词的时候,当前模型里面的每个英文单词对于翻译目标单词“杰瑞”贡献是相同的,很明显这里不太合理,显然“Jerry”对于翻译成“杰瑞”更重要,但是当前模型是无法体现这一点的,这就是为何说它没有引入注意力的原因。
没有引入注意力的模型在输入句子比较短的时候问题不大,但是如果输入句子比较长,此时所有语义完全通过一个中间语义向量来表示,单词自身的信息已经消失,可想而知会丢失很多细节信息,这也是为何要引入注意力模型的重要原因。
为了解决这个问题,所以提出了Attention模型,或者说注意力模型。
还是以上面那个例子展开说:
如果引入Attention模型的话,
我们应该希望在在翻译“杰瑞”的时候,体现出不同的英文单词对于翻译当前中文单词不同的影响程度。
比如给出类似下面一个概率分布值:(Tom,0.3)(Chase,0.2) (Jerry,0.5)每个英文单词的概率代表了翻译当前单词“杰瑞”时,注意力分配模型分配给不同英文单词的注意力大小。很明显可以看到Jerry的注意力会比较大,那么翻译的概率就会比较大,准确性就会提高。这对于正确翻译目标语单词肯定是有帮助的,因为引入了新的信息。
同理,目标句子中的每个单词都应该学会其对应的源语句子中单词的注意力分配概率信息。这意味着在生成每个单词yi的时候,原先都是相同的中间语义表示C会被替换成根据当前生成单词而不断变化的Ci。
简单的说,这种模型在产生输出的时候,会产生一个“注意力范围”(可以是上文提到的概率密度)表示接下来输出的时候要重点关注输入序列中的哪些部分,然后根据关注的区域来产生下一个输出,如此往复。说白了就是由固定的中间语义表示C换成了根据当前输出单词来调整成加入注意力模型的变化的Ci。如下图所示:
由此生成目标句子单词的过程成了下面的形式:
而每个Ci可能对应着不同的源语句子单词的注意力分配概率分布,比如对于上面的英汉翻译来说,其对应的信息可能如下:
注意f2函数代表Encoder对输入英文单词的某种变换函数,比如如果Encoder是用的RNN模型的话,这个f2函数的结果往往是某个时刻输入xi后隐层节点的状态值;g代表Encoder根据单词的中间表示合成整个句子中间语义表示的变换函数,一般的做法中,g函数就是对构成元素加权求和,即下列公式:
其中,Lx代表输入句子Source的长度,aij代表在Target输出第i个单词时Source输入句子中第j个单词的注意力分配系数,而hj则是Source输入句子中第j个单词的语义编码。
至此,我们分析完了关于中间语义的生成,那么如何形象的表示这个过程呢?如下所示就是翻译中文单词“汤姆”的时候,数学公式对应的中间语义表示Ci的形成过程:
如何知道Attention模型所需要的输入句子单词注意力分配概率分布值呢?
就是说“汤姆”对应的输入句子Source中各个单词的概率分布:(Tom,0.6)(Chase,0.2) (Jerry,0.2) 是怎么来的呢,如下图所示:
对于采用RNN的Decoder来说,在时刻i,如果要生成yi单词,我们是可以知道Target在生成Yi之前的时刻i-1时,隐层节点i-1时刻的输出值Hi-1的,而我们的目的是要计算生成Yi时输入句子中的单词“Tom”、“Chase”、“Jerry”对Yi来说的注意力分配概率分布,那么可以用Target输出句子i-1时刻的隐层节点状态Hi-1去一一和输入句子Source中每个单词对应的RNN隐层节点状态hj进行对比,即通过函数F(hj,Hi-1)来获得目标单词yi和每个输入单词对应的对齐可能性,这个F函数在不同论文里可能会采取不同的方法,然后函数F的输出经过Softmax进行归一化就得到了符合概率分布取值区间的注意力分配概率分布数值。
在这个caption模型中,在解码的每个时刻都会接收由attention机制所计算出的编码向量。
模型同样分为俩个部分:
(1)encoder:卷积特征
在encoder端,模型使用CNN来提取 L个D 维vector,每一个都对应图像的一个区域,如式:
与此前的工作使用Softmax层之前的那一层vector作为图像特征不同,本文所提取的这些vector来自于 low-level 的卷积层,这使得decoder可以通过选择所有特征向量的子集来选择性地聚焦于图像的某些部分。
这个样子就有点像NLP里的seq2seq任务了,这里的输入从词序列转变成了图像区域vector的序列。
(2)decoder:LSTM
模型生成的一句caption被表示为各个词的one-hot编码所构成的集合时:
其中 K 是词表大小,C 是句子长度。
LSTM的数学模型如下:
第一个式子实际上是四个式子,分别得到输入门、遗忘门、输出门和被输入门控制的候选向量。其中,三个门控由sigmoid激活,得到的是元素值皆在 0 到 1 之间的向量,可以将门控的值视作保留概率;候选向量由tanh激活,得到的是元素值皆在 -1 到 1 之间的向量。
注意从上面数学模型我们可以发现:在NIC模型中,解码过程除了在首个时刻输入了图像特征之外,随后并不存在这个输入,而SAT模型则与标准的encoder-decoder框架一样,将encoder端得到的信息在每一时刻都输入decoder。
在SAT模型中提出了两种attention机制。通过attention机制计算出的 zt,被称为 context vector,是捕捉了特定区域视觉信息的上下文向量。
首先需要明确,attention要实现的是在解码的不同时刻可以关注不同的图像区域,进而可以生成更合理的词。那么,在attention中就有两个比较关键的量:
(1) 一个是和时刻 t 相关,对应于解码时刻
(2) 另一个是输入序列的区域 ai,对应图像的一个区域。
所以描述在SAT中的attention机制其实就是在时刻 t ,为输入序列的各个区域 i 计算出一个权重 αti。因为需要满足输入序列的各个区域的权重是加和为一的,所以需要使用Softmax来实现这一点。至于Softmax需要输入的信息,则如上所讲,需要包含两个方面:一个是被计算的区域 ai ,另一个就是上一时刻 t-1 的信息 ht−1 ,所以得到如下公式:
式中的 fatt 是耦合计算区域 i 和时刻 t 这两个信息的打分函数,打分函数可以是MLP或者其他的内积或者双线性。得到的eti就是Softmax的输出。
最终我们计算出权重ati,就可以计算 zt 实现特征融合了:
这个函数 ϕ 就代指文中提出的两种attention机制,对应于将权重施加到图像区域到两种不同的策略。下面对两种attention机制进行介绍:
(1)Hard attention
这里权重ati所起的作用的是否被选中,只有0、1两个选项,所以引入了
变量sti.其实sti就是ati,当区域i被选中时sti为1,否则sti为0。如下所示:
(1)Soft attention
对每个区域都关注,只是关注的重要程度不一样,所以此处的权重ati就对应着此区域所占比重,那么zt就可以直接通过比重加权求和得到。
这就和机器翻译中非常标准的end-to-end训练非常像了,整个模型光滑、可微,利用反向传播来进行end-to-end的训练。