链接地址:卷积神经网络_(1)卷积层和池化层学习
卷积神经网络(CNN)由输入层、卷积层、激活函数、池化层、全连接层组成,即INPUT-CONV-RELU-POOL-FC
(1)卷积层:用它来进行特征提取,如下:
输入图像是32*32*3,3是它的深度(即R、G、B),卷积层是一个5*5*3的filter(感受野),这里注意:感受野的深度必须和输入图像的深度相同。通过一个filter与输入图像的卷积可以得到一个28*28*1的特征图,上图是用了两个filter得到了两个特征图;
我们通常会使用多层卷积层来得到更深层次的特征图。如下:
关于卷积的过程图解如下:
输入图像和filter的对应位置元素相乘再求和,最后再加上b,得到特征图。如图中所示,filter w0的第一层深度和输入图像的蓝色方框中对应元素相乘再求和得到0,其他两个深度得到2,0,则有0+2+0+1=3即图中右边特征图的第一个元素3.,卷积过后输入图像的蓝色方框再滑动,stride=2,如下:
其计算过程就是把对应位值的值相加,然后加bias,就可以得到其中的一幅全特征图。其另一个例子如下:
如上图,完成卷积,得到一个3*3*1的特征图;在这里还要注意一点,即zero pad项,即为图像加上一个边界,边界元素均为0.(对原输入无影响)一般有
F=3 => zero pad with 1
F=5 => zero pad with 2
F=7=> zero pad with 3,边界宽度是一个经验值,加上zero pad这一项是为了使输入图像和卷积后的特征图具有相同的维度,如:
输入为5*5*3,filter为3*3*3,在zero pad 为1,则加上zero pad后的输入图像为7*7*3,则卷积后的特征图大小为5*5*1((7-3)/1+1),与输入图像一样;
而关于特征图的大小计算方法具体如下:
卷积层还有一个特性就是“权值共享”原则。如下图:
如没有这个原则,则特征图由10个32*32*1的特征图组成,即每个特征图上有1024个神经元,每个神经元对应输入图像上一块5*5*3的区域,即一个神经元和输入图像的这块区域有75个连接,即75个权值参数,则共有75*1024*10=768000个权值参数,这是非常复杂的,因此卷积神经网络引入“权值”共享原则,即一个特征图上每个神经元对应的75个权值参数被每个神经元共享,这样则只需75*10=750个权值参数,而每个特征图的阈值也共享,即需要10个阈值,则总共需要750+10=760个参数。
注意:上面的只是权值共享的其中一种方法,上面的方法有优点也有缺点,优点:大大的减少了权值的数量,使得网络更容易训练,大大减少了电脑内存负担。缺点:由于深度网络的特征提取主要依赖卷积层,其卷积参数越多则特征越丰富,越有利于识别物体,权值共享在一定程度上消减了特征丰富性。
另一种常用的权值共享方法:就是在同一通道共享权值,不同通道使用不同权值,例如上面的:加入输入图像大小为40*40*3,当使用5*5的卷积核并且通道数为128时,则其卷积核参数就为:5*5*3*128个。而使用上面的方法卷积参数也是:5*5*3*128个,这种共享方式最常用的,基本都是这种方法。
池化层:对输入的特征图进行压缩,一方面使特征图变小,简化网络计算复杂度;一方面进行特征压缩,提取主要特征,如下:
池化操作一般有两种,一种是Avy Pooling,一种是max Pooling,如下:
同样地采用一个2*2的filter,max pooling是在每一个区域中寻找最大值,这里的stride=2,最终在原特征图中提取主要特征得到右图。
(Avy pooling现在不怎么用了,方法是对每一个2*2的区域元素求和,再除以4,得到主要特征),而一般的filter取2*2,最大取3*3,stride取2,压缩为原来的1/4.
注意:这里的pooling操作是特征图缩小,有可能影响网络的准确度,因此可以通过增加特征图的深度来弥补(这里的深度变为原来的2倍)。
全连接层:连接所有的特征,将输出值送给分类器(如softmax分类器)。
总的一个结构大致如下:
另外:CNN网络中前几层的卷积层参数量占比小,计算量占比大;而后面的全连接层正好相反,大部分CNN网络都具有这个特点。因此我们在进行计算加速优化时,重点放在卷积层;进行参数优化、权值裁剪时,重点放在全连接层。
2、网络的Bflops、跟卷积网络大小的输出计算:
下面是yolo的bflops计算代码:
//fprintf(stderr, "conv %5d %2d x%2d /%2d %4d x%4d x%4d -> %4d x%4d x%4d\n", n, size, size, stride, w, h, c, l.out_w, l.out_h, l.out_c);
//这里的bflops指的是浮点型的数据运算,由于卷积是把所有通道的卷积值进行求和后再进行加偏移量
//即其加的浮点计算量为Ci*(K*K-1)+Ci-1=Ci*K*K,即在考虑了bias后其运算次数跟乘法的一样
l.bflops = (2.0 * l.n * l.size*l.size*l.c * l.out_h*l.out_w) / 1000000000.;
fprintf(stderr, "conv %5d %2d x%2d /%2d %4d x%4d x%4d -> %4d x%4d x%4d %5.3f BF\n", n, size, size, stride, w, h, c, l.out_w, l.out_h, l.out_c, l.bflops);
注意:即其加的浮点计算量为Ci*(K*K-1)+Ci-1=Ci*K*K,即在考虑了bias后其运算次数跟乘法的一样。这里的flops值的是对浮点数据的运算次数包括乘法跟加法。所以这里要乘2.
其中网络的输出大小为:
W_out=(W_int + 2*pad - Filter)/stride + 1