官方学习文档:https://linklearner.com/activity/16/15/62
往期task01链接:http://t.csdnimg.cn/I2Gk2
往期task02链接:http://t.csdnimg.cn/gkUfh
李宏毅老师对应视频课程可搭配食用:https://www.bilibili.com/video/BV1JA411c7VT/?p=5
深度学习基础
先衔接一下task01提到的内容,深度学习基础这章介绍了深度学习常见的概念,理解这些概念能够帮助我们从不同角度来更好地优化神经网络。
要想更好地优化神经网络,首先,要理解为什么优化会失败,收敛在局部极限值与鞍点会导致优化失败。其次,可以对学习率进行调整,使用自适应学习率和学习率调度。最后,批量归一化可以改变误差表面,这对优化也有帮助。
批量归一化
如果误差表面很崎岖,它比较难训练,能不能直接改变误差表面的地貌,“把山铲平”,让它变得比较好训练呢?批量归一化(Batch Normalization,BN)就是其中一个“把山铲平”的想法。
不要小看优化这个问题,有时候就算误差表面是凸(convex)的,就是一个碗的形状,都不一定很好训练。如图 3.37 所示,假设两个参数对损失的斜率差别非常大,在这个方向上面,斜率变化很小,在
这个方向上面斜率变化很大。
如果使用固定的学习率,可能很难得到好的结果,所以我们才需要自适应的学习率、Adam等比较进阶的优化的方法,才能够得到好的结果。
从另外一个方向想,直接把难做的误差表面把它改掉,看能不能够改得好做一点。在做这件事之前,第一个要问的问题就是:w1 跟 w2斜率差很多的这种状况到底是从什么地方来的?
图 3.38 是一个非常简单的模型,其输入是 x1 跟 x2,对应的参数为 跟
,它是一个线性的模型,没有激活函数。
乘 x1,
乘 x2 加上 偏置项b 以后就得到 yˆ,然后会计算 yˆ 跟 y 之间的差距当做 e,把所有训练数据 e 加起来就是损失,然后去最小化损失。
“线性的模型,没有激活函数”这句话意味着该模型在处理输入数据并生成输出的过程中,其内部运算遵循线性关系,并且不包含任何非线性变换,即所谓的激活函数。
当模型没有激活函数时,意味着模型中的每一层都是直接将输入线性地映射到输出。换句话说,模型中的每个节点输出仅仅是它接收到的输入的加权求和加上一个偏置项。
那么什么样的状况会产生像上面那样比较不好训练的误差表面呢?
对 有一个小小的改变,比如加上 ∆
,L 也对应会有一个改变,这是通过
改变了 y,y 改变的时候就改变了 e,随之改变了 L。
什么时候 的改变会对 L 的影响很小呢,也就是它在误差表面上的斜率会很小呢?
一个可能性是当输入很小的时候,假设 x1 的值在不同的训练样本里它的值都很小,那 有一个变化的时候,x1乘上
对 y 的影响也是小的,对 e 的影响也是小的,它对 L 的影响就会是小的。
反之,如图 3.39 所示,如果是x2 的话,假设 x2 的值都很大,当 有一个小小的变化的时候,虽然
这个变化可能很小,但是因为它乘上了 x2,x2 的值很大,那 y 的变化就很大,e 的变化就很大,L 的变化就会很大,就会导致我们在
这个方向上做变化时,把
改变一点点,误差表面就会有很大的变化。
所以既然在这个线性的的模型里面,当输入的特征,它们之间的范围差距很大的时候,我们就可能产生像这样的误差表面。
所以有没有可能给特征里面不同的维度,让它有同样的数值范围?这样可能就可以制造比较好的误差表面,让训练变得比较容易一点。这其实有很多不同的方法,这些方法统称为特征归一化(feature normalization)。
以下所讲的方法只是特征归一化的一种可能性,即 Z 值归一化(Z-score normalization),也称为标准化(standardization)。它假设到
是我们所有的训练数据的特征向量。向量
里面
就代表
的第一个元素,以此类推。我们把不同特征向量同一个维度里面的数值取出来,对于每个维度 i,计算其平均值(mean)
和标准差(standard deviation)σi。接下来我们就可以做一种归一化:
我们就是把同一维度上的所有数值 x都分别先减掉这一维度算出的平均值,再除掉这个维度算出的标准差,最后把得到的新的数值 x˜替换回去。
归一化有个好处,做完归一化后,这个维度上面的数值就会平均是 0,方差是 1,所以这一排数值的分布就都会在 0 上下。如果对每个维度都做一样的归一化,所有特征不同维度的数值都在 0 上下,可能就可以制造一个比较好的误差表面。所以像这样的特征归一化方式往往对训练有帮助,它可以在做梯度下降时,让损失收敛更快一点,训练更顺利一点。
考虑深度学习
x˜ 代表归一化的特征,把它丢到深度网络里面去做接下来的计算和训练。如图 3.41 所示, 通过第一层得到
,有可能通过激活函数(不管是选 sigmoid 或者 ReLU 都可以),再得到
,接着再通过下一层等等。对每个 x 都做类似的事情。
虽然 x˜ 已经做归一化了,但是通过以后,没有做归一化。如果 x˜ 通过
得到
,而
不同的维度间,它的数值分布仍然有很大的差异,训练第二层的参数也会有困难。对于
,a 或 z 其实也是一种特征,也应该要对这些特征做归一化。
如果选择 sigmoid,比较推荐对 z 做特征归一化,因为 sigmoid 是一个 s 的形状,其在 0 附近斜率比较大,如果对 z 做特征归一化把所有的值都挪到 0 附近,到时候算梯度算出来的值会比较大。如果使用别的激活函数,可能对 a 归一化也会有好的结果。一般而言,特征归一化放在激活函数之前之后都是可以的,在实现上,没有太大的差别。
那么如何对 z 做特征归一化?这其实就是对上述过程的重现,z 可以看成另外一种特征。首先计算下 ,
,
的平均值(这里的z都是向量,对的是每个向量同一维度的元素之和作平均值,最后组成的
也是一个向量),即:
接下来计算标准差:
注意,式中的平方就是指对每一个元素都去做平方,开根号指的是对向量里面的每一个元素开根号。这里算出的也是一个向量。
最后,根据计算出的 µ 和 σ 进行归一化:
其中,除号代表逐元素的除,即分子分母两个向量对应元素相除。
归一化的过程如图 3.42 所示。
如图 3.43 所示,接下来可以通过激活函数得到其他向量,µ 跟 σ 都是根据 ,
,
计算出来的。改变了
的值,a1 、µ 和 σ 也会改变,
, a2,
, a3的值也会相应地改变。之前的 x˜1, x˜2 x˜3 是独立分开处理的,但是在做特征归一化以后,这三个样本变得彼此关联了。
所以做特征归一化的时候,可以把整个过程当做是网络的一部分。即有一个比较大的网络,该网络吃一堆输入,用这堆输入在这个网络里面计算出 µ,σ,接下来产生一堆输出。
这边就会有一个问题,因为训练数据非常多,现在一个数据集可能有上百万笔数据,GPU 的显存无法把它整个数据集的数据都加载进去。因此,在实现的时候,我们不会让这一个网络考虑整个训练数据里面的所有样本,而是只会考虑一个批量里面的样本。比如批量设 64,这个网络就是把 64 笔数据读进去,对其做归一化。
因为实际实现时只对一个批量里面的数据做归一化,所以这个技巧称为批量归一化。批量归一化适用于批量大小比较大的时候,这样这个批量里面的数据就足以表示整个数据集的分布。
这个时候就不需要对整个数据集做特征归一化,而改成只在一个批量上做特征归一化作为近似。
在做批量归一化的时候,如图 3.44 所示,往往还会做如下操作:
其中,⊙ 代表逐元素的相乘。β, γ 可以想成是网络的参数,需要另外再被学习出来。
Q:为什么要加上 β 跟 γ 呢?
A:如果做归一化以后,z˜ 的平均值一定是 0,这会给网络一些限制,这个限制可能会带来负面的影响,所以需要把 β, γ 加回去,让网络隐藏层输出的平均值不是 0。
Q:批量归一化是为了要让每个输入特征的范围相同,如果把 γ 跟 β 加进去,这样输入特征的范围不会又都不一样了吗?
A:有可能,但是实际上在训练的时候,γ 的初始值都设为 1,β 初始是零向量。这让网络在一开始训练时,输入特征的分布是比较接近的,也许训练到后来,已经训练够长的一段时间,已经找到一个比较好的误差表面以后,再把 γ, β 慢慢地加进去。所以加了 γ, β 的批量归一化,往往对训练是有帮助的。
测试时的批量归一化
以上说的都是训练的部分,那么批量归一化在测试时,会有什么样的问题呢?在训练的时候,我们一次会得到所有的训练数据,确实可以在上面制造一个一个批量。但是假设系统上线做一个真实线上的应用,比如批量大小设 64,我一定要等 64 笔数据都进来,才做一次运算,这显然是不行的。
测试有时候又称为推断(inference)
在做批量归一化的时候,µ,σ 是用一个批量的数据算出来的。但如果在测试的时候根本就没有批量,如何算 µ,σ 呢?所以真正实现上的解法是这样的:批量归一化在测试的时候,并不需要做什么特别的处理,PyTorch 已经处理好了。在训练的时候,批量归一化时每一个批量计算出来的 µ,σ,都会拿出来算移动平均(moving average)。假设现在有各个批量计算出来的、
· · · · · ·
,则可以计算移动平均:
其中,是 µ 的移动平均值,p 是因子,这是一个常数,也是一个超参数(自己调试)。在 PyTorch 里面,p 设 0.1。这样最后在测试的时候,就不用算批量里面的 µ 跟 σ 了。因为测试的时候可以直接拿µ¯ 跟 σ¯ ,也就是 µ,σ 在训练的时候得到的移动平均来取代原来的 µ 跟 σ,如图 3.45 所示,这就是批量归一化在测试的时候的运作方式。
图 3.46 是批量归一化原始文献的实验结果,横轴代表的是训练的过程,纵轴代表的是验证集上的准确率。黑色的虚线是没有做批量归一化的结果,它用的是 inception 的网络(一种网络以 CNN 为基础的网络架构)。红色的虚线是做了批量归一化的结果。红色虚线的训练速度显然比黑色的虚线还要快很多。虽然只要给模型足够的训练的时间,最后会都收敛到差不多的准确率。但是红色虚线可以在比较短的时间内跑到一样的准确率。蓝色的菱形代表几个点的准确率是一样的。粉红色的线是 sigmoid 函数。蓝色的实线和虚线呢是学习率设大一点的情况,×5 就是学习率变原来的 5倍;×30 就是学习率变原来的 30 倍。因为如果做批量归一化,误差表面会比较平滑,比较容易训练,所以就可以把学习率设大一点。这边有个不好解释的地方,学习率设 30 倍的时候比5 倍差,作者也没有解释。
一般都会选择ReLU而不是用 sigmoid 函数,因为 sigmoid 函数的训练是比较困难的。但是这边想要强调的是,就算 sigmoid 比较难搞,但还是可以训练的。这边没有 sigmoid并且没有做批量归一化的结果,因为在这个实验上sigmoid 不加批量归一化,根本连训练都训练不起来。
内部协变量偏移
接下来的问题就是批量归一化为什么会有帮助呢?原始的批量归一化论文里面提出内部协变量偏移(internal covariate shift)概念。如图 3.47 所示,假设网络有很多层,x 通过第一层后得到 a,a 通过第二层以后得到 b;计算出梯度以后,把 A 更新成 A′,把 B 这一层的参数更新成 B′。但是作者认为说,我们在计算 B 更新到 B′ 的梯度的时候,这个时候前一层的参数是 A,或者是前一层的输出是 a。那当前一层从 A 变成 A′ 的时候,其输出就从 a 变成 a′ 。但是我们计算这个梯度的时候,是根据 a 算出来,所以这个更新的方向也许它适合用在 a 上,但不适合用在 a′ 上面。因为我们每次都有做批量归一化,就会让 a 和a′ 的分布比较接近,也许这样就会对训练有帮助。
但是论文“How Does Batch NormalizationHelp Optimization?”从不同的角度来说明内部协变量偏移不一定是训练网络的时候的一个问题。批量归一化会比较好,可能不一定是因为它解决了内部协变量偏移。这篇论文里面做了很多实验,比如其比较了训练时 a 的分布的变化,发现不管有没有做批量归一化,其变化都不大,就算是变化很大,对训练也没有太大的伤害。不管是根据 a 算出来的梯度,还是根据 a′ 算出来的梯度,方向居然都差不多。所以内部协变量偏移可能不是训练网络时最主要的问题,它可能也不是批量归一化会好的一个的关键。
协变量偏移(covariate shift),训练集和预测集样本分布不一致的问题就叫做协变量偏移现象,这个词汇是原来就有的,内部协变量偏移是批量归一化的作者自己发明的。
那为什么批量归一化会比较好呢?在“How Does Batch Normalization Help Optimization?”这篇论文从实验和理论上支持批量归一化可以改变误差表面,让误差表面比较不崎岖这个观点。但是如果要让网络误差表面变得比较不崎岖,其实不一定要做批量归一化,还有很多其他的方法都可以让误差表面变得不崎岖,这篇论文就试了一些其他的方法,发现跟批量归一化表现也差不多,甚至还稍微好一点,这篇论文的作者觉得批量归一化是一种偶然的发现,但无论如何,其是一个有用的方法(所以这是一个未解之谜)。其实批量归一化不是唯一的归一化,还有很多归一化方法,比如批量重归一化(batchrenormalization)、层归一化(layer normalization)、实例归一化(instance normalization)、组归一化(group normalization)、权重归一化(weight normalization) 和谱归一化(spectrum normalization)。
卷积神经网络
结束了深度学习基础这一大板块的学习后,我们将从卷积神经网络开始,探讨网络的架构设计。卷积神经网络是一种非常典型的网络架构,常用于图像分类等任务。通过卷积神经网络,我们可以知道网络架构如何设计,以及为什么合理的网络架构可以优化网络的表现。
所谓图像分类,就是给机器一张图像让它去判断这张图像里面有什么东西——是猫还是狗、是飞机还是汽车。那么怎么把图像当做模型的输入呢?对于机器,图像可以描述为三维张量(张量可以想成维度大于 2 的矩阵,其中一维代表图像的宽,另外一维代表图像的高,还有一维代表图像的通道(channel)的数目。
Q:什么是通道?
A:彩色图像的每个像素都可以描述为红色(red)、绿色(green)、蓝色(blue)的组合,这 3 种颜色就称为图像的 3 个色彩通道,叠加起来形成各种各样的颜色。这种颜色描述方式称为 RGB 色彩模型,常用于在屏幕上显示颜色。
网络的输入往往是向量,因此,将代表图像的三维张量“丢”到网络里之前,需要先将它“拉直”,如图 4.1 所示。在这个例子里面,这里的100×100指的是宽度乘高度,张量有100×100×3个数字,所以这张图像是由100×100×3个数字所组成的,把这些数字排成一排就是一个巨大的向量。把这个向量作为网络的输入,而这个向量里面每一维里面存的数值是某一个像素在某一个通道下的颜色强度。
图像有大有小,而且不是所有图像尺寸都是一样的。常见的处理方式是把所有图像先调整成相同尺寸,再“丢”到图像的识别系统里面。以下的讨论中,默认模型输入的图像尺寸固定为 100像素 × 100像素。
如图 4.2 所示,如果把向量当做全连接网络的输入,输入的特征向量(feature vector)的长度就是 100×100×3。这是一个非常长的向量。由于每个神经元相对输入向量中的每个数值都需要一个权重,所以当输入的向量长度是 100×100×3,且第 1 层有 1000 个神经元时,第 1 层的权重就需要 1000×100×100×3 = 个权重,这是一个非常巨大的数目。更多的参数为模型带来了更好的弹性和更强的能力,但也增加了过拟合的风险。模型的弹性越大,就越容易过拟合。
为了避免过拟合,在做图像识别的时候,考虑到图像本身的特性,并不一定需要全连接,即不需要每个神经元对于输入的每个维度都有一个权重。接下来就是针对图像识别这个任务,对图像本身特性进行一些观察。
模型的输出应该是什么呢?模型的目标是分类,因此可将不同的分类结果表示成不同的独热向量 y′。在这个独热向量里面,类别对应的值为 1,其余类别对应的值为 0。例如,我们规定向量中的某些维度代表狗、猫、树等分类结果,那么若分类结果为猫,则猫所对应的维度的数值就是 1,其他东西所对应的维度的数值就是 0。
如图 4.3 所示。独热向量 y′ 的长度决定了模型可以识别出多少不同种类的东西。如果向量的长度是 5,代表模型可以识别出 5 种不同的东西。现在比较强的图像识别系统往往可以识别出 1000 种以上,甚至上万种不同的东西。如果希望图像识别系统可以识别上万种目标,标签就会是维度上万的独热向量。模型的输出通过 softmax 以后,输出是 yˆ。我们希望 y′ 和 yˆ 的交叉熵越小越好。
在机器学习和深度学习中,Softmax 函数是一个常用的数学函数,用于将一个实数向量转换为一个概率分布。它常被用作多分类问题的最后一层,输出每个类别的预测概率。交叉熵(Cross-Entropy)损失函数通常与 Softmax 函数一起使用来训练这样的分类模型。目标是最小化模型预测概率与真实标签之间的差异,从而提高模型的准确性。
观察 1:检测模式不需要整张图像
假设我们的任务是让网络识别出图像的动物,对一个图像识别的类神经网络里面的神经元而言,它要做的就是检测图像里面有没有出现一些特别重要的模式(pattern),这些模式是代表了某种物体的。比如有三个神经元分别看到鸟嘴、眼睛、鸟爪 3 个模式,这就代表类神经网络看到了一只鸟,如图 4.4 所示。
人在判断一个物体的时候,往往也是抓最重要的特征,看到这些特征后就会直觉地看到了某种物体。对于机器,也许这也是一个有效的判断图像中物体的方法。
但假设用神经元来判断某种模式是否出现,也许并不需要每个神经元都去看一张完整的图像,因为并不需要看整张完整的图像才能判断重要的模式(比如鸟嘴、眼睛、鸟爪)是否出现,如图 4.5 所示,要知道图像有没有一个鸟嘴,只要看非常小的范围。
这些神经元不需要把整张图像当作输入,只需要把图像的一小部分当作输入,就足以让它们检测某些特别关键的模式是否出现,这是第 1 个观察。
简化 1:感受野
根据观察 1 可以做第 1 个简化,卷积神经网络会设定一个区域,即感受野(receptivefield),每个神经元都只关心自己的感受野里面发生的事情,感受野是由我们自己决定的。比如在图 4.6 中,蓝色的神经元的守备范围就是红色正方体框的感受野。这个感受野里面有3×3×3 个数值。
对这个神经元,它只需要关心这个小范围,不需要在意整张图像里面有什么东西,只在意它自己的感受野里面发生的事情就好。这个神经元会把 3×3×3 的数值“拉直”变成一个长度是 3×3×3=27 维的向量,再把这个向量作为神经元的输入,这个神经元会给这个向量的每个维度一个权重,所以这个神经元有 3×3×3=27 个权重,再加上偏置(bias)得到输出。这个输出再送给下一层的神经元当作输入。
如图 4.7 所示,蓝色的神经元看左上角这个范围,这是它的感受野。黄色的神经元看右下角这个范围。感受野彼此之间也可以是重叠的,比如绿色的神经元的感受野跟蓝色的、黄色的神经元都有一些重叠的空间。我们没有办法检测所有的模式,所以同个范围可以有多个不同的神经元,即多个神经元可以去守备同一个感受野。
这里的“无法检测所有的模式”意味着在图像处理或者计算机视觉任务中,我们不能穷尽所有可能出现的特征或模式。这是因为图像数据非常复杂,可能存在无限多种潜在的特征组合和模式。为了有效地提取这些特征并识别出重要的信息,我们需要设计具有不同感受野的神经元来捕捉不同尺度、位置和形状的特征。
在图4.7中,蓝色、黄色和绿色的神经元分别对应着不同的感受野。虽然它们各自关注的区域不同,但它们之间存在一定的重叠。这种重叠的设计使得神经网络能够更全面地捕获图像中的各种特征。比如,蓝色神经元关注左上角的区域,黄色神经元关注右下角的区域,而绿色神经元则同时关注到两者的一部分。这样,即使我们无法预知所有可能的模式,也可以通过多个神经元的共同作用来尽可能多地发现和学习这些模式。
此外,同一感受野有多个神经元去守备,也称为权值共享(weight sharing),这有助于减少参数的数量,降低过拟合的风险,并且允许网络学习更通用的特征,而不局限于特定的位置。通过这种方式,我们可以构建深层的卷积神经网络来逐步提取越来越复杂的特征,以应对更加复杂的任务。
在一个给定的感受野中,对于输入的每一个位置,有多个不同的卷积核(神经元)应用不同的权重集来提取不同的特征。这样做的目的是为了捕捉输入的不同方面,而不是增加参数数量。每个卷积核都有自己的参数集,但这些参数在整个输入上是共享的,这就是为什么虽然有多个核(多个神经元),但参数数量并不会像没有共享权重时那样显著增加。
接下来我们讨论下如何设计感受野。
感受野可以有大有小,因为有的模式比较小,有的比较大。有的模式也许在 3×3 的范围内就可以被检测出来,有的模式也许要 11 × 11 的范围才能被检测出来。此外,感受野可以只考虑某些通道。目前感受野是 RGB 三个通道都考虑,但也许有些模式只在红色或蓝色的通道会出现。之后在讲到网络压缩的时候,会讲到这种网络的架构。感受野的形状也是各异的,它不仅可以是正方形的,例如刚才举的例子里面 3 × 3、11 × 11,也可以是长方形的,完全可以根据对问题的理解来设计感受野。
虽然感受野可以任意设计,但下面要跟大家讲一下最经典的感受野安排方式。
Q: 感受野一定要相连吗?
A: 感受野的范围不一定要相连,理论上可以有一个神经元的感受野就是图像的左上角跟右上角。但是就要想想为什么要这么做,会不会有什么模式也要看一个图像的左上角跟右下角才能够找到。如果没有,这种感受野就没什么用。要检测一个模式,这个模式就出现在整个图像里面的某一个位置,而不是分成好几部分出现在图像里面的不同的位置。所以通常的感受野都是相连的领地,但如果要设计很奇怪的感受野去解决很特别的问题,完全是可以的,这都是自己决定的。
一般在做图像识别的时候,可能不会觉得有些模式只出现在某一个通道里面,所以会看全部的通道。既然会看全部的通道,那么在描述一个感受野的时候,只要讲它的高跟宽,不用讲它的深度,因为它的深度就等于通道数,而高跟宽合起来叫做核大小。图 4.8 中的核大小就是 3 × 3。在图像识别里面,一般核大小不会设太大,3 × 3 的核大小就足够了,7 × 7、9 × 9算是蛮大的核大小。如果核大小都是 3 × 3,意味着我们觉得在做图像识别的时候,重要的模式都只在 3 × 3 这么小的范围内就可以被检测出来了。但有些模式也许很大,也许 3 × 3 的范围没办法检测出来,后面我们会再回答这个问题。常见的感受野设定方式就是核大小为 3 × 3。
一般同一个感受野会有一组神经元去守备这个范围,比如 64 个或者是 128 个神经元去守备一个感受野的范围。目前为止,讲的都是一个感受野,接下来介绍下各个不同感受野之间的关系。我们把左上角的感受野往右移一个步幅,就制造出一个新的守备范围,即新的感受野。移动的量称为步幅(stride),图 4.9 中的这个例子里面,步幅就等于 2。步幅是一个超参数,需要人为调整。因为希望感受野跟感受野之间是有重叠的,所以步幅往往不会设太大,一般设为 1 或 2。
Q: 为什么希望感受野之间是有重叠的呢?
A: 因为假设感受野完全没有重叠,如果有一个模式正好出现在两个感受野的交界上面,就没有任何神经元去检测它,这个模式可能会丢失,所以希望感受野彼此之间有高度的重叠。如令步幅 = 2,感受野就会重叠。
接下来需要考虑一个问题:感受野超出了图像的范围,怎么办呢?如果不在超过图像的范围“摆”感受野,就没有神经元去检测出现在边界的模式,这样就会漏掉图像边界的地方,所以一般边界的地方也会考虑的。如图 4.10 所示,超出范围就做填充(padding),填充就是补值,一般使用零填充(zero padding),超出范围就补 0,如果感受野有一部分超出图像的范围之外,就当做那个里面的值都是 0。其实也有别的补值的方法,比如补整张图像里面所有值的平均值或者把边界的这些数字拿出来补没有值的地方。
除了水平方向的移动,也会有垂直方向上的移动,垂直方向步幅也是设 2,如图 4.11 所示。我们就按照这个方式扫过整张图像,所以整张图像里面每一寸土地都是有被某一个感受野覆盖的。也就是图像里面每个位置都有一群神经元在检测那个地方有没有出现某些模式。这个是第 1 个简化。
观察 2:同样的模式可能会出现在图像的不同区域
第 2 个观察是同样的模式,可能会出现在图像的不同区域。比如说模式鸟嘴,它可能出现在图像的左上角,也可能出现在图像的中间,同样的模式出现在图像的不同的位置也不是太大的问题。如图 4.12 所示,因为出现在左上角的鸟嘴,它一定落在某一个感受野里面。因为感受野是盖满整个图像的,所以图像里面所有地方都在某个神经元的守备范围内。所以就算鸟嘴出现在中间也没有关系。但这些检测鸟嘴的神经元做的事情是一样的,只是它们守备的范围不一样。既然如此,其实没必要每个守备范围都去放一个检测鸟嘴的神经元。如果不同的守备范围都要有一个检测鸟嘴的神经元,参数量会太多了,因此需要做出相应的简化。
简化 2:共享参数
在提出简化技巧前,我们先举个类似的例子。这个概念就类似于教务处希望可以推大型的课程,假设每个院系都需要深度学习相关的课程,没必要在每个院系都开机器学习的课程,可以开一个比较大型的课程,让所有院系的人都可以修课。这个放在图像处理上,则可以让不同感受野的神经元共享参数,也就是做参数共享(parameter sharing),如图 4.13 所示。所谓参数共享就是两个神经元的权重完全是一样的。
如图 4.14 所示,颜色相同表示权重相同,比如上面神经元的第 1 个权重是 w1,下面神经元的第 1 个权重也是 w1,它们是同一个权重,就用同一种颜色黄色来表示。上面神经元跟下面神经元守备的感受野是不一样的,但是它们的参数是相同的。
虽然两个神经元的参数是一模一样,但它们的输出不会永远都是一样的,因为它们的输入是不一样的,它们照顾的范围是不一样的。上面神经元的输入是 x1, x2, · · · · · · ,下面神经元的输入是 x′1, x′2, · · · · · · 。上面神经元的输出为 :
而下面神经元的输出为:
因为输入不一样,所以就算是两个神经元共用参数,它们的输出也不会是一样的。这是第 2 个简化,让一些神经元可以共享参数,共享的方式完全可以自己决定。
接下来将介绍图像识别方面,常见的共享方法是如何设定的。
如图 4.15 所示,每个感受野都有一组神经元在负责守备,比如 64 个神经元,它们彼此之间可以共享参数。图 4.16 中使用一样的颜色代表这两个神经元共享一样的参数,所以每个感受野都只有一组参数,就是上面感受野的第 1 个神经元会跟下面感受野的第 1 个神经元共用参数,以此类推 。这些参数称为滤波器(filter)。这是第 2 个简化的方法。
简化 1 和 2 的总结
目前已经讲了两个简化的方法,我们来总结下。如图 4.17 所示,全连接网络是弹性最大的。全连接层(fully-connected layer)可以自己决定看整张图像还是一个小范围。但加上感受野的概念以后,只能看一个小范围,网络的弹性变小。参数共享又进一步限制了网络的弹性。本来在学习的时候,每个神经元可以各自有不同的参数,它们可以学出相同的参数,也可以有不一样的参数。但是加入参数共享以后,某一些神经元无论如何参数都要一模一样的,这又增加了对神经元的限制。而感受野加上参数共享就是卷积层(convolutional layer),用到卷积层的网络就叫卷积神经网络。
卷积神经网络的偏差比较大。但模型偏差大不一定是坏事,因为当模型偏差大,模型的灵活性较低时,比较不容易过拟合。全连接层可以做各式各样的事情,但它可能没有办法在任何特定的任务上做好。而卷积层是专门为图像设计的,感受野、参数共享都是为图像设计的。虽然卷积神经网络模型偏差很大,但用在图像上不是问题。如果把它用在图像之外的任务,就要仔细想想这些任务有没有图像的特性。
接下来通过另一种来说明卷积神经网络。如图 4.18 所示,一个卷积层里面就是有一排的滤波器,每个滤波器的大小是 3 × 3 × 通道。如果图像是彩色的,它有 RGB 三个通道。如果是黑白的图像,它的通道就等于 1。其作用是要去图像里面检测某个模式。这些模式要在 3 × 3 × 通道这个小的范围内,它才能够被这些滤波器检测出来。
举个例子,假设通道为 1,也就是图像是黑白的。 滤波器就是一个一个的张量,这些张量里面的数值就是模型里面的权重参数。这些滤波器里面的数值其实是未知的,它是可以通过学习找出来的。假设这些滤波器里面的数值已经找出来了,如图 4.19 所示。
如图 4.20 所示,这是一个 6 × 6 的大小的图像。先把滤波器放在图像的左上角,接着把滤波器里面所有的 9 个值跟左上角这个范围内的 9 个值对应相乘再相加,也就是做内积,结果是 3。接下来设置好步幅,然后把滤波器往右移或往下移,重复几次,可得到模式检测的结果,图 4.20 中的步幅为 1。使用滤波器 1 检测模式时,如果出现图像 3 × 3 范围内对角线都是 1 这种模式的时候,输出的数值会最大。输出里面左上角和左下角的值最大,所以左上角和左下角有出现对角线都是 1 的模式,这是第 1 个滤波器。
如图 4.21 所示,接下来把每个滤波器都做重复的过程。比如说有第 2 个滤波器,它用来检测图像 3 × 3 范围内中间一列都为 1 的模式。把第 2 个滤波器先从左上角开始扫起,得到一个数值,往右移一个步幅,再得到一个数值,重复同样的操作,直到把整张图像都扫完,就得到另外一组数值。每个滤波器都会给我们一组数字,红色的滤波器给我们一组数字,蓝色的滤波器给我们另外一组数字。如果有 64 个滤波器,就可以得到 64 组的数字。这组数字称为特征映射(feature map)。当一张图像通过一个卷积层里面一堆滤波器的时候,就会产生一个特征映射。
假设卷积层里面有 64 个滤波器,产生的特征映射就有 64 组数字。在上述例子中每一组是 4 × 4,即64 个滤波器都产生 4 × 4 个数字。特征映射可以看成是另外一张新的图像,只是这个图像的通道不是 RGB 3 个通道,有64 个通道,每个通道就对应到一个滤波器。本来一张黑白图像有 1 个通道,通过卷积变成一张新的有 64 个通道的图像。
卷积层是可以叠很多层的,如图 4.22 所示,第 2 层的卷积里面也有一堆的滤波器,每个滤波器的大小设成 3 × 3。其高度必须设为 64,因为滤波器的高度就是它要处理的图像的通道(第一层处理的是黑白图像,高度为1)。
刚才用了两种方式解释卷积神经网络,这两种方式内核是一模一样的。第一种方式里面说到了有一些神经元,这些神经元会共用参数,这些共用的参数就是第 2 种方式里面的滤波器。如图 4.24 所示,这组参数有 3 × 3 × 3个,即滤波器里面有 3 × 3 × 3 个数字,这边特别还用颜色把这些数字圈起来,权重就是这些数字。为了简化,这边去掉了偏置。神经元是有偏置的,滤波器也是有偏置的。在一般的实践上,卷积神经网络的滤波器都是有偏置的。
如图 4.25 所示,在第一种方式中,不同的神经元可以共享权重,去守备不同的范围。而共享权重其实就是用滤波器扫过一张图像,这个过程就是卷积。这就是卷积层名字的由来。把滤波器扫过图像就相当于不同的感受野神经元共用参数,这组共用的参数就叫做一个滤波器。
观察 3:下采样不影响模式检测
第 3 个观察是下采样不影响模式检测。把一张比较大的图像做下采样(downsampling),把图像偶数的列都拿掉,奇数的行都拿掉,图像变成为原来的 1/4,但是不会影响里面是什么东西。如图 4.26 所示,把一张大的鸟的图像缩小,这张小的图像还是一只鸟。
简化 3:汇聚
根据第 3 个观察,汇聚被用到了图像识别中。汇聚没有参数,所以它不是一个层,里面没有权重,它没有要学习的东西。汇聚比较像 Sigmoid、ReLU 等激活函数,因为它里面是没有要学习的参数的,它就是一个操作符(operator),其行为都是固定好的,不需要根据数据学任何东西。
每个滤波器都产生一组数字,要做汇聚的时候,把这些数字分组,可以 2 × 2 个一组,3 × 3、4 × 4 也可以,这个是我们自己决定的,图 4.27 中的例子是 2 × 2 个一组。汇聚有很多不同的版本,以最大汇聚(max pooling)为例。最大汇聚在每一组里面选一个代表,选的代表就是最大的一个,如图 4.28 所示。除了最大汇聚,还有平均汇聚(mean pooling),平均汇聚是取每一组的平均值。
做完卷积以后,往往后面还会搭配汇聚。汇聚就是把图像变小。做完卷积以后会得到一张图像,这张图像里面有很多的通道。做完汇聚以后,这张图像的通道不变。如图 4.29 所示,在刚才的例子里面,本来 4 × 4 的图像,经过最大汇聚,4 × 4 的图像就会变成 2 × 2 的图像。
一般在实践上,往往就是卷积跟汇聚交替使用,可能做几次卷积,做一次汇聚。比如两次卷积,一次汇聚。不过汇聚对于模型的性能(performance)可能会带来一点伤害。假设要检测的是非常微细的东西,随便做下汇聚,性能可能会稍微差一点。所以近年来图像的网络设计往往也开始把汇聚丢掉,它会做这种全卷积的神经网络,整个网络里面都是卷积,完全都不用汇聚。汇聚最主要的作用是通过下采样把图像变小减少运算量。随着近年来运算能力越来越强,如果运算资源足够支撑不做汇聚,很多网络的架构设计往往就不做汇聚,而是使用全卷积,卷积从头到尾,看看做不做得起来,看看能不能做得更好。
一般架构就是卷积加汇聚,汇聚是可有可无的,很多人可能会选择不用汇聚。如图 4.30所示,如果做完几次卷积和汇聚以后,把汇聚的输出做扁平化(flatten),再把这个向量丢进全连接层里面,最终还要过个 softmax 来得到图像识别的结果。这就是一个经典的图像识别的网络,里面有卷积、汇聚和扁平化,最后再通过几个全连接层或 softmax 来得到图像识别的结果。
扁平化就是把图像里面本来排成矩阵样子的东西“拉直”,即把所有的数值“拉直”变成一个向量。
卷积神经网络的应用:下围棋
除了图像识别以外,卷积神经网络另外一个最常见的应用是用来下围棋,以 AlphaGo 为例。下围棋其实是一个分类的问题,网络的输入是棋盘上黑子跟白子的位置,输出就是下一步应该要落子的位置。网络的输入是一个向量,棋盘上有 19 × 19 个位置,可以把一个棋盘表示成一个 19 × 19 维的向量。在这个向量里面,如果某个位置有一个黑子,这个位置就填1,如果有白子,就填 -1,如果没有子,就填 0(不一定要黑子是 1,白子是 -1,没有子就是0,这只是一个可能的表示方式)。
通过把棋盘表示成向量,网络就可以知道棋盘上的盘势。把这个向量输到一个网络里面,下围棋就可以看成一个分类的问题,通过网络去预测下一步应该落子的最佳位置。所以下围棋就是一个有 19 × 19 个类别的分类问题,网络会输出 19 × 19个类别中的最好类别,据此选择下一步落子的位置。这个问题可以用一个全连接网络来解决,但用卷积神经网络的效果更好。
Q: 为什么卷积神经网络可以用在下围棋上?
A: 首先一个棋盘可以看作是一个分辨率为 19×19 的图像。一般图像很大,100×100 的分辨率的图像,都是很小的图像了。但是棋盘是一个更小的图像,其分辨率只有 19×19。这个图像里面每个像素代表棋盘上一个可以落子的位置。
一般图像的通道就是 RGB。而在 AlphaGo 的原始论文里面,每个棋盘的位置,即每个棋盘上的像素是用 48 个通道来描述,即棋盘上的每个位置都用 48 个数字来描述那个位置发生的事情。48 个数字是围棋高手设计出来的,包括比如这个位置是不是要被叫吃了,这个位置旁边有没有颜色不一样的等等。所以当我们用 48 个数字来描述棋盘上的一个位置时,这个棋盘就是 19 × 19 的分辨率的图像,其通道就是 48。
卷积神经网络其实并不是随便用都会好的,它是为图像设计的。如果一个问题跟图像没有共通的特性,就不该用卷积神经网络。既然下围棋可以用卷积神经网络,这意味着围棋跟图像有共同的特性。图像上的第1个观察是,只需要看小范围就可以知道很多重要的模式。下围棋也是一样的,图 4.32中的模式不用看整个棋盘的盘势,就知道发生了什么事(白子被黑子围住了)。接下来黑子如果放在被围住的白子下面,就可以把白子提走。白子如果放在白子下面,被围住的白子才不会被提走。其实 AlphaGo 的第 1 层的滤波器大小就是 5 × 5,所以显然设计这个网络的人觉得棋盘上很多重要的模式,也许看 5 × 5 的范围就可以知道。
此外,图像上的第 2 个观察是同样的模式可能会出现在不同的位置,在下围棋里面也是一样的。如图 4.33 所示,这个叫吃的模式,它可以出现在棋盘上的任何位置,它可以出现在左上角,也可以出现在右下角,所以从这个观点来看图像跟下围棋有很多共同之处。
一般在识别图像的时候都会做汇聚,一张图像做下采样后,并不会影响我们对图像中物体的判断。但汇聚对于下围棋这种精细的任务并不实用,下围棋时随便拿掉一个列拿掉一个行,整个棋局就不一样。AlphaGo 在 Nature 上的论文正文里面没有提它用的网络架构,而是在附件中介绍了这个细节。
AlphaGo 把一个棋盘看作19×19×48大小的图像。接下来它有做零填充。它第 1 层的滤波器的大小是 5 × 5,步幅设 1,然后有 k = 192 个滤波器,k 的值是试出来的,它也试了128、256,发现 192 的效果最好。然后它在第 2 层到第 12 层同样做零填充,核大小都是 3 × 3,一样是 k 个滤波器,也就是每一层都是 192 个滤波器,步幅一样设 1,这样叠了很多层以后,最后加上了一个 softmax,没有用汇聚。这是一个很好的设计类神经网络的例子。
在下围棋的时候不适合用汇聚。所以我们要想清楚,在用一个网络架构的时候,这个网络的架构到底代表什么意思,它适不适合用在这个任务上。卷积神经网络除了下围棋、图像识别以外,近年来也用在语音上和文字处理上。比如论文“Convolutional Neural Networks for Speech Recognition”将卷积神经网络应用到语音上,论文“UNITN: Training Deep Convolutional Neural Network for Twitter SentimentClassification”把卷积神经网络应用到文字处理上。
如果想把卷积神经网络用在语音和文字处理上,就要对感受野和参数共享进行重新设计,其跟图像不同,要考虑语音跟文字的特性来设计。所以不要以为在图像上的卷积神经网络,直接套到语音上它也奏效,可能是不奏效的。要想清楚图像语音有什么样的特性,怎么设计合适的感受野。
其实卷积神经网络不能处理图像放大缩小或者是旋转的问题,假设给卷积神经网络看的狗的图像大小都相同,它可以识别这是一只狗。当把这个图像放大的时候,它可能就不能识别这张图像是一只狗。卷积神经网络就是这么“笨”,对它来说,这是两张图像。虽然两张图像的形状是一模一样的,但是如果把它们“拉直”成向量,里面的数值就是不一样的。虽然人眼一看觉得两张图像的形状很像,但对卷积神经网络来说它们是非常不一样的。所以事实上,卷积神经网络并不能够处理图像放大缩小或者是旋转的问题。假设图像里面的物体都是比较小的,当卷积神经网络在某种大小的图像上面学会做图像识别,我们把物体放大,它的性能就会降低不少,卷积神经网络并没有想像的那么强。因此在做图像识别的时候往往都要做数据增强。所谓数据增强就是把训练数据每张图像里面截一小块出来放大,让卷积神经网络看过不同大小的模式;把图像旋转,让它看过某一个物体旋转以后长什么样子,卷积神经网络才会做到好的结果。
卷积神经网络不能够处理缩放(scaling)跟旋转(rotation)的问题,但 SpecialTransformer Layer 网络架构可以处理这个问题。
感谢您的学习,本期对深度学习的探索就先到此为止了,希望大家不要停止学习的脚步。山水相逢,我们有缘再见!