学习提示
上周,我们学完了CNN的基础组成模块。而从这周开始,我们要换一种学习方式:我们会认识一些经典的CNN架构,从示例中学习。一方面来说,通过了解他人的网络,阅读他人的代码,我们能够更快地掌握如何整合CNN的基础模块;另一方面,CNN架构往往泛化能力较强,学会了其他任务中成熟的架构,可以把这些架构直接用到我们自己的任务中。
接下来,我们会按照CNN的发展历史,认识许多CNN架构。首先是经典网络:
- LeNet-5
- AlexNet
- VGG
之后是近年来的一些网络:
- ResNet
- Inception
- MobileNet
我们不会把这些研究的论文详细过一遍,而只会学习各研究中最精华的部分。学有余力的话,最好能在课后把论文自己过一遍。
课堂笔记
经典网络
LeNet-5
LeNet-5是用于手写数字识别(识别0~9的阿拉伯数字)的网络。它的结构如下:
网络是输入是一张[32, 32, 1]的灰度图像,输入经过4个卷积+池化层,再经过两个全连接层,输出一个0~9的数字。这个网络和我们上周见过的网络十分相似,数据体的宽和高在不断变小,而通道数在不断变多。
这篇工作是1998年发表的,当时的神经网络架构和现在我们学的有不少区别:
- 当时padding还没有得到广泛使用,数据体的分辨率会越降越小。
- 当时主要使用平均池化,而现在最大池化更常见。
- 网络只输出一个值,表示识别出来的数字。而现在的多分类任务一般会输出10个值并使用softmax激活函数。
- 当时激活函数只用sigmoid和tanh,没有人用ReLU。
- 当时的算力没有现在这么强,原工作在计算每个通道卷积时使用了很多复杂的小技巧。而现在我们直接算就行了。
LeNet-5只有6万个参数。随着算力的增长,后来的网络越来越大了。
AlexNet
AlexNet是2012年发表的有关图像分类的CNN结构。它的输入是[227, 227, 3]的图像,输出是一个1000类的分类结果。
原论文里写的是输入形状是[224, 224, 3],但实际上这个分辨率是有问题的,按照这个分辨率是算不出后续结果的分辨率的。但现在一些框架对AlexNet的复现中,还是会令输入的分辨率是224。这是因为框架在第一层卷积中加了一个padding的操作,强行让后续数据的分辨率和原论文对上了。
AlexNet和LeNet-5在架构上十分接近。但是,AlexNet做出了以下改进:
- AlexNet用了更多的参数,一共有约6000万个参数。
- 使用ReLU作为激活函数。
AlexNet还提出了其他一些创新,但与我们要学的知识没有那么多关系:
- 当时算力还是比较紧张,AlexNet用了双GPU训练。论文里写了很多相关的工程细节。
- 使用了Local Response Normalization这种归一化层。现在几乎没人用这种归一化。
AlexNet中的一些技术在今天看来,已经是常识般的存在。而在那个年代,尽管深度学习在语音识别等任务上已经初露锋芒,人们还没有开始重视深度学习这项技术。正是由于AlexNet这一篇工作的出现,计算机视觉的研究者开始关注起了深度学习。甚至在后来,这篇工作的影响力已经远超出了计算机视觉社区。
VGG-16
VGG-16也是一个图像分类网络。VGG的出发点是:为了简化网络结构,只用3x3等长(same)卷积和2x2最大池化。
可以看出,VGG也是经过了一系列的卷积和池化层,最后使用全连接层和softmax输出结果。顺带一提,VGG-16里的16表示有16个带参数的层。
VGG非常庞大,有138M(1.38亿)个参数。但是它简洁的结构吸引了很多人的关注。
吴恩达老师鼓励大家去读一读这三篇论文。可以先看AlexNet,再看VGG。LeNet有点难读,可以放到最后去读。
ResNets(基于残差的网络)
非常非常深的神经网络是很难训练的,这主要是由梯度爆炸/弥散问题导致的。在这一节中,我们要学一种叫做“跳连(skip connection)”的网络模块连接方式。使用跳连,我们能让浅层模块的输出直接对接到深层模块的输入上,进而搭建基于残差的网络,解决梯度爆炸/弥散问题,训练深达100层的网络。
残差块
回忆一下,在全连接网络中,假如我们有中间层的输出 a [ l ] , a [ l + 2 ] a^{[l]}, a^{[l+2]} a[l],a[l+2], a [ l + 2 ] a^{[l+2]} a[l+2]是怎么由 a [ l ] a^{[l]} a[l]算出来的呢?我们之前用的公式如下:
z [ l + 1 ] = W [ l + 1 ] a [ l ] + b [ l + 1 ] a [ l + 1 ] = g ( z [ l + 1 ] ) z [ l + 2 ] = W [ l + 2 ] a [ l + 1 ] + b [ l + 2 ] a [ l + 2 ] = g ( z [ l + 2 ] ) \begin{aligned} z^{[l+1]}&=W^{[l+1]}a^{[l]}+b^{[l+1]} \\ a^{[l+1]}&=g(z^{[l+1]}) \\ z^{[l+2]}&=W^{[l+2]}a^{[l+1]}+b^{[l+2]} \\ a^{[l+2]}&=g(z^{[l+2]}) \\ \end{aligned} z[l+1]a[l+1]z[l+2]a[l+2]=W[l+1]a[l]+b[l+1]=g(z[l+1])=W[l+2]a[l+1]+b[l+2]=g(z[l+2])
也就是说, a [ l ] a^{[l]} a