Deep Learning Network Architectures: CNNs, RNNs, and Seq2Seq
在介绍完深度学习的基础知识以后,我们可以正式构建我们喜欢的网络了, 这里我们来介绍一些深度学习初期发展出来的,虽然简单但是非常实用的网络架构,他们对于帮助我们理解深度学习的进行很有帮助
卷积神经网络 CNN
我们从卷积神经网络开始,探讨网络的架构设计。卷积神经网络是一种非常典型的网络架构,常用于图像分类等任务。通过卷积神经网络,我们可以知道网络架构如何设计,以及为什么合理的网络架构可以优化网络的表现。
这一节将是我们研究网络架构的第一节
特别的,我们第一次研究网络的架构是在机器学习导论与监督学习中的神经网络,那里我们研究的网络结构是最基础的全连接网络
卷积也可以是一维的,用于处理时间序列或者其他序列问题,也可以用于缩放序列大小
图像分类任务引入
首先,我们需要知道怎么把图像当做模型的输入。一般我们使用RGB格式描述一张数字图片,使用一个三维的向量(机器学习领域称为张量)我们就可以描述这张图片。其中一维代表图像的宽,另外一维代表图像的高,还有一维代表图像的通道(channel) 的数目 RGB模型有红绿蓝三个通道
网络的输入往往是向量,因此,将代表图像的三维张量“丢”到网络里之前,需要先将它“拉直”。假设我们用一个高和宽都为100像素的照片。一张图像就是由100×100×3 个数字所组成的,把这些数字排成一排就是一个巨大的向量。
在图像处理领域,为了方便进行网络的设计,一般需要保证图像有一样的大小再投入到深度学习中
图像处理领域的输入向量往往是比较长的,把向量当做全连接网络的输入,会导致第一层就有大量的权重需要优化。更多的参数为模型带来了更好的弹性和更强的能力,但也增加了过拟合的风险。一般情况下,我们不会选择全连接网络,至于具体怎么做,则是人们在研究图像识别领域的一些观察和经验,我们留在后面介绍
图像分类问题,其核心点是分类,我们需要使用独热向量把分类指标进行编码,使用交叉熵来优化损失,这点可以参考深度学习基础中的分类部分,没太多值得额外介绍的
检测模式不需要整张图像
局部检测思想
假设我们的任务是让网络识别出图像的动物。对一个图像识别的类神经网络里面的神经元而言,它要做的就是检测图像里面有没有出现一些特别重要的模式(pattern),这些模式是代表了某种物体的。比如有三个神经元分别看到鸟嘴、眼睛、鸟爪 3 个模式,这就代表类神经网络看到了一只鸟。
人在判断一个物体的时候,往往也是抓最重要的特征。看到这些特征以后,就会直觉地看到了某种物体。对于机器,也许这是一个有效的判断图像中物体的方法。但假设用神经元来判断某种模式是否出现,也许并不需要每个神经元都去看一张完整的图像。因为并不需要看整张完整的图像才能判断重要的模式(比如鸟嘴、眼睛、鸟爪)是否出现
这意味着:只需要把图像的一小部分当作输入,就足以让它们检测某些特别关键的模式是否出现
感受野的引入
有了这样的思想以后,我们就可以考虑开始对全连接网络进行第一次简化
卷积神经网络会设定一个区域,即感受野(receptive field),每个神经元都只关心自己的感受野里面发生的事情,感受野是由我们自己决定的。比如我们可以设置一个大小为的感受野,那么与之对应的神经元就只有个输入,哪怕带上 偏置bias 也不会超过30个参数。
感受野彼此之间也可以是重叠的,我们也可以让多个神经元守备一个感受野(同一个范围放多个神经元)
感受野可以有大有小,因为模式有的比较小,有的比较大。有的模式也许在 3 × 3 的范围内就可以被检测出来,有的模式也许要 11 × 11 的范围才能被检测出来。
感受野可以只考虑某些通道。目前感受野是 RGB 三个通道都考虑,但也许有些模式只在红色或蓝色的通道会出现,即有的神经元可以只考虑一个通道。之后在讲到网络压缩的时候,会讲到这种网络的架构。
感受野一般是相连的,但是对于有些问题我们可能真的需要不相连的感受野来捕捉某些特征,有些特征可能确实离散在图像的不同位置。
感受野不仅可以是正方形的,例如刚才举的例子里面 3 × 3、11 × 11,也可以是长方形的,完全可以根据对问题的理解来设计感受野。下面我们介绍一些基本的设计思路,他们适用于大多数问题
感受野的基本设计思想
一般在做图像识别的时候,可能不会觉得有些模式只出现在某一个通道里面,所以会看全部的通道。既然会看全部的通道,那么在描述一个感受野的时候,只要讲它的高跟宽,不用讲它的深度,因为它的深度就等于通道数,而高跟宽合起来叫做核大小。
常见的感受野设定方式就是核大小为 3 × 3。7 × 7、9 × 9 算是蛮大的核大小,不是我们的第一选择。一般同一个感受野会有一组神经元去守备这个范围,比如 64 个或者是 128 个神经元去守备一个感受野的范围。
我们把左上角的感受野往右移一个步幅,就制造出一个新的守备范围,即新的感受野。移动的量称为步幅(stride)。步幅是一个超参数,需要人为调整。因为希望感受野跟感受野之间是有重叠的以保证感受野交界线上的特征能够被正确识别,所以步幅往往不会设太大,一般设为 1 或 2。
如果不在超过图像的范围“摆”感受野,就没有神经元去检测出现在边界的模式,这样就会漏掉图像边界的地方,所以一般边界的地方也会考虑的。超出范围就做填充(padding),填充就是补值,一般使用零填充(zero padding),超出范围就补 0,如果感受野有一部分超出图像的范围之外,就当做那个里面的值都是 0。
除了水平方向的移动,也会有垂直方向上的移动,垂直方向步幅设置和水平方向一样。
综上我们就按照这个方式扫过整张图像,所以整张图像里面每一寸土地都是有被某一个感受野覆盖的。也就是图像里面每个位置都有一群神经元在检测那个地方,有没有出现某些模式。
同样的模式可能会出现在图像的不同区域
模式重复的思想
同样的模式,可能会出现在图像的不同区域。比如说模式鸟嘴,它可能出 现在图像的左上角,也可能出现在图像的中间,同样的模式出现在图像的不同的位置也不是太大的问题。因为我们使用多个神经元守备同一个感受野,因此模式无论出现在哪里,都有会匹配的神经元来识别他。
但这些检测鸟嘴的神经元做的事情是一样的,只是它们守备的范围不一样。既然如此,其实没必要每个守备范围都去放一个检测鸟嘴的神经元。如果不同的守备范围都要有一个检测鸟嘴的神经元,参数量会太多了,因此需要做出相应的简化。
共享参数
让不同感受野的神经元共享参数,也就是做参数共享(parameter sharing),所谓参数共享就是两个神经元的权重完全是一样的。
参数共享一般针对守备不同感受野的神经元而言,他们使用完全一样的参数,但它们的输出不会永远都是一样的,因为它们的输入是不一样的,它们照顾的范围是不一样的。
共享的方式完全可以自己决定,不过我们图像处理领域也有一些习惯性的原则。非常自然的,我们说过每个感受野都有若干个神经元用来识别模式,不同感受野之间编号一样的神经元应当共享参数 因为他们在识别同样的特征
所以实际上,各个感受野使用的都是同一组参数,这些参数称为滤波器(filter) 这大大的降低了我们需要优化的参数规模
卷积层
感受野加上参数共享就是卷积层(convolutional layer),用到卷积层的网络就叫卷积神经网络。
卷积神经网络的偏差比较大。但模型偏差大不一定是坏事,因为当模型偏差大,模型的灵活性较低时,比较不容易过拟合。
卷积层是专门为图像设计的,感受野、参数共享都是为图像设计的。虽然卷积神经网络模型偏差很大,但用在图像上不是问题。如果把它用在图像之外的任务,就要仔细想想这些任务有没有图像用的特性。
多层卷积神经网络
经过了一个卷积层的映射后,我们可以想象一下我们得到了什么,假设我们研究一张 6 × 6 的大小的图像,使用64 个滤波器(神经元),感受野设置为 3 × 3, 步幅设置为 1。
那么每个滤波器会给我们 4 × 4 的一组数字 一共64组 这组数字称为特征映射(feature map) 特征映射可以看成是另外一张新的图像,只是这个图像的通道不是 3 个通道,而有 64 个通道,每个通道就对应到一个滤波器。
卷积层是可以叠很多层的,我们可以继续设置滤波器的大小设成 3 × 3,但是把高度变为了64 来符合通道数目的需求。
堆叠多层卷积层,就可以实现深度神经网络的深度学习效果。
特别的:滤波器的大小一直设 3 × 3,不会让网络没有办法看比较大范围的模式。随着卷积层数目的增加,网络能看到的范围就越来越大,从而观察到更加整体的模式,这就是为什么核大小不同太大,我们用深度弥补了这一点
下采样不影响模式检测
下采样
把一张比较大的图像做下采样(downsampling),把图像偶数的列都拿掉,奇数的行都拿掉,图像变成为原来的 1/4,但是不会影响里面是什么东西。图像的模式不发生变化
汇聚
汇聚没有参数,所以它不是一个层,它里面没有权重,它没有要学习的东西。它就是一个操作符(operator),其行为都是固定好的,不需要根据数据学任何东西。
每个滤波器都产生一组数字,要做汇聚的时候,把这些数字分组,可以 2 × 2 个一组,3 × 3、4 × 4 也可以,这个是我们自己决定的。
汇聚有很多不同的版本。最大汇聚(max pooling) 在每一组里面选一个代表,选的代表就是最大的一个。除了最大汇聚,还有平均汇聚(mean pooling),平均汇聚是取每一组的平均值。
汇聚和池化是同一个意思的不同翻译,从英文名词解释中能看出。
汇聚所做的事情是把图像变小,将原本动辄数百像素的宽高的图片一下子缩小到原本的几分之一。做完汇聚以后,这张图像的通道不变,但是宽和高都会快速缩小
一般的卷积神经网络
一般在实践上,往往就是卷积跟汇聚交替使用,可能做几次卷积,做一次汇聚。比如两次卷积,一次汇聚。不过汇聚对于模型的性能(performance)可能会带来一点伤害。假设要检测的是非常微细的东西,随便做下采样,性能可能会稍微差一点。
所以近年来图像的网络的设计往往也开始把汇聚丢掉,它会做这种全卷积的神经网络,整个网络里面都是卷积,完全都不用汇聚。汇聚最主要的作用是减少运算量,通过下采样把图像变小,从而减少运算量。
随着近年来运算能力越来越强,如果运算资源足够支撑不做汇聚,很多网络的架构的设计往往就不做汇聚,而是使用全卷积,卷积从头到尾,看看做不做得起来,看看能不能做得更好。
一般架构就是卷积加汇聚,汇聚是可有可无的,很多人可能会选择不用汇聚。如果做完几次卷积和汇聚以后,把汇聚的输出做扁平化(flatten),再把这个向量丢进全连接层里面,最终过个 softmax 来得到图像识别的结果。这就是一个经典的图像识别的网络。
扁平化就是将矩阵拉直为向量,方便将矩阵化的结果输入到全连接层等结构中进行运算。
卷积神经网络的应用:下围棋与结束语
除了图像识别以外,卷积神经网络另外一个最常见的应用是用来下围棋,
下围棋其实是一个分类的问题,网络的输入是棋盘上黑子跟白子的位置,输出就是下一步应该要落子的位置。网络的输入是一个向量,棋盘上有 19 × 19 个位置,可以把一个棋盘表示成一个 19 × 19 维的向量。在这个向量里面,如果某个位置有一个黑子,这个位置就填1,如果有白子,就填 -1,如果没有子,就填 0。
通过把棋盘表示成向量,网络就可以知道棋盘上的盘势。把这个向量输到一个网络里面,下围棋就可以看成一个分类的问题,通过网络去预测下一步应 该落子的最佳位置,所以下围棋就是一个有 19 × 19 个类别的分类问题,网络会输出 19 × 19个类别中的最好类别,据此选择下一步落子的位置。这个问题可以用一个全连接网络来解决,但用卷积神经网络的效果更好。
特别的:AlphaGo 的原始论文里面,每个棋盘的位置,即每个棋盘上的像素是用 48 个通道来描述,即棋盘上的每个位置都用 48 个数字来描述那个位置发生的事情。这个数字是由围棋专家给出的。
卷积神经网络其实并不是随便用都会好的,它是为图像设计的。如果一个问题跟图像没有共通的特性,就不该用卷积神经网络。既然下围棋可以用卷积神经网络,这意味着围棋跟图像有共同的特性。比如局部模式以及模式的重复,当然他不适用池化,这是很自然地。
其实卷积神经网络不能处理图像放大缩小或者是旋转的问题。假设图像里面的物体都是比较小的,当卷积神经网络在某种大小的图像上面学会做图像识别,我们把物体放大,它的性能就会降低不少。
因此在做图像识别的时候往往都要做数据增强。所谓数据增强就是把训练数据每张图像里面截一小块出来放大,让卷积神经网络看过不同大小的模式;把图像旋转,让它看过某一个物体旋转以后长什么样子,卷积神经网络才会做到好的结果。
循环神经网络 RNN
循环神经网络(Recurrent Neural Network)是深度学习领域中一种非常经典的网络结构,在现实生活中有着广泛的应用。
以槽填充(slot filling)为例。假设订票系统听到用户说:“我想在 6 月 1 日抵达上海。”,系统有一些槽(slot):目的地和到达时间,系统要自动知道这边的每一个单词是属于哪一个槽,比如“上海”属于目的地槽,“6 月 1 号”属于到达时间槽。
这个问题可以使用一个前馈神经网络(feedforward neural network)来解,将用户输入的单词逐个输入到神经网络中,让网络告诉我们哪个词应该放在哪个位置。
非常自然的,我们这里需要稍微介绍一些NLP相关的基础问题,当然不需要太多,这是所有研究者都需要掌握的基础内容
独热编码
独热编码是统计学领域研究出来的,我们在广义线性回归中的分类自变量与虚拟变量问题中介绍过多种编码方式,这里我们使用的是最基础的 广义线性回归中的 one-hot 编码
当然,由于单词可能都没有见过,所以我们习惯用一个维度代表 other
假设把单词表示为向量,把这个向量丢到前馈神经网络里面去,在该任务里面,输出是一个概率分布,该概率分布代表着输入单词属于每一个槽的概率。
但是前馈网络会有问题。假设用户 1 说:“在 6 月 1 号抵达上海”。用户 2 说:“在 6 月 1 号离开上海”,这时候“上海”就变成了出发地。但是对于神经网络,输入一样的东西,输出就应该是一样的东西。在例子中,输入“上海”,输出要么让目的地概率最高,要么让出发地概率最高。
在这种情况下,如果神经网络有记忆力的,它记得它看过“抵达”,在看到“上海”之前;或者它记得它已经看过“离开”,在看到“上海”之前。通过记忆力,它可以根据上下文产生不同的输出。前面的前馈神经网络的问题就被解决了。这就引入了我们这一章要介绍的 循环神经网络 RNN
RNN 基础
什么是 RNN
在 RNN 里面,每一次隐藏层的神经元产生输出的时候,该输出会被存到记忆元(memory cell),下一次有输入时,这些神经元不仅会考虑输入 ,还会考虑存到记忆元里的值。
记忆元可简称为单元(cell),记忆元的值也可称为隐状态(hidden state)
在做循环神经网络时,它会考虑序列的顺序,输入序列调换顺序之后输出不同。
注意,RNN网络架构的输入是序列,这是一个针对序列输入的模型,什么是序列可以参考前面的例子前文独热编码部分
因为当前时刻的隐状态使用与上一时刻隐状态相同的定义,所以隐状态的计算是循环的(recurrent),基于循环计算的隐状态神经网络被称为循环神经网络。这是RNN名字的由来。
RNN 架构
我们还是处理前面槽填充的例子,用户说:“我想在 6 月 1 日抵达上海”,“抵达”就变成了一个向量“丢”到神经网络里面去,神经网络的隐藏层的输出为向量 , 产生“抵达”属于每一个槽填充的概率 。
接下来 会被存到记忆元里面去,“上海”会变为输入,这个隐藏层会同时考虑“上海”这个输入和存在记忆元里面的 ,得到 。根据 得到 , 是属于每一个槽填充的概率。
我们使用的是同一个神经网络,他在不同的时间节点对一个序列的各个元素分别使用了多次,而网络的权重都是一样的
有了记忆元以后,输入同一个单词,希望输出不同的问题就有可能被解决。因为存在记忆元里面的值不同,所以隐藏层的输出会不同,所以最后的输出也就会不一样。
循环神经网络的架构是可以任意设计的,比如从刚才介绍的单个隐藏层就直接到达输出层,我们也可以增加多个隐藏层,隐藏层也可以有不同的记忆元设定,从而形成各种不同的RNN
Elman 网络 和 Jordan 网络
刚才讲的是简单循环网络(Simple Recurrent Network,SRN,也称为Elman),即把隐藏层的值存起来,在下一个时间点在读出来。每个神经元值处理自己在序列的上一个输入的隐藏值。
还有另外一种叫做 Jordan 网络,Jordan 网络存的是整个网络输出的值,它把输出值在下一个时间点在读进来,把输出存到记忆元里。在序列的下一个元素输入的时候将他加进去。
Elman 网络没有目标,很难控制说它能学到什么隐藏层信息(学到什么放到记忆元里),但是 Jordan 网络是有目标,比较很清楚记忆元存储的东西。
双向循环神经网络
循环神经网络还可以是双向。刚才 RNN 输入一个句子,它就是从句首一直读到句尾。但其读取方向也可以是反过来的。
我们可以同时训练一个正向的循环神经网络,又可以训练一个逆向的循环神经网络(序列逆序读入,网络结构不变),然后把这两个循环神经网络的隐藏层拿出来,都接给一个输出层得到最后的
双向循环神经网络(Bidirectional Recurrent Neural Network,Bi-RNN)的好处是,神经元产生输出的时候,它看的范围是比较广的。如果只有正向的网络,产生 、 的时候,神经元只看过 到 的输入。
但双向循环神经网络产生 的时候,网络不只是看过 , 到 所有的输入,它也看了从句尾到 的输入。网络就等于整个输入的序列。
假设考虑的是槽填充网络,就等于看了整个句子后,才决定每一个单词的槽,这样会比看句子的一半还要得到更好的性能。
长短期记忆网络 LSTM
LSTM基本原理
之前提到的记忆元是最单纯的,可以随时把值存到记忆元去,也可以把值读出来。但最常用的记忆元是长短期记忆网络(Long Short-Term Memory network,LSTM),长时间的短期记忆。
LSTM 是比较复杂的。一个LSTM记忆元 有三个门(gate),当外界某个神经元的输出想要被写到记忆元里面的时候,必须通过一个输入门(input gate),输入门要被打开的时候,才能把值写到记忆元里面。如果把这个关起来的话,就没有办法把值写进去。至于输入门的开关是神经网络自己学的,其可以自己学什么时候要把输入门打开,什么时候要把输入门关起来。
输出的地方也有一个输出门(output gate),输出门会决定外界其他的神经元能否从这个记忆元里面把值读出来。把输出门关闭的时候是没有办法把值读出来,输出门打开的时候才可以把值读出来。这个记忆元才会有输出。跟输入门一样,输出门什么时候打开什么时候关闭,网络是自己学到的。
第三个门称为遗忘门(forget gate),遗忘门决定什么时候记忆元要把过去记得的东西忘掉。这个遗忘门什么时候会把存在记忆元的值忘掉,什么时候会把存在记忆元里面的值继续保留下来,这也是网络自己学到的。
整个 LSTM 可以看成有 4 个输入、1 个输出。在这 4 个输入中,一个是想要被存在记忆元的值,但不一定能存进去,还有操控输入门的信号、操控输出门的信号、操控遗忘门的信号,有着四个输入但它只会得到一个输出。
之前的循环神经网络,它的记忆元在每一个时间点都会被洗掉,只要有新的输入进来,每一个时间点都会把记忆元洗掉,所以的短期是非常短的。
但如果是长时间的短期记忆元,它记得会比较久一点,只要遗忘门不要决定要忘记,它的值就会被存起来。这就是长时间的短期记忆 LSTM。长时间在于遗忘门的遗忘功能,短期则体现在记忆元只能记忆最近的情况
一个LTSM记忆元的数学结构如下
假设要被存到单元的输入叫做,操控输入门的信号为,操控遗忘门的信号为,操控输出门为 综合这些东西会得到一个输出记为。
假设单元里面有这四个输入之前,它里面已经存了值。把通过激活函数得到,通过另外一个激活函数得到 (激活函数通常会选择 sigmoid 函数),因为其值介在 0 到 1 之间的,这个 0 到 1 之间的值代表了这个门被打开的程度。(如果的输出是 1,表示为被打开的状态,反之代表这个门是关起来的)。
接下来,把乘以得到,对于遗忘门的,也通过 sigmoid 的函数得到接下来把存到记忆元里面的值乘以得到 c,加起来, 那么就是重新存到记忆元里面的值。
以根据目前的运算,这个控制这个。假设输入 ,那就等于0,就好像是没有输入一样,如果 就等于是把当做输入。
那这个决定是否要把存在记忆元的值洗掉,假设 ,遗忘门开启的时候,这时候会直接通过,之前的值还会记得。如果 (遗忘门关闭的时候)
然后把这个两个值加起来写到记忆元里面得到。这个遗忘门的开关是跟直觉是相反的,遗忘门打开的时候代表的是记得,关闭的时候代表的是遗忘。
那这个通过,将乘以得到。输出门受所操控,等于 1 的话,就说明能通过,等于 0 的话,说明记忆元里面存在的值没有办法通过输出门被读取出来。
整个LSTM神经元的执行顺序为:输入,输入门,遗忘门,输出门 其中最复杂的门状态运算部分可以并行
LSTM 原理
在原来的神经网络里面会有很多的神经元,我们会把输入乘以不同的权重当做不同神经元的输入,每一个神经元都是一个函数,输入一个值然后输出一个值。 他们的内部都是一个线性函数加上偏置。最后将神经元的输出加上一个激活函数赋予非线性,就可以当作下一层的神经元的输入了。
我们介绍的基本的RNN网络架构增加了记忆元,将上一次存储的记忆的结果也增添到了这个神经元的输入中,增加了一个参数,让网络有了记忆。
实际上,我们前面介绍的LSTM记忆元架构也基本符合简单的神经元的形式。 我们把原始的输入的四个独立的线性组合(含有偏置)分别作为了输入,输入门检查,遗忘门检查,输出门检查。根据最后的各个检查的结果,给出了一个输出,可能是无输出的0或者记忆元中存储的数字。
从这个角度看,如果是 LSTM 的话,只要把 LSTM 想成是一个神经元。所以要用一个 LSTM 的神经元,其实就是原来简单的神经元换成 LSTM。
综上,LSTM 是有四个输入跟一个输出。假设用的神经元的数量跟 LSTM 是一样的,则 LSTM 需要的参数量是一般神经网络的四倍。但是在网络的架构上,我们没有更多的结构创新。
在实际投入使用的LSTM实际上不仅仅长这个样子,真正的 LSTM 会把上一个时间的输出接进来,当做下一个时间的输入,即下一个时间点操控这些门的值不是只看那个时间点的输入 ,还看前一个时间点的输出 。还会添加 peephole 连接,把存在记忆元里面的值也拉过来。也就是同时考虑同时考虑了
门控循环单元(Gated Recurrent Unit,GRU) 是 LSTM 稍微简化的版本,它只有两个门。虽然少了一个门,但其性能跟 LSTM 差不多,少了 1/3 的参数,也是比较不容易过拟合。
GRU 的精神就是:旧的不去,新的不来。它会把输入门跟遗忘门联动起来,也就是说当输入门打开的时候,遗忘门会自动的关闭 (格式化存在记忆元里面的值),当遗忘门没有要格式化里面的值,输入门就会被关起来。也就是要把记忆元里面的值清掉,才能把新的值放进来。
RNN 学习方式
如果要做学习,需要定义一个损失函数(loss function)来评估模型的好坏,选一个参数要让损失最小。 CNN 是一个分类任务,输出是编码好的分类向量,使用交叉熵来衡量损失。
对于RNN,我们刚才介绍的槽填充问题其实输出的目标也是分类用的向量,因此我们计算损失的方法应该是一样的。
有了损失函数以后,我们需要优化超参数,在诸如CNN以及我们在机器学习导论与监督学习中的神经网络 里面都使用经典的反向传播算法来更新参数。
循环神经网络里面,为了要计算方便,提出了反向传播的进阶版,即随时间反向传播(BackPropagation Through Time,BPTT)。BPTT 跟反向传播其实是很类似的,只是循环神经网络它是在时间序列上运作,所以 BPTT 它要考虑时间上的信息。
RNN 的训练是比较困难的,一般来说,我们会希望随着回合的数量越来越多,随着参数不断的更新,损失会慢慢地下降,最后趋向收敛。
但是不幸的是,在训练循环神经网络的时候,学习曲线会非常剧烈的抖动,然后抖到某个地方,这并不是程序有Bug,而是RNN的特色。
RNN 的误差表面是总损失的变化是非常陡峭的或崎岖的。误差表面有一些地方非常平坦,一些地方非常陡峭。这会导致我们在使用梯度下降找合适的参数的时候,由于学习率设置得比较大和梯度突然变大,可能会跳过损失悬崖导致损失突然爆长。对于这种情况,裁剪(clipping)可以解决该问题,当梯度大于某一个阈值的时候,不要让它超过那个阈值。保证不要飞的太远。
之前讲过 ReLU 激活函数的时候,梯度消失(vanishing gradient) 来源于 Sigmoid 函数。但 RNN 会有很平滑的误差表面不是来自于梯度消失。把 Sigmoid 函数换成 ReLU并不会有什么帮助。
RNN难以训练(同时存在梯度爆炸与消失)的核心原因在于其处理有序序列的网络结构,在处理整个序列的过程中,所有的参数是共享的,并且重复使用了多次。
为了计算早期时间步长的梯度,需要将后续时间步长的梯度通过权重矩阵连续相乘。如果权重矩阵的特征值小于1,这些连续的乘积会导致梯度值迅速减小。想反的,如果权重矩阵的特征值大于1,那么在反向传播过程中,连续的乘积会导致梯度值迅速增大。
解决RNN 的梯度消失或者爆炸
有什么样的技巧可以解决这个问题呢?广泛被使用的技巧是 LSTM,LSTM 可以让误差表面不要那么崎岖。它会把那些平坦的地方拿掉,解决梯度消失的问题。
LSTM不会解决梯度爆炸(gradient exploding)的问题。有些地方还是非常的崎岖的,有些地方仍然是变化非常剧烈的,但是不会有特别平坦的地方。如果做 LSTM 时,大部分地方变化的很剧烈,所以做 LSTM 的时候,可以把学习率设置的小一点,保证在学习率很小的情况下进行训练。当然使用 clipping 压缩梯度也是非常可行的常用方法。
LSTM对于处理梯度消失有效在于他控制了信息的流动,在 LSTM 里面,一旦对记忆元造成影响,影响一直会被留着,除非遗忘门要把记忆元的值洗掉。不然记忆元一旦有改变,只会把新的东西加进来,不会把原来的值洗掉,所以它不会有梯度消失的问题。
遗忘门可能会把记忆元的值洗掉。其实 LSTM 的第一个版本其实就是为了解决梯度消失的问题,所以它是没有遗忘门,遗忘门是后来才加上去的。
RNN 其他应用
槽填充的例子中假设输入跟输出的数量是一样的,也就是说输入有几个单词,我们就给每一个单词槽标签,RNN 可以做到更复杂的事情。
多对一序列
情感分析(sentiment analysis)是典型的多对一序列。
机器可以学习一个循环神经网络,输入是字符序列,循环神经网络把这个序列读过一遍。在最后一个时间点,把隐藏层拿出来,在通过几个变换,就可以得到最后的情感分析。
情感分析是一个分类问题,但是因为输入是序列,所以用 RNN 来处理。类似的,我们可以用 RNN 来作关键术语抽取(key term extraction)。
多对多序列
RNN 也可以处理多对多的问题,比如输入和输出都是序列,但输出序列比输入序列短。语音识别问题是多对多RNN的经典例子。
序列到序列
另一个 RNN 的应用是序列到序列(Sequence-to-Sequence,Seq2Seq)学习,在序列到序列学习里面,RNN 的输入跟输出都是序列 (但是两者的长度是不一样的)。
刚才输入比较长,输出比较短。在这边我们要考虑的是不确定输入跟输出谁比较长谁比较短。比如机器翻译(machine translation),输入英文单词序列把它翻译成中文的字符序列。英文和中文序列的长短是未知的。
这里仅仅是对RNN网络的一个初步研究,很多细节并不完善,也需要更多的论文来帮助我们了解不同算法的不同细节,RNN的核心是序列与记忆,而这在现代社会中广泛存在,因此他的改进型可以说是非常的广泛
- Title: Deep Learning Network Architectures: CNNs, RNNs, and Seq2Seq
- Author: Hyacehila
- Created at : 2024-11-13 06:26:58
- Link: https://hyacehila.github.io//blog/2024/11/13/deep-learning-network-architectures/
- License: This work is licensed under CC BY-NC-SA 4.0.