TensorFlow学习--GoogLeNet实现
来源:互联网 发布:麦壳少儿编程 编辑:程序博客网 时间:2024/06/04 21:34
GoogLeNet结构
Google Inception Net通常被称为Google Inception V1,在ILSVRC-2014比赛中由论文<Going deeper with convolutions>提出.
Inception V1有22层,比AlexNet的8层和VGGNet的19层还要深.参数量(500万)仅有AlexNet参数量(6000万)的1/12,但准确率远胜于AlexNet的准确率.
Inception V1降低参数量的目的:
1. 参数越多模型越庞大,需要模型学习的数据量就越大,且高质量的数据非常昂贵.
2. 参数越多,消耗的计算资源越多.
Inception V1网络的特点:
1. 模型层数更深(22层),表达能力更强.
2. 去除最后的全连接层,用全局平均池化层(即将图片尺寸变为1x1)来代替它.(借鉴了NIN)
3. 使用Inception Module提高了参数利用效率.
Inception V3中的种类:
Inception Module结构图:
1x1卷积可以跨通道组织信息,提高网络的表达能力,同时可以对输出通道升维和降维.Inception Module的4个分支都用到了1x1卷积来进行降维.第一个分支对输入进行了1x1卷积;第二个分支先使用1x1卷积然后连接3x3卷积,相当于进行了两次特征变换;第三个分支先使用了1x1卷积,然后使用5x5卷积;第四个分支是3x3最大池化后用1x1卷积.1x1卷积用很小的计算量就能增加一层特征变换和非线性化.Filter concatenation层将1×1/3×3/5×5的卷积结果连接起来(在输出通道数这个维度上聚合).这样防止了层数增多带来的计算资源的需求,使网络的宽度和深度均可扩大.
将高度相关的节点连接在一起,形成稀疏网络:
网络模型如图:
GoogLeNet性能测试
import tensorflow as tfslim = tf.contrib.slimtrunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)# 生成默认参数def inception_v3_arg_scope(weight_decay=0.00004, # L2正则weight_decay stddev=0.1, # 标准差 batch_norm_var_collection='moving_vars'): batch_norm_params = { 'decay': 0.9997, 'epsilon':0.001, 'updates_collections': tf.GraphKeys.UPDATE_OPS, 'variables_collections':{ 'beta': None, 'gamma': None, 'moving_mean': [batch_norm_var_collection], 'moving_variance': [batch_norm_var_collection], } } # 提供了新的范围名称scope name # 对slim.conv2d和slim.fully_connected两个函数的参数自动赋值 with slim.arg_scope([slim.conv2d, slim.fully_connected], weights_regularizer=slim.l2_regularizer(weight_decay)): with slim.arg_scope( [slim.conv2d], # 对卷积层的参数赋默认值 weights_initializer=tf.truncated_normal_initializer(stddev=stddev), # 权重初始化器 activation_fn=tf.nn.relu, # 激活函数用ReLU normalizer_params=batch_norm_params) as sc: # 标准化器参数用batch_norm_params return sc# inputs为输入图片数据的tensor(299x299x3),scope为包含了函数默认参数的环境def inception_v3_base(inputs, scope=None): # 保存某些关键节点 end_points = {} # 定义InceptionV3的网络结构 with tf.variable_scope(scope, 'InceptionV3', [inputs]): # 设置卷积/最大池化/平均池化的默认步长为1,padding模式为VALID # 设置Inception模块组的默认参数 with slim.arg_scope([slim.conv2d, # 创建卷积层 slim.max_pool2d, # 输出的通道数 slim.avg_pool2d], # 卷积核尺寸 stride=1, # 步长 padding='VALID'): # padding模式 # 经3个3x3的卷积层后,输入数据(299x299x3)变为(35x35x192),空间尺寸降低,输出通道增加 net = slim.conv2d(inputs, 32, [3,3], stride=2, scope='Conv2d_1a_3x3') net = slim.conv2d(net, 32, [3, 3], scope='Conv2d_2a_3x3') net = slim.conv2d(net, 64, [3, 3], padding='SAME', scope='Conv2d_2b_3x3') net = slim.max_pool2d(net, [3, 3], stride=2, scope='MaxPool_3a_3x3') net = slim.conv2d(net, 80, [1, 1], scope='Conv2d_3b_1x1') net = slim.conv2d(net, 192, [3, 3], scope='Conv2d_4a_3x3') net = slim.max_pool2d(net, [3, 3], stride=2, scope='MaxPool_5a_3x3') # 设置卷积/最大池化/平均池化的默认步长为1,padding模式为SAME # 步长为1,padding模式为SAME,所以图像尺寸不会变,仍为35x35 with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='SAME'): # 设置Inception Moduel名称为Mixed_5b with tf.variable_scope('Mixed_5b'): # 第1个分支:64输出通道的1x1卷积 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') # 第2个分支:48输出通道的1x1卷积,连接64输出通道的5x5卷积 with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 48, [1, 1], scope='Con2d_0a_1x1') branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d_0b_5x5') # 第3个分支:64输出通道的1x1卷积,连接两个96输出通道的3x3卷积 with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3') branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3') # 第4个分支:3x3的平均池化,连接32输出通道的1x1卷积 with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 32, [1, 1], scope='Conv2d_0b_1x1') # 4个分支输出通道数之和=64+64+96+32=256,输出tensor为35x35x256 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 第1个Inception模块组的第2个Inception Module with tf.variable_scope('Mixed_5c'): # 第1个分支:64输出通道的1x1卷积 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') # 第2个分支:48输出通道的1x1卷积,连接64输出通道的5x5卷积 with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 48, [1, 1], scope='Conv2d_0b_1x1') branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d_0c_5x5') # 第3个分支:64输出通道的1x1卷积,连接两个96输出通道的3x3卷积 with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3') branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3') # 第4个分支:3x3的平均池化,连接64输出通道的1x1卷积 with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸为35x35x288 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 第1个Inception模块组的第3个Inception Module with tf.variable_scope('Mixed_5d'): # 第1个分支:64输出通道的1x1卷积 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') # 第2个分支:48输出通道的1x1卷积,连接64输出通道的5x5卷积 with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 48, [1, 1], scope='Conv2d_0a_1x1') branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d_0b_5x5') # 第3个分支:64输出通道的1x1卷积,连接两个96输出通道的3x3卷积 with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3') branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3') # 第4个分支:3x3的平均池化,连接64输出通道的1x1卷积 with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸为35x35x288 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 第2个Inception模块组 with tf.variable_scope('Mixed_6a'): # 第1个分支:3x3卷积,步长为2,padding模式为VALID,因此图像被压缩为17x17 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 384, [3, 3], stride=2 , padding='VALID', scope='Conv2d_1a_1x1') # 第2个分支:64输出通道的1x1卷积,连接2个96输出通道的3x3卷积 with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1') branch_1 = slim.conv2d(branch_1, 96, [3, 3], scope='Conv2d_0b_3x3') # 步长为2,padding模式为VALID,因此图像被压缩为17x17 branch_1 = slim.conv2d(branch_1, 96, [3, 3], stride=2, padding='VALID', scope='Conv2d_1a_1x1') # 第3个分支:3x3的最大池化层,步长为2,padding模式为VALID,因此图像被压缩为17x17x256 with tf.variable_scope('Branch_2'): branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID', scope='MaxPool_1a_3x3') net = tf.concat([branch_0, branch_1, branch_2], 3) # 第2个Inception模块组,包含5个Inception Module with tf.variable_scope('Mixed_6b'): # 第1个分支:192输出通道的1x1卷积 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') # 第2个分支:128输出通道的1x1卷积,接128输出通道的1x7卷积,接192输出通道的7x1卷积 with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1') branch_1 = slim.conv2d(branch_1, 128, [1, 7], scope='Conv2d_0b_1x7') branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1') with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 128, [7, 1], scope='Conv2d_0b_7x1') branch_2 = slim.conv2d(branch_2, 128, [1, 7], scope='Conv2d_0c_1x7') branch_2 = slim.conv2d(branch_2, 128, [7, 1], scope='Conv2d_0d_7x1') branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_1x7') with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸=17x17x(192+192+192+192)=17x17x768 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 经过一个Inception Module输出tensor尺寸不变,但特征相当于被精炼类一遍 # 第3个Inception模块组 with tf.variable_scope('Mixed_6c'): with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1') branch_1 = slim.conv2d(branch_1, 160, [1, 7], scope='Conv2d_0b_1x7') branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1') with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0b_7x1') branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='Conv2d_0c_1x7') branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0d_7x1') branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_1x7') with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸为17x17x768 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 第4个Inception模块组 with tf.variable_scope('Mixed_6d'): with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1') branch_1 = slim.conv2d(branch_1, 160, [1, 7], scope='Conv2d_0b_1x7') branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1') with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0b_7x1') branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='Conv2d_0c_1x7') branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0d_7x1') branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_1x7') with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸为17x17x768 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 第5个Inception模块组 with tf.variable_scope('Mixed_6e'): with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') branch_1 = slim.conv2d(branch_1, 192, [1, 7], scope='Conv2d_0b_1x7') branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1') with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 192, [7, 1], scope='Conv2d_0b_7x1') branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0c_1x7') branch_2 = slim.conv2d(branch_2, 192, [7, 1], scope='Conv2d_0d_7x1') branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_1x7') with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸为17x17x768 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 将Mixed_6e存储于end_points中 end_points['Mixed_6e'] = net # 第3个Inception模块 # 第1个Inception模块组 with tf.variable_scope('Mixed_7a'): # 第1个分支:192输出通道的1x1卷积,接320输出通道的3x3卷积 步长为2 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') branch_0 = slim.conv2d(branch_0, 320, [3, 3], stride=2, padding='VALID', scope='Conv2d_0a_3x3') # 第2个分支:4个卷积层 with tf.variable_scope('Branch_1'): # 192输出通道的1x1卷积 branch_1 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1') # 192输出通道的1x7卷积 branch_1 = slim.conv2d(branch_1, 192, [1, 7], scope='Conv2d_0b_1x7') # 192输出通道的7x1卷积 branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1') # 192输出通道的3x3卷积 步长为2,输出8x8x192 branch_1 = slim.conv2d(branch_1, 192, [3, 3], stride=2, padding='VALID', scope='Conv2d_1a_3x3') # 第3个分支:3x3的最大池化层,输出8x8x768 with tf.variable_scope('Branch_2'): branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID', scope='MaxPool_1a_3x3') # 输出tensor尺寸:8x8x(320+192+768)=8x8x1280,尺寸缩小,通道数增加 net = tf.concat([branch_0, branch_1, branch_2], 3) # 第2个Inception模块组 with tf.variable_scope('Mixed_7b'): # 第1个分支:320输出通道的1x1卷积 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1') # 第2个分支:384输出通道的1x1卷积 # 分支内拆分为两个分支:384输出通道的1x3卷积+384输出通道的3x1卷积 with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 384, [1, 1], scope='Conv2d_0a_1x1') branch_1 = tf.concat([ slim.conv2d(branch_1, 384, [1, 3], scope='Conv2d_0b_1x3'), slim.conv2d(branch_1, 384, [3, 1], scope='Conv2d_0b_3x1')], 3) # 第3个分支:448输出通道的1x1卷积,接384输出通道的3x3卷积,分支内拆分为两个分支 with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 448, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 384, [3, 3], scope='Conv2d_0b_3x3') # 分支内拆分为两个分支:384输出通道的1x3卷积+384输出通道的3x1卷积 branch_2 = tf.concat([ slim.conv2d(branch_2, 384, [1, 3], scope='Conv2d_0c_1x3'), slim.conv2d(branch_2, 384, [3, 1], scope='Conv2d_0d_3x1')], 3) # 第4个分支:3x3的平均池化层,接192输出通道的1x1卷积,输出8x8x768 with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸:8x8x(320+768+768+192)=8x8x2048 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) # 第3个Inception模块组 with tf.variable_scope('Mixed_7c'): # 第1个分支:320输出通道的1x1卷积 with tf.variable_scope('Branch_0'): branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1') # 第2个分支:384输出通道的1x1卷积 # 分支内拆分为两个分支:384输出通道的1x3卷积+384输出通道的3x1卷积 with tf.variable_scope('Branch_1'): branch_1 = slim.conv2d(net, 384, [1, 1], scope='Conv2d_0a_1x1') branch_1 = tf.concat([ slim.conv2d(branch_1, 384, [1, 3], scope='Conv2d_0b_1x3'), slim.conv2d(branch_1, 384, [3, 1], scope='Conv2d_0c_3x1')], 3) # 第3个分支:448输出通道的1x1卷积,接384输出通道的3x3卷积,分支内拆分为两个分支 with tf.variable_scope('Branch_2'): branch_2 = slim.conv2d(net, 448, [1, 1], scope='Conv2d_0a_1x1') branch_2 = slim.conv2d(branch_2, 384, [3, 3], scope='Conv2d_0b_3x3') # 分支内拆分为两个分支:384输出通道的1x3卷积+384输出通道的3x1卷积 branch_2 = tf.concat([ slim.conv2d(branch_2, 384, [1, 3], scope='Conv2d_0c_1x3'), slim.conv2d(branch_2, 384, [3, 1], scope='Conv2d_0d_3x1')], 3) # 第4个分支:3x3的平均池化层,接192输出通道的1x1卷积,输出8x8x768 with tf.variable_scope('Branch_3'): branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1') # 输出tensor尺寸:8x8x(320+768+768+192)=8x8x2048 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3) return net, end_points# 全局平均池化def inception_v3(inputs, num_classes=1000, # 最后分类数量 is_training=True, # 是否是训练过程的标志 dropout_keep_prob=0.8, # Dropout保留节点的比例 prediction_fn=slim.softmax,# 进行分类的函数 spatial_squeeze=True, # 是否对输出进行squeeze操作,即去除维数为1的维度 reuse=None, # tf.variable_scope的reuse默认值 scope='InceptionV3'): # tf.variable_scope的scope默认值 with tf.variable_scope(scope, 'InceptionV3', [inputs, num_classes], reuse=reuse) as scope: with slim.arg_scope([slim.batch_norm, slim.dropout], is_training=is_training): net, end_points = inception_v3_base(inputs, scope=scope) # 设置卷积/最大池化/平均池化的默认步长为1,padding模式为SAME with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='SAME'): aux_logits = end_points['Mixed_6e'] # 辅助分类节点 with tf.variable_scope('AuxLogits'): # 5x5的平均池化,步长设为3,padding模式设为VALID aux_logits = slim.avg_pool2d(aux_logits, [5, 5], stride=3, padding='VALID', scope='AvgPool_1a_5x5') aux_logits = slim.conv2d(aux_logits, 128, [1, 1], scope='Conv2d_1b_1x1') aux_logits = slim.conv2d(aux_logits,768, [5, 5], weights_initializer=trunc_normal(0.01), padding='VALID', scope='Conv2d_2a_5x5') aux_logits = slim.conv2d(aux_logits, num_classes, [1, 1], activation_fn=None, normalizer_fn=None, weights_initializer=trunc_normal(0.001), scope='Conv2d_2b_1x1') if spatial_squeeze: # 进行squeeze操作,去除维数为1的维度 aux_logits = tf.squeeze(aux_logits, [1, 2], name='SpatialSqueeze') end_points['AuxLogits'] = aux_logits # 处理正常的分类预测 with tf.variable_scope('Logits'): # 8x8的平均池化层 net = slim.avg_pool2d(net, [8, 8], padding='VALID', scope='AvgPool_1a_8x8') # Dropout层 net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b') end_points['PreLogits'] = net logits = slim.conv2d(net, num_classes, [1, 1], activation_fn= None, normalizer_fn=None,scope='Conv2d_1c_1x1') if spatial_squeeze: # 进行squeeze操作,去除维数为1的维度 logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze') # 辅助节点 end_points['Logits'] = logits # 利用Softmax对结果进行分类预测 end_points['Predictions'] = prediction_fn(logits, scope='Predictions') return logits, end_pointsimport mathfrom datetime import datetimeimport time# 评估每轮计算占用的时间# 输入TensorFlow的Session,需要测评的算子target,测试的名称info_stringdef time_tensorflow_run(session, target, info_string): # 定义预热轮数(忽略前10轮,不考虑显存加载等因素的影响) num_steps_burn_in = 10 total_duration = 0.0 total_duration_squared = 0.0 for i in range(num_batches + num_steps_burn_in): start_time = time.time() _ = session.run(target) # 持续时间 duration = time.time()- start_time if i >= num_steps_burn_in: # 只考量10轮迭代之后的计算时间 if not i % 10: print '%s: step %d, duration = %.3f' % (datetime.now().strftime('%X'), i - num_steps_burn_in, duration) # 记录总时间 total_duration += duration total_duration_squared += duration * duration # 计算每轮迭代的平均耗时mn,和标准差sd mn = total_duration / num_batches vr = total_duration_squared / num_batches - mn * mn sd = math.sqrt(vr) # 打印出每轮迭代耗时 print '%s: %s across %d steps, %.3f +/- %.3f sec / batch' % (datetime.now().strftime('%X'), info_string, num_batches, mn, sd)# Inception V3运行性能测试if __name__ == '__main__': batch_size = 32 height, width = 299, 299 inputs = tf.random_uniform((batch_size, height, width, 3)) with slim.arg_scope(inception_v3_arg_scope()): # 传入inputs获取logits,end_points logits, end_points = inception_v3(inputs, is_training=False) # 初始化 init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) num_batches = 100 # 测试Inception V3的forward性能 time_tensorflow_run(sess, logits, 'Forward')
输出:
08:44:25: step 0, duration = 12.33508:46:28: step 10, duration = 12.28608:48:37: step 20, duration = 12.26008:50:40: step 30, duration = 12.25908:52:42: step 40, duration = 12.27508:54:47: step 50, duration = 12.41508:56:53: step 60, duration = 12.82408:59:38: step 70, duration = 17.70809:03:55: step 80, duration = 29.92109:08:59: step 90, duration = 37.04209:14:36: Forward across 100 steps, 18.237 +/- 8.856 sec / batch
GoogLeNet相关连接
论文连接:Going deeper with convolutions
Large Scale Visual Recognition Challenge 2014 (ILSVRC2014)
- TensorFlow学习--GoogLeNet实现
- tensorflow下GoogLeNet的实现
- Googlenet 学习
- TensorFlow学习--ResNet实现
- TensorFlow学习--tensorflow图像预处理
- TensorFlow学习--实现简单的卷积网络
- TensorFlow学习--AlexNet实现&图像识别
- TensorFlow学习--VGGNet实现&图像识别
- 学习笔记:GoogLeNet
- GoogLeNet论文学习笔记
- 学习笔记:GoogLeNet
- 学习笔记:GoogLeNet
- GoogleNet:inceptionV3论文学习
- inception_v3迁移学习(GoogleNet)
- GoogLeNet网络结构学习
- 深度学习: GoogleNet 网络
- Tensorflow 笔记 用 GoogLeNet 做模式识别
- TensorFlow Time Benchmark for Googlenet (inception_v1_benchmark.py)
- 可迭代对象&迭代器
- Qt实用技巧:界面切换使用Dialog全屏切换
- 一些实用的网站
- java判断一个字符串是否是回文
- Java集合框架之ArrayList
- TensorFlow学习--GoogLeNet实现
- JAVA集合类总结以及写博客的初衷
- 线程
- Google C++ Style Guide中英对照(二)
- struts2对于bigdecimal类型不支持默认转换的解决办法
- 实验三 NFA确定化和DFA最小化
- 交大OJ 1272 写数游戏/背包问题
- 11.正则表达式
- Google C++ Style Guide中英对照(三)