看fensorflow的書發現使用的是slim庫,那就要研究slim的常用函數,這個文章寫的很好,轉一下哈。
slim庫的導入:
import tensorflow as tf
import tensorflow.contrib.slim as slim
常用函數:
與tensorflow自帶的函數相比,slim能夠讓我們不用重復寫函數的參數。那么函數的參數寫在哪里呢?核心方法就是slim.arg_scope。
slim.arg_scope
def arg_scope(list_ops_or_scope, **kwargs)
list_ops_or_scope:要用的函數的作用域,可以在需要使用的地方用@add_arg_scope 聲明
**kwargs: keyword=value 定義了list_ops中要使用的變量
也就是說可以通過這個函數將不想重復寫的參數通過這個函數自動賦值。
示例:
import tensorflow.contrib.slim as slim
@slim.add_arg_scope
def hh(name, add_arg):
print("name:", name)
print("add_arg:", add_arg)
with slim.arg_scope([hh], add_arg='this is add'):
hh('test')
#結果:
#name: test
#add_arg: this is add
進入add_arg_scope函數查看代碼可知:
def add_arg_scope(func):
"""Decorates a function with args so it can be used within an arg_scope.
Args:
func: function to decorate.
Returns:
A tuple with the decorated function func_with_args().
"""
def func_with_args(*args, **kwargs):
current_scope = _current_arg_scope()
current_args = kwargs
key_func = _key_op(func)
if key_func in current_scope:
current_args = current_scope[key_func].copy()
current_args.update(kwargs)
return func(*args, **current_args)
_add_op(func)
setattr(func_with_args, '_key_op', _key_op(func))
return tf_decorator.make_decorator(func, func_with_args)
其實就是看看你調用的是那個函數,給參數中添加你之前賦值的參數。
之后是使用slim構建神經網絡常用的函數。
slim.conv2d
slim.conv2d是對tf.conv2d的進一步封裝。常見調用方式:
net = slim.conv2d(inputs, 256, [3, 3], stride=1, scope='conv1_1')
源代碼:
@add_arg_scope
def convolution(inputs,num_outputs,
kernel_size,
stride=1,
padding='SAME',
data_format=None,
rate=1,
activation_fn=nn.relu,
normalizer_fn=None,
normalizer_params=None,
weights_initializer=initializers.xavier_initializer(),
weights_regularizer=None,
biases_initializer=init_ops.zeros_initializer(),
biases_regularizer=None,
reuse=None,
variables_collections=None,
outputs_collections=None,
trainable=True,
scope=None)
常用的有:
padding : 補零的方式,例如'SAME'
activation_fn : 激活函數,默認是nn.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
scope:你繪制的網絡結構圖中它屬于那個范圍內
slim.max_pool2d
net = slim.max_pool2d(net, [2, 2], scope='pool1')
前兩個參數分別為網絡輸入、輸出的神經元數量,第三個同上。
slim.batch_norm
def batch_norm(inputs,
decay=0.999,
center=True,
scale=False,
epsilon=0.001,
activation_fn=None,
param_initializers=None,
param_regularizers=None,
updates_collections=ops.GraphKeys.UPDATE_OPS,
is_training=True,
reuse=None,
variables_collections=None,
outputs_collections=None,
trainable=True,
batch_weights=None,
fused=False,
data_format=DATA_FORMAT_NHWC,
zero_debias_moving_mean=False,
scope=None,
renorm=False,
renorm_clipping=None,
renorm_decay=0.99):
這個我沒有理解。以下是原博客說的。
接下來說我在用slim.batch_norm時踩到的坑。slim.batch_norm里有moving_mean和moving_variance兩個量,分別表示每個批次的均值和方差。在訓練時還好理解,但在測試時,moving_mean和moving_variance的含義變了。在訓練時,有一些語句是必不可少的:
# 定義占位符,X表示網絡的輸入,Y表示真實值label
X = tf.placeholder("float", [None, 224, 224, 3])
Y = tf.placeholder("float", [None, 100])
#調用含batch_norm的resnet網絡,其中記得is_training=True
logits = model.resnet(X, 100, is_training=True)
cross_entropy = -tf.reduce_sum(Y*tf.log(logits))
#訓練的op一定要用slim的slim.learning.create_train_op,只用tf.train.MomentumOptimizer.minimize()是不行的
opt = tf.train.MomentumOptimizer(lr_rate, 0.9)
train_op = slim.learning.create_train_op(cross_entropy, opt, global_step=global_step)
#更新操作,具體含義不是很明白,直接套用即可
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
if update_ops:
updates = tf.group(*update_ops)
cross_entropy = control_flow_ops.with_dependencies([updates], cross_entropy)
之后的訓練都和往常一樣了,導出模型后,在測試階段調用相同的網絡,參數is_training一定要設置成False。```
logits = model.resnet(X, 100, is_training=False)
否則,可能會出現這種情況:所有的單個圖像分類,最后幾乎全被歸為同一類。這可能就是訓練模式設置反了的問題。