终于进入我们的主题了ConvNets或者CNNs,它的结构和普通神经网络都一样,之前我们学习的各种技巧方法都适用,其主要不同之处在于:
ConvNet假定输入的是图片,我们根据图片的特性对网络进行设定以达到提高效率,减少计算参数量的目的。
首先我们分析下传统神经网络对于图片的处理,如果还是用CIFAR-10上的图片,共3072个特征,如果普通网络结构输入那么第一层的每一个神经单元都会有3072个权重,如果更大的像素的图片进入后参数更多,而且用于图片处理的网络一般深度达10层之上,加在一起参数的量实在太大,参数过多也会造成过拟合,而且图片也有自身的特点,我们需要利用这些特点,将传统网络改革,加快处理速度和精确度。
我们注意到图片的像素是由3个通道构成的,我们就利用了这个特点将其神经元安置到了三维空间(width, height, depth),分别对应着图片的32x32x3(以CIFAR为例)如下图:
红色是输入层这里的深度是3,输出层是1x1x10的结构。其他几层的含义后面会介绍,现在先知道每层都是height × width × depth结构。
卷积神经网络有三种层:卷积层、池化层和全连接层(Convolutional Layer, Pooling Layer, 及 Fully-Connected Layer)。
以处理CIFAR-10的卷积神经网络为例,简单的网络应包含这几层:
[INPUT - CONV - RELU - POOL - FC]也就是[输入-卷积-激活-池化-分类得分],各层分述如下:
注意:
1. 卷及神经网络包含不同的层 (e.g. CONV/FC/RELU/POOL 也是最受欢迎的)
2. 每一层都输入输出3d结构的数据,除了最后一层
3. 有些层可能没有参数,有些层可能有参数 (e.g. CONV/FC do, RELU/POOL don’t)
4. 有些层可能有超参数有些层也可能没有超参数(e.g. CONV/FC/POOL do, RELU doesn’t)
下图是一个例子,没法用三维表示只能展成一列的形式了。
下面展开讨论各层具体细节:
卷积层是卷积神经网络的核心层,大大提高了计算效率。
卷积层由很多过滤器组成,每个过滤器都只有一小部分,每次只与原图像上的一小部分连接,UFLDL上的图:
这是一个过滤器不停滑动的结果,
我们这里要更深入些,我们输入的图像是一个三维的,那么每个过滤器也是有三个维度,假设我们的过滤器是5x5x3的那么我们也会得到一个类似于上图的激活值的映射也就是convolved feature 下图中叫作 activion map,其计算方法是 wT×x+b 其中w是5x5x3=75个数据,也就是权重,他是可以调节的。
我们可以有多个过滤器:
更深入一些,当我们滑动的时候有三个超参数:
1. 深度,depth,这是过滤器的数量决定的。
2. 步长,stride,每次滑动的间隔,上面的动画每次只滑动1个数,也就是步长为1.
3. 补零数, zero-padding,有时候根据需要,会用零来拓展图像的面积,如果补零数为1,变长就+2,如下图中灰色的部分就是补的0
下面是一个一维的例子:
其输出的空间维度计算公式是
上面可以知道在卷积层之后得到的结果还是挺多,而且由于滑动窗口的存在,很多信息也有重合,于是有了池化pooling 层,他是将卷积层得到的结果无重合的分来几部分,然后选择每一部分的最大值,或者平均值,或者2范数,或者其他你喜欢的值,我们以取最大值的max pool为例:
- 反向传播:最大值的梯度我们之前在反向传播的时候就已经学习过了,这里一般都跟踪最大的激活值,这样在反向传播的时候会提高效率.
- Getting rid of pooling. 一些人认为pooling是没有必要的,如The All Convolutional Net ,很多人认为没有池层对于生成式模型(generative models)很重要,似乎以后的发展中,池层可能会逐渐减少或者消失。
全连接层和卷积层除了连接方式不一样,其计算方式都是内积,可以相互转换:
1. FC如果做CONV layer 的工作就相当于其矩阵的多数位置都是0(稀疏矩阵)。
2. FC layer 如果被转变为 CONV layer. 相当于每一层的局部连接变为了全部链接如FC layer with K=4096的输入是7×7×512那么对应的卷积层为 F=7,P=0,S=1,K=4096输出为1×1×4096。
例子:
假设一个cnn输入 224x224x3图像,经过若干变化之后某一层输出 7x7x512 到这里之后使用两4096的FC layer及最后一个1000的FC计算分类得分下面是把这三层fc转化为Conv 的过程:
1. 使用 F=7的conv layer 输出为 [1x1x4096];
2. 使用F=1的过滤器,输出为 [1x1x4096];
3. 使用F=1的卷积层,输出为 [1x1x1000]。
每次转化都会将FC的参数转变为conv的参数形式. 如果在转变后的系统中传入更大的图片,也会非常快速的向前运算。例如将384x384的图像输入上面的系统,会在最后三层之前得到[12x12x512]的输出, 经过上面转化的conv 层会得到 [6x6x1000], ((12 - 7)/1 + 1 = 6). 我们一下就得出了6x6的分类结果。
这样一次得到的比原来使用迭代36次得到的要快。这是实际应用中的技巧。
另外我们可以用两次步长16的卷积层代替一次步长为32的卷积层来输入上面的图片,提高效率。
下面我们就用CONV, POOL,FC ,RELU 搭建一个卷积神经网络:
我们按照以下结构搭建
INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
其中N >= 0 (一般N <= 3), M >= 0, K >= 0 (一般K < 3).
这里要注意:我们更倾向于使用多层小size的CONV。
为什么呢?
比如3个3x3的和一个7x7的conv层,他们都可以 得到7x7的receptive fields.但是3x3的有以下优点:
1. 3层的非线性组合要比一层线性组合表达能力强;
2. 3层小尺寸的卷积层的参数数量要少,3x3x3<7x7;
3. 反向传播中我们需要使用更多的内存来储存中间层结果。
值得注意的是Google’s Inception architectures 及Residual Networks from Microsoft Research Asia. Both 等创造了相比以上结构更加复杂的连接结构。
INPUT: [224x224x3] memory: 224*224*3=150K weights: 0
CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*3)*64 = 1,728
CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*64)*64 = 36,864
POOL2: [112x112x64] memory: 112*112*64=800K weights: 0
CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*64)*128 = 73,728
CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*128)*128 = 147,456
POOL2: [56x56x128] memory: 56*56*128=400K weights: 0
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*128)*256 = 294,912
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824
POOL2: [28x28x256] memory: 28*28*256=200K weights: 0
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*256)*512 = 1,179,648
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296
POOL2: [14x14x512] memory: 14*14*512=100K weights: 0
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
POOL2: [7x7x512] memory: 7*7*512=25K weights: 0
FC: [1x1x4096] memory: 4096 weights: 7*7*512*4096 = 102,760,448
FC: [1x1x4096] memory: 4096 weights: 4096*4096 = 16,777,216
FC: [1x1x1000] memory: 1000 weights: 4096*1000 = 4,096,000
TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd)
TOTAL params: 138M parameters
注意到内存使用最多的时候在开始几个CONV layers, 参数基本都在最后几个FC层第一个FC有100M个!
内存主要在以下几个方面消耗较多
1. 大量的激活值和梯度值。测试时可以只储存当前的激活值丢弃之前的在下方几层激活值会大大减少激活值的储存量。
2. 参数的储存,在反向传播时的梯度及使用 momentum, Adagrad, or RMSProp时的缓存都会占用储存,所以估计参数使用的内存时一般至少要乘以3倍
3. 每次网络运行都要记住各种信息比如图形数据的批量等
如果估计网络需要的内存太大,可以适当减小图片的batch,毕竟激活值占用了大量的内存空间。
总结