Tensorflow slim模塊

最近在看tf-faster-rcnn的代碼,看到了VGG16網絡的定義中使用到了slim這個模塊,如下圖所示,因此百度了一下slim這個模塊,下面的內容是基于一些博客按照自己的思路整理的,便于理解和日后查用。


VGG16.jpeg

slim這個模塊是在16年新推出的,主要是來做所謂的“代碼瘦身”, 可以消除原生tensorflow里面很多重復的模板性的代碼,讓代碼更緊湊,更具備可讀性。另外slim提供了很多計算機視覺方面的著名模型(VGG, ResNet等),我們可以直接下載使用(checkpoint,即 .ckpt文件)。


Pre-trained Models.jpeg
slim被放在tensorflow.contrib這個庫下面,導入的方法如下:
import tensorflow.contrib.slim as slim

下面分別介紹slim的代碼瘦身功能和slim中一些常用函數。

一、代碼瘦身功能:

1、首先讓我們看看tensorflow怎么實現一個層,例如卷積層:

input = ...
with tf.name_scope('conv1_1') as scope:
  kernel = tf.Variable(tf.truncated_normal([3, 3, 64, 128], dtype=tf.float32,
                                           stddev=1e-1), name='weights')
  conv = tf.nn.conv2d(input, kernel, [1, 1, 1, 1], padding='SAME')
  biases = tf.Variable(tf.constant(0.0, shape=[128], dtype=tf.float32),
                       trainable=True, name='biases')
  bias = tf.nn.bias_add(conv, biases)
  conv1 = tf.nn.relu(bias, name=scope)

然后slim的實現:

input = ...
net = slim.conv2d(input, 128, [3, 3], scope='conv1_1')

2、repeat操作
假設在tensorflow中定義三個相同的卷積層:

net = ...
net = slim.conv2d(net, 256, [3, 3], scope='conv3_1')
net = slim.conv2d(net, 256, [3, 3], scope='conv3_2')
net = slim.conv2d(net, 256, [3, 3], scope='conv3_3')
net = slim.max_pool2d(net, [2, 2], scope='pool2')

在slim中的repeat操作:

net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3')
net = slim.max_pool2d(net, [2, 2], scope='pool2')

3、stack操作:處理卷積核或者輸出不一樣的情況
假設在tensorflow中定義三層FC:

x = slim.fully_connected(x, 32, scope='fc/fc_1')
x = slim.fully_connected(x, 64, scope='fc/fc_2')
x = slim.fully_connected(x, 128, scope='fc/fc_3')

在slim中的stack操作:

slim.stack(x, slim.fully_connected, [32, 64, 128], scope='fc')

同理卷積層也一樣:

# 普通方法:
x = slim.conv2d(x, 32, [3, 3], scope='core/core_1')
x = slim.conv2d(x, 32, [1, 1], scope='core/core_2')
x = slim.conv2d(x, 64, [3, 3], scope='core/core_3')
x = slim.conv2d(x, 64, [1, 1], scope='core/core_4')
 
# 簡便方法:
slim.stack(x, slim.conv2d, [(32, [3, 3]), (32, [1, 1]), (64, [3, 3]), (64, [1, 1])], scope='core')

4、slim中的argscope:如果網絡有大量相同的參數,如下:

net = slim.conv2d(inputs, 64, [11, 11], 4, padding='SAME',
                  weights_initializer=tf.truncated_normal_initializer(stddev=0.01),
                  weights_regularizer=slim.l2_regularizer(0.0005), scope='conv1')
net = slim.conv2d(net, 128, [11, 11], padding='VALID',
                  weights_initializer=tf.truncated_normal_initializer(stddev=0.01),
                  weights_regularizer=slim.l2_regularizer(0.0005), scope='conv2')
net = slim.conv2d(net, 256, [11, 11], padding='SAME',
                  weights_initializer=tf.truncated_normal_initializer(stddev=0.01),
                  weights_regularizer=slim.l2_regularizer(0.0005), scope='conv3')

然后用arg_scope處理一下:

with slim.arg_scope([slim.conv2d], padding='SAME',
                      weights_initializer=tf.truncated_normal_initializer(stddev=0.01)
                      weights_regularizer=slim.l2_regularizer(0.0005)):
    net = slim.conv2d(inputs, 64, [11, 11], scope='conv1')
    net = slim.conv2d(net, 128, [11, 11], padding='VALID', scope='conv2')
    net = slim.conv2d(net, 256, [11, 11], scope='conv3')

Tips:arg_scope的作用范圍內,定義了指定層的默認參數,若想特別指定某些層的參數,可以重新賦值(相當于重寫),如上倒數第二行代碼。那如果除了卷積層還有其他層呢?那就要如下定義:

with slim.arg_scope([slim.conv2d, slim.fully_connected],
                      activation_fn=tf.nn.relu,
                      weights_initializer=tf.truncated_normal_initializer(stddev=0.01),
                      weights_regularizer=slim.l2_regularizer(0.0005)):
  with slim.arg_scope([slim.conv2d], stride=1, padding='SAME'):
    net = slim.conv2d(inputs, 64, [11, 11], 4, padding='VALID', scope='conv1')
    net = slim.conv2d(net, 256, [5, 5],
                      weights_initializer=tf.truncated_normal_initializer(stddev=0.03),
                      scope='conv2')
    net = slim.fully_connected(net, 1000, activation_fn=None, scope=

寫兩個arg_scope就行了。

基于以上的“瘦身”后,定義一個VGG16,二十來行代碼就搞定了。

def vgg16(inputs):
  with slim.arg_scope([slim.conv2d, slim.fully_connected],
                      activation_fn=tf.nn.relu,
                      weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
                      weights_regularizer=slim.l2_regularizer(0.0005)):
    net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1')
    net = slim.max_pool2d(net, [2, 2], scope='pool1')
    net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2')
    net = slim.max_pool2d(net, [2, 2], scope='pool2')
    net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3')
    net = slim.max_pool2d(net, [2, 2], scope='pool3')
    net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv4')
    net = slim.max_pool2d(net, [2, 2], scope='pool4')
    net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv5')
    net = slim.max_pool2d(net, [2, 2], scope='pool5')
    net = slim.fully_connected(net, 4096, scope='fc6')
    net = slim.dropout(net, 0.5, scope='dropout6')
    net = slim.fully_connected(net, 4096, scope='fc7')
    net = slim.dropout(net, 0.5, scope='dropout7')
    net = slim.fully_connected(net, 1000, activation_fn=None, scope='fc8')
  return net

二、常用函數:
1、slim.arg_scope: slim.arg_scope: 可以定義一些函數的默認參數值,在scope內,我們重復用到這些函數時可以不用把所有參數都寫一遍。

with slim.arg_scope([slim.conv2d, slim.fully_connected], 
                    trainable=True,
                    activation_fn=tf.nn.relu, 
                    weights_initializer=tf.truncated_normal_initializer(stddev=0.01), 
                    weights_regularizer=slim.l2_regularizer(0.0001)):
    with slim.arg_scope([slim.conv2d], 
                        kernel_size=[3, 3], 
                        padding='SAME',
                        normalizer_fn=slim.batch_norm):
        net = slim.conv2d(net, 64, scope='conv1'))
        net = slim.conv2d(net, 128, scope='conv2'))
        net = slim.conv2d(net, 256, [5, 5], scope='conv3'))

slim.arg_scope的用法基本都體現在上面了。一個slim.arg_scope內可以用list來同時定義多個函數的默認參數(前提是這些函數都有這些參數),另外,slim.arg_scope也允許相互嵌套。在其中調用的函數,可以不用重復寫一些參數(例如kernel_size=[3, 3]),但也允許覆蓋(例如最后一行,卷積核大小為[5,5])。
2、slim.cov2d: 卷積層,一般調用方法如下:

net = slim.conv2d(inputs, 256, [3, 3], stride=1, scope='conv1_1')

前三個參數依次為網絡的輸入,輸出的通道,卷積核大小,stride是做卷積時的步長。除此之外,還有幾個經常被用到的參數:

padding : 補零的方式,例如'SAME'
activation_fn : 激活函數,默認是nn.relu, VGG16中就用的是ReLU
normalizer_fn : 正則化函數,默認為None,這里可以設置為batch normalization,函數用slim.batch_norm
normalizer_params : slim.batch_norm中的參數,以字典形式表示
weights_initializer : 權重的初始化器,initializers.xavier_initializer()
weights_regularizer : 權重的正則化器,一般不怎么用到
biases_initializer : 如果之前有batch norm,那么這個及下面一個就不用管了
biases_regularizer : 
trainable : 參數是否可訓練,默認為True

3、slim.max_pool2d: 池化層(最大池化和平均池化),用法如下:

net = slim.max_pool2d(net, [2, 2], scope='pool1')

4、slim.fully_connected: 全連接層,前兩個參數分別為網絡輸入、輸出的神經元數量。

slim.fully_connected(x, 128, scope='fc1')
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容

  • TensorFlow-Slim TF-Slim 是一個用于定義、訓練、和評估復雜模型的TensorFlow高級庫。...
    fade2black閱讀 4,218評論 1 4
  • Google Inception Net,ILSVRC 2014比賽第一名。控制計算量、參數量,分類性能非常好。V...
    利炳根閱讀 1,690評論 0 7
  • 卷積神經網絡是基于人工神經網絡的深度機器學習方法,成功應用于圖像識別領域。CNN采用了局部連接和權值共享,保持了網...
    dopami閱讀 1,051評論 0 0
  • 今天周五,下午媽媽應邀參加兒子家長會,已經上中二班的兒子,雖然感到很快,但最真實的感到兒子真的長大了許多,不管...
    毛毛雨5281閱讀 205評論 0 0
  • 今年8月份,西方世界剛剛出版了一本新書,叫《你能做任何工作:“無用的”自由技藝的驚人力量》( You Can Do...
    AlwaysAskWhy閱讀 3,844評論 1 4