上次我们介绍了多层感知机(MLP),本次将介绍深度学习领域中第二个基本的模型:卷积神经网络(CNN)。CNN在MLP之上又引入了两种新的层:卷积层和池化层。
神经科学家 Hubel 和 Wiesel 于1962在猫的视觉皮层上面发现:
有一种简单细胞用于检测图像物体的局部特征;
另外一种复杂细胞将视网膜上向邻近的简单视网膜的输出“池化”。
按照他们的发现,构造出如下概念模型:
由此提出人工视觉系统的构建方式:
从而人们建立了多个模型:
我们先简单介绍下Neocognitron模型从而了解一下卷积网络模型,后面的模型由于使用较少,本次不进行介绍。
其中U0为输入层
我们所学的CNN结构上与这个模型基本上是一样的,主要的区别是:该模型提出时,还没有后向传播算法(BP)或BP还没有被重视。
如图:
注:C1对Input进行卷积,输入就是一个二维矩阵;C3对S2进行卷积,此时输入一个张量(tensor).
卷积层有两个主要的特点:
经过上面我们就可以看到,CNN相比于MLP多出了两种层:卷积层和池化层。
卷积池化处理完毕之后衔接全连接层。
卷积:对于一个输入,我们给它一个卷积核(如上上图5x5个元素还有那25个参数w)在输入图片上进行滑动,求一个响应结果,得到一个相应图片或叫特征图片。图片上的亮度表示每个相应值得大小。
池化:把前一层得输入变小,如把4x4中四个角对应的2x2进行一下取最大(或平均或随机),这样4x4就变成了2x2。
接下来我们详细介绍一下卷积层和池化层及其前向计算,目的是让大家了解其工作原理。
至于后向计算感兴趣朋友的可以自行了解。当然也有很多优秀的工具库我们可以直接拿来用以求解梯度。
对于一维
假设有A和B两个一维序列,其中B的长度小于A,计算B与A的每个部分之间的相似度(similarity)
自然地,将B在A上滑动并逐个计算相似度,简便起见,称为关联计算(correlation calculation)
和 两个向量间的余弦相似度(Cosine Similarity):
对于二维
同理假设A和B是两个二维序列,其中B的长宽小于A:
和 两个矩阵间的余弦相似度(Cosine Similarity):
注:得到的响应二维矩阵会比输入小一点,因此其3x3每次向右移动一小格取一次输出,且B始终在A里面,不出头。
但这个滑动的过程非常缓慢,为解决此问题,我们:
当然引入卷积并不一定要非用FFT,当前使用并行计算更加流行也更快一些。
连续卷积:
离散卷积 (对于有限长的序列):
这与我们上面介绍的滑动相似度基本是一样的,不过本次是“交叉计算”。
的长度: , 的长度: , 其中 ≥
将full卷积的结果截断至 维
Same卷积也可以从 与用零填充(zero-padded)的 之间的Valid卷积得到
例如:
假设有两个序列:
f=[0,1,2,-1,3] g=[1,1,0]
则:
python代码:
import numpy as np from scipy import signal f = np.array([0, 1, 2, -1, 3]) g = np.array([1, 1, 0]) h1 = signal.convolve(f, g, mode='valid') h2 = signal.convolve(f, g, mode='full') h3 = signal.convolve(f, g, mode='same')
计算 与 的每个部分 之间的相似度等价于计算 ∗ , 其中
也就是我们所谓的交叉计算
上述翻转操作可以通过两次 numpy.rot90() 命令来实现 (之后用rot180()表示)
假设有矩阵 和 , 大小分别 × 和 1 × 2, 其中 ≥ 1, ≥ 2
两个矩阵间的离散卷积
python例子:
import numpy
from scipy import signal
A = numpy.array([[0, 0, 1, 2], [2, 2, 0, 0], [2, 1, 2, 2], [3, 0, 1, 1]])
B = numpy.array([[0, 0, -1], [1, -1, 1], [-1, 1, 1]])
C = signal.convolve2d(A, B, mode='full')
print(C)
C = signal.convolve2d(A, B, mode='valid')
print(C)
C = signal.convolve2d(A, B, mode='same')
print(C)
同样是交叉计算,f 左上角对应 g 的右下角,g 的右上角对应 f 的左下角...
左侧输入图像就是A矩阵,卷积核B矩阵;
上图是对矩阵A和矩阵B进行相关联计算/似度计算,把卷积核B在A上滑动每个地方求一个响应。
ps:真正用卷积实现关联计算的话,应该先把卷积核翻转180°,再做卷积(因为卷积是交叉计算的),结果是一样的。相当于转了个弯,卷积:直接交叉计算,卷积表示关联计算:旋转再交叉计算。
特征图上的值越大(亮),表示图像上的该区域与卷积核的相似度越高。
此外:
我们可以看到第一种卷积核上面亮下面暗,第二种卷积核左边亮右边暗,则对应特征图上分体现出原图像上亮下暗,左亮右暗明显一些。
卷积:
全连:
1. 保留空间尺寸
下一次输入尺寸减小了 如 LeNet 5网络中的例子
如果不想减小输入尺寸,该怎么做?
一种方法是使用 same 卷积,但是有一些库不支持same卷积操作(前面介绍的只是python的操作,不是像tensorflow这样的操作),我们可以对valid进行填充0的操作:
通常我们选择K为奇数
为了保持输出尺寸与输入一致,当步长为1时,边缘应该填充多少?( (k-1)/2 )
2. 步长不为1的卷积
输出大小: (M-K)/stride+1
如果(M-K)/stride不是整数?
假设输入通道数与卷积核通道数一致
将三维输入中的一组二维特征图与卷积核对应的部分关联, 并对所有部分求和得到一组输出的特征图
-- 可以通过翻转三维卷积核和三维卷积实现
下图8*10池化为2*2
将卷积后的特征图划分为 × 个不相交区域,对每个区域分别进行取平均(或取最大值)操作,得到池化后的特征。在一维输入上的操作类似。
如果步长不等于池化大小怎么办?
说明是一种有重叠的池化
如何处理三维输入?
逐通道池化
减少分类中的特征数目
增大下一层的感受区域
不变性(invariance)
类似于视觉神经元的感受野,其大小随视觉皮层层次的提高而增大。
卷积层和池化层可以跟之前讨论的层组合使用
以及一些未讨论过的层,例如:
示例:
MNIST手写体数字识别 : ConvNetJS MNIST demo (stanford.edu)
CIFAR-10数据集分类: ConvNetJS CIFAR-10 demo (stanford.edu)
3*3 卷积核被广 泛使用,GPU实现。
在Inception-v2上添加额外的技术:
ImageNet数据集上的结果
ImageNet数据集上的结果