2018年11月20日,在看tensorflow的时候发现还是有很多概念没有理解透彻,发现一个很赞的资源(估计大家都知道的,只有我现在才发现),吴恩达老师在网易云课堂上开的深度学习的课程,感觉很赞.本文实际上是吴恩达卷积神经网络视频学习笔记。
2019年2月14日,再次温故这部分的内容,添加了1.1章节的自问自答,添加了对池化层实现反向传播的方式,添加了激活函数relu和sigmoid的对比。
1.1 知识点总结和巩固
1.1.1 可以带着下面的问题来学习:
- 为什么卷积核或者说过滤器f x f,其中的 f 一般都是奇数?
- 卷积之后的通道数由什么决定?原始矩阵的通道数还是过滤器的数量?
- 通常说的卷积网络的卷积层layer由什么构成?
- 池化层和卷积层的不同之处?可以从超参数的数量、输入和输出的channel数量有什么区别,
- 池化层如何处理反向传播过程?
- 学会计算一个网络的参数个数?
- 为什么使用卷积,或者说使用卷积的好处。
- 在使用参数共享的卷积之后,是怎么实现反向传播算法的?
- 激活函数relu如何实现反向传播算法?relu算法相对于sigmoid有什么优缺点?
1.1.2 上面的问题的答案
- 一般来说我们会设置f为奇数,很少看见偶数的过滤器。其中的原因之一是,如果是same-conv的卷积模式,那么对称填充方便。另一个原因可能是一般需要将过滤器的中间点用于定位卷积的位置,而偶数过滤器没有中间点。
- 通道数由过滤器的数量决定
- 卷积核、偏置值、非线性函数(也就是激活函数)。
- 池化层可以理解成一个采样层,其超参数一共只有两个,分别是矩阵大小f和步长s。池化层的输出维度或者说通道数和输入一致。
- 池化层的反向传播方式按照mean pooling和max pooling不同而有所区别,对于mean pooling,将loss均摊到上一层即可;对于max pooling,需要在前向传播算法的时候记录max id,在反向传播算法中将loss传给上一层的max id位置,其余的位置为0。
- 参数数量的计算方式可以根据1.6节最后一张图的方式计算。
- 每个过滤器的参数对于整个图的所有节点都是共享的,一个卷积层的参数比全连接的参数少很多;每个输出只受到周围f x f个点的影响,对于图片等情况来说,更加符合真实情况;卷积善于捕捉平移不变性的特征。
- relu函数原本在0处不可导,因此直接在0处设置为1即可。relu相对于sigmoid的优点在于不容易导致梯度消失问题、稀疏激活性和计算方便。
1.2 边沿检测
通过一个3 * 3的每列值相同、第一列为1,第二列为0,第三列为-1的过滤器可以检测垂直的边沿。注意到1表示亮,-1表示暗。这样可以发现正负值的边沿。
对于垂直边缘过滤器而言,重要的是中间一列为0,左右两列的值可以相差尽可能的大。
这个过滤器的数值也是可以通过反向传播算法学习的,不一定需要在算法开始之前就决定。
深度学习甚至可以去学习其他的边沿,无论是45度、73度乃至是其他的角度,虽然比手工要复杂一些,但是确实具有这样的能力。
1.3 在卷积之前的填充操作
为什么需要填充?大家都知道,卷积就是用过滤器(f x f)从左到右、从上到下的扫描一个矩阵(n x n)。有两种卷积操作,一种称为valid-conv,一种称为same-conv。每次卷积的时候,过滤器右侧碰到矩阵右边界就结束当前行的扫描,下侧碰到矩阵下边界就结束扫描,因此通过过滤器的图像都会缩小,变为(n-f+1) * (n-f+1)。valid-conv就是这样的卷积操作,而same-conv会在卷积之前填充原始图,使得卷积之后的大小不变。
一般来说,若原图像大小为n * n,过滤器大小为f * f,那么需要padding的大小为p=(f-1)/2。一般来说我们会设置f为奇数,很少看见偶数的过滤器。其中的原因之一就是为了对称填充。另一个原因可能是一般需要将过滤器的中间点用于定位卷积的位置,而偶数过滤器没有中间点。
1.4卷积步长
上面的提到的卷积过程每次只移动一步。实际上过滤器可以移动不止一步,用s表示步长。那么n x n的矩阵输入, f x f的过滤器, p填充padding,以及s步长的情况下,输出的矩阵大小为 (n+2p-f)/2+1 x (n+2p-f)/2+1 ,这里是向下取整的,这意味过滤器只能在输入图像内部移动,不可以移动出边缘。
注意 在tensorflow中,有两种填充方式,一种是same,一种是valid。same是填充,而valid是不填充。如果遇到valid,那么实际计算矩阵大小的时候,是向上取整,而不是这里提到的向下取整。如果是same模式,那么最后的矩阵形状是n/s,也是向上取整
1.5 多维输入上的卷积
上面提到的卷积的输入是n x n的,这一般是灰度图像。对应彩色图像则存在RGB三个颜色channel,这样的图片是n x n x 3。此时的过滤器也必须存在第三个维度,即channel维度,且一个过滤器的channel维度必须和输入的channel维度一致。这样的卷积结果就是三个维度上,过滤器和输入的重叠位置乘积之和。最后的输出是(n - f + 1) x ( n - f +1)的。注意,输出是二维的
我们可以使用N个不同的过滤器得到不同的N个二维输出,按照输入的格式将其叠起来,这样输出就是 (n - f + 1) x ( n - f +1) x N了。
1.6 卷积网络上的layer
在上面一节中已经讲了如何得到输入和一个过滤器卷积之后的结果。通常会给卷积的结果添加一个偏执,然后使用非线性的函数进行处理,得到的就是这层网络的输出。将过滤器的参数标记为W,偏置为 b(一个channel的输出矩阵Wa的偏置是一个实数,而非一个矩阵。一个layer的偏置b的维度和通道数channel一致) , 输入数据为上层的激活值。这样每个过滤器处理之后的结果就可以看成是经过了该layer一个节点之后的输出。
下面是每层的符号标记,以及根据上一层计算下一层输入大小的公式,右下角是使用BP学习更新的时候参数更新的次数。可以看到每层的参数的个数只和这层的filter的大小、数目有关,而和输入的规模无关。这样就可以通过控制参数的数量避免过拟合了。
1.7 一个只由卷积层构成的卷积网络框架
可以从下面的课件中看到,卷积神经网络的趋势是长度和高度逐渐减少,而channel逐渐加深。最后一层会将卷积层平铺开来,形成一个全连接。全连接层会连接到最后一个判别函数上,判别函数可以是logistic或者softmax层,用于输出类别或者概率。
一般情况下,卷积网络除了卷积层之外,还会有池化层和全连接层,这些层可以提供更好的学习。
1.8 池化层
池化层一般在卷积层之后,可以也可以看成一个过滤器,实际上实现的一个采样的功能,其主要的思想是,着重提取具有某种倾向的特征,比如最大池化对应的是更显著的特征;平均池化对应的是更加平滑的特征。过滤器有几点不同
- 参数少,只有两个超参数,分别是f大小,以及s步长。一般很少使用padding.因此没有需要学习的参数,是卷积神经网络中的静态属性。
- 不同的channel单独使用池化层,因此输入和输出是相同channel层数的。
一般常用的池化层有max_pooling和average_pooling.max_pooling更加常用。,最大池化层意味着检测某个特征,并始终将这个特征留在池化层的输出中。
池化层的输入n x n x nc,过滤器 f x f,步长s,输出 ((n-f)/s+1) x ((n-f)/s+1) * nc。
一般取s=2,这意味着输入的长宽减小一半。
比较好奇的一个问题是,池化层的存在对反向传播有什么影响?我们都知道在传统的神经网络中,反向传播算法实际上就是利用函数的梯度进行反向传播的,那么池化层这种既改变了矩阵大小又不好求导的情况,怎么处理呢?
(下面的内容来自迷川浩浩_ZJU 的博客)
- mean pooling
假如做2×2的池化,步长s=2,假设那么第l+1层的feature map有16个梯度,那么第l层就会有64个梯度,这使得梯度无法对位的进行传播下去。其实解决这个问题的思想也很简单,就是把1个像素的梯度传递给4个像素,但是需要保证传递的loss(或者梯度)总和不变。根据这条原则,mean pooling和max pooling的反向传播也是不同的。
mean pooling的前向传播就是把一个patch中的值求取平均来做pooling,那么反向传播的过程也就是把某个元素的梯度等分为n份分配给前一层,这样就保证池化前后的梯度(残差)之和保持不变,还是比较理解的。mean pooling比较容易让人理解错的地方就是会简单的认为直接把梯度复制N遍之后直接反向传播回去,但是这样会造成loss之和变为原来的N倍,网络是会产生梯度爆炸的。
2、max pooling
max pooling也要满足梯度之和不变的原则,max pooling的前向传播是把patch中最大的值传递给后一层,而其他像素的值直接被舍弃掉。那么反向传播也就是把梯度直接传给前一层某一个像素,而其他像素不接受梯度,也就是为0。所以max pooling操作和mean pooling操作不同点在于需要记录下池化操作时到底哪个像素的值是最大,也就是max id
1.9 一个简单的卷积神经网络
一般概念上的一层包括卷积层和池化层,之所以不把池化层当做新的一层是因为池化层没有需要学习的参数,一般意义上的layer是有权重和参数需要学习的。
尽量不要自己设置超参数,而是尽量参考别人论文里面使用的超参数,选择一个在别人任务中效果很好的超参数。
下面的表中列举了上面的网络每一层的数据规模a^(l)以及参数数量。可以发现数据的规模逐渐减小。主卷积层的参数比较少,而进入全连接层之后参数数量很大。(表格中最后三列的参数数量可能存在错误,应该是48000 + 120, 120 * 84 + 84, 84 * 10 + 10)
1.10 为什么使用卷积
- 每个过滤器的参数对于整个图的所有节点都是共享的,这意味着对于32 * 32 * 3的输入,5 * 5 * 6的卷积过滤器以及28 * 28 * 6的输出,全连接需要3072 * 4704的参数,而卷积只需要5 * 5 * 6个参数。之所以可以参数共享,是因为如果一个过滤器可以检测图像上半部分的某个特征(比如垂直)那么也可以检测其他部分的相同特征。
- 稀疏连接。输出的一个点只受到输入的一个f*f大小的矩阵决定,不受其他区域的影响。
以上的两个特征可以明显的减少参数。减少过拟合
-
卷积具有善于捕捉平移不变性的特点。
1.11 激活函数的选择
(内容来自迷川浩浩_ZJU 的博客)
常用的激活函数有sigmoid函数和relu函数.
Relu(x)={if x>0 then x;else 0}为了在反向传播算法中可以正常使用,将其在x=0x=0处的导数置为1,所以它的导数也就变为了 δRelu(x)={if x>0 then 1 else 0}
Relu是一个非常优秀的激活哈数,相比较于传统的Sigmoid函数,有三个作用
- 防止梯度弥散,sigmoid的导数只有在0附近的时候有比较好的激活性,在正负饱和区的梯度都接近于0,所以这会造成梯度弥散,而relu函数在大于0的部分梯度为常数,所以不会产生梯度弥散现象。
- 稀疏激活性:elu函数在负半区的导数为0 ,所以一旦神经元激活值进入负半区,那么梯度就会为0,也就是说这个神经元不会经历训练,即所谓的稀疏性。
- 加快计算: relu函数的导数计算更快,程序实现就是一个if-else语句,而sigmoid函数要进行浮点四则运算