吴恩达深度学习笔记——卷积神经网络(Convolutional Neural Networks)

深度学习笔记导航

前言

本系列文章是吴恩达深度学习攻城狮系列课程的笔记,分为五部分。

这一章讲了卷积神经网络相关的知识。

我的笔记不同于一般的笔记,我的笔记更加凝练,除了结论以及公式,更多的是对知识的理解,结合课程可以加速理解,省去很多时间,但是请注意,笔记不能替代课程,应该结合使用。

传送门

结构化机器学习项目,我建议放在最后看。

首先学这一节对你后面的学习没有影响,我就是跳过去学的。而且他更多的讲的是策略,尤其是举了很多后面的例子,你听了不仅不太好懂,而且没啥意思,所以我建议放在最后看。

神经网络与深度学习(Neural Networks and Deep Learning)

改善深层神经网络:超参数调整,正则化,最优化(Hyperparameter Tuning)

卷积神经网络(Convolutional Neural Networks)

序列模型与循环神经网络(Sequence Models)

结构化机器学习项目(Structuring Machine Learning Projects)

卷积神经网络(Convolutional Neural Networks)

卷积神经网络基础(Foundations of Convolutional Neural Networks)

概述

本章我不打算按着讲课顺序记录,而是按着便于复习的顺序。

标记约定(notations):
  1. f [ l ] = f i l t e r s i z e f^{[l]}=filter size f[l]=filtersize,一般来说卷积核都是方形的。
  2. p [ l ] = p a d d i n g p^{[l]}=padding p[l]=padding,填充宽度。
  3. s [ l ] = s t r i d e s^{[l]}=stride s[l]=stride,卷积步长
  4. n c [ l ] = n u m b e r o f f i l t e r s n_c^{[l]}=number of filters nc[l]=numberoffilters,每层的卷积核数量(类比于神经元数量)
  5. A [ l ] − m × n H [ l ] × n W [ l ] × n C [ l ] A^{[l]}-m\times n_H^{[l]}\times n_W^{[l]}\times n_C^{[l]} A[l]m×nH[l]×nW[l]×nC[l],样本(activations)(其实这个维度不固定,HWC的顺序可能被调整)。

    每层的输入为 A [ l − 1 ] A^{[l-1]} A[l1],输出为 A [ l ] A^{[l]} A[l]
  6. W [ l ] − f [ l ] × f [ l ] × n C [ l − 1 ] × n C [ l ] W^{[l]}-f^{[l]}\times f^{[l]}\times n_C^{[l-1]}\times n_C^{[l]} W[l]f[l]×f[l]×nC[l1]×nC[l],过滤器(权重weights):(这个W和A的维度的顺序可能有玄机,或许对后面的计算有好处)
  7. B [ l ] − 1 × 1 × 1 × n C [ l ] B^{[l]}-1\times1\times1\times n_C^{[l]} B[l]1×1×1×nC[l]
卷积神经网络一般架构
  1. 卷积层,负责提取特征
  2. 池化层,负责将3维图像转换成1维向量
  3. 全连接层,负责训练。

理论上仅仅一个卷积层+池化层+一个logistic/softmax层就够了,但是加上全连接层的表现还是会更好。

卷积层可以类比神经网络:

  1. 线性部分:filter=W
  2. 偏差:相同
  3. 非线性作用:相同

卷积层理解:

  1. 不管图片有多大,只要卷积核的尺寸和数量不变,经过卷积作用的参数都是恒定的,这样可以防止过拟合
  2. 在卷积过程中,每层处理设置的超参数有, f [ l ] , p [ l ] , s [ l ] , n C [ l ] f^{[l]},p^{[l]},s^{[l]},n_C^{[l]} f[l],p[l],s[l],nC[l],然后要学习的参数有 W [ l ] , B [ l ] W^{[l]},B^{[l]} W[l],B[l]
  3. 随着卷积过程,有一个大的趋势(trend)就是,图片的尺寸减小,但是深度增加,实际上是总特征数在减小,因为尺寸是平方的。而且后面的池化操作还会进一步的缩小尺寸。

池化层:

池化层其实就是一个固定的函数,将卷积后的图片进行进一步的处理,缩小,提取,然后变成一个 X ( i ) X^{(i)} X(i)向量。

全连接层:

这个就和我们前面的接上了。

卷积层(Convolution)

卷积层的处理就是用filters去卷积图片,然后添加偏差,最后应用激活函数去非线性化。这个完全类似于经典神经网络,核心思路都是多参数。

这些层一般简称Conv layer

卷积运算概述

概述:

目前有一个大前提就是,一张图片的参数太多,一方面占据过多资源,另一方面没有足够的样本量以至于容易过拟合。

还有就是,人识别一个东西不会去一个像素一个像素地看,我们人类是要提取主要特征的,所以这就涉及到特征提取。

卷积就是将一个卷积核/过滤器(kernal/filter)覆盖到图像上,然后进行element-wise运算,再求和,将一个卷积核面积的图像变成一个像素,然后逐像素移动,直到遍历完整个图像。

实际上,我们计算机里的“卷积”实际上是互相关(cross-correlation),真正的数学意义上的卷积,是在cross-correlation之前先对filter沿着副对角线进行镜像翻转(flip)。

卷积运算的原理

卷积的原理:

[ 1 0 − 1 1 0 − 1 1 0 − 1 ] \begin{bmatrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\ 1 & 0 & -1 \\ \end{bmatrix} 111000111 [ a b c a b c a b c ] \begin{bmatrix} a & b & c \\ a & b & c \\ a & b & c \\ \end{bmatrix} aaabbbccc 举例

  1. 如果图像是一整块没有变化,即a=b=c,那么运算后就是0
  2. 反过来,如果图像左右不同,就会产生一个非0数,差距越大,非0数就越大。
  3. 进一步深挖,实际上这个有一点像导数,我们写出最后的算式,我们改成类似于导数的形式就是 3 2 × a − c 2 \dfrac{3}{2}\times\dfrac{a-c}{2} 23×2ac
  4. 最后总结,卷积就是可以控制方向的,对颜色变化求导的一个过程。然后求导的正方向就是从-1到1的方向。比如我们最开始举的例子,就是从右到左求导的。

原理的推广理解:

  1. 在方向上推广:

    如果要求横向的,只需要翻转90°即可 [ 1 1 1 0 0 0 − 1 − 1 − 1 ] \begin{bmatrix} 1 & 1 & 1 \\ 0 & 0 & 0 \\ -1 & -1 & -1 \\ \end{bmatrix} 101101101 ,甚至你也可以求斜向的,我猜测是用 [ 0 1 0 − 1 0 1 0 − 1 0 ] \begin{bmatrix} 0 & 1 & 0 \\ -1 & 0 & 1 \\ 0 & -1 & 0 \\ \end{bmatrix} 010101010 或者 [ 0 1 1 − 1 0 1 − 1 − 1 0 ] \begin{bmatrix} 0 & 1 & 1 \\ -1 & 0 & 1 \\ -1 & -1 & 0 \\ \end{bmatrix} 011101110 这种样子的。
  2. 在大小上推广:

    说白了,过滤器的大小决定了检测区域的精细度,本质上就是改变求导的步长

    如果是 2 × 2 2\times 2 2×2,那么步长就为1

    甚至我们还可以改变宽度,不一定是方的,因为一个区域在我们求导的垂直方向上,是会互相影响中和的。垂直方向的宽度越大,代表更粗的精细度。
  3. 在数值上推广:

    既然宽度方向上会互相中和,那我也能选择性的放大某一个位置,比如 [ 1 0 − 1 2 0 − 2 1 0 − 1 ] \begin{bmatrix} 1 & 0 & -1 \\ 2 & 0 & -2 \\ 1 & 0 & -1 \\ \end{bmatrix} 121000121 就可以让中间的影响最大,提高robust,在计算机历史上,这个叫Sobel滤波器,又比如 [ 3 0 − 3 10 0 − 10 3 0 − 3 ] \begin{bmatrix} 3 & 0 & -3 \\ 10 & 0 & -10 \\ 3 & 0 & -3 \\ \end{bmatrix} 31030003103 ,这个叫Scharr滤波器,效果和刚才那个又有所不同,但是我个人感觉不过是修改了绝对数量的大小(我猜会影响对比度,陡峭度)以及比例。
  4. 学习权重!

    可以把卷积核的数值设置成参数,然后通过bp训练,来达到识别特定边缘特征的数值。
卷积玩法——填充边界(Padding)

卷积是有一些缺点的:

  1. 每次卷积,图像都会缩小为 ( n − f + 1 ) × ( n − f + 1 ) (n-f+1)\times (n-f+1) (nf+1)×(nf+1)的尺寸。
  2. 卷积运算对于图像边角像素的利用不够,也就是说丢失了图像边缘的信息

解决方法——padding:

  1. 卷积之前在图像周围填充一圈像素,填充宽度为p,一般来说都是 2 p = f − 1 2p=f-1 2p=f1,这样可以保持大小,这种叫same convolution p = f − 1 2 p=\dfrac{f-1}{2} p=2f1,潜在要求就是f是奇数,奇数的卷积核还有一个好处就是,有一个中心。

    当然,p也可以搞成偶数,只要你做好不对称(asymmetric)填充的准备即可。

    p也可以设别的。比如valid convolution: p = 0 p=0 p=0
  2. 至于数值,一般填充0,也可以填充别的。
卷积玩法——步长控制(Strided Convolutions)

我们为卷积过程再添加一个参数:stride

跨越的步长会使得最后的生成成比例的缩小,体现在公式上就是分母+向下取整(round down)作用:
生成的尺寸 = ⌊ n + 2 p − f s ⌋ + 1 生成的尺寸=\lfloor\dfrac{n+2p-f}{s}\rfloor+1 生成的尺寸=sn+2pf+1

卷积玩法——3D卷积和多卷积核卷积(3D Convolution and Multiple Filters)

3D卷积:

这个其实也仅仅是增加了一个通道(channel)的维度,对于图片就是RGB三通道,卷积核就变成三个通道叠加。计算方法也就是和2D的一样,elem-wise相乘再求和。

最后,3D*3D=2D

  1. 可以将另外两个通道都设为0,这样就可以单独对一个通道进行卷积
  2. 也可以设为统一的,总之可以自行调整参数,来识别多通道条件下的特殊边缘。

Multiple Filters:

无论是3D还是kD的卷积,最后只生成了一张2D平面,我们还可以继续增加维度,就是卷积核的数量。

比如我同时使用horizontal和vertical和45°的卷积核,这时就把这些堆叠起来。

最后总结一下维度:

我们使用C来表示Channels,那么卷积操作就是
n × n × n C ∗ f × f × n C ⋯ n × n × n C ∗ f × f × n C = ( n − f ) + 1 × ( n − f ) + 1 × n C ′ n\times n\times n_C * f\times f\times n_C \\ \cdots \\ n\times n\times n_C * f\times f\times n_C \\ =(n-f)+1\times(n-f)+1\times n_C^\prime \\ n×n×nCf×f×nCn×n×nCf×f×nC=(nf)+1×(nf)+1×nC
其中, n C ′ = 卷积核数量 n_C^\prime=卷积核数量 nC=卷积核数量

n C n_C nC这一维度,不论是通道数量还是卷积核数量,通常被叫做3维立方体的深度(depth of 3D volume)

池化层(Pooling)

概述

池化是一个没有学习参数,只由超参数决定的作用过程。其目标是进一步提取特征,缩小尺寸。

作用方式同样是用一个过滤器去覆盖,作用。但是过滤器是分别对每一个通道独立作用,所以如果输入时3D,那么输出也是3D,这是和卷积最大的不同。

重点用max-pooling,后面的例子也都是max-pooling。作用方式是取过滤器面积中最大的那个作为结果。虽然average-pooling也有用,但是不常用,多用于深卷积层网络。

池化层通常叫pool layer

超参数:

没有可以学习的参数

  1. f和s,常用的是<2,2>,效果是缩小一半尺寸,以及<3,2>
  2. 很少用p,是因为我们本来就是缩小尺寸的。
  3. 池化方式,比如max-pooling和average-pooling。

但是average不被常用,大概是特征提取不够强烈。当然,这个还是可以用在很深的网络中,防止过拟合(我猜的效果)

理解
  1. 如果在过滤器中提取到了某个特征,就保留其最大值。如果没有特征,那么最大值也会很小。(然而实际上主要还是因为实践中比较有效果罢了)
  2. 如果有一个全局最大的特征,那么周围的一圈池化结果都会变成这个值,这恰恰体现出了提取效果。
  3. 至于大小变化,因为作用方式类似于卷积,只不过我们是求最大,他是求和,所以大小变化规律相同。 ⌊ n H − f s + 1 ⌋ × ⌊ n H − f s + 1 ⌋ × n C \lfloor\dfrac{n_H-f}{s}+1\rfloor\times\lfloor\dfrac{n_H-f}{s}+1\rfloor\times n_C snHf+1×snHf+1×nC(这里默认p=0)
平铺(flattening)

池化还涵盖一个概念就是展开,将池化后的3D特征转化为1D的向量,便于投喂到全连接层。

搭建卷积神经网络

卷积层和池化层是可以交错搭配的。一种经典的方案就是一个卷积层配一个池化层,称作一个Layer1,Layer2以此类推。

然后经过最后一步flattening,生成的向量样本就可以投入到全连接层了,我们称全连接层为FC3,FC4,以此类推。

经过全连接层,最后给一个sigmoid或者是soft-max层做出判断。

可以表示为:Conv-Pool-Conv-Pool-flatten-FCs-Soft-max

另一种常见的方式就是:Convs-Pool-Convs-Pool-flatten-FCs-soft-max

从这里就可以看出,这些层的变量都可以用W和B来表示。不过总的来说,卷积层的参数要远少于全连接层。

而且貌似FCs层,神经元个数会逐渐减少,大概是特征逐渐归纳。

卷积网络的合理性

首先就是,逐像素判断太费事儿而且,生物上,我们也不是逐个像素去识别的,而是通过特征。

而卷积层的参数相比于全连接层是真的少,原因如下:

  1. 参数共享。本质上,一个过滤器代表一个目标特征,这种提取是可以作用于整个图片的,重复使用就降低了参数数量。不论是对低级别特征比如边缘,还是对高级别特征,比如眼睛鼻子,或者是人,猫。
  2. 稀疏连接(sparse connection)。根据常理,一个特征往往是分布于一个区域的,所以由卷积产生的结果中的一个小格子,只和原有图片中 f 2 f^2 f2大小的格子相关联,而不是全连接,这样就将无用的连接抹除了。这种稀疏连接还带来了平移不变(translation invariance)属性,即使是你移动一些像素,只要整体特征没有发生明显变化,我们的判断不会改变。

深度卷积模型:案例研究(Deep Convolutional Models: Case Studies)

搞研究的灵感,很多来源于他人的成果。而且相同的结构可能对不同的任务起效果。

经典网络(classic networks)

阅读顺序建议AlexNet - VGG-16 - LeNet-5

LeNet-5

[LeCun et al.,1998. Gradient-based learning applied
to document recognition]

架构

  1. Conv-Pool-Conv-Pool-FC-FC-SoftMax

  2. Convs-Pool-Convs-Pool-FC-FC-SoftMax

解读:

  1. 5 = 2 + 2 + 1 5=2+2+1 5=2+2+1
  2. 论文重点读section2,介绍了结构,section3有一些有趣的实验现象。
  3. 因为计算速度的问题,当时采用了复杂的计算来加速
AlexNet

[Krizhevsky et al., 2012. ImageNet classification with deep convolutional neural networks]

架构:

Conv-MaxPool-SameConv-MaxPool-SameConv × \times × 3-MaxPool-FC × \times × 3-SoftMax

解读:

  1. 这篇文章向学术圈展示了deep learning在CV方面的潜力,有种开山鼻祖的感觉,所以也适合初学者入门。
  2. 其实结构上,和LeNet还是大致相似,但是大小却远大于LeNet。
  3. 另一个就是使用了ReLU激活函数
  4. 因为GPU不太行,所以当时采用了比较复杂的分布式训练,部署到两个GPU上。
  5. 文中提到了Local Response Normalization(LRN),但是人们发现没什么用。
VGG-16

[Simonyan & Zisserman 2015.Very deep convolutional networks for large-scale image recognition]

架构:

SameConv[n=64] × \times × 2 - MaxPool - SameConv[n=128] × \times ×
2 - MaxPool - SameConv[n=256] × \times × 3 - MaxPool - SameConv[n=512] × \times × 3 - MaxPool - SameConv[n=512] × \times × 3 - MaxPool - FC - FC - SoftMax

解读:

  1. 16代表总层数= 2 + 2 + 3 + 3 + 3 + 2 + 1 2+2+3+3+3+2+1 2+2+3+3+3+2+1。可以看出,卷积层很深。
  2. VGG-16的吸引点就是,随着卷积深入,尺寸在缩小,信道在增加,信道翻倍增长,直到512
  3. VGG虽然参数多,但是看起来很规整,uniform,结构简单,缺点就是参数太多
  4. VGG-19也是一种,但是效果和16差不多,所以人们还是用16多

残差网络(ResNets-Residual Networks)

[He et al., 2015. Deep Residual Networks for Image Recognition]

深层网络难以训练的原因之一就是梯度爆炸和梯度消失(vanishing)。残差网络可以有效解决这种问题,让我们可以训练100层级别的神经网络。

随着深度加深,一般的神经网络的效果会呈现一个v型变化,但是ResNet可以适应更深的网络。

残差块(Residual Block)

A [ l ] 到 A [ l + 2 ] A^{[l]}到A^{[l+2]} A[l]A[l+2]要经过linear+nonlinearity+linear+nonlinearity的作用。我们直接将两层网络合并为一个残差块。

所以公式把
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 ] + B [ l + 2 ] A [ l + 2 ] = g ( Z [ l + 2 ] ) 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]}+B^{[l+2]} \\ A^{[l+2]}=g(Z^{[l+2]})\\ 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]+B[l+2]A[l+2]=g(Z[l+2])
中的最后一个变为
A [ l + 2 ] = g ( Z [ l + 2 ] + A [ l ] ) A^{[l+2]}=g(Z^{[l+2]}+{A^{[l]}})\\ A[l+2]=g(Z[l+2]+A[l])

理解:

  1. 这个就是将l和l+2层建立远跳链接,建立一个捷径(shortcut)
  2. 远跳链接(skip connection)也可以用跳多个,不仅仅是2个。
  3. 一般来说,需要用ReLU函数,这样保证A肯定是非负的,然后再用ReLU作用就是恒等关系。
  4. 对一个残差块来说,如果碰到趋近于W=0,B=0的情况,比如受到L2-Regularization的影响+(个人感觉还有梯度消失的影响),然后ReLU( Z [ l + 2 ] + A [ l ] ) ≈ A [ l ] Z^{[l+2]}+A^{[l]})\approx A^{[l]} Z[l+2]+A[l])A[l],也就是,如果效果不好,再不济也就是和原来一样(术语叫做很容易就能学习到恒等函数)。如果效果好,那就和正常的神经网络效果相近,可以发挥深度的优势。也就是稳赚不赔!
  5. 由此,可以对已有的网络添加远跳链接,也可以在神经网络里加残差块扩容。
维度的细节处理

因为有一个矩阵相加,所以应该统一维度。

  1. 对卷积层,可以通过same convolution来保留维度,所以连续用同样的卷积很有可能是为了配合使用ResNet,连续的same convolution就是残差块。
  2. 还可以 Z [ l + 2 ] + W s A [ l ] Z^{[l+2]}+W_sA^{[l]} Z[l+2]+WsA[l],让 W s W_s Ws自己去学习(存疑,因为这英语听得不是太清楚)
  3. 另一种就是单纯的将 A [ l ] A^{[l]} A[l]进行Padding扩容操作,填0,直到维度统一

Inception Network (GoogLeNet)

网络中的网络以及 1 × 1 1\times 1 1×1卷积(network in network and 1 by 1 convolution)

[Lin et al., 2013. Network in Network]

f=1的卷积,也有用。

理解:

  1. 之所以叫network in network,是因为f=1的卷积其实就是一个elem-wise的乘求和,和神经元没什么区别,所以本质上,一个 1 × 1 1\times 1 1×1的filter就相当于一个神经元,也有 n c n_c nc个权重,然后filter的数量就是神经元的数量。
  2. 每一个filter对输入进行卷积,生成一个信道,然后拼凑成输出。
  3. 还可以理解为same convolution的另一种实现方法,但是这两个东西仍然从本质上就不一样。(怎么个不一样具体还说不清)

应用:

  1. 改变信道数量,效果上和same相同,但是结果的数值不同。
  2. 应用在Inception网络中。
Inception Block

背景:

在构建卷积层的时候,你要思考使用什么尺寸的filter。

Inception要解决两个问题:

  1. 随着卷积深度的增加,原有的VGG网络会有一个性能饱和的问题,Inception要提高分类性能。
  2. 如何能在保留或提升性能的同时,尽可能降低内存开销。

Inception Block的构建细节:
[插入图片]

  1. 对于卷积,首先,先用三个bottleneck layer,然后在后面加上各自的sameConv。注意1卷积没必要重复加,所以只有一个
  2. 对于池化,先samePool,再用一个bottleneck layer去压缩信道。为什么不先压缩信道?我也不知道。
  3. 最后把生成的四个模块concatenate即可。

基本思想:

把各种尺寸的filter和Pool层产生的结果直接拼起来,然后由神经网络来学习权重,实现自动决策。

开销计算

加法和乘法数量差不多,所以就用乘法数量来代表开销。

对于一个卷积操作,生成了一个 n × n × n c [ l ] n\times n\times n_c^{[l]} n×n×nc[l]的volume, 使用的是 f × f × n c [ l − 1 ] f\times f\times n_c^{[l-1]} f×f×nc[l1],volume的每一个方块都是由一次卷积重叠操作生成的,每一次重叠,都有 f × f × n c [ l − 1 ] f\times f\times n_c^{[l-1]} f×f×nc[l1]次乘法,然后生成这么多块,总共的开销实际上很简单

就是 A [ l − 1 ] A^{[l-1]} A[l1]的尺寸 × \times × W [ l ] W^{[l]} W[l]的尺寸,即输入样本的三个维度 × \times ×过滤器的三个维度。

举个例子:

先用1=f的卷积(这一个步通常被叫做瓶颈层bottleneck layer)压缩信道数量,将尺寸减少,然后再用一个卷积扩大信道数量。

从例子上来看,把一个卷积层拆成两个,可以将大×大转化成小×小+小×小,实现保留性能的前提下,降低成本,同时能够减少(shrink down)参数数量。

构建Inception Network

[插入图片]

  1. Inception网络的结构主要由Inception Block构成
  2. 有时还会池化一下。
  3. 还有一些分支,分支通过隐层来提前做出分类,和主干最后的分类是类似的。这起到了正则化作用,防止过拟合。
  4. GoogLeNet是致敬LeNet,Inception是用盗梦空间的梗,we need to go deeper,表达一种建立更深网络的决心

灵活运用神经网络架构

使用开源方案

神经网络尴尬的地方在于,复现难度比较高,因为条件不一样,你的GPU,初始化等等。

主要是git,windows的安装与配置PATH都比较容易搞定,然后git clone URL即可。

但是需要注意的是,网上没有找到配置默认clone 目录的地方,所以如果用cmd的话,先cd 到合适的目录再clone,不然位置比较尴尬,整到默认根目录了。东西一多,就不好管理。

迁移学习(Transfer Learning)

说白了就是用别人已经训练好的东西或者预训练好的模型,去魔改。省事,不用痛苦地寻找最优参数。

如果你样本不多:

你可以把别人的模型下载好,然后就是用别人的模型再和你的浅层拼一下,就可以实现你自己的模型了。

目前框架已经实现了冻结特定层权重的操作,可以把别人的模型冻结,然后只训练你自己的,这样就可以用小样本来训练。

另一个技巧就是,既然你已经冻结前面的了,那你就可以直接计算出 A [ L ] A^{[L]} A[L]做为你的 X ′ X^\prime X,就省去了反复计算一个相同值的过程(我感觉框架可以把这个功能内置进去)

如果你有大量样本:

那就少冻结点,或者自己的层多弄点,直到最后解冻所有,然后把他的权重作为initialization。

如果有巨量样本:

自己训练from scratch,一般这种的也不缺GPU。

总之:

还是样本量和参数量要匹配。

数据增强(Data Augmentation)
  1. 对称(mirroring)翻转(rotation)剪切(random Cropping)
  2. 色彩转换(shifting):给不同通道加上一个失真(distortion),说白了就是调色,可以让模型对颜色更有鲁棒性。(注意有一个关键词PCA增强)
  3. 这个可以多线程实现,构建mini-batch
  4. 这个也得调参,推荐从别人开始。

计算机视觉现状(The State of CV)

详见视频。

对象识别(Object Detection)

目标定位与特征点检测(Object Localization and Landmark Detection)

首先区分几个概念:

  1. Image Classification:图像分类,一般都是一个大物体在中心,然后进行识别。
  2. Classification with Localization:相比于1,加上了位置确定,给出一个方框。
  3. Detection:可能有多个对象,要给出他们的位置

定位原理:

以左上角为(0,0),右下角为(1,1),定位就是给soft-max层再加四个输出表示边框,边框的参数为 b x , b y , b h , b w b_x,b_y,b_h,b_w bx,by,bh,bw,因此,标签还要加上位置的四个参数。

具体的标签: [ P C b x b y b h b w c 1 c 2 ⋯ c C − 1 ] \begin{bmatrix} P_C \\ b_x \\ b_y \\ b_h \\ b_w \\ c_1 \\ c_2 \\ \cdots \\ c_{C-1} \end{bmatrix} PCbxbybhbwc1c2cC1

第一个参数为是否有物体,有就是1,然后跟着坐标,以及类别。没有就是0,后面的数没有意义,应该是任意的。

损失函数:

L ( y ^ , y ) = { ∣ ∣ y ^ − y ∣ ∣ 2 2 , y 1 ( P C ) = 1 ,有对象,对比全体 ( y ^ 1 − y 1 ) 2 , y 1 = 0 ,只有背景,仅仅对比背景判断 L(\hat{y},y)= \begin{cases} ||\hat{y}-y||_2^2 &, y_1(P_C)=1,有对象,对比全体\\ (\hat{y}_1-y_1)^2 &, y_1=0,只有背景,仅仅对比背景判断\\ \end{cases} L(y^,y)={∣∣y^y22(y^1y1)2,y1(PC)=1,有对象,对比全体,y1=0,只有背景,仅仅对比背景判断
需要注意的是,这里的L函数是简写了,实际上还可以分成三个部分写,第一个就是 P c P_c Pc用交叉熵,然后坐标用差平方和,类别用交叉熵。

特征点识别(Landmark Detection):

这个是比边框检测更加精细的识别,比如眼角,嘴角等等特征。有了特征点,可以进行很多操作,比如识别人的表情,姿势,p脸。

至于标签,类似于目标定位,第一个是有没有目标,然后剩下的就是特征点坐标的顺次排列。

注意要保持特征点类别一致,这个也很好理解,不能教错对吧。

滑动窗口(sliding windows)

指定方框大小和步长,然后遍历图片,每次裁剪出一个小块去分类检测分类。

这个有一个巨大的问题就是,计算成本,以前用线性分类器的时候还比较快速,但是现在卷积神经网络计算一次成本比较高,所以需要替代方案。

论文参考[sermanet et.al.,2014,OverLeaf: Integrated recognition,localization and detection using convolutional works]

将卷积神经网络的FC层转化成卷积层。其实就是用一个和原图片同样大小的volume去进行卷积,效果等同于全连接的计算,都是乘一个系数然后求和,然后有多少个神经元就用多少个filter。

我们训练用的图片大小都是相等的,比如14 × \times × 14,问题来了,如果来一张16 × \times × 16的,会有什么结果?配合特定大小的MaxPool,就可以实现类似于滑动窗口遍历的效果。

比如我们原来是生成一个 1 × 1 × n 1\times 1\times n 1×1×n的结果向量,如果我们用这种方式,最后就会生成 m × m × n m\times m\times n m×m×n大小的volume, m × m m\times m m×m 就是所有滑动窗口的数量。

这种方式可以提高效率的原因有一点类似于动态规划,可以避免重复计算,不同的window可以共享一片区域的计算结果。

但是这个还有一个问题就是,我们这个其实仅仅是分类而已(但我觉得也可以同时计算边框位置,但是成本或许太大了?),真实的轮廓和我们的windows往往不重叠,而且我们用的还是方块,真实情况不一定是方块,所以下一步要让定位和尺寸更加准确,优化/换一种方法。

YOLO算法(You Only Look Once)

[Redmon et al.,2015,You Only Look Once:Unified real-time object detection]

这篇文章是著名的YOLO算法的出处(据说难度不小,比较玄学)。

这个和前面的slide windows是两个不同的东西,只不过都用到了用卷积加速分块操作。

核心思路就是,将前面的Classification with Localization一次性运用到图片切分后的grid中,至于一次性计算所有分块,就通过卷积来实现。

具体思路就是,slide windows不是会有重叠部分嘛,我们这个对图片做一个划分,将每一个块看做独立的图。用卷积操作计算出 m × m × n m\times m\times n m×m×n的结果,因为图片块少,所以我们的n的维度可以多一些,加上坐标和方框大小。

给我的感觉就是,是一种加强版的slide windows,去除了重叠部分,只进行划分,同时计算的更精细,这样又准速度又快,可以达到实时(real-time)。

需要注意的是,在制作标签的时候, b H , b w b_H,b_w bH,bw完全可以>1,因为虽然把小块看做图片,但是不是真正独立的图。

优化YOLO

交并比(IOU-Intersection over Union)

本算法用于评估检测算法,基于这个算法可以用来优化检测算法。

字面意思, 交集 并集 \dfrac{交集}{并集} 并集交集,这个函数比较有意思,相同的预测,交并比的结果<交预比。他的变化更剧烈,因此0.5就不错了,可以视作正确。

非极大值抑制(non-max suppression)

除了识别不出,还可能发生一个对象被不同的块重复识别,尤其是切得太小的时候,每个小块都觉得自己是物体中心。

如果没有措施,会产生很多框,以下操作不考虑类别:

  1. 去掉(discard) P C P_C PC<阈值(比如0.6)的,这些识别不合格
  2. 我们要 p C p_C pC最大的,还没有被抑制的框,然后计算其他框的交并比,如果交并比超过阈值(比如0.5),那么可以认定这俩是重叠的,就将重叠框抑制(suppress),实际上就是去掉。
  3. 然后循环直到遍历完全部框。

如果考虑类别,就用类别分类,然后分别进行单类别的non-max suppression

Anchor Boxes

切割太细容易导致多个框出现同一个物体,这个问题通过non-max suppression来解决。

切割太大容易导致一个框出多个物体,这个问题用到Anchor Boxes。

一般来说,这种问题很少出现,所以我们假设最多出现两个物体(极端情况可以增加Anchor Box,我们可以针对性定制)

  1. 预定义一些形状作为Anchor Boxes,接下来将预测结果和这两个形状联系在一起。一个形状并不代表一种物体,但是可以代表形状相似的一类物体。请注意,Anchor只是固定了比例,实际大小是可以变的,所以计算IOU的时候肯定是通过长宽比例来计算的。
  2. 有几个Anchor Box,y向量长度就为 8 × 8\times 8×,然后你按照顺序将Anchor Box与y从上往下对应。
  3. 我们在制作label的时候,如果图片里有某个物体,就把他归到对应的形状里,然后编码就和以前一样,8个参数
  4. 在训练时,要输出 y ^ \hat{y} y^,要对比现有边框和Anchor Box的边框,将IOU(注意这里应该用比例)最高的现有边框,对应到相应box。某个box的位置没有现有边框,那么就 p c = 0 p_c=0 pc=0即可
  5. 说白了,就是一个实际边框,他不仅归属于一个grid,还归属于一个Anchor Box

但是我们也可以看出,如果两个物体都是同一类Anchor Box,那么仍然无法解决。

终极版YOLO

综合上面的操作,我们来举个例子。

  1. 进行Anchor Boxes的判断,比如是 3 × 3 3\times 3 3×3的grid,2个Anchor,那么每个grid就可以分配到两个Anchor,其中大多是 P C = 0 P_C=0 PC=0
  2. 抛弃(get rid of)概率低的预测
  3. 对每一类单独运用non-max suppression,抛弃交并比过大的重复框

候选区域(region proposal)

[Girshik et.al,2013,Rich feature hierarchies for accurate object detection and semantic segmentation]

这个在b站上貌似是丢失了一些视频,就简单记录一点。

R-CNN思路:

  1. 找出候选区域
  2. 在候选区域跑分类器
  3. 有一种优化思路是将候选区域用一个卷积来一次性处理。[Grishik,2015.Fast R-CNN]
  4. 另一种优化思路是利用卷积来找出候选区域而不是传统的分割。[Ren et.al,2016.Faster R-CNN:Towards real-time object detection with region proposal networks]

其实我感觉这个才更像是人眼判断,首先是用连续区域来着色,一个色块就是一个区域,然后对这种区域内进行卷积判断。

这样可以省去很多计算,毕竟,人眼是先找到哪个区域有东西,再进行分类的。但是实际运用的时候,这个还是比YOLO慢很多。不过总的来说,这个引起了广泛的关注

特殊应用:人脸识别以及风格迁移(Special Applications:Face Recognition and Neural Style Transfer)

Siamese Network

One-Shot Learning

人脸识别的一个挑战就是,单个样本情况下的识别表现并不是很好,这也是为什么我们平时人脸识别都要动动嘴啥的。

一方面,小样本训练不出具有鲁棒性的网络,另一方面,如果用soft-max输出,要加人怎么办?不太好扩容。

所以要弃用soft-max,用新的判断方式:

新的函数为d(img1,img2)=两张图片差异度大小,然后设置一个阈值 τ \tau τ,如果超过这个阈值,就不是一个人。这种图对图的判断具有好的扩充性。

[Taigamen et.al.,2014.DeepFace closing the gap to human level performance]

如何去训练我们上面说的d函数呢?

我们搭建一个网络,输出一个vector,那么这个网络的作用相当于将一个图片转化成一个向量,用来精准表示一个图片的主要特征,写成 f ( x ) f(x) f(x)

由此,可以定义 d ( x ( 1 ) , x ( 2 ) ) = ∣ ∣ f ( x ( 1 ) ) − f ( x ( 2 ) ) ∣ ∣ 2 2 d(x^{(1)},x^{(2)})=||f(x^{(1)})-f(x^{(2)})||_2^2 d(x(1),x(2))=∣∣f(x(1))f(x(2))22

问题由训练d转化成训练f函数,我们需要定义一个损失函数。

Triplet Loss

[Schroff et al.,2015,FaceNet:A unified embedding for face recognizing and clustering]

我们要训练f函数,要有三张图片,Anchor,Positive,Negative,简称(abbreviate)为A,P,N。

我们要实现这个效果,令AP差距尽可能小于AN差距, α \alpha α越大,这个差距就越大。
如果实现了,就是成功,准确识别。

α \alpha α作为一个超参数,如果太小,太容易满足,就容易误判,即不是同一个人也判断为同一个人,如果太大,不容易满足,就会将同一个人判断成不同的人。
∣ ∣ f ( A ) − f ( P ) ∣ ∣ 2 + α ≤ ∣ ∣ f ( A ) − f ( N ) ∣ ∣ 2 ||f(A)-f(P)||^2+\alpha \leq ||f(A)-f(N)||^2 ∣∣f(A)f(P)2+α∣∣f(A)f(N)2
因此,我们定下这个损失函数,如果达到前面的效果,就视为0损失,否则就是正损失。
L ( A , P , N ) = m a x ( ∣ ∣ f ( A ) − f ( P ) ∣ ∣ 2 + α − ∣ ∣ f ( A ) − f ( N ) ∣ ∣ 2 , 0 ) = R e L U ( ∣ ∣ f ( A ) − f ( P ) ∣ ∣ 2 + α − ∣ ∣ f ( A ) − f ( N ) ∣ ∣ 2 ) L(A,P,N)=max(||f(A)-f(P)||^2+\alpha -||f(A)-f(N)||^2 , 0) \\ =ReLU(||f(A)-f(P)||^2+\alpha -||f(A)-f(N)||^2 ) L(A,P,N)=max(∣∣f(A)f(P)2+α∣∣f(A)f(N)2,0)=ReLU(∣∣f(A)f(P)2+α∣∣f(A)f(N)2)
对应的cost function:
J = 1 m ∑ i = 1 m L ( A ( i ) , P ( i ) , N ( i ) ) J=\dfrac{1}{m}\sum_{\mathclap{i=1}}^{m}L(A^{(i)},P^{(i)},N^{(i)}) J=m1i=1mL(A(i),P(i),N(i))

下面问题就又来了,样本怎么做?

一个样本就是一个三元组。

假设给你10k个图片,对应1k个人,那么平均1人有10张图,我们可以随机提取图片构成三元组。但是这样训练的不够好,我们可以优化一下,专门挑难的来训练。

现在的人脸识别系统都是基于大数据的,可以选择拿别人现成的模型来看。

二分类法

除了Triplet Loss,其实还有一种直观的方式去衡量差距并训练f函数。

按我的第一印象来看,我感觉Triplet有点多余,因为实际上就相当于用A作为PN差距的参考系,用PA-NA,来间接反映PN差距,将其调整到 α \alpha α以上。为什么就不能直接算PN的差距呢?

虽然还没有理解Triplet的核心,但是二分类给出了另一条直接算差距的路。

首先定义样本,是二元组,将二元组输入进去,得到 f ( x ( i ) ) , f ( x ( j ) ) f(x^{(i)}),f(x^{(j)}) f(x(i)),f(x(j)),计算得向量 v e c t o r = ∣ f ( x ( i ) ) − f ( x ( j ) ) ∣ vector=|f(x^{(i)})-f(x^{(j)})| vector=f(x(i))f(x(j)),然后把这个向量扔到一个logistic单元里判断即可。

至于损失函数和成本函数,就用logistic即可

公式可以调整,只要表现出差距那个意思即可,然后从中找出最好用的公式。

神经风格转换(Neural Style Transfer)

[Gatys et al.,2015.A neural algorithm of artistic style.]

简单说,神经风格转换,就是将一个风格(style)加到另一个内容(content)上,生成一个图片(generate),风格提供了色彩等元素,内容提供了轮廓。

滤镜貌似和这玩意有关系。

理解深度卷积网络

[Zeiler and Fergus.,2013,Visualizing and understanding convolutional networks]

第一层卷积可以提取轮廓,那么深层的在干什么?

随着卷积和池化的进行,图片尺寸会越来越小,这意味着图片蕴含的信息区域越来越大,也就是观察的维度越来越高,并且在不断寻找突出特征。

比如第一层提取了一些角度的线段。第二层可能会提取一些形状,比如纹路,圆形等等。后面就越来越广。第三层可能就给你合成一个耳朵,同层的filter负责其他特征,比如给你弄一个嘴出来。有了第三层的耳朵和嘴等特征,可能第四层就整出个脸来,第五层就给你弄出个人。

最后就是,观察的范围越来越大,维度越来越多,最后变成一个细长的东西,可以作为后面训练的输入。

代价函数概述

我们的目标就是让生成的G与C的内容尽可能相似,与S的风格尽可能相似。

J ( G , C , S ) = α J c o n t e n t ( C , G ) + β J s t y l e ( S , G ) J(G,C,S)=\alpha J_{content}(C,G)+\beta J_{style}(S,G) J(G,C,S)=αJcontent(C,G)+βJstyle(S,G)

其实用一个 α \alpha α就够了,毕竟我们只是用一个相对比例,然而作者用了两个,我们就用两个,这表明了图片更趋向于哪个。

之后就是梯度下降了,实际上梯度下降的过程就是将初始的白噪音图片逐步调整成我们要的部分。

请注意,我们训练的不是神经网络,而是图片的像素,神经网络是拿来且冻结的,仅仅是用来提取一定深度的特征用来对比的。

内容代价

我们需要控制网络的深度,如果比较浅,那么在内容上就会导致GC的像素过于趋同,如果比较深,就会导致GC的物体过于趋同,比如C中有个狗,G中就得有个狗。

适当的深度,可以保证有个形状又不至于完全挪过去。

内容比较简单,我们就弄一个预训练好的网络比如VGG,然后直接对比最后一层输出的区别,让最后一层越相近越好,深度控制的好,那么我们对比的特征就越准确。

J c o n t e n t [ l ] ( C , G ) = ∣ ∣ a [ l ] ( C ) − a [ l ] ( G ) ∣ ∣ 2 J_{content}^{[l]}(C,G)=||a^{[l](C)}-a^{[l](G)}||^2 Jcontent[l](C,G)=∣∣a[l](C)a[l](G)2
这里默认将矩阵展开为vector,所以我们用2范数(如果用矩阵就是F范数,这不统一属实别扭)

这里吴恩达只用最后输出的向量处理了,我个人感觉其实可以用所有层的一个均值,比如定义:
J c o n t e n t ( C , G ) = ∑ l λ [ l ] J c o n t e n t [ l ] ( C , G ) J_{content}(C,G)=\sum_{\mathclap{l}}\lambda^{[l]}J_{content}^{[l]}(C,G) Jcontent(C,G)=lλ[l]Jcontent[l](C,G)
权重 λ [ l ] \lambda^{[l]} λ[l]根据不同的层来设定,取决于你最想要统一哪个级别的内容。

风格代价

风格的定义:

风格这个东西比较玄乎,你说内容把,就单纯像素的轮廓,形状即可,但是风格就比较复杂。

我们将风格定义为某一层的不同channel之间的相关度(correlation)

进一步理解,风格说白了就是,A出现,B,C就应该伴随出现,比如汉服出现,那么袖子下摆或者刺绣等大概率都会出现,这就是一种典型的风格。

那么放到不同的channel之间,channel是分块的,每一小块就对应一个部位或者特征,这个特征要伴随另一层的某个特征,我们的目的是将这些特征绑定起来,也就是提高相关度,提高同时出现的概率。

风格的数学表示——Style Matrix:

首先定义 a i , j , k [ l ] a^{[l]}_{i,j,k} ai,j,k[l]为l层的i行j列k信道的元素。

然后定义风格矩阵 G [ l ] − n C [ l ] × n C [ l ] G^{[l]}-n_C^{[l]}\times n_C^{[l]} G[l]nC[l]×nC[l],其两个维度代表信道,这个很像我之前做过的R语言数据分析的作业,其中就有一个协方差(cross-covariance)矩阵,也就是说,这其中的每一个元素都应该是某两个信道之间,类似于协方差 C o v ( X , Y ) = E [ X Y ] − E [ X ] E [ Y ] Cov(X,Y)=E[XY]-E[X]E[Y] Cov(X,Y)=E[XY]E[X]E[Y]的东西

实际上,元素为:
G k k ′ [ l ] = ∑ i = 1 n H [ l ] ∑ j = 1 n w [ l ] a i , j , k [ l ] a i , j , k ′ [ l ] G^{[l]}_{kk^\prime}=\sum_{\mathclap{i=1}}^{n^{[l]}_H}\sum_{\mathclap{j=1}}^{n^{[l]}_w}a^{[l]}_{i,j,k}a^{[l]}_{i,j,k^\prime} Gkk[l]=i=1nH[l]j=1nw[l]ai,j,k[l]ai,j,k[l]
也就是,第k信道和 k ′ k^\prime k信道的两个矩阵进行elem-wise的乘积求和,和协方差的区别就是没有减去均值

理解style matrix:

a代表突出特征,如果在两个信道同一个位置都有突出特征,那么大概率这两个信道有联系,所以,这种同位置同特征的元素越多, G k k ′ [ l ] G^{[l]}_{kk^\prime} Gkk[l]就越大,意味着就有强联系,也就是我们说的风格。

说白了,这个G矩阵,就是表达了l层位置,我们这张图片不同信道之间的联系程度。G就可以代表图片在l层的风格!

计算风格的区别:

说白了矩阵不就是G和S的风格矩阵差的F范数嘛。

J s t y l e [ L ] ( S , G ) = 1 ( 2 n H [ l ] n W [ l ] n C [ l ] ) 2 × ∣ ∣ G [ L ] [ S ] − G [ L ] [ G ] ∣ ∣ F 2 J^{[L]}_{style}(S,G)=\dfrac{1}{(2n_H^{[l]}n_W^{[l]}n_C^{[l]})^2}\times ||G^{[L][S]}-G^{[L][G]}||^2_F \\ Jstyle[L](S,G)=(2nH[l]nW[l]nC[l])21×∣∣G[L][S]G[L][G]F2

我们前面只是用了一层,事实上,如果你想彻底统一一下,那么可以让所有层数的风格都统一了,也就是对1-L层的所有层的 J [ l ] J^{[l]} J[l]参数化加权平均。前面的系数可以控制不同层之间统一的比例。
J s t y l e ( S , G ) = ∑ l λ [ l ] J s t y l e [ l ] ( S , G ) J_{style}(S,G)=\sum_{\mathclap{l}}\lambda^{[l]}J_{style}^{[l]}(S,G) Jstyle(S,G)=lλ[l]Jstyle[l](S,G)

最后做个总结:

  1. 计算S和G在每一层的风格矩阵
  2. 计算每一层的 J s t y l e [ l ] ( S , G ) J_{style}^{[l]}(S,G) Jstyle[l](S,G)
  3. 计算所有层的加权平均得出 J s t y l e [ l ] J_{style}^{[l]} Jstyle[l]

将ConvNet推广到1D3D

1D卷积,2D卷积,3D卷积都是一样的:

  1. 用维度相同的过滤器,以固定的步长实现全覆盖遍历。
  2. 过滤一次后不会降低维度,只是会合并所有的channel,如果要保持channel维,可以用多个filter产生新的channels

也就是说,1D,3D的数据也都是可以用卷积神经网络的,比如1D的心电图数据,音频文字,3D的CT片,可以检测器官病变啥的,视频段可以检测动作,行为之类的

格局打开好吧!

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦梦亦醒乐逍遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值