原文鏈接:blog.csdn.net/zchang81/article/details/77770880
slim作為一種輕量級(jí)的tensorflow庫(kù),使得模型的構(gòu)建侣姆,訓(xùn)練亲铡,測(cè)試都變得更加簡(jiǎn)單。
使用方法:
import tensorflow.contrib.slimas slim
組成部分:
arg_scope: 使得用戶可以在同一個(gè)arg_scope中使用默認(rèn)的參數(shù)
data酒贬,evaluation嫡良,layers,learning本谜,losses初家,metrics,nets乌助,queues溜在,regularizers,variables
定義模型
在slim中眷茁,組合使用variables, layers和scopes可以簡(jiǎn)潔的定義模型炕泳。
(1)variables: 定義于variables.py。生成一個(gè)weight變量, 用truncated normal初始化它, 并使用l2正則化上祈,并將其放置于CPU上, 只需下面的代碼即可:
weights= slim.variable('weights',shape=[10,10,3 ,3],
initializer=tf.truncated_normal_initializer(stddev=0.1),
regularizer=slim.l2_regularizer(0.05),
device='/CPU:0')
原生tensorflow包含兩類變量:普通變量和局部變量培遵。大部分變量都是普通變量,它們一旦生成就可以通過(guò)使用saver存入硬盤登刺,局部變量只在session中存在籽腕,不會(huì)保存。
slim進(jìn)一步的區(qū)分了變量類型纸俭,定義了model variables皇耗,這種變量代表了模型的參數(shù)。模型變量通過(guò)訓(xùn)練活著微調(diào)而得到學(xué)習(xí)揍很,或者在評(píng)測(cè)或前向傳播中可以從ckpt文件中載入郎楼。
非模型參數(shù)在實(shí)際前向傳播中不需要的參數(shù)万伤,比如global_step。同樣的呜袁,移動(dòng)平均反應(yīng)了模型參數(shù)敌买,但它本身不是模型參數(shù)。例子見(jiàn)下:
# Model Variables
weights= slim.model_variable('weights',shape=[10,10,3 ,3],initializer=tf.truncated_normal_initializer(stddev=0.1),regularizer=slim.l2_regularizer(0.05),device='/CPU:0')
model_variables= slim.get_model_variables()
# model_variables包含weights# Regular variables
my_var= slim.variable('my_var',shape=[20,1],initializer=tf.zeros_initializer())
regular_variables_and_model_variables= slim.get_variables()
#get_variables()得到模型參數(shù)和常規(guī)參數(shù)
當(dāng)我們通過(guò)slim的layers或著直接使用slim.model_variable創(chuàng)建變量時(shí)阶界,tf會(huì)將此變量加入tf.GraphKeys.MODEL_VARIABLES這個(gè)集合中,當(dāng)你需要構(gòu)建自己的變量時(shí)虹钮,可以通過(guò)以下代碼
將其加入模型參數(shù)。
my_model_variable= CreateViaCustomCode()# Letting TF-Slim know about the additional variable.
slim.add_model_variable(my_model_variable)
(2)layers:抽象并封裝了常用的層膘融,并且提供了repeat和stack操作芙粱,使得定義網(wǎng)絡(luò)更加方便。
下面的代碼利用repeat實(shí)現(xiàn)了三個(gè)卷積層的堆疊
net= slim.repeat(net,3, slim.conv2d,256, [3,3],scope='conv3')
repeat不僅只實(shí)現(xiàn)了相同操作相同參數(shù)的重復(fù)氧映,它還將scope進(jìn)行了展開(kāi)春畔,例子中的scope被展開(kāi)為 'conv3/conv3_1', 'conv3/conv3_2' and 'conv3/conv3_3'。
slim.stack操作使得我們可以重復(fù)的講同一個(gè)操作以不同參數(shù)一次作用于一些層岛都,這些層的輸入輸出時(shí)串聯(lián)起來(lái)的拐迁。比如:
slim.stack(x, slim.fully_connected, [32,64,128],scope='fc')
slim.stack(x, slim.conv2d, [(32, [3,3]), (32, [1,1]), (64, [3,3]), (64, [1,1])],scope='core')
(3)scopes:除了tensorflow中的name_scope和variable_scope, tf.slim新增了arg_scope操作,這一操作符可以讓定義在這一scope中的操作共享參數(shù)疗绣,即如不制定參數(shù)的話,則使用默認(rèn)參數(shù)铺韧。且參數(shù)可以被局部覆蓋多矮。使得代碼更加簡(jiǎn)潔,如下:
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')
而且哈打,我們也可以嵌套多個(gè)arg_scope在其中使用多個(gè)操作塔逃。
訓(xùn)練模型Tensorflow的模型訓(xùn)練需要模型,損失函數(shù)料仗,梯度計(jì)算湾盗,以及根據(jù)loss的梯度迭代更新參數(shù)。
(1)losses使用現(xiàn)有的loss:
loss= slim.losses.softmax_cross_entropy(predictions, labels)
對(duì)于多任務(wù)學(xué)習(xí)的loss立轧,可以使用:
# Define the loss functions and get the total loss.
classification_loss= slim.losses.softmax_cross_entropy(scene_predictions, scene_labels)
sum_of_squares_loss= slim.losses.sum_of_squares(depth_predictions, depth_labels)# The following two lines have the same effect:
total_loss= classification_loss+ sum_of_squares_loss
total_loss= slim.losses.get_total_loss(add_regularization_losses=False)
如果使用了自己定義的loss格粪,而又想使用slim的loss管理機(jī)制,可以使用:
pose_loss= MyCustomLossFunction(pose_predictions, pose_labels)
slim.losses.add_loss(pose_loss)
total_loss= slim.losses.get_total_loss()
#total_loss中包涵了pose_loss
(2) 訓(xùn)練循環(huán)
slim在learning.py中提供了一個(gè)簡(jiǎn)單而有用的訓(xùn)練模型的工具氛改。我們只需調(diào)用
slim.learning.create_train_op和slim.learning.train就可以完成優(yōu)化過(guò)程帐萎。
g= tf.Graph()# Create the model and specify the losses......
total_loss= slim.losses.get_total_loss()
optimizer= tf.train.GradientDescentOptimizer(learning_rate)# create_train_op ensures that each time we ask for the loss, the update_ops# are run and the gradients being computed are applied too.
train_op= slim.learning.create_train_op(total_loss, optimizer)
logdir=...# Where checkpoints are stored.
slim.learning.train(
train_op,
logdir,number_of_steps=1000,#迭代次數(shù)save_summaries_secs=300,#存summary間隔秒數(shù)save_interval_secs=600)#存模型建個(gè)秒數(shù)
(3)訓(xùn)練的例子:
import tensorflowas tfslim= tf.contrib.slimvgg= tf.contrib.slim.nets.vgg...train_log_dir=...ifnot tf.gfile.Exists(train_log_dir):? tf.gfile.MakeDirs(train_log_dir)with tf.Graph().as_default():# Set up the data loading:? images, labels=...# Define the model:? predictions= vgg.vgg16(images,is_training=True)# Specify the loss function:? slim.losses.softmax_cross_entropy(predictions, labels)? total_loss= slim.losses.get_total_loss()? tf.summary.scalar('losses/total_loss', total_loss)# Specify the optimization scheme:? optimizer= tf.train.GradientDescentOptimizer(learning_rate=.001)# create_train_op that ensures that when we evaluate it to get the loss,# the update_ops are done and the gradient updates are computed.? train_tensor= slim.learning.create_train_op(total_loss, optimizer)# Actually runs training.
slim.learning.train(train_tensor, train_log_dir)
根據(jù)已有模型進(jìn)行微調(diào)
(1)利用tf.train.Saver()從checkpoint恢復(fù)模型
# Create some variables.v1= tf.Variable(...,name="v1")v2= tf.Variable(...,name="v2")...# Add ops to restore all the variables.restorer= tf.train.Saver()# Add ops to restore some variables.restorer= tf.train.Saver([v1, v2])# Later, launch the model, use the saver to restore variables from disk, and# do some work with the model.with tf.Session()as sess:# Restore variables from disk.? restorer.restore(sess,"/tmp/model.ckpt")print("Model restored.")# Do some work with the model...
(2)部分恢復(fù)模型參數(shù)
# Create some variables.v1= slim.variable(name="v1",...)v2= slim.variable(name="nested/v2",...)...# Get list of variables to restore (which contains only 'v2'). These are all# equivalent methods:variables_to_restore= slim.get_variables_by_name("v2")# orvariables_to_restore= slim.get_variables_by_suffix("2")# orvariables_to_restore= slim.get_variables(scope="nested")# orvariables_to_restore= slim.get_variables_to_restore(include=["nested"])# orvariables_to_restore= slim.get_variables_to_restore(exclude=["v1"])# Create the saver which will be used to restore the variables.restorer= tf.train.Saver(variables_to_restore)with tf.Session()as sess:# Restore variables from disk.? restorer.restore(sess,"/tmp/model.ckpt")print("Model restored.")# Do some work with the model...
(3)當(dāng)圖的變量名與checkpoint中的變量名不同時(shí),恢復(fù)模型參數(shù)當(dāng)從checkpoint文件中恢復(fù)變量時(shí)胜卤,Saver在checkpoint文件中定位到變量名疆导,并且把它們映射到當(dāng)前圖中的變量中。之前的例子中葛躏,我們創(chuàng)建了Saver澈段,并為其提供了變量列表作為參數(shù)悠菜。這時(shí),在checkpoint文件中定位的變量名败富,是隱含地從每個(gè)作為參數(shù)給出的變量的var.op.name而獲得的悔醋。這一方式在圖與checkpoint文件中變量名字相同時(shí),可以很好的工作囤耳。而當(dāng)名字不同時(shí)篙顺,必須給Saver提供一個(gè)將checkpoint文件中的變量名映射到圖中的每個(gè)變量的字典,例子見(jiàn)下:
# Assuming that 'conv1/weights' should be restored from 'vgg16/conv1/weights'defname_in_checkpoint(var):return'vgg16/'+ var.op.name# Assuming that 'conv1/weights' and 'conv1/bias' should be restored from 'conv1/params1' and 'conv1/params2'defname_in_checkpoint(var):if"weights"in var.op.name:return var.op.name.replace("weights","params1")if"bias"in var.op.name:return var.op.name.replace("bias","params2")
variables_to_restore= slim.get_model_variables()
variables_to_restore= {name_in_checkpoint(var):varfor varin variables_to_restore}
restorer= tf.train.Saver(variables_to_restore)with tf.Session()as sess:# Restore variables from disk.
restorer.restore(sess,"/tmp/model.ckpt")
(4)在一個(gè)不同的任務(wù)上對(duì)網(wǎng)絡(luò)進(jìn)行微調(diào)
比如我們要將1000類的imagenet分類任務(wù)應(yīng)用于20類的Pascal VOC分類任務(wù)中充择,我們只導(dǎo)入部分層德玫,見(jiàn)下例: