GoogLeNet(Inception)基础概念
1.简介
GoogLeNet是2014年ILSVRC挑战赛排名第一的算法。与其他进一步加深神经网络的宽度和深度的网络结构不同,GoogLeNet团队提出了一种Inception网络结构,就是构造一种“基础神经元”结构,来搭建一个稀疏性、高计算性能的网络结构。
优点:克服了深层次神经网络的带来的过拟合、难以计算训练的问题。
2.Inception网络结构
上述就是一个最原始的Inception结构,简单来说:与常规的神经网络将卷积层串联起来相比, Inception 结构是将不同的卷积层通过井联的方式结合在一起,如上图:分别使用了边长为1、3、5的过滤器,然后将各自得到的矩阵拼接起来。
但是,在上述结构中:所有的卷积核都在上一层的所有输出上来做,经过3×3、5x5的卷积,会使得特征图的参数过多,计算量就太大。为了避免这种情况,在3x3前、5x5前、max pooling后分别加上了1x1的卷积核,主要目的是为了减少维度,以及修正线性激活,这也就形成了Inception v1的网络结构。
(减少维度举例说明:
输入的feature map是28x28x192,设1x1卷积通道为64, 3x3卷积通道为128, 5x5卷积通道为32,如图原始结构,那么卷积核参数为:1x1x192x64+3x3x192x128 +5x5x192x32=387072.
而对3x3和5x5卷积层前分别加入了通道数为96、16的1x1卷积层,参数就成了:1x1x192x64+(1x1x192x96+3x3x96x128)+(1x1x192x16+5x5x16x32)=215040。整个参数大约减少了一半。)
该架构的一个有用的方面是它允许显著增加每个阶段的单元数量,而不会在后面的阶段出现计算复杂度不受控制的爆炸。这是在尺寸较大的卷积核进行代价大的卷积之前通过普遍使用降维实现的。此外,设计遵循了实践直觉,即视觉信息应该在不同的尺度上处理然后聚合,为的是下一阶段可以从不同尺度同时抽象特征。
3. GoogLeNet
(“#3×3 reduce”和“#5×5 reduce”表示在3×3和5×5卷积之前,使用的1×1滤波器降维;所有的卷积均使用线性激活函数)
输入:224×224×3的RGB图像(均值0处理)
第一层(卷积):
7×7的卷积核(步长为2,64通道),输出112×112×64;
3×3的max pooling层(步长为2),输出56×56×64
第二层(卷积):
3×3的卷积核(步长1,192通道),输出56×56×192;
3×3的max pooling层(步长为2),输出28×28×192
第三层(Inception 3a):
分为4个分支:
(1)1×1的卷积核(64通道),输出就是28×28×64;
(2)1×1的卷积核(96通道)降维,然后3×3的卷积核(128通道),输出28×28×128
(3)1×1的卷积核(16通道)降维,然后5×5的卷积核(32通道),输出28×28×32
(4)3×3的pool层,然后经过1×1的卷积核(通道32),输出28×28×32
以下由此类推...
最终的网络模型如下:
(辅助分类器的分类结果会乘以一个权重加到最终的分类结果上)
4. 代码参考
用tensorflow实现一个Inception:
1 slim= tf.contrib.slim 2 3 net = slim.conv2d (Input, 32 , [3 , 3]) 4 5 # slim.arg_scope 函数可以用于设置默认的参数取值 6 7 with slim.arg_scope ( [slim.conv2d, slim .max_pool2d, slim.avg_pool2d), 8 9 stride=1, padding=’VALID’): 10 11 net=上-层的输出节点矩阵 12 13 with tf .variable_scope ( 'Mixed_7c ’): 14 15 #第一条路径 16 17 with tf.variable_scope(’Branch_0’): 18 19 #实现一个过滤器边长1,深度320的卷积层 20 21 branch_0= slim.conv2d(net,320,[1 , 1] scope=’Conv2d_0a_1*1’) 22 23 # Inception 模块中第二条路径。这条计算路径上的结构本身也是一个 Inception 结构。 24 25 with tf.variable_scope (’Branch_1’): 26 27 branch_1 = slim.conv2d(net,384 , [1,1], scope=’Conv2d_0a_1*1') 28 29 # tf.concat函数可以将多个矩阵拼接起来.tf.concat函数的第一个参数指定了拼接的维度,这里给出的“ 3 ”代表了矩阵是在深度这个维度上进行拼接。 30 31 branch_1 = tf.concat(3 , [slim.conv2d(branch_1 , 384 , [1 , 3], scope='Conv2d_0b_1*3 ’),slim.conv2d(branch_1, 384, [3 , 1], scope= ’Conv2d_0c_3*1 ’)]) 32 33 # Inception 模块中第三条路径 34 35 with tf .variable_scope ( ’ Branch_2 ’): 36 37 branch_2 = slim.conv2d(net, 448, [1, 1] , scope=’ Conv2d_0a_1*1 ’) 38 39 branch_2 = slim.conv2d(branch_2 , 384 , [3 , 3], scope= ’ Conv2d_0b_3*3 ’) 40 41 branch_2 = tf.concat(3 , [slim.conv2d(branch_2 , 384 ,[1, 3] , scope=’ Conv2d_0c_1*3 ’,slim.conv2d(branch_2, 384 ,[3 , 1], scope=’ Conv2d_0d_3*1’) ]) 42 43 # Inception 模块中第四条路径 44 45 with tf.variable scope (’Branch_3 ’): 46 47 branch_3 = slim .avg_pool2d(net,[3, 3] , scope=’AvgPool_0a_3*3 ’) 48 49 branch_3 = slim.conv2d(branch_3,192 , [1, 1],scope=’Conv2d_0b_1*1’) 50 51 #当前Inceptio模块的最后输出是由上面 4 个计算结果拼攘得到的 52 53 net = tf . concat (3, [branch_0 , branch_1, branch_2 , branch_3])