吴恩达深度学习课程笔记(精华版)--2.卷积神经网络CNN和计算机视觉CV

本系列是编者学习吴恩达deeplearning.ai 深度学习系列课程的笔记。
编者有一定机器学习基础,也看过Andrew的机器学习课程。由于Andrew的课程非常通俗易懂,笔记中会省略那些帮助理解的例子、图形等,只把最终的观点、解释、结论和解决方案做整理,以供日后查看,另外编者也在某些地方,结合原版论文做出了一些批注和补充,所以称之为精华版。
本篇是Course4,主要讲述卷积神经网络CNN的基础和应用,包括卷积和卷积网络的定义,典型的卷积网络,残差网络,应用层面主要是CV领域的目标检测,人脸识别和风格转换。

4 卷积神经网络

4.1 卷积神经网络基础

在神经网络中,有时输入特征特别复杂特别多,因此导致输入层到第一层的矩阵也非常大,大到内存装不下,因此需要卷积神经网络用以计算。

4.1.1-4.1.3 卷积运算与边缘检测

下图左侧是一个6*6图片的灰度图,中间的是一个3*3过滤器,卷积运算就是将灰度图中的每个3*3块和过滤器做运算:具体来说,每个位置对应相乘,然后求和,填入结果对应位置。其中灰度值越大,色块越亮。

  • 卷积结果中绝对值较大的,大概率就是一个垂直边缘,因为两侧有明显灰度差异。
  • 正值呢,就是从左到右变亮的,称为正边;反之称为负边。
  • 水平边缘检测也是类似的。
  • 过滤器中的数值其实是可变的,实际可以当成参数来进行学习。


    image.png

4.1.4 Padding

上述的边缘检测有两个问题:

  1. 越卷图像越小了;
  2. 边缘上的点,尤其是角上的点,只被计算了一次。

解决方案:Padding,即在图像外层围一圈0或者围几圈0,根据过滤器维数而定,可以保证图像大小不变(只要过滤器维数是奇数),且边缘被反复使用。

给两个定义:

  • 有效卷积(valid conv):不搞padding
  • 相同卷积(same conv):pdding使得长宽不变:,即,f是过滤器大小。

4.1.5 卷积步长

之前的步长都是1,因为每次match都向右移动一格,或向下换一行。如果步长为m,则要向右移动m格,向下换m行。在这个过程中过滤器必须完全match一个block,不许出格。

  • 注意,这里提到的卷积在数学上可能称为cross-correlation(互相关),需要首先将过滤器沿副对角线翻转再互相关,才能叫卷积,但是在dl领域,互相关通常就叫卷积了。

4.1.6 三维卷积

图片可以用灰度刻画,也可以用RGB三色通道刻画,此时要求过滤器也是一个立方体,和图片有相同数量的颜色通道,然后仍然以类似的方式进行卷积,得到一个矩阵。

  • 注意到虽然必须有相同的通道,但是也可以单独检验红色边界,如手写第一行所示即可。
  • 如想检验任意边界,则按手写第二行所示设置过滤器即可。


    image.png
  • 若想检验多种角度的边缘,则可以多搞一些过滤器,多生成一些卷积结果矩阵,按顺序也可以排列成一个立方体,这个立方体的深度是过滤器个数,而非特征个数。

4.1.7-4.1.8 卷积网络CNN

上述的卷积操作,就可以看作是神经网络中的权重矩阵W干的事,这样每个卷积输出矩阵,加一个偏移量,最后用一个激活函数,就完成了一个(超级)神经元的工作;如果过滤器比较多,那就形成了一层神经元,神经元的数量就是过滤器的数量。

  • 在这样的一层中,参数主要是过滤器中的格子的值,其次还有各个神经元的偏移量,和图片输入大小没有关系。这称为卷积网络的避免过拟合特性。
  • 虽然参数不是很多,但是这一层的神经元还是输出了一组新图像,即那些卷积后的矩阵。
  • 输入图像的通道数决定了过滤器的深度,过滤器的数量决定了输出图像的通道数。

这样一层层地堆叠起来,就是CNN。一般来说,前面的层不会激烈减少图像的宽和高,只会缓慢减少,但会增长不少通道数(提取了很多特征);到深层图像的宽和高就很小了,但是通道数很多(特征很多)。

  • 堆叠的最后,把得道的图像特征全部一维展开成一个向量,插一个logistic回归或者softmax,做下分类,完工!
  • 但一般来说,CNN是有三种类型的层,第一种是卷积层Conv,第二种是池化层POOL,第三种是全连接层FC。

4.1.9 池化层

池化操作和卷积操作有点相似,卷积是给过滤器一些数值去做乘积,池化不需要。以最大池化为例,他会选择对应方格里的最大值填到输出。如果输入有深度,那么输出也有同样深度(这和卷积不一样)。平均池化也是顾名思义的。

  • 池化参数没有引入任何需要学习的参数,就是一个静态变换;
  • 超参就是过滤器大小和步长;相比于平均池化,最大池化最常用;
  • 主要作用是压缩特征,提高效率。

为什么最大池化生效呢?因为如果一个区域里面捕获到了一个特征,那一定有一个个格子的值很大,那最大值可以提现,否则最大值也会很小。

4.1.10 CNN示例

Conv和Pool已经讲过了,全连接层和普通的神经网络层没什么区别。
典型的CNN如下所示:
Input->Conv->Pool->Conv->Pool->Conv->Pool->FC->FC->FC->softmax

  • 如我们之前提到,逐个卷积层减少图像长和宽,增加通道数;池化层可以起到进一步减少图像长和宽的作用;在FC之前,特征被打平成一维向量。
  • 从参数数量上来看,卷积层参数相对较少(过滤器),池化层没有参数,反倒是FC参数非常多。

4.1.11 为什么使用卷积

  • 参数少。
    • 上面已经提到,通过卷积可以大量减少参数,相比于FC,原因有以下两方面:
      • 首先是对于图像的各个位置,特征检测器可以复用(比如垂直边缘检测器)
      • 其次是稀疏连接。输出的矩阵的每个值都只与输入的一部分有关(过滤器大小),而不是与所有而有关,这实际上是一种稀疏的连接。

4.2 深度卷积模型

4.2.2 经典网络

LeNet-5

以图片灰度特征为输入:


image.png

AlexNet

AlexNet是CV领域使用DL的启蒙作。以RGB特征为输入,相比于LeNet-5有以下两个优势:

  • 参数是其1000倍之多;
  • 用了ReLU激活函数。


    image.png

VGG-16

所有卷积过滤器都基本相同,除了过滤器数量;所有池化器也都是一样的。所以超参变得很少,但是层数非常多,参数更是到了惊人的138million。


image.png

4.2.3 残差网络

残存块

简单来说,就是把前层的激励值和后层的激励前值相加,再激活,能够用来训练更深的网络。称为short cutskip connection

image.png

每个残差块包含两层,多个残差块连在一起就构成了残差网络。
普通网络训练层数大幅增加的时候,训练误差也会反而增加,其原因在于现有的优化方法训不明白这么大一个网络。但对于Resnet就没有这种问题,层数越深,训练误差越小。

  • 其中原理可以解释为,残存块有利于帮助解决梯度消失和梯度爆炸问题。

4.2.4 为什么残差网络奏效

普通网络训练层数大幅增加的时候,训练误差也会反而增加,其原因在于现有的优化方法训不明白这么大一个网络。考虑到更深的网络哪怕把更深的那几层变成恒等映射,总之也不会比浅层网络效果更差吧?

  • 那解释只有一个:普通DNN学习恒等映射并不是一个容易的事。
  • 那残差网络学习恒等映射容易么?挺容易的,简单的说明如下。

    只要W和b两组训练参数全0即可得

    因为一定是非负的,所以用ReLU的话激活是恒等激活
  • 这样的话,用残差块的话,至少不会深度网络比更浅的网络还要差,稍微能学到点东西,也可以比更浅的网络要好。


    image.png

4.2.5 网络中的网络(1×1卷积)

filter的长宽都是1,深度自然和输入一致,这种方式可以在不改变长宽的情况下,改变通道数。和一个简单的非线性层效果类似。

4.2.6-4.2.7 Inception网络

把各种形状的过滤器和池化器当成多种组件,输出长宽相同,然后拼在一起,就称为一个Inception模块。
Inception模块会重点使用1×1卷积,主要原因是减少计算代价:

  • 同样的输出规模,如果直接使用像same conv这样的过滤器,会导致计算规模非常的大,但是如果中间用了1×1卷积做了缩减,然后再用其他规模的过滤器做放大,计算量可以减少几十倍,而且效果差不多。
  • 多个Inception模块拼在一起,就是一个Inception网络。不同模块之间可能直接相连,可能加个池化层之类的。网络的最后用FC和softmax做分类输出。
  • 不止在最后,在中间模块输出之后也可以加FC和Softmax做分类输出,用于理解各层到底做了什么,判断过拟合、欠拟合。


    image.png

4.2.9 迁移学习

现在的DNN要训练起来有两个大问题,一个是训练太久了,一个是数据不够。这两个问题都可以通过用开源的网络,开源的参数来解决。
我们只需要找到一个和我们问题非常相似的网络,和它训练已久的参数。
然后首先改掉Softmax层,接着根据我们的数据量情况,决定训练网络后面的几层,前面的层的参数全部冻结,当做固定函数来用。
当然如果数据量非常充足,用开源的参数来做初始化,用我们的数据来修正参数当然是最好的。

4.2.10 数据扩充

CV领域特别缺数据,也就是精度总是不饱和的。
下面介绍几个数据扩充方法:

  1. 镜像翻转;
  2. 随机剪裁
  3. RGB颜色平移

一般来说,训练时候可以一组线程load data,扩充数据,再扔到训练线程里面。

4.3 卷积网络应用(1)

4.3.1 目标定位

我们有一组对象是有意义的需要被检测的,假设有x种。
目标检测的输出向量是这样定义的:第一维表示图像中是否有这x种对象的其中一种,接下来4个维度表示对象的位置和长宽,然后是x个维度表示是哪一种对象。

4.3.2 特征点检测

特征点就是图像的关键转折点,比如眼角,嘴角,胸重点等。

4.3.3 目标检测

滑动窗口检测

多次迭代,每次用一个窗口遍历所有位置,看看是否能检测到目标。这种方法计算代价是比较高的,因为要搜索空间比较大,要跑很多次分类器。

4.3.4 卷积的滑动窗口实现

将FC层转换为卷积层

方法也很简单,比如一个5*5*16的输出特征,我们不将其直接打平,而是用400个5*5*16的过滤器,做卷积操作,得到的自然是1*1*400的输出特征。

  • 注意到,输出特征的每一维,都是由一个单独的过滤器和每个输入特征做线性组合得到的,因此这实际上和普通NN层没什么区别。

卷积的滑动窗口实现

将原网络的FC层全部转化成卷积层,然后即使输入特征尺寸比预设的大,也可以用同样的参数(过滤器),照样产生输出。输出的每一个元素,就是滑动窗口的一个输出向量。

  • 图中第一行是网络,后两行是测试用例。


    image.png

4.3.5 边界框预测

上述两节的用于目标检测的网络有点死板,它固定了对象的size和比例(受滑动窗口的size和步长决定),实际上在一张图里,目标可能以各种比例和size出现。
YOLO算法用于解决这个问题,它的输出值和4.3.1的定义是一样的。
具体做法是:

  1. 首先将图像分格子;
  2. 每个目标会被分配到其中心所在的格子上;
  3. 每个格子对应一个目标输出(如4.3.1)。【其中目标长宽大于格子长宽是很常见的,非常有可能目标横跨几个格子】

4.3.6 交并比IoU

如何评价找到的目标边界是否合适呢?用矩形的交并比,类似于Jaccard Similarity. 一般大于等于0.5就算基本准确了。

4.3.7 非极大值抑制

实际上在进行目标检测时,会对图像分格子,每个格子都要跑一下算法,确定下有目标存在的概率是多大,而很多格子可能都包含目标,也都会输出目标存在的概率,那我们如何将目标分配给其中心的格子呢?

  • 我们可以每次找到概率值最大的格子,认可它为某目标中心,然后遍历其他概率值较高的格子,如果和刚才的中心格子IoU较大,那么就舍弃它。

4.3.8 Anchor Box

一个格子可能存在多个目标,之前的算法只能检测出一个目标,这是一个问题。
基本解决思路就是预先设置一些size的anchor box(矩形形状),然后每个grid的输出特征要扩充,对每个anchor box都要有一组特征如4.3.1。 然后对每一个捕捉到的形状去找IoU最大的anchor box写进特征输出。

每个格子都会输出几个anchor box对应的bounding box,但是肯定有很多概率很低,丢弃它们即可。对于剩下的概率较高的格子,对每个种类跑跑非极大值抑制,去除冗余边框

4.3.10 候选区域R-CNN

首先做图像分割,在分割出来有意义的区域里面去做检测,丢弃那些没用的区域。
R-CNN目前还是比YOLO算法慢很多。

  • R-CNN:首先做图像分割。对每个分割区域进行分类,得到标签和目标bounding box。
  • Fast R-CNN:首先做图像分割。用卷积实现同时对各个区域进行分类,得到标签和bounding box。
  • Faster R-CNN:使用CNN来做图像分割。

4.4 卷积网络应用(2)

4.4.1-4.4.5 人脸识别

问题定义

  • 人脸认证:给一张照片,一个人id,判断他们是否match。
  • 人脸识别:数据库里有很多人,给一张照片,判断照片上的人是否在DB里面,在的话,是哪一个?

One-shot Learning

人脸识别问题比较麻烦的是数据库里每个人一般只有一张照片,学习样本太少,另外把它当一个分类任务用softmax也不太合适,所以最终一般性的方案是学习一个距离函数,表示两张照片的差异值,这样系统很容易扩展。

Siamese网络

找一个CNN,用相同的参数,跑两张图片,最终分别得到一个输出向量,通过计算向量间距离,得到两张图片的相似度。这实际上是对图片的一种编码方式。
这个CNN如何训练呢,代价函数就是同一个人的两张图片距离应该较小,不同人的应该较大。

Triplet损失

三元组指的是Anchor样本(原图片A),正样本(同一个人的不同图片P),负样本(不同人的图片N)。
我们希望dist(A,P) < dist(A,N),甚至是。这就是定义的损失函数原型,正式的损失函数为:

代价函数就是累加。

  • 用这样的代价函数,需要训练集对每个人有多张图片,构成多种三元组,如果每个人就一张照片,那没法构建了。
  • 而且即使有这样的训练集,也需要仔细地去构建三元组;如果随机抽的话,可能大部份d(A,N)都会非常大,这样的话起不到很好的训练效果。应该人为地增加难度,让那些d(A,N)比较小的去构成三元组。

人脸认证与二分类

在训练好Siamese网络之后,我们已经具备了将照片转换为特征向量的能力,我们只需要再训练一个logistic回归二分类器,解决人脸认证问题即可,用的就是两个特征向量之间的相似性作为代价函数。
在一个人脸识别系统中,每个人都会提前算好其embedding向量;当要识别时,就把要识别的人作为输入进入CNN,获得embedding向量,然后进logistic回归分类器,和库里的人进行比较,找到一个具体的人作为分类结果。

4.4.6-4.4.11 图片风格转换

问题定义

有一个内容图片C,有一个风格图片S,把这种风格应用到内容上面生成新图片G,就是风格转换。

概要

代价函数由两部分构成,一部分是内容代价J(C,G),一部分是风格代价J(S,G),加权相加。
基本算法就是先随机初始化一个初始图片,然后梯度下降,逐渐改善这张图片。

内容代价函数

内容代价的定义方式,就是从CNN中选择一个隐藏层,然后把C扔进网络计算层的激活值,G也扔进去,然后比较激活值的差异作为代价函数。

  • 基本思想是CNN的较浅层学习的东西较为基础,更靠近内容方面。

风格代价函数

风格的定义
  • 给定一个前提知识,CNN的每一层的每个通道,都能学到特定的一组特征,比如前层的某个通道是45度垂直边缘,后层的某个通道表示是否是一只狗。这种特征的学习由初级到高级,从浅层到深层层层递进。
  • 图片风格的定义就建立在这种基础上。风格在每层定义为一个矩阵,矩阵的每一个元素表示两两通道之间的互相关关系(对应位置相乘再累加),各层都有这样一个矩阵。其意思表示,如果某层,A通道表示是一个卷发,B通道表示是橘色,如果高度相关就说明这种风格就是橘色卷发。
风格的代价函数

代价函数就是,S和G分别跑一次网络,各自得到自己的风格。对应层,S和G的风格对应位置相减然后求个F范数,各层加权相加,就是代价函数了。

你可能感兴趣的:(吴恩达深度学习课程笔记(精华版)--2.卷积神经网络CNN和计算机视觉CV)