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