1.计算机视觉
如果我们使用DNN来解决计算机视觉问题。当输入的图片像素过大时,例如(1000,1000,3)的图片其输入层将是3m大小,如果第一层有1000个节点。而第一层的w的维度将达到3m*1000=3billion,使用这么多参数,我们很难获得足够的数据以避免神经网络过拟合(因参数量过多,导致训练的模型与样本几乎无差别,虽然在训练集中cost很小,但是测试集中cost很大并且准确率不高)。并且这么多参数对计算量和内存需求是不太可行的。因此为了能使用更大的图片进行训练,可以运用CNN进行卷积神经网络的运算。
2.边缘检测
之前提到过,在DNN网络中浅层神经元大多是检测简单的特征,在卷积神经网络我们会用到对输入的卷积运算来实现特征检测,如以下垂直边缘检测的例子:
图1 卷积运算法则
将原始6x6的数据与右边3x3的filte(过滤器,有的文献中也称作kernel内核)进行卷积运算,卷积定义可看高数中对两个函数的卷积。在这里的卷积运算是指,将filter与6x6的原始数据的前3x3个方块依次按对应位置乘积,并将这些乘积累加,最后得到-5,将-5填充到卷积结果的第一个元素。以此类推,结果中的第二元素-4是通过6x6的原始数据中的第1-3行和的2-4列的一个3x3矩阵按位置乘积然后累加得出的结果。按照这样的步骤,最后我们得到一个4x4输出矩阵。这就是神经网络的卷积。卷积符号用*表示。这个和python的乘法符号相同,但是在各个深度学习平台都有自己卷积函数。例如python中 用 conv-forword,tensorlow:tf.nn.conv2d,keras:Conv2D。
在上一张图卷积后得出的结果并不明朗,是因为给出的6x6图片垂直边缘并不明显。在之后这个例子中,可以看到进行垂直过滤器卷积后的效果:
图2 带有垂直边缘的图片经过垂直边缘检测器卷积后的效果
可以看到卷积后出现了两列值为30的列且在中间,刚好与图片中垂直的位置相对应。
3.更多类型的边缘检测
1)明暗的边界区分
图3 明暗边界区分示意
如图所示,垂直的边缘检测器同样可以检测明暗变化,如果是由明到暗则中间边间数值为+30,如果是由暗到明则中间边界数值为-30。
2)水平边缘检测
图4 水平边缘检测过滤器
如图所示将垂直边缘检测器进行顺时针90度翻转后可以得到相应的水平边缘检测器。
3)广泛意义上的边缘检测器
图5 通过学习得到过滤器参数
图5中阐述了过滤器不一定要人为定制成固定的,比如Sobel filter 与Scharr filter这种人为定义的过滤器虽然可能使得垂直检测的效果更好,但是还是不如将过滤器中9个参数设为w参数,让网络进行反向传播而自行适应,这样我们的最后学习得到效果可以是任何角度的边缘检测器以应对复杂边缘的图片。这就是卷积神经网络的核心部分,将过滤器定义为可变参进行学习,来识别图片的基本特征。
4.图片填充
如果我们不给原始图像进行填充那么卷积后得到的矩阵必将会比原图像要小,这样会使得做了几次卷积后原图像会变得非常小而不能进行卷积。实际上nxn图像与fxf过滤器卷积后得到的大小为n-f+1xn-f+1所以6x6的图片与3x3图片卷积后得到的大小是4x4。
这时候我们如果我们给原始图像的边缘加上1层填充(p=1),那么得到新的卷积矩阵大小为n+2p-f+1xn+2p-f+1
Valid 和 Same 卷积
Valid 是指不作填充对原始图像进行卷积
而Same则是加上填充对原始图像进行卷积并使得得到的矩阵与原始图像大小一样。即n+2p-f+1=n
求得p=(f-1)/2所以只有当f为奇数时才会产生Same卷积,这就是为什么过滤器大小f永远使用奇数的理由。
5.stride(步幅)卷积
之前我们卷积每次计算都是从原图像的一个位置位移一格到下位置进行卷积计算,如果我们将卷积的位移步长定义为2,则6x6的图像与3X3的过滤器进行卷积的逻辑是先是6x6图像中0-2行的0-2列与3x3过滤器卷积,下一步是2-4行与0-2列和3x3进行卷积,跳过了1-3行的0-2列与3x3进行卷积。这便是步幅卷积,它会将原图片隔行和隔列与过滤器进行卷积
图6 0-2行0-2列与3x3过滤器卷积
图7 2-4行0-2列与3X3过滤器卷积
而卷积的结果大小为
其中类似中括号的符号代表向下取整。
注释:如果是在数学运算中,卷积操作需要将过滤器进行90度翻转后再进行卷积目的是为了符合(A*B)*C=A*(B*C)相等,即实现卷积的交换律。但是在深度学习中,我们定义卷积是直接进行卷积不需要翻转操作。
6.体积图像的卷积
之前介绍的都是在一个维度上进行卷积,而现实是在输入层一版都有3层图像也就是rgb层,这时候我们的过滤器也需要3层。这样卷积的时候依然能一一对应输入的每个像素点进行卷积运算。
图8 6x6x3的图片与3x3x3的图片进行卷积得到一个4x4的图片
而得到结果仍然是4x4的2维矩阵,其中输出矩阵的每个元素都是过滤器3x3x3与原图像对应位置相乘然后累加的结果,也就是27个值的累加。如果需要输出的是多张4x4矩阵,则需要多个3x3x3的过滤器。所以我们需要检测几种边缘,就在卷积时使用多少个与原图像维度相同的过滤器。
7.卷积神经网络的每一层结构
之前说到如果想要检测多种边缘则就需要多少个过滤器,如果需要检测10种边缘则需要10个过滤器,而其中参数w有3X3X3X10 总共270个,另外我们每个过滤器还需要一个偏移值bias也就是b,所以总共是270+10x1=280个参数,可以看到即使有10个过滤器,卷积网络每一层的参数量仍然非常少,所以这可以很好地防止学习过程的过拟合现象。
图9 一层卷积层的参数列表
而每一层的参数矩阵大小如下列所示:
f[l]=自定义的过滤器大小
p[l]=自定义的填充大小
s[l]=自定义的步长大小
nc[l]=自定义的过滤器个数
激活值:
A[l]=m x f[l] x f[l] x nc[l-1] (这里把m个样本的情况考虑进去)
W[l]=f[l] x f[l] x nc[l-1] x nc[l] (例如之前例子中w大小是3x3x3x10)
b[l]=1 x 1 x 1 x nc[l]
输入:nh[l-1] x nw[l-1] x nc[l-1]
输出:nh[l-1] x nw[l-1] x nc[l-1]
其中nw[l]=floor( (nw[l-1]+2p[l]-f[l])/2+1) (nh[l]算法与其一样,此处的floor代表向下取整)
8.一个卷积神经网络的例子
图10 一个简单的卷积神经网络
如图,一个卷积网络从39x39x3 ,变为37x37x10,再变为17x17x20再变为7x7x40,最后将7x7x40的矩阵打平后用逻辑回归softmax进行输出,可以看到,随着网络增加,每一维度的宽和高都在减小,而每一维度的通道个数会增加,到最后用逻辑回归的方式对卷积层进行综合分析。
总结,一个标准的卷积神经网络具有:
1.Convolution 卷积层
2 Pooling 池化层 (在下节有讲到池化)
3 Fully connected 全连接层
9.池化
卷积神经网络通常还使用池化层来减少展示量,以此来提高计算速度 ,并使一些特征的检测功能更强大。
1)Max pooling 最大值池化
图11 最大值池化
如上图所示便是选择过滤器大小为2x2,步长为2的最值池化,它将一个4X4的矩阵被分为4块(因为步长为2,过滤器大小也为2,因此刚好是被分为4块)如图,输出的是对应颜色的2X2区域内的最大值。吴老师还讲了为什么最大池化会是有用的,因为如果在对应区域内没有相应的特征,那么其最大值也不会表现出那个特征,但是这只是一种解释,实际上是因为最大值池化在实际应用中效果非常好,所以被广泛使用。
图12 一般化的最大池化层
这里给出一般的池化后的矩阵大小算法 n[l]=floor((n[l-1]+2p-f)/s+1) ,在这里f和s都是超参数,在整个学习中并不会改变,因此池化层都是不具备学习能力的。
2)Average pooling 均值池化
均值池化则是将取最大值变为取均值,其他与最大池化一样。
10.新的神经网络结构
图13 在加入池化后的卷积神经网络结构
可以看到整个网络经过了以下逻辑 conv>pool>conv>pool->fc->fc->fc的一个流程。其中参数数量如下:
图14 示例的卷积神经网络的参数列表
可以看到数量并不是很多,而且卷积层的参数量从6000一直变为400整个过程都是在减小的。(注:吴恩达课件中给出的图其中参数个数存在计算问题,在课后有提示)
11.总结,为什么卷积神经网络在图像识别上表现很好?
1)参数共享,全连接会将每个节点与输入进行连接,而卷积网络一个层所有参数共享一个过滤器,而所有参数都只会在过滤器上。全连接的参数量会因为参数不共享每个输入独占一个节点,所以参数量会比卷积层多的多。
2)稀疏性,图像中左上角的一个特征计算出来为0,并不会影响到图像右下角的特征(如果这个特征计算出来是10,那么它与左上角的那个特征计算出来的0不会又联系)。
因为参数共享和稀疏性,就造就了卷积神经网络既能很好地检查特征,又不会失特征之间相互干扰,并且参数量还很少防止过拟合。所以剩下我们需要做的是使用一个方法来使得卷积神经网络具有学习能力能够根据梯度下降来使得最后的损失函数J降到最低,这样就能与DNN网络达到相似的结果。
12.编程作业
1)为图像添加补丁 np.pad()用法,下面是在a的第1维添加宽度为1值为0的补丁、在第3维添加宽度为3值为0的补丁的一个例子:
a = np.pad(a, ((0,0), (1,1), (0,0), (3,3), (0,0)), mode='constant', constant_values = (0,0))
2) np切片[:,:,:,c]代表选择第4维的第c个值,[1:2,3:4]代表选择列1-2行3-4的一个2x2矩阵。
3)np.max(z)求出z中的最大值
4) np.average(z)求出z所有元素的平均值
5)keras两种用法,因为keras在课程中并未讲解,因此在此列出自己写的代码,以作参考。
使用Sequential
model = tf.keras.Sequential([
## ZeroPadding2D with padding 3, input shape of 64 x 64 x 3
tfl.ZeroPadding2D(
padding=(3, 3),input_shape=(64,64,3)
),
## Conv2D with 32 7x7 filters and stride of 1
tfl.Conv2D(
32,7,strides=(1,1)
),
## BatchNormalization for axis 3
tfl.BatchNormalization(
axis=3
),
## ReLU
tfl.ReLU(
),
## Max Pooling 2D with default parameters
tfl.MaxPool2D(
),
## Flatten layer
tfl.Flatten(
),
## Dense layer with 1 unit for output & 'sigmoid' activation
tfl.Dense(
1, activation='sigmoid'
)
# YOUR CODE STARTS HERE
# YOUR CODE ENDS HERE
])
使用函数方法:
input_img = tf.keras.Input(shape=input_shape)
## CONV2D: 8 filters 4x4, stride of 1, padding 'SAME'
# Z1 = None
Z1=tfl.Conv2D(8,4,strides=(1,1),padding='SAME')(input_img)
## RELU
# A1 = None
A1=tfl.ReLU()(Z1)
## MAXPOOL: window 8x8, stride 8, padding 'SAME'
# P1 = None
P1=tfl.MaxPool2D(pool_size=(8,8),strides=8,padding='SAME')(A1)
## CONV2D: 16 filters 2x2, stride 1, padding 'SAME'
# Z2 = None
Z2=tfl.Conv2D(16,2,strides=(1,1),padding='SAME')(P1)
## RELU
# A2 = None
A2=tfl.ReLU()(Z2)
## MAXPOOL: window 4x4, stride 4, padding 'SAME'
# P2 = None
P2=tfl.MaxPool2D(pool_size=(4,4),strides=4,padding='SAME')(A2)
## FLATTEN
# F = None
F=tfl.Flatten()(P2)
## Dense layer
## 6 neurons in output layer. Hint: one of the arguments should be "activation='softmax'"
# outputs = None
outputs=tfl.Dense(6,activation='softmax')(F)
# YOUR CODE STARTS HERE
# YOUR CODE ENDS HERE
model = tf.keras.Model(inputs=input_img, outputs=outputs)