1. 程式人生 > >tensorflow實現 Inception V3

tensorflow實現 Inception V3

架構

輸入影象尺寸: 299x299x3 卷積1: 3x3/2

輸入影象尺寸: 149x149x32 卷積2: 3x3/1

輸入影象尺寸: 147x147x32 卷積3: 3x3/1

輸入影象尺寸: 147x147x64 池化1: 3x3/2

輸入影象尺寸: 73x73x64 卷積4: 3x3/1

輸入影象尺寸: 71x71x80 卷積5: 3x3/2

輸入影象尺寸: 35x35x192 卷積5: 3x3/1

Inception 模組組:

輸入影象尺寸: 35x35x192,

3個Inception module (strides=1, 且Padding=SAME,所以輸出大小不變,只是通道個數發生變化) 輸出影象尺寸: 35x35x288,

5個Inception module , 輸出影象尺寸: 17x17x768

3個Inception module, 輸出影象尺寸: 8x8x1280

池化2:8x8 輸出影象尺寸:1x1x2048

softmax 輸出影象尺寸:1x1x1000

# 首先定義一個簡單(lambda)的函式,來產生截斷的正態分佈
import tensorflow as tf
import tensorflow.contrib.slim as slim

trunce_normal = lambda stddev: tf.trucated_normal_initializer(0.0, stddev)
# lambda 函式
# g = lambda x:x+1 # 呼叫:g(1) -- > 2

由於inception中有很多引數值相同,因此用slim中的arg_scope來設定一些常用預設值。(卷積的啟用函式、權重初始化方式、標準化方式等)

def inception_v3_arg_scope(weight_decay=0.00004, stddev=0.1, batch_norm_var_collction='moving_vars'):
    #  weight_decay :   學習率  stddev 權重初始化標準差
    #  batch_nrm_var_collction: 
    #  定義BN的一些引數
batch_norm_params={ 'decay': 0.9997, # 'epsilon': 0.001, 'updates_collections': tf.GrapKeys.UPDATE_OPS, 'variables_colleaction':{ '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=trunce_normal(stddev), activation_fn=tf.nn.relu, normalizer_fn=slim.batch_norm, normalizer_params=batch_norm_params) as sc: return sc # 事先定義好卷積需要的各種引數,後面就可以只需要一行就可以建立一個卷積層
# 接下來搭建InceptionV3的網路

def inception_v3_base(inputs, scope=None): # 輸入299×299×3
    # scope: 包含了函式預設的引數環境
    end_point = {} # 用來儲存某些關鍵節點供之後使用
    # tf.variable_scope(name_or_scope,default_name=None,values=None,
    #                   initializer=None,regularizer=None,caching_device=None,partitioner=None)
    with tf.variable_scope(scope, 'InceptionV3',[inputs]): 
        with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding="VALID"):
            # valid : (w-f)/s +1
            net = slim.conv2d(inputs, 32, [3,3], stride=2, scope='conv2d_1a_3x3') #  (299-3)/2+1=149  149×149×32
            net = slim.conv2d(net, 32, [3,3], scope='conv2d_2a_3x3') # (149-3)/1+1 = 147  147*147*32
            net = slim.conv2d(net, 64, [3,3], padding="SAME", scope='conv2d_2b_3x3') # 147/1  147*147*64
            net = slim.max_pool2d(net, [3,3], stride=2, scope="Maxpool_3d_3x3") # (147-3)/2+1=73 73*73*64
            net = slim.conv2d(net, 80, [3,3],scope='conv2d_3b_1x1') # (73-3)/1+1 =71 71*71*80
            net = slim.conv2d(net, 192, [3,3], stride=2, scope='conv2d_4a_3x3') # (71-3)/2+1=35 35*35*192
            net = sim.max_pool2d(net, [3,3], padding="SAME", scope='Maxpool_5a_3x3') # 35/1=35  35*35*192
            # 完成了前部的幾個卷積層

    # 下面開始搭建Incepyion模組組。

    with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding="SAME"):
        # SAME: w/s

        # 第一個模組組中的第一個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') # 輸入35×35×192, 輸出 35×35×64
            with tf.variable_scope('Beanch_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') # 35/1 輸出35×35×64
            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') # 輸出35×35×96
            with tf.variable_scope('Branch_3'): # 第四個分支
                branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') # 35*35*192
                branch_3 = slim.conv2d(branch_3, 32, [1, 1], scope='conv2d_0b_1x1') # 35*35*32

            # 進行輸出在channel上的連線
            #  注: 新版的tf.concat的維度是放在前面,後面是要連線的tensor
            # 最終輸出35×35×(64+64+96+32) = 35×35×256
            net = tf.concat(3, [branch_0, branch_1, branch_2, branch_3])

        #上面完成了第一個Inception模組組的中的第一個,接下來搭建第二個
        # 與第一個一樣也是4個分支,唯一不同的是 最後一個分支由32個1x1換成64個
        with tf.variable_scope('Mixed_5c'):
            with tf.variable_scope('Branch_0'): # 第一個分支
                branch_0 = slim.conv2d(net, 64, [1, 1], scope='conv2d_0a_1x1') # 輸入35×35×192, 輸出 35×35×64
            with tf.variable_scope('Beanch_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') # 35/1 輸出35×35×64
            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') # 輸出35×35×96
            with tf.variable_scope('Branch_3'): # 第四個分支
                branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') # 35*35*192
                branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='conv2d_0b_1x1') # 35*35*64
            # 最終輸出35×35×(64+64+96+64) = 35×35×288
            net = tf.concat(3, [branch_0, branch_1, branch_2, branch_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') # 輸入35×35×192, 輸出 35×35×64
            with tf.variable_scope('Beanch_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') # 35/1 輸出35×35×64
            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') # 輸出35×35×96
            with tf.variable_scope('Branch_3'): # 第四個分支
                branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3') # 35*35*192
                branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='conv2d_0b_1x1') # 35*35*64
            # 最終輸出35×35×(64+64+96+64) = 35×35×288
            net = tf.concat(3, [branch_0, branch_1, branch_2, branch_3])

        # 開始搭建第二個模組組(共有5個module), 並且第二個到第5個完全相同。 每個module共有3個分支

        # 第一個module的架構
        # 第一個: [email protected]卷積,並且步長為2,padding為VALID,因此輸出 壓縮為 (35-3)/2+1=17
        # 第二個分支: 有3層。分別是[email protected]×1和兩個[email protected]×3 (最後一層s=2 VALID,壓縮大小)
        # 第三個分支: max_pool層 (s=2, VALID)      
        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') # 輸出17×17×384
            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')
                branch_1 = slim.conv2d(branch_1, 96, [3, 3], stride=2, padding="VALID", scope='conv2d_1a_1x1') # 17×17×96
            with tf.variable_scope('Branch_2'):
                branch_2 = slim.max_pool2d(net, [3,3], stride=2, padding="VALID", scope='maxPool_1a_3x3') # 輸出 17×17×288
            net = tf.concat(3, [branch_0, branch_1, branch_2]) # 17×17×(384+96+288) = 17×17×768

        # 第2-5個module
        # 共有4個分支,利用到了“非平均卷積”的操作,為Inceptiop V3的核心 
        # 第一個分支:簡單的 [email protected]×1 卷積
        # 第二個分支: 共包含3層: [email protected]×1 -- [email protected]×7 -- [email protected]×1 (非對稱,減少了引數和過擬合,同時多了一個啟用函式層增加了非線性特徵變換)
        # 第三個分支:5層 :  [email protected]×1 -- [email protected]×1-- [email protected]×7 -- [email protected]×1 -- [email protected]×7
        # 第四個分支: 3×3平均池化[email protected]×1
        with tf.variable_scope('Mixed_6b'):  # 預設stride=1,SAME
            with tf.variable_scope('Branch_0'):
                branch_0 = slim.conv2d(net, 192, [1, 1], scope='conv2d_0a_1x1') # 輸入17×17×768  -輸出: 17×17×192
            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_1x7')
            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_1x1')
                branch_2 = slim.conv2d(branch_2, 128, [1, 7], scope='conv2d_0c_1x1')
                branch_2 = slim.conv2d(branch_2, 128, [7, 1], scope='conv2d_0d_1x1')
                branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='conv2d_0e_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, 192, [1, 1], scope='conv2d_0b_1x1')
            net = tf.concat(3, [branch_0, branch_1, branch_2, branch_3]) # 17*17*(192+12+192+192) = 17*17*768
        # 第3個module中,基本和第二個相同,自由在第二個分支和第3分支中前幾個卷積輸出通道數由128變為160
        with tf.variable_scope('Mixed_6c'):  # 預設stride=1,SAME
            with tf.variable_scope('Branch_0'):
                branch_0 = slim.conv2d(net, 192, [1, 1], scope='conv2d_0a_1x1') # 輸入17×17×768  -輸出: 17×17×192
            with tf.variable_scope('Branch_1'):
                branch_1 = slim.conv2d(net, 160, [1, 1], scope='conv2d_0a_1x1')
                branch_1 = slim.conv2d(branch_1, 1260, [1, 7], scope='conv2d_0b_1x7') # 
                branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='conv2d_0c_1x7')
            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_1x1')
                branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='conv2d_0c_1x1')
                branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='conv2d_0d_1x1')
                branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='conv2d_0e_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, 192, [1, 1], scope='conv2d_0b_1x1')
            net = tf.concat(3, [branch_0, branch_1, branch_2, branch_3]) # 17*17*(192+12+192+192) = 17*17*768
        # 第4個module
        with tf.variable_scope('Mixed_6d'):  # 預設stride=1,SAME
            with tf.variable_scope('Branch_0'):
                branch_0 = slim.conv2d(net, 192, [1, 1], scope='conv2d_0a_1x1') # 輸入17×17×768  -輸出: 17×17×192
            with tf.variable_scope('Branch_1'):
                branch_1 = slim.conv2d(net, 160, [1, 1], scope='conv2d_0a_1x1')
                branch_1 = slim.conv2d(branch_1, 1260, [1, 7], scope='conv2d_0b_1x7') # 
                branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='conv2d_0c_1x7')
            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_1x1')
                branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='conv2d_0c_1x1')
                branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='conv2d_0d_1x1')
                branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='conv2d_0e_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, 192, [1, 1], scope='conv2d_0b_1x1')
            net = tf.concat(3, [branch_0, branch_1, branch_2, branch_3]) # 17*17*(192+12+192+192) = 17*17*768
        # 第5個
        # 將該mudule的輸出儲存下來,組網額Auxiliary Classifier輔助模型的分類
        with tf.variable_scope('Mixed_6e'):  # 預設stride=1,SAME
            with tf.variable_scope('Branch_0'):
                branch_0 = slim.conv2d(net, 192, [1, 1], scope='conv2d_0a_1x1') # 輸入17×17×768  -輸出: 17×17×192
            with tf.variable_scope('Branch_1'):
                branch_1 = slim.conv2d(net, 160, [1, 1], scope='conv2d_0a_1x1')
                branch_1 = slim.conv2d(branch_1, 1260, [1, 7], scope='conv2d_0b_1x7') # 
                branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='conv2d_0c_1x7')
            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_1x1')
                branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='conv2d_0c_1x1')
                branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='conv2d_0d_1x1')
                branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='conv2d_0e_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, 192, [1, 1], scope='conv2d_0b_1x1')
            net = tf.concat(3, [branch_0, branch_1, branch_2, branch_3]) # 17*17*(192+12+192+192) = 17*17*768
            # 
            end_points['Mixed_6e'] = net

        # 第三個Inception 模組組,包含3個module
        # 第一個module:一共三個分支 
            # 第一個分支為 [email protected]×1 接著為 [email protected]×3(s=2,VALID 壓縮圖片),
            # 第二個分支:(4個卷積層) [email protected] -- [email protected] [email protected] -- [email protected](s=2 VALID 壓縮圖片)
            # 第三個分支:3x3最大池化層 s=2 VALID
        # 圖片大小不斷減小,通道數增加
        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.con2d(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(3, [branch_0, branch_1, branch_2]) # 8*8*(320+192+768) = 8*8*1280

        # 第二個module
        # 四個分支
            # 第一個分支:[email protected]卷積
            # 第二個分支:[email protected]的卷積,然後分為兩個分支(1: [email protected] 2 : [email protected]) concat後得到384+384=768個通道
            # 第三個分支:[email protected] -- [email protected] -- 兩個分支(1: [email protected] 2 : [email protected]))
            # 第四個分支:3x3池化層,後接一個[email protected]的卷積
        with tf.variable_scope('Mixed_7b'): # 預設stride=1,SAME
            with tf.variable_scope('Branch_0'):
                brach_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(3, [
                    slim.conv2d(branch_1, 384, [1, 3], scope='conv2d_0b_1x3'),
                    slim.conv2d(branch_1, 384, [3,1], scope='conv2d_0b_3x1')
                ])
            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_1x1')
                branch_2 = tf.concat(3, [
                    slim.conv2d(branch_1, 384, [1, 3], scope='conv2d_0c_1x3'),
                    slim.conv2d(branch_1, 384, [3,1], scope='conv2d_0d_3x1')
                ])
            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(3, [branch_0, branch_1, branch_2, branch_3]) # 8*8*(320+768+768+192) = 8*8*2048

            # 第三個module 與前面一致

        with tf.variable_scope('Mixed_7c'): # 預設stride=1,SAME
            with tf.variable_scope('Branch_0'):
                brach_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(3, [
                    slim.conv2d(branch_1, 384, [1, 3], scope='conv2d_0b_1x3'),
                    slim.conv2d(branch_1, 384, [3,1], scope='conv2d_0b_3x1')
                ])
            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_1x1')
                branch_2 = tf.concat(3, [
                    slim.conv2d(branch_1, 384, [1, 3], scope='conv2d_0c_1x3'),
                    slim.conv2d(branch_1, 384, [3,1], scope='conv2d_0d_3x1')
                ])
            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(3, [branch_0, branch_1, branch_2, branch_3]) # 8*8*(320+768+768+192) = 8*8*2048

        return net, end_points                    

分析:

首先是5個卷積層和兩個池化層交替的普通結構,然後是3個Inception模組組,每個模組組中包含多個Inception module。

經過這些層,圖片大小是逐漸縮小的,通道數持續增加。每一層卷積、池化或者Inception module將空間結構簡化,同時將空間資訊轉化為高階抽象的特徵資訊(將空間維度轉換為通道維度)

Inception Module一般有四個分支:
1: 一般是1×1的卷積
2:一般是1×1卷積後在分解為1×n和n×1的卷積
3: 和2類似,但是層數更多一點
4:一般是最大或者平均池化層

因此,Inception module是通過組合簡單的特徵抽象(分支1)、比較複雜的特徵抽象(分支2、3)以及簡化結構的池化層、有選擇的保留不同層次的高階特徵,這樣可以最大程度豐富網路的表達能力。

Inception V3還有全域性平均池化、Auxliliry logits 和softmax層

# 定義一個函式來實現這些層
def inception_v3(inputs, num_classes=1000, is_training=True, dropout_keep_prob=0.8, prefiction_fn=slim.softmax,
                spatial_squeeze=True, reuse=None, scope='InceptionV3'):
    """
    inputs: 輸入的影象(299×299×3)
    num_classes: 類別數
    is_training:只有在訓練時需要dropout和BN
    predction_fn:進行分類的函式
    spatial_squeeze: 是否對輸出進行squeeze操作(注1)
    reuse: 是否對網路和Variable進行重複利用
    """

    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部分,
        # 對endpoints中MIxed_6e的輸出net,先5*5的平均池化(s=3, VALID,縮小尺寸),
        # 然後[email protected]×1和[email protected]×5的卷積,(VALID),輸出1×1×768
        # 最後通過[email protected]的卷積得到最終類別的概率。並儲存起來
        with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding="SAME"):
            aux_logits = endpoints['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') # 輸出1×1×768
                aux_logits = slim.conv2d(aux_logits, nm_classes, [1,1], activation_fn=None,
                                         weights_initializer=trunc_normal(0.01),
                                         padding="VALID", scope='conv2d_2b_1x1') # 輸出1×1×num_classes

                if spatial_squeeze:
                    aux_logits = tf.squeeze(aux_logits, [1, 2], name='SpatialSqueeze')  # 注2
                end_points["AuxLogits"] = aux_logits

            # 下面處理正常的分類預測邏輯logits
            with tf.variable_scope("Logits"):
                # 對Mixed_7e(z最後一層的輸出)進行平均池化
                net = slim.avg_pool2d(net, [8, 8], padding="VALID", scope="AvgPool_1a_8x8") # 1*1*2048
                # dropout
                net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')

                end_points['prelogits'] = net 

                logits = slim.conv2d(aux_logits, nm_classes, [1,1], activation_fn=None, normalizer_fn=None, 
                                     scope='conv2d_1c_1x1')
                if spatial_squeeze:
                    logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')

                end_points['Logits'] = logits
                end_points['Predictions'] = prediction_fn(logits, scope='Predictions') # softmax

            return logits, end_points

注1:

squeeze操作:去除維度為1的維度,比如5×3×1 –>> 5×3

注2:

給定張量輸入,此操作返回相同型別的張量,並刪除所有尺寸為1的尺寸。 如果不想刪除所有尺寸1尺寸,可以通過指定squeeze_dims來刪除特定尺寸1尺寸。

‘t’ is a tensor of shape [1, 2, 1, 3, 1, 1]
shape(squeeze(t)) ==> [2, 3]

Or, to remove specific size 1 dimensions:

‘t’ is a tensor of shape [1, 2, 1, 3, 1, 1]
shape(squeeze(t, [2, 4])) ==> [1, 2, 3, 1]

至此,我們已經降Inception V3的網路構建完成。其模型非常複雜,其中用到了很多涉及大型網路的經驗和技巧:

(1)“卷積分解”很有效,可以降低引數、減輕過擬合、增加網路非線性的表達能力

(2)卷積網路從輸入到輸出、應該讓圖片尺寸逐漸減小,輸出通道數逐漸增加,讓空間結構簡化,將空間資訊轉化為高階抽象的特徵資訊

(3)Inception Module用多個分支提取不同抽象程度的高階特徵的思路很有效,可以豐富網路的表達能力。

引數量:

Inception V1: 700萬 (22層)

Inception V3: 2500萬 (42層)

AlexNet : 6000萬 (8層)

VGGNet:1.4億(16/19層)

相關推薦

tensorflow實現 Inception V3

架構 輸入影象尺寸: 299x299x3 卷積1: 3x3/2 輸入影象尺寸: 149x149x32 卷積2: 3x3/1 輸入影象尺寸: 147x147x32 卷積3: 3x3/1 輸入影象尺寸: 147x147x64 池化1: 3x3/2

tensorflow利用Inception-v3實現遷移學習

1、Tensorflow 實現遷移學習。 #photo地址: #http://download.tensorflow.org/example_images/flower_photos.tgz #Inception-v3模型 #https://storage.googleapi

tensorflow實現inception Net資料增強

在CNN中,為了增大資料量避免模型的過擬合,通常都會對訓練資料做資料增強處理,這篇文章主要介紹在Inception Net中是如何做資料增強的,tensorflow官方通過slim已經實現了VGG、Inception、LeNet網路的資料增強的,官網連結如下:https://github.com

Tensorflow— 使用inception-v3做各種影象的識別

程式碼:import tensorflow as tf import os import numpy as np import re from PIL import Image import matplotlib.pyplot as plt程式碼:class NodeLook

【膜拜大神】Tensorflow實現YOLO v3(TF-Slim)

最近我一直在使用Tensorflow中的YOLO v3。我在GitHub上找不到任何適合我需要的實現,因此我決定將這個用PyTorch編寫的程式碼轉換為Tensorflow。與論文一起釋出的YOLO v3的原始配置可以在Darknet GitHub repo中找到。 我

TensorFlow入門-Inception(v3)影象識別

Inception-v3是最新的一個模型,在ImageNet-2012上訓練進行分類。 與其他網路對比 AlexNet achieved by setting a top-5 error rate of 15.3% on the 2012 validat

【深度學習系列】用PaddlePaddle和Tensorflow實現GoogLeNet InceptionV2/V3/V4

targe 所有 conn ride 出了 prev 縮減 tro 例如   上一篇文章我們引出了GoogLeNet InceptionV1的網絡結構,這篇文章中我們會詳細講到Inception V2/V3/V4的發展歷程以及它們的網絡結構和亮點。 GoogLeNet I

運用java 呼叫tensorflow中的inception v3模型

首先使用maven新增依賴項: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3

tensorflow-Inception-v3模型訓練自己的資料程式碼示例

一、宣告   本程式碼非原創,源網址不詳,僅做學習參考。 二、程式碼   1 # -*- coding: utf-8 -*- 2 3 import glob # 返回一個包含有匹配檔案/目錄的陣列 4 import os.path 5 import rand

Tensorflow使用Inception思想實現CIFAR-10十分類demo

使用Inception思想實現一個簡單的CIFAR-10十分類.最主要的是領會Inception的結構. Inception結構圖如下: 思想:   分別使用1*1,3*3,5*5卷積核和一個3*3最大池化層對上一層進行處理,然後將輸入進行合併.  

SE-Inception v3架構的模型搭建(keras程式碼實現

首先,先上SENet架構的原理圖: 圖是將SE模組嵌入到Inception結構的一個示例。方框旁邊的維度資訊代表該層的輸出。這裡我們使用global average pooling作為Squeeze操作。緊接著兩個Fully Connected 層組成一個Bottlen

深度學習框架Tensorflow學習與應用(八 儲存和載入模型,使用Google的影象識別網路inception-v3進行影象識別)

一 模型的儲存 [email protected]:~/tensorflow$ cat 8-1saver_save.py # coding: utf-8 # In[1]: import tensorflow as tf from tensorflow.examples.tutorials

tensorRt加速tensorflow模型推理(inception V3為例)

摘要 在一個人工智慧大爆發的時代,一個企業不來點人工智慧都不好意思說自己是科技企業。隨著各公司在各自領域資料量的積累,以及深度學習的強擬合特點,各個公司都會訓練出屬於自己的模型,那麼問題就來了,你有模型,我也有模型,那還比什麼?對,就是速度,誰的速度快,誰就厲害。 引言 te

TensorFlow實現Google InceptionNet V3(forward耗時檢測)

Google InceptionNet-V3網路結構圖: Inception V3網路結構圖: 型別 kernel尺寸/步長(或註釋) 輸入尺寸 卷積 3*3 / 2 299 * 299 * 3 卷積 3*3

TensorFlow 深度學習框架(9)-- 經典卷積網路模型 : LeNet-5 模型 & Inception-v3 模型

LeNet -5 模型LeNet-5 模型總共有 7 層,以數字識別為例,圖展示了 LeNet-5 模型的架構第一層,卷積層這一層的輸入就是原始的影象畫素,LeNet-5 模型接受的輸入層大小為 32*32*1 。第一個卷積層過濾器的尺寸為 5 * 5,深度為 6,步長為 1

Tensorflow 卷積神經網路 Inception-v3模型 遷移學習 花朵識別

 Inception-v3模型結構:Inception-v3簡介:1.基於大濾波器尺寸分解卷積在視覺網路中,預期相近啟用的輸出是高度相關的。因此,我們可以預期,它們的啟用可以在聚合之前被減少,並且這應該會導致類似的富有表現力的區域性表示。全卷積網路 減少計算可以提高效率2.分

Tensorflow學習筆記--使用遷移學習做自己的影象分類器(Inception v3

本文主要使用inception v3的模型,再後面接一個softmax,做一個分類器。具體程式碼都是參照tf github。 整體步驟: 步驟一:資料準備,準備自己要分類的圖片訓練樣本。 步驟二:retrain.py 程式,用於下載inception v3模型及訓練後面的

Tensorflow例項分析Google Inception v3 網路

本文直接從Inception v3的程式碼實現入手,分析其中值得借鑑的思想 首先要知道一個slim的元件,可以給引數自動賦值,可以省去很多操作 def inception_arg_scope(weight_decay=0.00004,

Tensorflow載入goodle的inception-v3模型

import tensorflow as tf import os import tarfile import requests # inception模型下載地址 inception_pretrai

機器學習與Tensorflow(7)——tf.train.Saver()、inception-v3的應用

1. tf.train.Saver() tf.train.Saver()是一個類,提供了變數、模型(也稱圖Graph)的儲存和恢復模型方法。 TensorFlow是通過構造Graph的方式進行深度學習,任何操作(如卷積、池化等)都需要operator,儲存和恢復操作也不例外。 在tf.trai