论文地址
inception-v1,inception-v2,inception-v3,inception-v4
事前准备
我这边使用的是Windows平台TensorFlow1.4 gpu版本,当然如果是cpu版本也玩不了,太慢了,这个网络可是用来跑ImageNet的。另外你可以下载前面的inception-v4论文,因为接下来要对照论文进行实现。当然这里只是尝试模拟,可能会有错误,欢迎指正。最后就是数据集的准备了,这里使用的是ImageNet dog的一部分,来自网友分享
链接: https://pan.baidu.com/s/1pMS6Xon 密码: dnha
里面有训练集的数据和标签,测试集只有数据没有标签,当然,如果你问Windows怎么装TensorFlow啊,推荐:
准备好了就准备进入正题吧
inception-resnet网络主体
如果你已经阅读了inception-v4的论文,你可能会发现里面提到了两个inception-resnet,一个是v1,一个是v2,v1是对应于inception-v3进行resnet改造的,v2就自然是对应于inception-v4,这里我们只管v2,其实他俩结构是一样的。另外读者可以下载TensorFlow的开源模组实现,在research/slim/net中有其他网络的实现,这里也是参考了一部分。
现在我们可以打开inception-v4论文了,我们找到17号图
Schema for Inception-ResNet-v1 and Inception-ResNet-v2 networks. This schema applies to both networks but the underlying components differ. Inception-ResNet-v1 uses the blocks as described in Figures 14, 10, 7, 11, 12 and 13. Inception-ResNet-v2 uses the blocks as described in Figures 3, 16, 7,17, 18 and 19. The output sizes in the diagram refer to the activation vector tensor shapes of Inception-ResNet-v1.
它说这个架构是resnet v1和v2共用的,但是里面的组件细节可能有不同,v1使用组件为图14,10巴拉巴拉,v2为巴拉巴拉,输出大小两者都适用。
知道了这些,我们就清楚了如何来看这篇论文了,其实这篇论文叙述文字并不多,主要是以图来讲解结构,因为使用的理论前面都有了。所以我们直接按顺序来看那些用于组成inception-v2的图,当然,论文中提到了一些细节,后面会说。回过头来看这张图,首先它的输入是299x299x3,这是ImageNet当年的规定。然后进入一个叫stem的模组,出来后变为35x35x256,这是第一步提取特征。
Stem
我们找到stem模组,图号为3
我们可以新建一个python文件mystruct.py,里面用于存放这里模组,本着简单说事的原则,这里就不详细展开其中的卷积操作了,希望读者已经熟悉卷积操作,对图中的输入输出能够自己推算。所以如果不是特殊情况,这里就直接上代码了。先说明一下,图中矩形,从上到下从左到右依次为
- 卷积核大小
- 操作,卷积或者池化
- 通道数
- 标出stride代表步长,一般为1时不标出
- V代表valid,不填充,不标出则表示SAME填充,读者从输入输出大小变化也可以看出
- filter concat表示张量连接,图中可以看见连接后通道数为前者的和
import tensorflow as tf
import tensorflow.contrib.slim as slim
def Stem(inputs):
output = slim.conv2d(inputs, 32, [3, 3], stride=2, padding='VALID')
output = slim.conv2d(output, 32, [3, 3], padding='VALID')
output = slim.conv2d(output, 64, [3, 3])
output_left = slim.max_pool2d(output, [3, 3])
output_right = slim.conv2d(output, 96, [3, 3], stride=2, padding='VALID')
output = tf.concat([output_left, output_right], 3)
output_left = slim.conv2d(output, 64, [1, 1])
output_left = slim.conv2d(output_left, 96, [3, 3], padding='VALID')
output_right = slim.conv2d(output, 64, [1, 1])
output_right = slim.conv2d(output_right, 64, [7, 1])
output_right = slim.conv2d(output_right, 64, [1, 7])
output_right = slim.conv2d(output_right, 96, [3, 3], padding='VALID')
output = tf.concat([output_left, output_right], 3)
output_left = slim.conv2d(output, 192, [3, 3], stride=2, padding='VALID')
output_right = slim.max_pool2d(output, [3, 3])
output = tf.concat([output_left, output_right], 3)
return tf.nn.relu(output)
要提的一点是,这里为了简化网络构建,使用TensorFlow中的slim组件,可以将激活函数,批次归一化这些操作统一到一个操作中了,所以你现在看到conv2d函数并没有接激活函数。代码完全根据图上的结构写的,conv2d函数默认stride为1,padding为SAME,max_pool2d函数默认stride为2,padding为VALID。concat函数便是张量连接函数,第二个参数用于指定连接的维度,因为TensorFlow中的维度顺序是[样本数,宽,高,通道数],所以我们要连接通道数,从0开始第3个。
inception-res