Tensorflow 实战8:Tensoflow实现Google Inception Net

TensorFlow入门 | 人脸检测与识别 人脸识别概述 人脸识别,特指利用分析比较人脸视觉特征信息进行身份鉴别的计算机技术。属于生物特征识别技术的一种。 广义的人脸识别实际包括构建人脸识别系统的一系列相关技术,包括人脸图像采集、人脸定位、人脸识别预处理、身份确认以及身份查找等;而狭义的人脸识别特指通过人脸进行身份确认或者身份查找的技术或系统。 人脸识别典型流程 典型流程分为3个步骤: 1)人脸检测: 对图像中人脸位置的检测 2)人脸对齐... 阅读详情

介绍

\quadGoogle Inception Net首次出现在ILSVRC 2014的比赛中(和VGGNet同年),就以较大优势取得第一名。那届比赛中的Inception Net通常称为Inception V1,它最大的特点是控制了计算量和参数量的同时,获得了非常好的分类性能-top-5错误率6.67%。,只有AlexNet的一半不到。Inception V1有22层,比AlexNet的8层或者VGGNet的19层还要深。但其计算量只有15亿次浮点运算,同时只有500万参数量,仅为AlexNet参数量(6000万)的1/12,却可以达到远胜于AlexNet的准确率,可以说是非常优秀且实用的模型。Inception V1降低参数量的目的主要有2点,第一,参数越多模型越庞大,需要提供模型学习的数据量就越大,而目前高质量的数据十分昂贵。第二,参数越多,耗费的计算资源也会更大。Inception V1参数少但效果好的原因除了模型层数更多,表达能力更强外,还有2点:一是去除了最后的全连接层,用全局平均池化层来取代它。全连接层几乎占据了AlexNet或VGGNet中90%的参数量,而且会引起过拟合,去除全连接层后模型训练更快且减轻了过拟合。用全局平均池化层取代全连接层的做法借鉴了Network In Network论文。而是Inception V1中精心设计的Inception Module提高了参数的利用效率。
\quad我们来看一下Inception Module的基本结构,其中有4个分支,第一个分支对输入进行1 ×\times× 1卷积,这其实也是NIN种提出的一个重要结构。1 ×\times× 1的卷积是一个非常优秀的结构,它可以跨通道组织信息,提高网络的表达能力,同时可以对输出通道升维和降维。可以看到Inception Module的4个分支都用到了1 ×\times× 1卷积,来降低成本(计算量比3 ×\times× 3小很多)的跨通道的特征变换。第二个分支使用了1 ×\times× 1卷积,然后连接 3 ×\times× 3卷积,相当于进行了两次特征变换。第3个分支类似,先是1 ×\times× 1卷积,然后连接 5 ×\times× 5卷积。最后一个分支则是 3 ×\times× 3最大池化后直接使用1 ×\times× 1卷积。我们可以发现,有的分支只使用1 ×\times× 1卷积,有的分支使用了其他尺寸的卷积时也会再用1 ×\times× 1卷积,这是因为1 ×\times× 1卷积的性价比很高,用很小的计算量就可以增加一层特征变换和非线性化。Inception Module的4个分支在最后通过一个聚合操作合并(在输出通道这个维度上聚合)。Inception Module中包含了3种不同尺寸的卷积和1个最大池化,增加了网络对不同尺度的适应性,这一部分和Multi-Scale的思想类似。早期计算机是觉得研究中,收到灵长类神经视觉系统的启发,Serre使用不同尺寸的Gabor滤波器处理不同尺寸的图片,Inception V1借鉴了这种思想。Inception V1的论文中指出,Inception Module可以让网络的深度和宽度高效率的扩充,提升准确率且不至于过拟合。
\quad在Inception Module中,通常1 ×\times× 1卷积的比例(输出通道数占比)最高,3 ×\times× 3卷积核5 ×\times× 5卷积稍低。而在整个网络中,会有多个堆叠的Inception Module,我们希望靠后的Inception Module可以捕捉更高阶的抽象特征,因此靠后的Inception Module的卷积的空间集中度应该组件降低,这样可以捕获更大面积的特征。因此,越靠后的Inception Module中,3 ×\times× 3和5 ×\times× 5这两个大面积的卷积核的占比(输出通道数)应该更多。
\quad Inception V2学习了VGGNet,用两个3 ×\times× 3的卷积代替 5 ×\times× 5的大卷积核(用以降低参数量并减轻过拟合),还提出了著名的Batch Normalization方法。BN是一个非常有效的正则化方法,可以让大型卷积网络的速度加快很多倍,同时收敛后的分类准确率也可以得到大幅度的提高。BN在用于神经网络某层时,会对每一个mini-batch数据的内存进行标准化处理,使输出规范化到N(0,1)的正太分布,减少了Internal Covariate Shift(内部神经元分布的改变)。BN的论文指出,传统的深度卷积网络在训练时,每一层输入的分布都在变化,导致训练变得困难,我们只能使用一个很小的学习速率解决这个问题。而对每一层使用BN之后,我们就可以有效地解决这个问题,学习速率可以增大很多倍,达到之前的准确率所需要的迭代次数只有1/14,训练时间大大缩短。而达到之前的准确率后可以继续训练,并最终取得远超于Inception V1模型的性能–top-5错误率4.8%,已经优于人眼水平。因为BN某种意义上还起到了正则化的作用,所以可以减少或者取消Dropout,简化网络结构。
\quad当然只是单纯的使用BN获得的增益还不明显,还需要一些相应的调整:增大学习速率并加快学习衰减速度以适用BN规范化后的数据;去除Dropout并减轻L2正则(因为BN已经起到正则化的作用);去除LRN;更彻底的对训练样本进行shuffle;减少数据增强过程中对数据的光学畸变(因为BN训练更快,每个样本被训练的次数更少,因此更真实的样本对训练更有帮助)。在使用了这些措施以后,Inception V2在训练达到Inception V1的准确率时快了14倍,并且模型的收敛时的上限更高。
\quad而Inception V3网络主要有两方面的改造:一是引入了Factorization into small convolutions的思想,将一个较大的二维卷积拆成两个较小的一维卷积,比如将7 ×\times× 7卷积拆成1 ×\times× 7卷积和7 ×\times× 1卷积,比拆成3个3 ×\times× 3卷积更节约参数,同时增加了一层非线性扩展模型表达能力。论文中指出,这种非对称的卷积结构拆分,其结果比对称的拆成几个相同的小卷积核效果更明显,可以处理更多,更丰富的空间特征,增加特征多样性。
\quad另一方面,Inception V3优化了Inception Module的结构,现在Inception Module有35 ×\times× 35, 17 ×\times× 17和8 ×\times× 8三种不同结构。这些Inception Module只在网络中的后部出现,前部还是普通的卷积层。并且Inception V3除了在Inception Module中使用分支,还在分支中使用了分支(8 ×\times× 8结构中),可以说是Network In Network。
\quad而Inception V4相比于V3主要是结合了微软的ResNet,而ResNet将在6.4节单独讲解,这里不多做追溯。接下来就来实现以下Inception V3,Inception V3的网络结构如下:
在这里插入图片描述由于Google Inception Net V3相对比较复杂,所以这里用tf.contrib.slim辅助设计这个网络。contrib.slim中的一些功能和组件可以大大减少设计Inception Net的代码量,我们只需要少量的代码即可构件好42层深的Inception V3。

  1. 首先定义一个简单的函数trunc_normal,产生截断的正态分布。
#coding=utf-8
#Inception-V3.py
import tensorflow as tf
from datetime import datetime
import math
import time
slim = tf.contrib.slim
#产生截断的正太分布
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
  1. 下面定义函数inception_v3_arg_scope,用来生成网络中经常用到的函数的默认参数,比如卷积的激活函数,权重初始化方式,标准化器等。设置L2正则的weight_decay默认值为0.00004,标准差stddev默认为0.1,参数batch_norm_var_collection默认值为moving_vars。接下来,定义batch normallization的参数字典,定义其衰减系数decay为0.9997,epsilon为0.001,updates_collctions为tf.GraphKeys.UPDATE_OPS,然后字典variable_collections中beta和gamma均设置为None,moving_mean和moving_variance均设置为前面的batch_norm_var_collection。
    \quad接下来使用slim.arg_scope,这是一个非常有用的工具,它可以给函数的参数自动赋予某些值。例如,这句with slim.arg_scope([slim.conv2d,slim.fully_connected],weights_regularizer=slim.l2_regularizer(weight_decay)),会对[slim.conv2d,slim.fully_connected]这两个函数的参数自动赋值,将参数weights_regularizer的值默认设为slim.l2_regularizer(weight_decay)。使用了slim.arg_scope后就不需要每次都重复设置参数了,只需要在有修改时设置。接下来,嵌套一个slim.arg_scope,对卷积层生成函数slim.conv2d的几个参数赋予默认值,其权重初始化器weights_initializer设置为trunc_normal(stddev),激活函数设置为ReLU,标准化器设置为slim.batch_norm,标准化器的参数设置为前面定义的batch_norm_params。最后返回定义好的scope。
    \quad因为事先定义好了slim.conv2d中的各种默认参数,包括激活函数和标准化器,因此后面定义一个卷积层将会变得非常方便。我们可以用一行代码定义一个卷积层,整体代码会变得非常简洁美观,同时设计网络的工作量也会大大减轻。
#定义inception_v3_arg_scope,用来生成网络中经常用到的函数的默认参数
def inception_v3_arg_scope(weight_decay=0.00004, 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]
        }
    }
    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,
                            normalizer_fn=slim.batch_norm,
                            normalizer_params=batch_norm_params) as sc:
            return sc
  1. 接下来我们就定义函数inception_v3_base,它可以生成Inception V3网络的卷积部分,参数inputs为输入的图片数据的tensor,scope为包含了函数默认参数的环境。我们定义一个字典表end_points,用来保存某些关键节点供以后使用。接着再使用slim.arg_scope,对slim.conv2d,slim.max_pool2d这3个函数的参数设置默认值,将stride设为1,padding设为VALID。下面正式开始定义Inception V3的网络结构,首先是前面的非Inception Module的卷积层。这里直接使用slim.conv2d创建卷积层,slim.conv2d的第一参数为输入的tensor,第二个参数为输出的通道数,第3个参数为卷积核尺寸,第4个参数为步长stride,第5个参数为padding模式。我们的第一个卷积层后的输出通道数为32,卷积核尺寸为3 ×\times× 3,步长为2,padding模式则是默认的VALID。后面的几个卷积层采用相同的形式,按照论文中的定义,逐层定义好网络结构。因为使用了slim及slim.arg_scope,我们一行代码就可以定义好一个卷积层,相比之前AlexNet的实现中使用好几行代码定义一个卷积层,或是VGGNet中专门写一个函数来定义卷积层,都更加方便。
    \quad我们可以观察到,在前面的几个普通非Inception Module的卷积层中,主要使用了3 ×\times× 3的小卷积核,这是充分借鉴了VGGNet的结构。同时,Inception V3论文中也提出了Factorization into small convolutions思想,利用两个一维卷积模拟大尺寸的2维卷积,减少参数量的同时增加非线性。前面几层卷积中还有一层1 ×\times× 1卷积,这也是前面提到的Inception Module中经常使用的结构之一,可低成本的跨通道的对特征进行组合。另外可以看到,除了第一个卷积层步长为2,其余的卷积层步长均为1,而池化层则是尺寸为3 ×\times× 3,步长为2的重叠最大池化,这是AlexNet中使用过得结构。网络的输入数据尺寸为299 ×\times× 299 ×\times× 3,在经历3个步长为2的层后,尺寸缩小为35 ×\times× 35 ×\times× 192,空间尺寸大大降低,但是输出通道增加了很多。这部分代码一共有5个卷积层,2个池化层,实现了对输入数据的尺寸压缩,并对图片特征进行了抽象。
def inception_v3_base(inputs, scope=None):
    end_points = {}
    with tf.variable_scope(scope, 'InceptionV3', [inputs]):
        with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='VALID'):
            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. 接下来就将是3个连续的Inception模块组,这3个Inception模块组中各自分别有多个Inception Module,这部分的网络结构即是Inception V3的精华所在。每个Inception 模块组内部的几个Inception Module结构非常类似,但存在一些细节不同。
    \quad第一个Inception模块组包含了3个结构类似的Inception Module。其中第一个Inception Module的名称为Mixed_5b。我们先使用tf.slim.arg_scope设置所有Inception模块组的默认参数,将所有卷积层,最大池化,平均池化层的步长设为1,padding模式设为SAME。然后设置这个Inception Module的variable_scope名称为Mixed_5b。这个Inception Module中有4个分支,从Branch_0到Branch_3,第一个分支为有64输出通道的1 ×\times× 1卷积;第二个分支为有48输出通道的1 ×\times× 1卷积,连接有64输出通道的5 ×\times× 5卷积;第三个分支为有64输出通道的1 ×\times× 1卷积,再连续连接2个有96输出通道的3 ×\times× 3卷积;第4个分支为3 ×\times× 3的平均池化,连接有32输出通道的1 ×\times× 1卷积。最后,使用tf.concat将4个分支的输出合并在一起(在第3个维度合并,即输出通道上合并),生成这个Inception Module的最终输出。因为这里所有的层步长均为1,并且padding模式为SAME,所以图片的尺寸并不会缩小,依然维持在35 ×\times× 35 ×\times× 256。这里需要注意,第一个Inception模块组中所有的Inception Module输出的图片尺寸为35 ×\times× 35,但是后两个Inception Module的通道数会发生变化。
#Inception Module
        with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='SAME'):
            # 第一个Inception Module的第一个模块
            with tf.variable_scope('Mixed_5b'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
                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')
                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')
                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
  1. 接下来是第一个Inception模块组的第二个Inceptiopn Module—Mixed_5c,这里依然使用前面设置的默认参数:步长为1,padding模式为SAME。这个Inception Module同样有4个分支,唯一不同的是第4个分支最后接的是64输出通道的1 ×\times× 1卷积,而此前是32输出通道。因此,我们输出tensor的最终尺寸为35 ×\times× 35 ×\times× 288,输出通道数相比之前增加了32。
# 第一个Inception Module的第2个模块
            with tf.variable_scope('Mixed_5c'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
                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')
                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_1x1')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3')
                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
  1. 而第一个Inception模块组的第3个Inception Module----Mixed_5d和上一个Inception Module完全相同,4个分支的结构,参数一模一样,输出tensor的尺寸也一样。
  #第一个Inception Module的第3个模块
            with tf.variable_scope('Mixed_5d'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
                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')
                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')
                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
  1. 第2个Inception模块组是一个非常大的模块组,包含了5个Inception Module,其中第二个到第5个Inception Module的结构非常类似,其中第一个Inception Module名称为Mixed)6a,它包含3个分支。第一个分支是一个384输出通道的3 ×\times× 3卷积,这个分支的通道数一下就超过了之前的通道数之和。不过步长为2,因此图片的尺寸将被压缩,且padding的模式为VALID,所以图片的尺寸缩小为17 ×\times× 17;第二个分支有3层,分别是一个64输出通道的1 ×\times× 1卷积和两个96输出通道的3 ×\times× 3卷积。这里需要注意,最后一层的步长为2,padding模式为VALID,因此图片尺寸也被压缩,本分支最终输出的tensor尺寸为17 ×\times× 17 ×\times× 96;第3个分支是一个3 ×\times× 3最大池化层,步长同样为2,padding模式为VALID,因此输出的tensor尺寸为17 ×\times× 17 ×\times× 256.最后依然是使用tf.concat将3个分支在输出通道上合并,最后的输出尺寸为17 ×\times× 17 ×\times× (384 + 96 + 256)=17 ×\times× 17 ×\times× 768。在第2个Inception模块组中,5个Inception Module输出tensor的尺寸全部定格在17 ×\times× 17 ×\times× 768, 即图片的尺寸和通道数都没有发生变化。
 #第二个Inception Module的第一个模块
            with tf.variable_scope('Mixed_6a'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 384, [3, 3], stride=2, padding='VALID', scope='Conv2d_1a_1x1')
                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_1a_1x1')
                    branch_1 = slim.conv2d(branch_1, 96, [3, 3], stride=2, padding='VALID', scope='Conv2d_1b_1x1')
                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)
  1. 接下来是第2个Inception 模块组的第2个Inception Module–Mixed_6b,它有4个分支。第一个分支是一个简单的192输出通道的1 ×\times× 1卷积;第2个分支是由3个卷积层组成,第一层时128输出通道的1 ×\times× 1卷积,第二层是128输出通道数的1 ×\times× 7卷积,第3层时192输出通道的7 ×\times× 1卷积。这里既是前面提到的Factorization into small convolutions思想,串联的1 ×\times× 7卷积和7 ×\times× 1卷积相当于合成了7 ×\times× 7卷积,不过参数量大大减少了,只有后者的2/7,且增加了一个激活函数增强了非线性特征变换;第3个分支一下子拥有5个卷积层,分别是128输出通道的1 ×\times× 1卷积,128输出通道的7 ×\times× 1卷积,128输出通道的1 ×\times× 7卷积,128输出通道的7 ×\times× 1卷积和192输出通道的1 ×\times× 7卷积。这个分支可以算是利用Factorization into small convolutions的典范,反复的将7 ×\times× 7卷积进行拆分;最后,第4个分支是一个3 ×\times× 3的平均池化层,再连接192输出通道的1 ×\times× 1卷积。最后将4个分支合并,这一层输出tensor的尺寸为17 ×\times× 17 ×\times× (192 + 192 + 192 + 192) = 17 ×\times× 17 ×\times× 768。
#第二个Inception Module的第二个模块
            with tf.variable_scope('Mixed_6b'):
                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, 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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
  1. 然后是我们第2个Inception模块组的第3个Inception Module—Mixed_6c。Mixed_6c和前面一个Inception Module非常相似,只有一个地方不同,即第二个分支和第3个分支中前几个卷积层的输出通道不同,从128变成了160,但是这两个分支的输出通道不变,都是192.其余地方则完全一致。需要注意的是,我们的网络没经过一个Inception Module,即是输出的tensor尺寸不变,但是特征都相当于被重新精炼了一遍,其中丰富的卷积核非线性池化对网络的提升非常大。
#第二个Inception Module的第三个模块
            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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
  1. Mixed_6d和前面的Mixed_6c完全一致,目的同样是通过Inception Module精心设计的结构增加卷积核非线性,提炼特征。
#第而个Inception Module的第四个模块
            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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
  1. Mixed_6e也和前面2个Inception Module完全一致。这是第2个Inception模块组的最后一个Inception Module。我们将Mixed_6e存储于end_points中,作为Auxiliary Classifier辅助模型的分类。
#第二个Inception Module的第五个模块,且需要把Mixed_6e存储在end_points中,用于辅助模型的分类
            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, 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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            end_points['Mixed_6e'] = net
  1. 第3个Inception模块组包含了3个Inception Module,其中后两个Inception Module的结构非常相似。其中第一个Inception Module的名称为Mixed_7a,包含了3个分支。第一个分支是192输出通道的1 ×\times× 1卷积,再接320输出通道的3 ×\times× 3卷积,不过步长为2,padding模式为VALID,因此图片尺寸缩小为8 ×\times× 8;第二个分支有4个卷积层,分别是192输出通道的1 ×\times× 1卷积,192输出通道的1 ×\times× 7卷积,192输出通道的7 ×\times× 1卷积,以及192输出通道的3 ×\times× 3卷积。注意最后一个卷积层同样步长为2,padding模式为VALID,因此最后输出的tensor尺寸为8 ×\times× 8 ×\times× 192;第3个分支则是一个3 ×\times× 3的最大池化层,步长为2,padding模式为VALID,而池化层不会对输出通道产生改变,因此这个分支的输出尺寸为8 ×\times× 8 ×\times× 768.最后,我们将3个分支在输出通道上合并,输出tensor的尺寸为8 ×\times× 8 ×\times× (320 + 192 + 768) = 8 ×\times× 8 ×\times× 1280.从这个Inception Module开始,输出图片的尺寸又被缩小了,同时通道数也增加了,tensor的总size在持续下降中。
#第3个Inception Module的第一个模块
            with tf.variable_scope('Mixed_7a'):
                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_1a_3x3')
                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')
                    branch_1 = slim.conv2d(branch_1, 192, [3, 3], stride=2, padding='VALID', scope='Conv2d_1a_3x3')
                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)
  1. 接下来是第3个Inception模块组的第二个Inception Module,它有4个分支。第一个分支是一个简单的320输出通道的1 ×\times× 1卷积;第二个分支先是1个384输出通道的1 ×\times× 1卷积,随后在分支内开了2个分支,这两个分支分别是384输出通道的1 ×\times× 3卷积核384输出通道的3 ×\times× 1卷积,然后使用tf.conca合并2个分支,得到的输出tensor的尺寸为8 ×\times× 8 ×\times× (384 + 384)=8 ×\times× 8 ×\times× 768;第3个分支更复杂,先是448输出通道的1 ×\times× 1卷积,然后是384输出通道的3 ×\times× 3卷积,然后同样在分支内拆成2个分支,分别是384输出通道的1 ×\times× 3卷积核384输出通道的3 ×\times× 3卷积,最后合并得到8 ×\times× 8 ×\times× 768的输出tensor;第4个分支是在一个3 ×\times× 3的平均池化层后接一个192输出通道的1 ×\times× 1卷积。最后,将这个非常复杂的Inception Module的4个分支合并在一起,得到的输出tensor的尺寸为8 ×\times× 8 ×\times× (320 + 768 + 768 + 192)=8 ×\times× 8 ×\times× 2048.到这个Inception Module,输出通道数从1280增加到了2048。
#第3个Inception Module的第二个模块
            with tf.variable_scope('Mixed_7b'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1')
                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)
                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')
                    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)

                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
  1. Mixed_7c是第3个Inception模块组的最后一个Inception Module,不过它和前面的Mixed_7b是完全一致的,输出tensor也是8 ×\times× 8 ×\times× 2048。最后,我们返回这个Inception Module的结果,作为inception_v3_base函数的最终输出。
第3个Inception Module的地三个模块
            with tf.variable_scope('Mixed_7c'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1')
                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)
                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')
                    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)

                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            return net, end_points
  1. 至此,Inception V3网络的核心部分,即卷积层部分就完成了。接下来我们来实现Inception V3网络的最后 一部分,全局平均池化,Softmax和Auxiliary Logits。先看函数inception_v3的输入参数,num_classes即最后需要分类的数量,这里默认的1000是ILSVRC比赛数据集的种类数;is_training标志是否是训练过程,对Batch Normalization和Dropout有影响,只有在训练时Batch Normalization和Dropout才会被启用;dropout_keep_prob即训练时Dropout所需保留节点的比例,默认为0.8;prediction_fn是最后用来分类的函数,这里默认是使用slim.softmax;spatial_squeeze参数标志是否对输出进行squeeze操作,即去除维数为1的维度。reuse标志是否会对网络和Variable进行重复使用;最后scope为包含了函数默认参数的环境。首先使用tf.variable_scope定义网络的name和reuse等参数的默认值,然后使用slim.arg_scope定义Batch Normalization和Dropout的is_training标志的默认值。最后,使用前面定义好的inception_v3_base构筑整个网络的卷积部分,拿到最后一层的输出net和重要节点的字典表end_points。
#定义一个inception_v3函数,实现全局平均池化,Softmax和Auxiliary Logits.
def inception_v3(inputs, num_classes=1000, is_training=True, dropout_keep_prob=0.8, prediction_fn=slim.softmax,
                 sptial_squeeze=True, reuse=None, scope='InceptionV3'):
    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. 接下来处理Auxiliary Logits这部分的逻辑,Auxiliary Logits作为辅助分类的节点,对分类结果预测有很大帮助。先使用slim.arg_scope将卷积,最大池化,平均池化的默认步长设为1,默认为padding模式为SAME。然后通过end_points取到Mixed_6e,并在Mixed_6e之后再接一个5 ×\times× 5的平均池化,步长为3,padding模式为VALID,这样输出的尺寸就从17 ×\times× 17 ×\times× 768变成5 ×\times× 5 ×\times× 768.接着连接一个128输出通道的1 ×\times× 1卷积核一个768输出通道的5 ×\times× 5卷积,这里权重初始化方式重设为标准差0.01的正态分布,padding模式设为VALID,输出尺寸变为1 ×\times× 1 ×\times× 768。然后再连接一个输出通道数为num_classes的1 ×\times× 1卷积,不设激活函数和规范化函数,权重初始化方式重设为标准差为0.001的正太分布,这样输出变为了1 ×\times× 1 ×\times× 1000,。接下啦,使用tf.squeeze函数消除输出tensor中前两个为1的维度。最后将辅助分类节点的输出aux_logits存储到字典表end_points中。
 #实现Auxiliary Logits这部分的逻辑
    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'):
            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 sptial_squeeze:
                aux_logits = tf.squeeze(aux_logits, [1, 2], name='SpatialSqueeze')
            end_points['Aux:ogits'] = aux_logits
  1. 下面处理正常的分类预测的逻辑。我们直接对Mixed_7e即最后一个卷积层的输出进行一个8 ×\times× 8全局平均池化,padding模式为VALID,这样输出tensor的尺寸就变为1 ×\times× 1 ×\times× 2048.然后连接一个Dropout层,节点保留率为dropout_keep_prob。接着连接一个输出通道为1000的1 ×\times× 1卷积,激活函数和规范化函数设为空。下面使用tf.squeeze去除输出tensor中维度为1的维度,再连接一个Softmax对结果进行分类预测。最后返回输出结果logits和包含辅助节点的end_points。
 #实现正常分类预测的逻辑
    with tf.variable_scope('Logits'):
        net = slim.avg_pool2d(net, [8, 8], padding='VALID', scope='AvgPool_1a_8x8')
        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 sptial_squeeze:
            logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
        end_points['Logits'] = logits
        end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
    return logits, end_points
  1. 至此,整个Inception V3网络的构建就完成了。Inception V3是一个非常复杂,精妙的模型,其中用到非常多之前积累下来的设计大型卷积网络的经验和技巧。不过,虽然Inception V3论文中给出了设计卷积网络的几个原则,但是其中很多超参数的选择,包括层数,卷积核的大小,池化的位置,步长的设置,factorization使用的时机,以及分支的设计,都很难一一解释。
    \quad下面对Inception V3进行运算性能测试。这里使用time_tensorflow_run函数。因为Inception V3网络结构大,所以令batch_size为32,以免显存不够用。图片尺寸设为299 ×\times× 299,并用tf.random.uniform生成随机图片作为input。接着,我们使用slim.arg_scope加载前面定义好的inception_v3_arg_scope(),在这个scope种包含了Batch Normalization的默认参数,以及激活函数和参数初始化方式的默认值。然后,在这个arg_scope下,调用inception_v3函数,并传入inputs,获取logits和end_points。下面创建Session并初始化全部模型参数。最后我们设置测试的batch数量为100,并使用time_tensorflow_run测试Inception V3网络的forward性能。
#定义AlexNet的每轮时间评估函数
def time_tensorflow_run(session, target, info_string):
    num_steps_burn_in = 10 #程序预热
    total_durations = 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:
            if not i % 10:
                print('%s: step %d, duration = %.3f'%(datetime.now(), i - num_steps_burn_in, duration))
            total_durations += duration
            total_duration_squared += duration * duration
    #计算每轮迭代的平均耗时和标准差sd,最后将结果显示出来
    mn = total_durations / 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(), info_string, num_batches, mn, sd))
#对Inception-V3 进行运算性能测试
batch_size = 32
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope(inception_v3_arg_scope()):
    logits, end_points = inception_v3(inputs, is_training=False)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
num_batches = 100
time_tensorflow_run(sess, logits, "Foward")

算法实现完整代码

#coding=utf-8
#Inception-V3.py
import tensorflow as tf
from datetime import datetime
import math
import time
slim = tf.contrib.slim
#产生截断的正太分布
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
#定义inception_v3_arg_scope,用来生成网络中经常用到的函数的默认参数
def inception_v3_arg_scope(weight_decay=0.00004, 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]
        }
    }
    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,
                            normalizer_fn=slim.batch_norm,
                            normalizer_params=batch_norm_params) as sc:
            return sc
#定义inception_v3_base生成Inception V3网络的卷积部分(Inception Module之前的卷积池化层)
def inception_v3_base(inputs, scope=None):
    end_points = {}
    with tf.variable_scope(scope, 'InceptionV3', [inputs]):
        with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='VALID'):
            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')
        #Inception Module
        with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='SAME'):
            # 第一个Inception Module的第一个模块
            with tf.variable_scope('Mixed_5b'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
                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')
                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')
                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            # 第一个Inception Module的第2个模块
            with tf.variable_scope('Mixed_5c'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
                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')
                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_1x1')
                    branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3')
                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            #第一个Inception Module的第3个模块
            with tf.variable_scope('Mixed_5d'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
                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')
                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')
                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            #第二个Inception Module的第一个模块
            with tf.variable_scope('Mixed_6a'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 384, [3, 3], stride=2, padding='VALID', scope='Conv2d_1a_1x1')
                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_1a_1x1')
                    branch_1 = slim.conv2d(branch_1, 96, [3, 3], stride=2, padding='VALID', scope='Conv2d_1b_1x1')
                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)
            #第二个Inception Module的第二个模块
            with tf.variable_scope('Mixed_6b'):
                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, 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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            #第二个Inception Module的第三个模块
            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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            #第而个Inception Module的第四个模块
            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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            #第二个Inception Module的第五个模块,且需要把Mixed_6e存储在end_points中,用于辅助模型的分类
            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, 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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            end_points['Mixed_6e'] = net
            #第3个Inception Module的第一个模块
            with tf.variable_scope('Mixed_7a'):
                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_1a_3x3')
                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')
                    branch_1 = slim.conv2d(branch_1, 192, [3, 3], stride=2, padding='VALID', scope='Conv2d_1a_3x3')
                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)
            #第3个Inception Module的第二个模块
            with tf.variable_scope('Mixed_7b'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1')
                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)
                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')
                    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)

                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            #第3个Inception Module的地三个模块
            with tf.variable_scope('Mixed_7c'):
                with tf.variable_scope('Branch_0'):
                    branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1')
                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)
                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')
                    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)

                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')
                net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
            return net, end_points
#定义一个inception_v3函数,实现全局平均池化,Softmax和Auxiliary Logits.
def inception_v3(inputs, num_classes=1000, is_training=True, dropout_keep_prob=0.8, prediction_fn=slim.softmax,
                 sptial_squeeze=True, reuse=None, scope='InceptionV3'):
    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)
    #实现Auxiliary Logits这部分的逻辑
    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'):
            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 sptial_squeeze:
                aux_logits = tf.squeeze(aux_logits, [1, 2], name='SpatialSqueeze')
            end_points['Aux:ogits'] = aux_logits
    #实现正常分类预测的逻辑
    with tf.variable_scope('Logits'):
        net = slim.avg_pool2d(net, [8, 8], padding='VALID', scope='AvgPool_1a_8x8')
        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 sptial_squeeze:
            logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
        end_points['Logits'] = logits
        end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
    return logits, end_points

#定义AlexNet的每轮时间评估函数
def time_tensorflow_run(session, target, info_string):
    num_steps_burn_in = 10 #程序预热
    total_durations = 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:
            if not i % 10:
                print('%s: step %d, duration = %.3f'%(datetime.now(), i - num_steps_burn_in, duration))
            total_durations += duration
            total_duration_squared += duration * duration
    #计算每轮迭代的平均耗时和标准差sd,最后将结果显示出来
    mn = total_durations / 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(), info_string, num_batches, mn, sd))
#对Inception-V3 进行运算性能测试
batch_size = 32
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope(inception_v3_arg_scope()):
    logits, end_points = inception_v3(inputs, is_training=False)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
num_batches = 100
time_tensorflow_run(sess, logits, "Foward")

inception-v1,v2,v3,v4----论文笔记 最近通读了inception的四篇论文,在此做一下笔记。先给出这四篇论文的地址:Going deeper with convolutions:https://arxiv.org/pdf/1409.4842.pdfBatch Normalization: https://arxiv.org/pdf/1502.03167.pdfRethinking the Inception Architecture... 阅读详情

相关推荐

从傅立叶变换到Gabor滤波器

作者:夏 敏 编辑:李文臣 PART 01 gabor介绍 gabor特征 首先我们介绍下Gabor 特征,它是一种可以用来描述图像纹理信息的特征,Gabor 滤波器的频率和方向与人类的视觉系统类似,特别适合于纹理表示与判别。它主要依靠 Gabor 核在频率域上对信号进行加窗,从而能描述信号的局部频率信息。 而Gabor

燕哥带你学算法 2131

[不定期更新长文]卷积神经网络工作原理研究

本人只是出于兴趣研究这个话题,本人并非学者,或者从业者,所以可能在写作中出现技术上的硬伤,请各位指正。 本文可能根据业界最新进展进行更新, 欢迎来评论中进行交流和研究。 本文所引用的资料将严格标明出处和版权。本文首发于简书平台,博客园和本人公众号,请勿转载 卷积神经网络在图像识别领域无限风光,通过一张图片,算法可以知道图片上的物体是什么,着实令人震惊,但是很多人和我一样,对于其背后的原理,都非常好...

weixin_34293902的博客 336

nvlddmkm事件ID14报错排查全指南:从找不到描述到显卡驱动崩溃

系统日志中的“无法找到描述”往往让人一头雾水,但这类提示其实隐藏着驱动故障的关键线索。Windows事件查看器通过事件源和ID记录系统异常,其中显卡驱动相关的内核模式驱动组件一旦超时失败,就会触发TDR机制,产生13、14、153等不同事件ID。理解这些ID的含义,比纠结“找不到描述”本身更重要。对于频繁出现的驱动崩溃问题,可以从日志频率和发生场景判断方向,再通过安全模式下彻底清理驱动、关闭冲突软件、检查供电和温度等步骤逐层定位。无论是游戏满载黑屏,还是睡眠唤醒后闪退,掌握NVIDIA驱动日志的解读逻辑,都

weixin_30545945的博客 401

tensorflow InceptionNet

tensorflow InceptionNet

qq_59631728的博客 270

python DEA: 基于非径向距离NDDF的Malmquist-Luenberger 指数及其分解

点赞发Nature 关注中Science Malmquist-Lenberger指数(ML指数)是距离函数与DEA计算中常用的指数,ML指数可以进一步分解为技术进步technological progress和效率改善effeciency change. 技术进步常被当做增长模型中的全要素生产率,用到许多计量经济研究中,探讨影响技术进步的环境变量。这里我分享一个考虑非期望产出下的NDDF方法计算ML指数。 该ML指数为global ML(区别于sequential ML) import numpy as

Cmmmmm丶的博客 5295

从理论到板级:FOC电机驱动硬件电路全链路设计解析

本文从硬件工程师视角,深度解析FOC电机驱动从理论到板级实现的全链路设计。重点剖析了电源保护、核心采样电路、三相逆变桥与驱动电路等关键硬件模块的设计要点与实战经验,强调硬件是FOC算法可靠运行的基石,并提供了PCB布局布线的核心原则,帮助开发者构建高性能、高可靠性的电机驱动硬件平台。

weixin_29240711的博客 331

DL with python(16)——tensorflow实现InceptionNet(GoogLeNet)

本文涉及到的是中国大学慕课《人工智能实践:Tensorflow笔记》第五讲第14,15节的内容,对tensorflow环境下几种经典卷积神经网络的搭建进行介绍,其基础是DL with python(14)——tensorflow实现CNN的“八股”中的代码,将其中第三步的代码替换为本文中的任意代码均可直接运行,其他部分无需改变。 经典的卷积神经网络有以下几种,这里介绍后面两种结构较为复杂的,实现的方法也相对困难。 InceptionNet InceptionNet 即 GoogLeNet,诞生于2014年

qq_36108664的博客 386

5分钟搞懂知识抽取:如何把非结构化数据变成知识图谱的宝藏?

本文通过一个电商评论分析实战案例,详细解析了如何利用spaCy、Neo4j等工具,将非结构化文本数据转化为结构化知识图谱的完整流程。文章重点阐述了知识抽取的核心步骤,包括命名实体识别、关系抽取以及知识存储与查询,帮助读者快速掌握将数据转化为知识宝藏的关键技术。

weixin_29054245的博客 233

Tensorflow实现Google Inception Net V3

Google Inception Net是一个大家族,包括Inception V1、Inception V2、Inception V3和Inception V4,而且都取得了不错的效果。 Inception V1 Inception V1有22层深,相比于AlexNet的8层和VGGNet的19层都要深,但是计算量却小了很多,只有AlexNet参数量的1...

Beans___Lee的博客 164

AutoLisp文件(.lsp)从编写到加载运行:一份给CAD新手的避坑指南

本文为CAD新手提供了一份AutoLisp文件(.lsp)从编写到加载运行的完整指南,涵盖编写环境配置、文件加载流程、调试技巧及工程化实践建议。通过详细的步骤和常见错误解决方案,帮助用户避免常见陷阱,提升AutoLisp脚本的开发效率和应用效果。

weixin_29228203的博客 890

Vscode搭配Keil Assistant插件,头文件红色波浪线终极修复指南

本文详细解析了Vscode搭配Keil Assistant插件时出现头文件红色波浪线问题的根源,即ARMCC与ARMCLANG编译器的兼容性问题,并提供了三种实用解决方案:复制文件夹、创建符号链接和手动配置includePath,帮助开发者彻底修复错误,恢复代码跳转和自动补全功能。

q1w3e5r7t9y的博客 351

使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)

使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow) 【尊重原创,转载请注明出处】https://blog.csdn.net/guyuealian/article/details/81560537 新增博客《使用自己的数据集训练MobileNet、ResNet图像识别(TensorFlow)》https://panjinquan.blo...

AI吃大瓜的博客 5万+

告别‘火龙’:实测BES2800/RK2108等主流芯片,聊聊AI眼镜的功耗与散热‘内卷’实战

本文深入探讨了AI智能眼镜在功耗与散热方面的挑战,重点分析了恒玄BES2800和瑞芯微RK2108等主控芯片的能效表现。通过实测数据和优化策略,揭示了在6nm工艺、异构计算和系统级散热方案下的实战经验,为AI眼镜的功耗管理提供了实用解决方案。

weixin_30839881的博客 945

TensorFlow实现Google Inception Net

一、InceptionNet介绍 Google Inception Net首次出现在ILSVRC 2014的比赛中,以较大的优势获得了第一名,那届比赛中的Inception Net通常被称为Inception V1,它最大的特点是控制了计算量和参数量的同时,获得了非常好的分类性能--top-5错误率6.67%。Inception V1有22层深,比AlexNet的8层或者VGGNet的19层还要...

励志的小胡子 571

YOLO11 Backbone改进:二值化、三值化权重实战(一)

本文介绍了二值化/三值化神经网络的基本概念、优势挑战及应用场景。二值化网络将权重限制为±1,三值化则增加0值,显著减少模型存储需求和计算复杂度。虽然存在精度下降等挑战,但通过技术改进已能在移动设备、自动驾驶等领域应用。文章分析了YOLO11中适合量化的层,并详细阐述了二值化权重原理及Straight-Through Estimator等关键技术。二值化/三值化神经网络为资源受限设备提供了高效的深度学习解决方案。

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 297

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

TensorFlow实战— —K-Means聚类

TensorFlow是Google最近开源的人工智能库。TensorFlow使用了data-flow graphs(DFG),如下图从图中可以看出,DFG是表示计算表达式的一种树形结构图。每个节点代表一个运算,非叶子节点是运算符,叶子节点是直接的值(确定的值或者不确定的值),箭头方向表示了不同节点间的依赖关系。TensorFlow目前提供两种API,Python和C++,目前只有Linux和MacO

Sin_Geek成长の迹 8104

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

TensorFlow 实现 Google Inception Net

TensorFlow 实现 Google Inception Net TensorFlow 实现 Google Inception Net Google Inception Net 首次出现在 ILSVRC 2014 的比赛中 ( 和VGGNet 同年 ),就以 较大优势取得 了第一名。那届比赛中的 Inception Net 通常被称为 Inception V1 ,...

lemontree232的博客 371

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Spatial transform network(STN)用于图像分类和图像识别

因为老板的另一个研究方向是文字识别(自然场景下的文字识别),故而会分享一些文字识别中performance很好的trick。在石葆光博士的http://www.vlrlab.net/admin/uploads/avatars/ASTER_An_Attentional_Scene_Text_Recognizer_with_Flexible_Rectification.pdf 将STN用于场景文字识...

WYXHAHAHA123的博客 1427

tensorflow实现inception Net数据增强

在CNN中,为了增大数据量避免模型的过拟合,通常都会对训练数据做数据增强处理,这篇文章主要介绍在Inception Net中是如何做数据增强的,tensorflow官方通过slim已经实现了VGG、Inception、LeNet网络的数据增强的,官网链接如下:https://github.com/tensorflow/models/tree/master/research/slim/preproc...

修炼之路 1905

关于小波变换和Gabor变换的一些知识

通过昨天的学术报告,觉得自己对这两个基本的概念还有些模糊,于是查询了相关的一些资料:1.关于小波变换:           一种多分辨率分析工具,为不同尺度上信号的的分析和表征提供了精确和统一框架。它的原理是来源于Fourier变换!但是它比传统的Fourier变换有更多优点,比如:1)小波变换可以覆盖整个频域;2)可以通过选取合适滤波器,减少或除去提取的不同特征之间的相关性;3)

Siny备忘录 1865

Alexnet详解以及tesnsorflow实现alexnet;什么是alexnet alexnet能做什么;alexnet教程

一、over roll archi Alexnet——2012年——标志性网络 该网络的亮点在于: (1)首次利用GPU进行网络加速训练。 (2)使用了ReLU激活函数,而不是传统的Sigmoid激活函数以及Tanh激活函数。(smoid求导比较麻烦而且当网路比较深的时候会出现梯度消失) (3)使用了LRN局部响应归一化。 (4)在全连接层的前两层中使用了Dropout随机失活神经元操作,以减少过拟合。 dropout解释:使用dropout后,在每一层中随机失活一些神经元——减少训练参数从而减少over

点赞的都能无bug通过! 9315

tensorflow 文档 inception_v3 解读

文档地址: https://github.com/tensorflow/models/blob/master/research/slim/nets/inception_v3.py # Copyright 2016 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Versio...

朱小丰的博客 1019

Gabor学习笔记

本文根据博客http://blog.csdn.net/watkinsong/article/details/7870996 ,博客http://www.cnblogs.com/yingying0907/archive/2012/11/22/2781945.html整理。   1.傅里叶变换 1) 简介 数字图像处理的方法主要分成两大部分:空域分析法和频域分析法。空域分析法就是对图像矩阵进行...

weixin_34064653的博客 1344

TensorFlow 人脸识别

TensorFlow 人脸识别 以下资料来源于极客时间学习资料 人脸识别问题概述 人脸识别概述   人脸识别,特指利用分析比较人脸视觉特征信息进行身份鉴别的计算机技术。 广义的人脸识别实际包括构建人脸识别系统的一系列相关技术,包括人脸图像采集、 人脸定位、人脸识别 预处理、身份确认以及身份查找等;而狭义的人脸识别特指 通过人脸进行身份确认或者身份查找的技术或 系...

weixin_30836759的博客 1373
上一篇: Tensorflow实战7:Tensorflow实现VGGNet
下一篇: OpenCV图像处理专栏一 | 盘点常见颜色空间互转
just_sort
博客等级 码龄11年 2356粉丝 1667原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值