TensorFlow-Slim使用方法说明

翻译自:https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/slim


TensorFlow-Slim

TF-Slim是Tensorflow中一个轻量级的库,用于定义、训练和评估复杂的模型。TF-Slim中的组件可以与Tensorflow中原生的函数一起使用,与其他的框架,比如与tf.contrib.learn也可以一起使用。

使用方法

import tensorflow.contrib.slim as slim

为什么用TF-Slim?---现在已经要被遗弃了

TF-Slim可以使建立、训练和评估神经网络更加简单。

l  允许用户通过减少模板代码使得模型更加简洁。这个可以通过使用argument scoping和大量的高层layers、variables来实现;

l  通过使用常用的正则化( regularizers)使得建立模型更加简单;

l  一些广泛使用的计算机视觉相关的模型(比如VGG,AlexNet)已经在slim中定义好了,用户可以很方便的使用;这些既可以当成黑盒使用,也可以被扩展使用,比如添加一些“multiple heads”到不同的内部的层;

l  Slim使得扩展复杂模型变得容易,可以使用已经存在的模型的checkpoints来开始训练算法。

What are the various components of TF-Slim?

TF-Slim由几个独立存在的组件组成,主要包括以下几个:

l  arg_scope:提供一个新的作用域(scope),称为arg_scope,在该作用域(scope)中,用户可以定义一些默认的参数,用于特定的操作;

l  data:包含TF-Slim的dataset定义,data providers,parallel_reader,和 decoding utilities;

l  evaluation:包含用于模型评估的常规函数;

l  layers:包含用于建立模型的高级layers;

l  learning:包含一些用于训练模型的常规函数;

l  losses:包含一些用于loss function的函数;

l  metrics:包含一些热门的评价标准;

l  nets:包含一些热门的网络定义,如VGG,AlexNet等模型;

l  queues:提供一个内容管理者,使得可以很容易、很安全地启动和关闭QueueRunners;

l  regularizers:包含权重正则化;

l  variables:提供一个方便的封装,用于变量创建和使用。

Defining Models

使用TF-Slim,结合variables, layers 和 scopes,模型可以很简洁地被定义。这些元件定义如下。

Variables

在原生的Tensorflow中,创建Variable需要一个预定义的值或者一种初始化机制(比如从一个高斯分布中随机采样)。此外,如果一个变量需要在一个特定的设备上(如GPU)创建,那么必须被明确说明。为了减少变量创建所需的代码,TF-Slim提供了一些封装函数(定义在variables.py中),可以使得用户定义变量变得简单。

举个例子,定义一个权重(weight)变量,使用一个截断的正态分布来初始化,使用l2 loss正则化,并将该变量放置在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中,有两种类型的variables,regular variables 和 local (transient) variables。绝大部分变量是regular variables,一旦被创建,可以使用saver来将这些变量保存到磁盘中;Local variables是那些仅仅存在于一个session内,并不会被保存到磁盘中。

TF-Slim通过定义model variables来进一步区别变量,这些是表示一个模型参数的变量。Model variables在学习期间被训练或者fine-tuned,在评估或者推断期间可以从一个checkpoint中加载。模型变量包括使用slim.fully_connected 或者 slim.conv2d创建的变量等。非模型变量(Non-model variables)指的是那些在学习或者评估阶段使用但是在实际的inference中不需要用到的变量。比如说,global_step在学习和评估阶段会用到的变量,但是实际上并不是模型的一部分。类似的,moving average variables也是非模型变量。

model variables和regular variables在TF-Slim中很容易地被创建和恢复:

# 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()# Regular variables
my_var = slim.variable('my_var',shape=[20, 1],initializer=tf.zeros_initializer())
regular_variables_and_model_variables = slim.get_variables()

这是如何工作的呢?当你通过TF-Slim的layer或者直接通过slim.model_variable函数创建一个模型的变量时,TF-Slim将变量添加到tf.GraphKeys.MODEL_VARIABLES集合中。如果你想拥有自己定制化的layers或者variables创建机制,但是仍然想利用TF-Slim来管理你的变量,此时,TF-Slim提供一个方便的函数,用于添加模型的变量到集合中:

my_model_variable = CreateViaCustomCode()# Letting TF-Slim know about the additional variable.
slim.add_model_variable(my_model_variable)

Layers

在原生的Tensorflow中,要定义一些层(比如说卷积层,全连接层,BatchNorm层等)是比较麻烦的。举个例子,神经网络中的卷积层由以下几个步骤组成:

  1. 创建权重和偏置变量
  2. 将输入与权重做卷积运算
  3. 将偏置加到第二步的卷积运算得到的结果中
  4. 使用一个激活函数

上面的步骤使用原始的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)

为了减少重复代码,TF-Slim提供了一些方便高级别更抽象的神经网络层。比如说,卷积层实现如下:

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

TF-Slim提供了大量的标准的实现,用于建立神经网络。包括如下函数:

Layer

TF-Slim

BiasAdd

slim.bias_add

BatchNorm

slim.batch_norm

Conv2d

slim.conv2d

Conv2dInPlane

slim.conv2d_in_plane

Conv2dTranspose (Deconv)

slim.conv2d_transpose

FullyConnected

slim.fully_connected

AvgPool2D

slim.avg_pool2d

Dropout

slim.dropout

Flatten

slim.flatten

MaxPool2D

slim.max_pool2d

OneHotEncoding

slim.one_hot_encoding

SeparableConv2

slim.separable_conv2d

UnitNorm

slim.unit_norm

TF-Slim也两个操作符,称为repeat 和 stack,允许用户重复执行相同的操作。比如说,下面几个卷积层加一个池化层是VGG网络的一部分,

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')

减少重复代码的其中一种方法是利用for循环,如下:

net = ...
for i in range(3):net = slim.conv2d(net, 256, [3, 3], scope='conv3_%d' % (i+1))
net = slim.max_pool2d(net, [2, 2], scope='pool2')

另一种方式是,使用TF-Slim中的repeat操作:

net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3') # 3代表重复3次
net = slim.max_pool2d(net, [2, 2], scope='pool2')

上面例子中,slim.repeat会自动给每一个卷积层的scopes命名为'conv3/conv3_1', 'conv3/conv3_2' 和 'conv3/conv3_3'。

另外,TF-Slim的 slim.stack操作允许用户用不同的参数重复调用同一种操作。slim.stack也为每一个被创建的操作创建一个新的tf.variable_scope。比如说,下面是一种简单的方式来创建多层感知器(Multi-Layer Perceptron (MLP)):

# Verbose way:
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')# Equivalent, TF-Slim way using slim.stack:
slim.stack(x, slim.fully_connected, [32, 64, 128], scope='fc')

在上面的例子中,slim.stack调用了slim.fully_connected三次。类似的,我们可以使用stack来简化多层的卷积层。

# Verbose way:
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')# Using stack:
slim.stack(x, slim.conv2d, [(32, [3, 3]), (32, [1, 1]), (64, [3, 3]), (64, [1, 1])], scope='core')

Scopes

除了Tensorflow中作用域(scope)之外(name_scope, variable_scope),TF-Slim增加了新的作用域机制,称为arg_scope。这个新的作用域允许使用者明确一个或者多个操作和一些参数,这些定义好的操作或者参数会传递给arg_scope内部的每一个操作。下面举例说明。先看如下代码片段:

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')

从上面的代码中可以清楚的看出来,有3层卷积层,其中很多超参数都是一样的。两个卷积层有相同的padding,所有三个卷积层有相同的weights_initializer和weight_regularizer。上面的代码包含了大量重复的值,其中一种解决方法是使用变量来说明一些默认的值:

padding = 'SAME'
initializer = tf.truncated_normal_initializer(stddev=0.01)
regularizer = slim.l2_regularizer(0.0005)
net = slim.conv2d(inputs, 64, [11, 11], 4,padding=padding,weights_initializer=initializer,weights_regularizer=regularizer,scope='conv1')
net = slim.conv2d(net, 128, [11, 11],padding='VALID',weights_initializer=initializer,weights_regularizer=regularizer,scope='conv2')
net = slim.conv2d(net, 256, [11, 11],padding=padding,weights_initializer=initializer,weights_regularizer=regularizer,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')

上面的例子表明,使用arg_scope可以使得代码变得更整洁、更干净并且更加容易维护。注意到,在arg_scope中规定的参数值,它们可以被局部覆盖。比如说,上面的padding参数被设置成‘SAME’,但是在第二个卷积层中用‘VALID’覆盖了这个参数。

我们也可以嵌套使用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='fc')

在上面的例子中,在第一个arg_scope中,卷积层和全连接层被应用于相同的权重初始化和权重正则化;在第二个arg_scope中,额外的参数仅仅对卷积层conv2d起作用。

Working Example: Specifying the VGG16 Layers

通过结合TF-Slim的Variables, Operations 和 scopes,我们可以使用比较少的代码来实现一个比较复杂的网络。比如说,整个VGG网络定义如下:

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

Training Models

训练Tensorflow模型要求一个模型、一个loss function、梯度计算和一个训练的程序,用来迭代的根据loss计算模型权重的梯度和更新权重。TF-Slim提供了loss function和一些帮助函数,来运行训练和评估。

Losses

Loss function定义了一个我们需要最小化的量。对于分类问题,主要是计算真正的分布与预测的概率分布之间的交叉熵。对于回归问题,主要是计算预测值与真实值均方误差。

特定的模型,比如说多任务学习模型,要求同时使用多个loss function;换句话说,最终被最小化的loss function是多个其他的loss function之和。比如说,一个同时预测图像中场景的类型和深度的模型,该模型的loss function就是分类loss和深度预测loss之和(the sum of the classification loss and depth prediction loss)。

TF-Slim通过losses模块为用户提供了一种机制,使得定义loss function变得简单。比如说,下面的是我们想要训练VGG网络的简单示例:

import tensorflow as tf
import tensorflow.contrib.slim.nets as nets
vgg = nets.vgg# Load the images and labels.
images, labels = ...# Create the model.
predictions, _ = vgg.vgg_16(images)# Define the loss functions and get the total loss.
loss = slim.losses.softmax_cross_entropy(predictions, labels)

在上面这个例子中,我们首先创建一个模型(利用TF-Slim的VGG实现),然后增加了标准的分类loss。现在,让我们看看当我们有一个多个输出的多任务模型的情况:

# Load the images and labels.
images, scene_labels, depth_labels = ...# Create the model.
scene_predictions, depth_predictions = CreateMultiTaskModel(images)# 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)

在这个例子中,我们有2个loss,是通过调用slim.losses.softmax_cross_entropy 和 slim.losses.sum_of_squares得到。我们可以将这两个loss加在一起或者调用slim.losses.get_total_loss()来得到全部的loss(total_loss)。这是如何工作的?当你通过TF-Slim创建一个loss时,TF-Slim将loss加到一个特殊的TensorFlow collection of loss functions。这使得你既可以手动得管理全部的loss,也可以让TF-Slim来替你管理它们。

如果你想让TF-Slim为你管理losses但是你有一个自己实现的loss该怎么办?loss_ops.py 也有一个函数可以将你自己实现的loss加到 TF-Slims collection中。举例如下:

# Load the images and labels.
images, scene_labels, depth_labels, pose_labels = ...# Create the model.
scene_predictions, depth_predictions, pose_predictions = CreateMultiTaskModel(images)# 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)
pose_loss = MyCustomLossFunction(pose_predictions, pose_labels)
slim.losses.add_loss(pose_loss) # Letting TF-Slim know about the additional loss.# The following two ways to compute the total loss are equivalent:
regularization_loss = tf.add_n(slim.losses.get_regularization_losses())
total_loss1 = classification_loss + sum_of_squares_loss + pose_loss + regularization_loss# (Regularization Loss is included in the total loss by default).
total_loss2 = slim.losses.get_total_loss()

在这个例子中,我们既可以手动的计算的出全部的loss function,也可以让TF-Slim知道这个额外的loss然后让TF-Slim处理这个loss。

Training Loop

TF-Slim提供了一个简单但是很强的用于训练模型的工具(在 learning.py)。其中包括一个可以重复测量loss,计算梯度和将模型保存到磁盘的训练函数。举个例子,一旦我们定义好了模型,loss function和最优化方法,我们可以调用slim.learning.create_train_op 和 slim.learning.train来实现优化。

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,save_summaries_secs=300,save_interval_secs=600):

在这个例子中,提供给slim.learning.train的参数有1)train_op,用于计算loss和梯度,2)logdir用于声明checkpoints和event文件保存的路径。我们可以用number_of_steps参数来限制梯度下降的步数;save_summaries_secs=300表明我们每5分钟计算一次summaries,save_interval_secs=600表明我们每10分钟保存一次模型的checkpoint。

Working Example: Training the VGG16 Model

下面是训练一个VGG网络的例子。

import tensorflow as tf
import tensorflow.contrib.slim.nets as netsslim = tf.contrib.slim
vgg = nets.vgg...train_log_dir = ...
if not 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.vgg_16(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)

微调现有模型Fine-Tuning Existing Models

从ckpt中恢复变量的简介Brief Recap on Restoring Variables from a Checkpoint

当一个模型被训练完毕之后,它可以从一个给定的checkpoint中使用tf.train.Saver()来恢复变量。在很多情况下,tf.train.Saver()提供一个简答的机制来恢复所有变量或者一部分变量。

# 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...

详细的信息可以查看 Restoring Variables 和 Choosing which Variables to Save and Restore这两个页面。

恢复部分模型Partially Restoring Models

在一个新的数据集或者一个新的任务上fine-tune一个预训练的模型通常是比较受欢迎的。我们可以使用TF-Slim的helper函数来选择想要恢复的一部分变量:

# 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")
# or
variables_to_restore = slim.get_variables_by_suffix("2")
# or
variables_to_restore = slim.get_variables(scope="nested")
# or
variables_to_restore = slim.get_variables_to_restore(include=["nested"])
# or
variables_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...

从模型中回复不同的变量名Restoring models with different variable names

当从一个checkpoint中恢复变量时,Saver定位在checkpoint文件中变量的名字,并且将它们映射到当前图(graph)的变量中去。上面,我们通过传递给saver一个变量列表来创建一个saver。在这种情况下,在checkpoint文件中定位的变量名隐式地从每个提供的变量的var. op. name中获得。

当checkpoint文件中的变量名与graph匹配时,将会工作良好。然而,有时候,我们想要从一个与当前的graph不同变量名的checkpoint中恢复变量,那么在这种情况下,我们必须给Saver提供一个字典,该字典将每个checkpoint中变量名映射到每个graph的变量。下面的例子是,通过一个简单的函数获得checkpoint中的变量的名字。

# Assuming than 'conv1/weights' should be restored from 'vgg16/conv1/weights'
def name_in_checkpoint(var):return 'vgg16/' + var.op.name# Assuming than 'conv1/weights' and 'conv1/bias' should be restored from 'conv1/params1' and 'conv1/params2'
def name_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):var for var in 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")

不同任务上微调模型Fine-Tuning a Model on a different task

考虑这么一种情况:我们有一个预训练好的VGG16模型,该模型是在ImageNet数据集上训练好的,有1000类。然而,我们想要将其应用到只有20类的Pascal VOC数据集上。为了实现这个,我们可以使用不包括最后一层的预训练模型来初始化我们的新模型。

# Load the Pascal VOC data
image, label = MyPascalVocDataLoader(...)
images, labels = tf.train.batch([image, label], batch_size=32)# Create the model
predictions = vgg.vgg_16(images)train_op = slim.learning.create_train_op(...)# Specify where the Model, trained on ImageNet, was saved.
model_path = '/path/to/pre_trained_on_imagenet.checkpoint'# Specify where the new model will live:
log_dir = '/path/to/my_pascal_model_dir/'# Restore only the convolutional layers:
variables_to_restore = slim.get_variables_to_restore(exclude=['fc6', 'fc7', 'fc8'])
init_fn = assign_from_checkpoint_fn(model_path, variables_to_restore)# Start training.
slim.learning.train(train_op, log_dir, init_fn=init_fn)

评估模型 

一旦我们已经训练好了一个模型(或者模型正在训练之中),我们想要看看模型的实际表现能力。这个可以通过使用一些评估度量来实现,该度量可以对模型的表现能力评分。而评估代码实际上是加载数据,做预测,将预测结果与真实值做比较,最后得到得分。这个步骤可以运行一次或者周期重复。

评估指标Metrics

我们将度量定义为一个性能度量,它不是一个loss函数(losses是在训练的时候直接最优化),但我们仍然感兴趣的是评估模型的目的。比如说,我们想要最优化log loss,但是我们感兴趣的度量可能是F1得分(test accuracy),或者是Intersection Over Union score(这是不可微的,因此不能作为损失使用)。

TF-Slim提供了一些使得评估模型变得简单的度量操作。计算度量的值可以分为以下三个步骤:

  1. 初始化(Initialization):初始化用于计算度量的变量
  2. 聚合(Aggregation):使用操作(比如求和操作)来计算度量
  3. 终止化(Finalization):(可选的)使用最终的操作来计算度量值,比如说计算均值,最小值,最大值等。

举个例子,为了计算mean_absolute_error,2个变量,count 和 total变量被初始化为0。在聚合期间,我们观测到一些预测值和标签值,计算它们的绝对差值然后加到total中。每一次我们观测到新的一个数据,我们增加count。最后,在Finalization期间,total除以count来获得均值mean。

下面的示例演示了声明度量标准的API。由于度量经常在测试集上进行评估,因此我们假设使用的是测试集。

images, labels = LoadTestData(...)
predictions = MyModel(images)mae_value_op, mae_update_op = slim.metrics.streaming_mean_absolute_error(predictions, labels)
mre_value_op, mre_update_op = slim.metrics.streaming_mean_relative_error(predictions, labels)
pl_value_op, pl_update_op = slim.metrics.percentage_less(mean_relative_errors, 0.3)

如示例所示,一个度量的创建返回两个值:value_op和update_op。value_op是一个幂等操作,它返回度量的当前值。update_op是执行上面提到的聚合步骤的操作,以及返回度量的值。

跟踪每个value_op和update_op是很费力的。为了解决这个问题,TF-Slim提供了两个便利功能:

# Aggregates the value and update ops in two lists:
value_ops, update_ops = slim.metrics.aggregate_metrics(slim.metrics.streaming_mean_absolute_error(predictions, labels),slim.metrics.streaming_mean_squared_error(predictions, labels))# Aggregates the value and update ops in two dictionaries:
names_to_values, names_to_updates = slim.metrics.aggregate_metric_map({"eval/mean_absolute_error": slim.metrics.streaming_mean_absolute_error(predictions, labels),"eval/mean_squared_error": slim.metrics.streaming_mean_squared_error(predictions, labels),
})

实例:追踪多个评价指标 Tracking Multiple Metrics

将代码全部放在一起:

import tensorflow as tf
import tensorflow.contrib.slim.nets as netsslim = tf.contrib.slim
vgg = nets.vgg# Load the data
images, labels = load_data(...)# Define the network
predictions = vgg.vgg_16(images)# Choose the metrics to compute:
names_to_values, names_to_updates = slim.metrics.aggregate_metric_map({"eval/mean_absolute_error": slim.metrics.streaming_mean_absolute_error(predictions, labels),"eval/mean_squared_error": slim.metrics.streaming_mean_squared_error(predictions, labels),
})# Evaluate the model using 1000 batches of data:
num_batches = 1000with tf.Session() as sess:sess.run(tf.global_variables_initializer())sess.run(tf.local_variables_initializer())for batch_id in range(num_batches):sess.run(names_to_updates.values())metric_values = sess.run(names_to_values.values())for metric, value in zip(names_to_values.keys(), metric_values):print('Metric %s has value: %f' % (metric, value))

评估 Loop

TF-Slim提供了一个评估模块(evaluation.py),它包含了使用来自 metric_ops.py 模块编写模型评估脚本的辅助函数--scripts。这些功能包括定期运行评估、对数据批量进行评估、打印和汇总度量结果的功能。

import tensorflow as tfslim = tf.contrib.slim# Load the data
images, labels = load_data(...)# Define the network
predictions = MyModel(images)# Choose the metrics to compute:
names_to_values, names_to_updates = slim.metrics.aggregate_metric_map({'accuracy': slim.metrics.accuracy(predictions, labels),'precision': slim.metrics.precision(predictions, labels),'recall': slim.metrics.recall(mean_relative_errors, 0.3),
})# Create the summary ops such that they also print out to std output:
summary_ops = []
for metric_name, metric_value in names_to_values.iteritems():op = tf.summary.scalar(metric_name, metric_value)op = tf.Print(op, [metric_value], metric_name)summary_ops.append(op)num_examples = 10000
batch_size = 32
num_batches = math.ceil(num_examples / float(batch_size))# Setup the global step.
slim.get_or_create_global_step()output_dir = ... # Where the summaries are stored.
eval_interval_secs = ... # How often to run the evaluation.
slim.evaluation.evaluation_loop('local',checkpoint_dir,log_dir,num_evals=num_batches,eval_op=names_to_updates.values(),summary_op=tf.summary.merge(summary_ops),eval_interval_secs=eval_interval_secs)

快捷接口

训练接口

slim.learning.train(

Args:
      train_op: A `Tensor` that, when executed, will apply the gradients and
        return the loss value.
      logdir: The directory where training logs are written to. If None, model
        checkpoints and summaries will not be written.
      train_step_fn: The function to call in order to execute a single gradient
        step. The function must have take exactly four arguments: the current
        session, the `train_op` `Tensor`, a global step `Tensor` and a dictionary.
      train_step_kwargs: A dictionary which is passed to the `train_step_fn`. By
        default, two `Boolean`, scalar ops called "should_stop" and "should_log"
        are provided.
      log_every_n_steps: The frequency, in terms of global steps, that the loss
        and global step are logged.
      graph: The graph to pass to the supervisor. If no graph is supplied the
        default graph is used.
      master: The address of the tensorflow master.
      is_chief: Specifies whether or not the training is being run by the primary
        replica during replica training.
      global_step: The `Tensor` representing the global step. If left as `None`,
        then training_util.get_or_create_global_step(), that is,
        tf.contrib.framework.global_step() is used.
      number_of_steps: The max number of gradient steps to take during training,
        as measured by 'global_step': training will stop if global_step is
        greater than 'number_of_steps'. If the value is left as None, training
        proceeds indefinitely.
      init_op: The initialization operation. If left to its default value, then
        the session is initialized by calling `tf.global_variables_initializer()`.
      init_feed_dict: A feed dictionary to use when executing the `init_op`.
      local_init_op: The local initialization operation. If left to its default
        value, then the session is initialized by calling
        `tf.local_variables_initializer()` and `tf.tables_initializer()`.
      init_fn: An optional callable to be executed after `init_op` is called. The
        callable must accept one argument, the session being initialized.
      ready_op: Operation to check if the model is ready to use. If left to its
        default value, then the session checks for readiness by calling
        `tf.report_uninitialized_variables()`.
      summary_op: The summary operation.
      save_summaries_secs: How often, in seconds, to save summaries.
      summary_writer: `SummaryWriter` to use.  Can be `None`
        to indicate that no summaries should be written. If unset, we
        create a SummaryWriter.

startup_delay_steps: The number of steps to wait for before beginning. Note
        that this must be 0 if a sync_optimizer is supplied.
      saver: Saver to save checkpoints. If None, a default one will be created
        and used.
      save_interval_secs: How often, in seconds, to save the model to `logdir`.
      sync_optimizer: an instance of tf.train.SyncReplicasOptimizer, or a list of
        them. If the argument is supplied, gradient updates will be synchronous.
        If left as `None`, gradient updates will be asynchronous.
      session_config: An instance of `tf.ConfigProto` that will be used to
        configure the `Session`. If left as `None`, the default will be used.
      session_wrapper: A function that takes a `tf.Session` object as the only
        argument and returns a wrapped session object that has the same methods
        that the original object has, or `None`. Iff not `None`, the wrapped
        object will be used for training.
      trace_every_n_steps: produce and save a `Timeline` in Chrome trace format
        and add it to the summaries every `trace_every_n_steps`. If None, no trace
        information will be produced or saved.
      ignore_live_threads: If `True` ignores threads that remain running after
        a grace period when stopping the supervisor, instead of raising a
        RuntimeError.
    
    Returns:
      the value of the loss function after training.
    
    Raises:
      ValueError: if `train_op` is empty or if `startup_delay_steps` is
        non-zero when `sync_optimizer` is supplied, if `number_of_steps` is
        negative, or if `trace_every_n_steps` is not `None` and no `logdir` is
        provided.

slim.learning.train(sess, train_op, global_step, train_step_kwargs)
    Function that takes a gradient step and specifies whether to stop.
    
    Args:
      sess: The current session.
      train_op: An `Operation` that evaluates the gradients and returns the
        total loss.
      global_step: A `Tensor` representing the global training step.
      train_step_kwargs: A dictionary of keyword arguments.
    
    Returns:
      The total loss and a boolean indicating whether or not to stop training.
    
    Raises:
      ValueError: if 'should_trace' is in `train_step_kwargs` but `logdir` is not.
(END)

评估接口

 slim.evaluation.evaluate_once(

    Args:
      master: The BNS address of the TensorFlow master.
      checkpoint_path: The path to a checkpoint to use for evaluation.
      logdir: The directory where the TensorFlow summaries are written to.
      num_evals: The number of times to run `eval_op`.
      initial_op: An operation run at the beginning of evaluation.
      initial_op_feed_dict: A feed dictionary to use when executing `initial_op`.
      eval_op: A operation run `num_evals` times.
      eval_op_feed_dict: The feed dictionary to use when executing the `eval_op`.
      final_op: An operation to execute after all of the `eval_op` executions. The
        value of `final_op` is returned.
      final_op_feed_dict: A feed dictionary to use when executing `final_op`.
      summary_op: The summary_op to evaluate after running TF-Slims metric ops. By
        default the summary_op is set to tf.summary.merge_all().
      summary_op_feed_dict: An optional feed dictionary to use when running the
        `summary_op`.
      variables_to_restore: A list of TensorFlow variables to restore during
        evaluation. If the argument is left as `None` then
        slim.variables.GetVariablesToRestore() is used.
      session_config: An instance of `tf.ConfigProto` that will be used to
        configure the `Session`. If left as `None`, the default will be used.
      hooks: A list of additional `SessionRunHook` objects to pass during the
        evaluation.
    
    Returns:
      The value of `final_op` or `None` if `final_op` is `None`.

slim.evaluation.evaluation_loop(

 Args:
      master: The BNS address of the TensorFlow master.
      checkpoint_dir: The directory where checkpoints are stored.
      logdir: The directory where the TensorFlow summaries are written to.
      num_evals: The number of times to run `eval_op`.
      initial_op: An operation run at the beginning of evaluation.
      initial_op_feed_dict: A feed dictionary to use when executing `initial_op`.
      init_fn: An optional callable to be executed after `init_op` is called. The
        callable must accept one argument, the session being initialized.
      eval_op: A operation run `num_evals` times.
      eval_op_feed_dict: The feed dictionary to use when executing the `eval_op`.
      final_op: An operation to execute after all of the `eval_op` executions. The
        value of `final_op` is returned.
      final_op_feed_dict: A feed dictionary to use when executing `final_op`.
      summary_op: The summary_op to evaluate after running TF-Slims metric ops. By
        default the summary_op is set to tf.summary.merge_all().
      summary_op_feed_dict: An optional feed dictionary to use when running the
        `summary_op`.
      variables_to_restore: A list of TensorFlow variables to restore during
        evaluation. If the argument is left as `None` then
        slim.variables.GetVariablesToRestore() is used.
      eval_interval_secs: The minimum number of seconds between evaluations.
      max_number_of_evaluations: the max number of iterations of the evaluation.
        If the value is left as 'None', the evaluation continues indefinitely.
      session_config: An instance of `tf.ConfigProto` that will be used to
        configure the `Session`. If left as `None`, the default will be used.
      timeout: The maximum amount of time to wait between checkpoints. If left as
        `None`, then the process will wait indefinitely.
      timeout_fn: Optional function to call after a timeout.  If the function
        returns True, then it means that no new checkpoints will be generated and
        the iterator will exit.  The function is called with no arguments.
      hooks: A list of additional `SessionRunHook` objects to pass during
        repeated evaluations.
    
    Returns:
      The value of `final_op` or `None` if `final_op` is `None`.

作者

Sergio Guadarrama and Nathan Silberman

参考资料

tensorflow.contrib.slim 模块官方说明文件: README.md

其他的函数

1、slim.conv2d:二维卷积

2、slim.nets.resnet_utils.conv2d_same():使用“SAME”填充的二维卷积

3、 tf.variable_scope()的original_name_scope 和 name的区别:

4、slim.utils.collect_named_outputs(collections, alias, outputs):为output的tensor添加别名,并将tensor添加到collections的列表中

5、slim.separable_conv2d():实现深度可分离卷积

6、slim.learning.train():开始训练

7、slim.evaluation.evaluation_loop():对模型的预测结果进行评估

8、slim.get_variables_to_restore(include=None, exclude=None):

9、slim.assign_from_checkpoint_fn():

10、tf.contrib.metrics.aggregate_metric_map():

11、Slim.conv2d_transpose():实现反卷积

12、slim.batch_norm():实现批量归一化

13、slim.max_pool2d()、slim.avg_pool2d():实现最大或者均值池化:


1、slim.conv2d:二维卷积

函数原型:

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):

参数介绍:

inputs:指需要做卷积的输入图像
    num_outputs:指定卷积核的个数(就是filter的个数)
    kernel_size:N个正整数的序列,指定卷积核的空间维度。 可以是单个整数,则所有空间维度具有相同值。
    stride:一组N个正整数,指定计算输出的stride。 可以是一个整数,则所有空间维具有相同的值。指定任何stride!= 1与指定任何rate!= 1不相容。
    padding:为padding的方式选择,VALID或者SAME
    data_format:是用于指定输入的input的格式
    rate:N个正整数的序列,指定用于萎缩卷积的扩张率。 可以是单个整数,以指定所有空间维度的相同值。 指定任何rate!= 1与指定任何stride!= 1不兼容。
    activation_fn:用于激活函数的指定,默认的为ReLU函数
    normalizer_fn:用于指定正则化函数
    normalizer_params:用于指定正则化函数的参数
    weights_initializer:用于指定权重的初始化程序
    weights_regularizer:为权重可选的正则化程序
    biases_initializer:用于指定biase的初始化程序
    biases_regularizer: biases可选的正则化程序
    reuse:指定是否共享层或者和变量
    variable_collections:指定变量的集合列表或者字典名,变量(weight、biase)会被添加到这个集合中。
    outputs_collections:指定一个列表名,输出(output)会被添加到这个列表。这个(列表名,[output])的键值对位于Graph类的self._collection字典中,如果该字典中没有列表名的关键字,则(列表名,[output])会被创建。
    trainable::卷积层的参数是否可被训练,如果为True,则同样会将变量添加到计算图集合GraphKeys.TRAINABLE_VARIABLES中
    scope:共享变量所指的variable_scope
2、slim.nets.resnet_utils.conv2d_same():使用“SAME”填充的二维卷积

函数原型:conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None)
    inputs: 一个4维tensor:[batch, height_in, width_in, channels].
    num_outputs:卷积核的个数
    kernel_size: 卷积核的尺寸
    stride: 输出的stride
    rate: 空洞卷积膨胀率
    scope: Scope.

net = conv2d_same(inputs, num_outputs, 3, stride=stride)
    # 等价于
    net = slim.conv2d(inputs, num_outputs, 3, stride=1, padding='SAME')
    net = subsample(net, factor=stride)
    # 但是和net = slim.conv2d(inputs, num_outputs, 3, stride=stride, padding='SAME')不等价,因为当输入的高度
    或宽度是偶数时,它是不同的,这就是我们添加当前函数的原因。
     
    # subsample的源码为:
    def subsample(inputs, factor, scope=None):
      """Subsamples the input along the spatial dimensions.
      Args:
        inputs: A `Tensor` of size [batch, height_in, width_in, channels].
        factor: The subsampling factor.
        scope: Optional variable_scope.
      Returns:
        output: A `Tensor` of size [batch, height_out, width_out, channels] with the
          input, either intact (if factor == 1) or subsampled (if factor > 1).
      """
      if factor == 1:
        return inputs
      else:
        return slim.max_pool2d(inputs, [1, 1], stride=factor, scope=scope)

3、 tf.variable_scope()的original_name_scope 和 name的区别:

with tf.variable_scope('a') as a:
        print(a.name)
        print(a.original_name_scope)
        print(a.original_name_scope)
     
    with tf.variable_scope('a') as b:
        print(b.name)
        print(b.original_name_scope)
     
    输出:
    a
    a/
    a/
    a
    a_1/

foo.name返回scope的名称(String)。 另一方面,foo.original_name_scope返回与foo.name相同的字符串,除非相同的scope被重新创建。 在这种情况下,所有子范围都会根据需要附加一个_#,以便对foo.original_name_scope进行所有调用,为范围的每个实例返回唯一的内容。
4、slim.utils.collect_named_outputs(collections, alias, outputs):为output的tensor添加别名,并将tensor添加到collections的列表中

如果这个(列表名,列表)键值对存在于Graph的self._collection字典中,则只是在列表上添加,否则会在字典中创建键值对。源码如下:

def collect_named_outputs(collections, alias, outputs):
      if collections:
        append_tensor_alias(outputs, alias)
        # 将outputs添加到collections的列表中,这个(collections,[outputs])位于Graph的self._collection中
        ops.add_to_collections(collections, outputs)
      return outputs
     
    def append_tensor_alias(tensor, alias):
      if alias[-1] == '/':
        alias = alias[:-1]
      if hasattr(tensor, 'aliases'):
        tensor.aliases.append(alias)
      else:
        tensor.aliases = [alias]
      return tensor

5、slim.separable_conv2d():实现深度可分离卷积

def separable_convolution2d(
        inputs,
        num_outputs,
        kernel_size,
        depth_multiplier=1,
        stride=1,
        padding='SAME',
        data_format=DATA_FORMAT_NHWC,
        rate=1,
        activation_fn=nn.relu,
        normalizer_fn=None,
        normalizer_params=None,
        weights_initializer=initializers.xavier_initializer(),
        pointwise_initializer=None,
        weights_regularizer=None,
        biases_initializer=init_ops.zeros_initializer(),
        biases_regularizer=None,
        reuse=None,
        variables_collections=None,
        outputs_collections=None,
        trainable=True,
        scope=None):
      """一个2维的可分离卷积,可以选择是否增加BN层。
      这个操作首先执行逐通道的卷积(每个通道分别执行卷积),创建一个称为depthwise_weights的变量。如果num_outputs
    不为空,它将增加一个pointwise的卷积(混合通道间的信息),创建一个称为pointwise_weights的变量。如果
    normalizer_fn为空,它将给结果加上一个偏置,并且创建一个为biases的变量,如果不为空,那么归一化函数将被调用。
    最后再调用一个激活函数然后得到最终的结果。
      Args:
        inputs: 一个形状为[batch_size, height, width, channels]的tensor
        num_outputs: pointwise 卷积的卷积核个数,如果为空,将跳过pointwise卷积的步骤.
        kernel_size: 卷积核的尺寸:[kernel_height, kernel_width],如果两个的值相同,则可以为一个整数。
        depth_multiplier: 卷积乘子,即每个输入通道经过卷积后的输出通道数。总共的输出通道数将为:
    num_filters_in * depth_multiplier。
        stride:卷积步长,[stride_height, stride_width],如果两个值相同的话,为一个整数值。
        padding:  填充方式,'VALID' 或者 'SAME'.
        data_format:数据格式, `NHWC` (默认) 和 `NCHW`
        rate: 空洞卷积的膨胀率:[rate_height, rate_width],如果两个值相同的话,可以为整数值。如果这两个值
    任意一个大于1,那么stride的值必须为1.     
        activation_fn: 激活函数,默认为ReLU。如果设置为None,将跳过。
        normalizer_fn: 归一化函数,用来替代biase。如果归一化函数不为空,那么biases_initializer
    和biases_regularizer将被忽略。 biases将不会被创建。如果设为None,将不会有归一化。
        normalizer_params: 归一化函数的参数。
        weights_initializer: depthwise卷积的权重初始化器
        pointwise_initializer: pointwise卷积的权重初始化器。如果设为None,将使用weights_initializer。
        weights_regularizer: (可选)权重正则化器。
        biases_initializer: 偏置初始化器,如果为None,将跳过偏置。
        biases_regularizer: (可选)偏置正则化器。
        reuse: 网络层和它的变量是否可以被重用,为了重用,网络层的scope必须被提供。
        variables_collections: (可选)所有变量的collection列表,或者是一个关键字为变量值为collection的字典。
        outputs_collections: 输出被添加的collection.
        trainable: 变量是否可以被训练
        scope: (可选)变量的命名空间。
      Returns:
        代表这个操作的输出的一个tensor

6、slim.learning.train():开始训练

slim.learning.train()的源码如下:

_USE_DEFAULT=0
    def train(train_op,
              logdir,
              train_step_fn=train_step,
              train_step_kwargs=_USE_DEFAULT,
              log_every_n_steps=1,
              graph=None,
              master='',
              is_chief=True,
              global_step=None,
              number_of_steps=None,
              init_op=_USE_DEFAULT,
              init_feed_dict=None,
              local_init_op=_USE_DEFAULT,
              init_fn=None,
              ready_op=_USE_DEFAULT,
              summary_op=_USE_DEFAULT,
              save_summaries_secs=600,
              summary_writer=_USE_DEFAULT,
              startup_delay_steps=0,
              saver=None,
              save_interval_secs=600,
              sync_optimizer=None,
              session_config=None,
              session_wrapper=None,
              trace_every_n_steps=None,
              ignore_live_threads=False):
      """
      使用TensorFlow 的监督器(supervisor)来运行训练循环。 提供sync_optimizer时,讲同步进行梯度更新,否则将异步进行梯度更新。
      args:
        train_op: 这是一个`Tensor`,当被执行的时候,将进行梯度更新并返回损失值。,
        logdir: 训练损失(trian loss)写入的目录。
        train_step_fn: 为了执行单次梯度跟新操作,这个函数将会被调用。这个函数必须有四个参数:session、train_op、 global step、dictionary.
        train_step_kwargs: 传给train_step_fn的一个dictionary,默认情况下,两个叫做"should_stop" 和"should_log"的布尔值需要提供。
        log_every_n_steps: 多少次迭代保存一次训练损失。
        graph: 传递给监督其supervisor的图,如果为空,则使用默认的graph。
        master: tensorflow master的地址
        is_chief: 指定是否在主要副本上运行training。
        global_step: 代表全局step的tensor,如果为空,那么将会调用training_util.get_or_create_global_step(),
        number_of_steps: 训练时最大的梯度更新次数,当global step大于这个值时,停止训练。如果这个值为空,则训练不会停止下来。
        init_op: 初始化操作,如果为空,则调用tf.global_variables_initializer()初始化
        init_feed_dict: 当执行初始化操作时的需要feed进去的一个字典
        local_init_op: 局部初始化操作,如果为空,则调用tf.local_variables_initializer()和 tf.tables_initializer()来初始化
        init_fn: 在Init_op被执行后,一个可选的调用函数。这个函数需要接受一个参数,即被初始化的session。
        ready_op: 检查模型是否准备好了的操作,如果为空,将会调用tf.report_uninitialized_variables()。
        summary_op: summary操作。
        save_summaries_secs: 多少秒保存一次summaries。
        summary_writer: 一个SummaryWriter,如果为None,则不会又summary会被写入。如果没有设置该值,将会自动创建一个SummaryWriter。
        startup_delay_steps: 在梯度更新之前需要等待的step数。如果sync_optimizer被提供,则这个值必须为0.
        saver: 保存checkpoint文件的saver,如果为None,一个默认的saver将会被创建。
        save_interval_secs: 多少秒保存一次模型的checkpoint文件到logdir。
        sync_optimizer: tf.train.SyncReplicasOptimizer的一个实例,或者这个实例的一个列表。如果这个参数被更新,则梯度更新操作将同步进行。如果为None,则梯度更新操作将异步进行。
        session_config: tf.ConfigProto的一个实例,用于配置Session,如果为None,则将会创建一个默认值。
        session_wrapper: 会话包装器,它把tf.Session作为唯一的参数传入,返回一个和tf.Session具有相同方法的包装后的session。如果不为None,则包装后的对象将会在训练中使用。
        trace_every_n_steps: 以一种Chrome trace format生成并保存Timeline 保存的频率为trace_every_n_steps,如果为None, 没有任何trace信息将会别保存。
        ignore_live_threads: 如果为True,则忽略那些在停止supervisor之后仍然在运行的线程,而不是引发RuntimeError。
      Returns:
        训练后的损失函数的值
    '''

7、slim.evaluation.evaluation_loop():对模型的预测结果进行评估

slim.evaluation.evalutation_loop()的源码如下:

通常,如果我们想要评估一个保存在磁盘上的模型的checkpoint文件时,可以在一个机制集合上进行单次或者多次评估。为了评估一个特定的模型,我们需要定义0或者更多metric和0或者更多summary,然后调用evaluation_loop。
      # 创建模型并获取预测值:
      images, labels = LoadData(...)
      predictions = MyModel(images)
      # 选择需要计算的评估指标
      names_to_values, names_to_updates = slim.metrics.aggregate_metric_map({
          "accuracy": slim.metrics.accuracy(predictions, labels),
          "mse": slim.metrics.mean_squared_error(predictions, labels),
      })
      # 定义需要写入的summary
      for metric_name, metric_value in metrics_to_values.iteritems():
        tf.summary.scalar(metric_name, metric_value)
      checkpoint_dir = '/tmp/my_model_dir/'
      log_dir = '/tmp/my_model_eval/'
      # 评估1000个batch
      num_evals = 1000
      # 每10分钟评估一次
      slim.evaluation_loop(
          '',
          checkpoint_dir,
          logdir,
          num_evals=num_evals,
          eval_op=names_to_updates.values(),
          summary_op=tf.contrib.deprecated.merge_summary(summary_ops),
          eval_interval_secs=600)
     
    def evaluation_loop(master,
                        checkpoint_dir,
                        logdir,
                        num_evals=1,
                        initial_op=None,
                        initial_op_feed_dict=None,
                        init_fn=None,
                        eval_op=None,
                        eval_op_feed_dict=None,
                        final_op=None,
                        final_op_feed_dict=None,
                        summary_op=_USE_DEFAULT,
                        summary_op_feed_dict=None,
                        variables_to_restore=None,
                        eval_interval_secs=60,
                        max_number_of_evaluations=None,
                        session_config=None,
                        timeout=None,
                        timeout_fn=None,
                        hooks=None):
      """返回Slim的评估循环
      Args:
        master:TensorFlow master的BNS地址
        checkpoint_dir: checkpoint文件所在的目录
        logdir: summaries被写入的目录。
        num_evals: 运行eval_op的次数,通常num_eval=num_batch
        initial_op: 初始化操作,在evaluation之前运行
        initial_op_feed_dict: 当执行初始化操作时的feed dictionary
        init_fn: (可选)一个回调函数,在初始化被调用之后执行。这个回调函数必须接受一个参数,即初始化的session。
        eval_op: 一个评估操作,总共需要运行num_evals次,即每个batch运行一次
        eval_op_feed_dict: 当执行eval_op时所要用的feed dictionary
        final_op: 一个最终操作,在所有的eval_op被执行完以后执行,final_op的值被返回
        final_op_feed_dict: 当执行final_op时的一个feed dictionary
        summary_op: 在运行slim的metric操作后的评估的summary_op,默认情况下,summary_op被设置为tf.summary.merge_all().
        summary_op_feed_dict: (可选)当运行summary_op时的一个feed dictionary
        variables_to_restore: 在评估期间需要恢复的变量列表,如果为None,那么默认为slim.variables.GetVariablesToRestore()
        eval_interval_secs: 两次评估之间的间隔(单位/秒),即多久evaluation一次
        max_number_of_evaluations: 评估迭代的最大次数,如果这个值设置为None,那么评估将无限进行。
        session_config: 一个tf.ConfigProto的实例,如果为None,则默认的将会别使用。
        timeout: 超时时间, The maximum amount of time to wait between checkpoints.如果为None,那么程序将一直等待。
        timeout_fn: (可选)在超时之后被调用的函数。如果这个函数返回True,那么意味着没有新的checkpoint文件会被创建,迭代将会被终止,这个函数被调用时没有任何参数。
        hooks: 一个额外的SessionRunHook对象的列表,在重复的评估时被传入
      Returns:
        如果final_op不为空的话返回final_op执行后的值,如果final_op为空的话,则返回None。
      """
      if summary_op == _USE_DEFAULT:
        summary_op = summary.merge_all()
      all_hooks = [evaluation.StopAfterNEvalsHook(num_evals),]
      if summary_op is not None:
        all_hooks.append(evaluation.SummaryAtEndHook(
            log_dir=logdir, summary_op=summary_op, feed_dict=summary_op_feed_dict))
      if hooks is not None:
        # Add custom hooks if provided.
        all_hooks.extend(hooks)
      saver = None
      if variables_to_restore is not None:
        saver = tf_saver.Saver(variables_to_restore)
     
      return evaluation.evaluate_repeatedly(
          checkpoint_dir,
          master=master,
          scaffold=monitored_session.Scaffold(
              init_op=initial_op, init_feed_dict=initial_op_feed_dict,
              init_fn=init_fn, saver=saver),
          eval_ops=eval_op,
          feed_dict=eval_op_feed_dict,
          final_ops=final_op,
          final_ops_feed_dict=final_op_feed_dict,
          eval_interval_secs=eval_interval_secs,
          hooks=all_hooks,
          config=session_config,
          max_number_of_evaluations=max_number_of_evaluations,
          timeout=timeout,
          timeout_fn=timeout_fn)

8、slim.get_variables_to_restore(include=None, exclude=None):

获取所有变量,包括模型变量(如权重和参数)和常规变量(如global step),可以传入scope进行过滤,源码如下:

def get_variables_to_restore(include=None, exclude=None):
      """Gets the list of the variables to restore.
      Args:
        include:一个可选的scope的列表或者元组,用来过滤来自VARIABLES collection中的变量。如果为None,则包含所有的变量。
        exclude: 一个可选的scope的列表或者元组,用来用来过滤来自VARIABLES collection中的变量。如果为None,则过滤掉所有的变量。
      Returns:
        变量列表
      """
      if include is None:
        # 包含所有变量,包括model_variable和regular_variable
        vars_to_include = get_variables()
      else:
        if not isinstance(include, (list, tuple)):
          raise TypeError('include is provided but is not a list or a tuple.')
        vars_to_include = []
        for scope in include:
          vars_to_include += get_variables(scope)
      vars_to_exclude = set()
      if exclude is not None:
        if not isinstance(exclude, (list, tuple)):
          raise TypeError('exclude is provided but is not a list or a tuple.')
        for scope in exclude:
          vars_to_exclude |= set(get_variables(scope))
      # Exclude the variables in vars_to_exclude
      return [v for v in vars_to_include if v not in vars_to_exclude]

9、slim.assign_from_checkpoint_fn():

返回一个函数,它从checkpoint文件读取变量值并分配给给特定变量。如果ignore_missing_vars为True,并且在检查点中找不到变量,则返回None。函数的源码如下

def assign_from_checkpoint_fn(model_path, var_list, ignore_missing_vars=False,
                                  reshape_variables=False):
      """
      Args:
        model_path: 模型的checkpoint文件的绝对路径。为了得到最新的checkpoint文件,可以使用:model_path = tf.train.latest_checkpoint(checkpoint_dir)
        var_list: A list of `Variable` objects or a dictionary mapping names in the
            checkpoint to the corresponding variables to initialize. If empty or
            `None`, it would return `no_op(), None`.
        ignore_missing_vars: Bool型,如果为True,它将忽略在checkpoint文件中缺失的那些变量,。
        reshape_variables: Bool型, 如果为真,那么那些与checkpoint文件中的变量有不同形状的变量将会自动被reshape。
      Returns:
        一个只需要一个参数(tf.Session)函数,它作用是进行赋值操作。如果在checkpoint文件中没有找到任何匹配的变量,那么将会返回None
      """
      if not var_list:
        raise ValueError('var_list cannot be empty')
      if ignore_missing_vars:
        reader = pywrap_tensorflow.NewCheckpointReader(model_path)
        if isinstance(var_list, dict):
          var_dict = var_list
        else:
          var_dict = {var.op.name: var for var in var_list}
        available_vars = {}
        for var in var_dict:
          if reader.has_tensor(var):
            available_vars[var] = var_dict[var]
          else:
            logging.warning(
                'Variable %s missing in checkpoint %s', var, model_path)
        var_list = available_vars
      if var_list:
        saver = tf_saver.Saver(var_list, reshape=reshape_variables)
        def callback(session):
          saver.restore(session, model_path)
        return callback
      else:
        logging.warning('No Variables to restore')
        return None

10、tf.contrib.metrics.aggregate_metric_map():

将{metric_name:(value_tensor, update_op)}的字典转为两个字典:{metric_name:value_tensor}和{metric_name:update_op},其中(value_tensor, update_op)由tf.metric.xxx函数产生。当metric列表的长度很长的话,将metric_name和与之相关的value_tensor和update_op配对是非常有效的。

Args:
      names_to_tuples: 一个metric_name到tuples的映射。每个tuple包含metric数据流的键值对:(value_tensor, update_op)
     
    Returns:
      返回两个字典,一个是包含metric_name到value_tensor的映射,另一个包含metric_name到update_op的映射。
     
    Example:
    metrics_to_values, metrics_to_updates = slim.metrics.aggregate_metric_map({
          'Mean Absolute Error': new_slim.metrics.streaming_mean_absolute_error(
              predictions, labels, weights),
          'Mean Relative Error': new_slim.metrics.streaming_mean_relative_error(
              predictions, labels, labels, weights),
          'RMSE Linear': new_slim.metrics.streaming_root_mean_squared_error(
              predictions, labels, weights),
          'RMSE Log': new_slim.metrics.streaming_root_mean_squared_error(
              predictions, labels, weights),
      })

11、Slim.conv2d_transpose():实现反卷积

这里反卷积的输出需要根据stride和padding方式进行计算。假设反卷积输入为 [x,x] , 输出为 [y,y],当padding为SAME时,y = x * stride ;当padding为VALID时, ( y - kernel_size ) /  stride  + 1 =  x ,根据x可以求出y。更详细的理解参考这里。

def convolution2d_transpose(
        inputs,
        num_outputs,
        kernel_size,
        stride=1,
        padding='SAME',
        data_format=DATA_FORMAT_NHWC,
        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):
      """
        增加一个带BN的反卷积层,这个函数创建一个weights变量代表卷积核,与输入进行卷积。如果normalizer_fn为None,第二个biase变量将会被创建,加在卷积后的结果上面。
      Args:
        inputs: 一个四维Tensor,形状为:[batch, height, width, in_channels]
        num_outputs: 整数,卷积核的个数.
        kernel_size: 卷积核大小,形状为[kernel_height, kernel_width],如果高和宽相同的话也可以是一个整数.
        stride: 卷积步长[stride_height, stride_width].如果高和宽相同的话也可以是一个整数.
        padding: 填充方式: 'VALID' 或者 'SAME'.
        data_format: 数据格式: `NHWC` (默认) 和 `NCHW`
        activation_fn: 激活函数,默认为ReLU。如果设置为None,则不使用激活函数。     
        normalizer_fn: 归一化函数,用于代替biase的,如果归一化函数不为空,那么`biases_initializer`和`biases_regularizer` 将会被忽略,而且`biases`不会被添加到卷积结果。默认设置为None.
        normalizer_params: 归一化函数的参数
        weights_initializer: 权重初始化器,默认为xavier_initializer()
        weights_regularizer:权重正则化器,默认为None。
        biases_initializer: 偏置初始化器,默认是0初始化。如果设置为None,则跳过。
        biases_regularizer: 偏置正则化器,默认为None。
        reuse: 是否重用该网络层机器变量,如果重用网络层,那么必须提供scope
        variables_collections: 变量集合,即把所有变量添加到这个集合中,默认为None.
        outputs_collections: 输出结果集合,把结果添加到这个集合中,默认为None
        trainable: 变量是否可训练,默认为True。
        scope: 变量的variable_scope
      Returns:
        A tensor representing the output of the operation.

12、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=None,
                   data_format=DATA_FORMAT_NHWC,
                   zero_debias_moving_mean=False,
                   scope=None,
                   renorm=False,
                   renorm_clipping=None,
                   renorm_decay=0.99,
                   adjustment=None):
      """
       添加一个BN层,对于conv2d和fully_connected而言,BN层相当于一个归一化函数。对于CNN中的一个batch而言,
    对所有样本的同一位置的所有特征图进行归一化,如第一个样本的第一个特征图、第二个样本的第一个特征图......、
    第m个样本的第一个特征图进行归一化,它们共享均值、方差、beta、gamma。每个特征图被当做一个神经元来处理。
      注意: 训练时moving_mean 和 moving_variance 需要被更新,默认情况下,更新操作位于 `tf.GraphKeys.UPDATE_OPS`,
    因此需要把这些更新操作添加到`train_op`的依赖中,比如:
      ```
        update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
        with tf.control_dependencies(update_ops):
          train_op = optimizer.minimize(loss)
      ```
      Args:
        inputs: 一个四维tensor:[batch_size ,height,width ,channel]
        decay: moving average的衰减因子. `decay`的合理值是接近于1. 典型为: 0.999, 0.99, 0.9等。如果模型在训练集上表现很好,但是验证集或者测试集很差,则可以把decay设置为更小的值,比如0.9. 为了改善性能,可以尝试zero_debias_moving_mean=True。
        center:如果为true,则对归一化后的tensor添加偏置,如果为false,'beta'将会别忽略。
        scale: 如果为true, 则乘以 `gamma`.如果为False, `gamma` 将不被使用. 如果下一层是线性的,比如nn.relu,那么scale将会失效,因为缩放可以被下一层实现。
        epsilon: 一个加在方差上的小的浮点数,避免除零错误。
        activation_fn: 激活函数,默认为None。
        param_initializers: (可选)初始化器,为beta, gamma, moving mean,oving variance进行初始化。
        param_regularizers: (可选)参数正则化器,为beta和gamma进行正则化。
        updates_collections: 更新操作的集合,这个跟新操作需要和train_op同时执行,如果为None,必须要添加控制依赖,确保更新操作被计算。C
        is_training: BN层是否是训练模式,如果是训练模式,将使用指数滑动平均和decay参数计算`moving_mean`和`moving_variance`. 如果不是训练模型,将直接使用`moving_mean`和'moving_variance`.
        reuse: 该BN层的变量是否被重用,如果要重用,则需要提供scope。
        variables_collections: (可选)变量的集合。
        outputs_collections: BN层输出的集合。
        trainable: 如果为True,则把变量添加到`GraphKeys.TRAINABLE_VARIABLES`
        batch_weights: (可选)一个tensor,形状为:'[batch_size]`,包含一系列batch条目的权重。如果提供,那么BN的归一化过程中将对mean和variance进行加权处理。
        fused: 如果为None或者True,则使用一个更快的实现方式。如果为False,那么使用系统推荐的实现方式。
        data_format: 数据格式 `NHWC` (default) 或`NCHW`。
        zero_debias_moving_mean: 为moving_mean使用zero_debias.它创建了一个新的变量对, 'moving_mean/biased' 和 'moving_mean/local_step'.
        scope: (可选)变量的`variable_scope`.
        renorm: 是否使用batch重归一化,这在训练时增加了额外的变量,该变量对预测时不影响。
        renorm_clipping: 这个重归一化的把'rmax', 'rmin', 'dmax' 映射为`Tensors`一个字典, 用来对重归一化指定范围。`(r, d)` 用于`corrected_value = normalized_value * r + d`,`r` 属于[rmin, rmax], `d`属于 [-dmax, dmax]. 如果没有rmax, rmin, dmax 将被设置为 inf, 0, inf.
        renorm_decay: 重归一化的权重衰减。
        adjustment: 这是一个调整函数,对输入值进行调整。
      Returns:
        A `Tensor` representing the output of the operation.

13、slim.max_pool2d()、slim.avg_pool2d():实现最大或者均值池化:

def max_pool2d(inputs,
                   kernel_size,
                   stride=2,
                   padding='VALID',
                   data_format=DATA_FORMAT_NHWC,
                   outputs_collections=None,
                   scope=None):
      """Adds a 2D Max Pooling op.
      Args:
        inputs: 一个4-D tensor,形状为[batch_size, height, width, channels]或者[batch_size, channels, height, width]
        kernel_size: 池化核的尺寸: [kernel_height, kernel_width],如果两个值相同的话可以为一个整数值。
        stride: 池化步长 [stride_height, stride_width].如果两个值相同的话可以为一个整数值。      
        padding: 填充方式,为 'VALID' 或者 'SAME'.
        data_format: 数据格式,支持 `NHWC` (default)和 `NCHW`
        outputs_collections: 输出被添加到的集合
        scope: 可选的name_scope.
      Returns:
        返回池化操作后的tensor.
      """
     
    def avg_pool2d(inputs,
                   kernel_size,
                   stride=2,
                   padding='VALID',
                   data_format=DATA_FORMAT_NHWC,
                   outputs_collections=None,
                   scope=None):
      """Adds a 2D average pooling op.
      """Adds a 2D Max Pooling op.
      Args:
        inputs: 一个4-D tensor,形状为[batch_size, height, width, channels]或者[batch_size, channels, height, width]
        kernel_size: 池化核的尺寸: [kernel_height, kernel_width],如果两个值相同的话可以为一个整数值。
        stride: 池化步长 [stride_height, stride_width].如果两个值相同的话可以为一个整数值。      
        padding: 填充方式,为 'VALID' 或者 'SAME'.
        data_format: 数据格式,支持 `NHWC` (default)和 `NCHW`
        outputs_collections: 输出被添加到的集合
        scope: 可选的name_scope.
      Returns:
        返回池化操作后的tensor.
      """

TensorFlow-Slim基础使用相关推荐

  1. 打造自己的图像识别模型2——使用 TensorFlow Slim 微调模型

    最近在搞自己的深度学习图像识别模型.这是第二步 本文主要讲解在现有常用模型基础上,如何微调模型,减少训练时间,同时保持模型检测精度. 主要参考书籍<21个项目玩转深度学习:基于TensorFlo ...

  2. 7.3 TensorFlow笔记(基础篇):加载数据之从队列中读取

    前言 整体步骤 在TensorFlow中进行模型训练时,在官网给出的三种读取方式,中最好的文件读取方式就是将利用队列进行文件读取,而且步骤有两步: 1. 把样本数据写入TFRecords二进制文件 2 ...

  3. 7.1 TensorFlow笔记(基础篇):加载数据之预加载数据与填充数据

    TensorFlow加载数据 TensorFlow官方共给出三种加载数据的方式: 1. 预加载数据 2. 填充数据 预加载数据的缺点: 将数据直接嵌在数据流图中,当训练数据较大时,很消耗内存.填充的方 ...

  4. 7.2 TensorFlow笔记(基础篇): 生成TFRecords文件

    前言 在TensorFlow中进行模型训练时,在官网给出的三种读取方式,中最好的文件读取方式就是将利用队列进行文件读取,而且步骤有两步: 1. 把样本数据写入TFRecords二进制文件 2. 从队列 ...

  5. 深度学习tensorflow数据流图基础知识点

    一.深度学习与机器学习区别 (一)特征提取方面 1.机器学习的特征工程步骤是要靠手动完成的,而且需要大量领域专业知识 深度学习通常由多个层组成,它们通常将更简单的模型组合在一起,通过将数 据从一层传 ...

  6. TensorFlow Slim 工具包使用

    TensorFlow Slim是Google提供的图像分类工具包,不仅提供一些方便接口,包含使用tf_slim训练和评估几个广泛使用于图像识别的卷积神经网络 (CNN) 图像分类模型的代码 ,还包含允 ...

  7. TensorFlow编程基础题库推荐

    TensorFlow表达了高层次的机器学习计算,大幅简化了第一代系统,并且具备更好的灵活性和可延展性.TensorFlow,简单看就是Tensor和Flow,即意味着Tensor和Flow是Tenso ...

  8. 【深度学习-微调模型】使用Tensorflow Slim fine-tune(微调)模型

    本文主要讲解在现有常用模型基础上,如何微调模型,减少训练时间,同时保持模型检测精度. 首先介绍下Slim这个Google公布的图像分类工具包,可在github链接:modules and exampl ...

  9. Tensorflow Slim入门教程(1)

    slim入门教程 slim入门教程 1. Variable 2. Layers 2.1 slim.bias_add 2.2 slim.batch_norm 2.3 slim.conv2d 2.4 sl ...

  10. tensorflow入门基础

    tensorflow程序一般分为两个阶段,在第一个阶段需要定义图中所有的计算.在第二个阶段就是执行计算. 1. 计算图的使用 首先在tensorflow的程序中系统会维护一个默认的计算图,通过tf.g ...

最新文章

  1. ls -l |wc -l命令多统计一行
  2. Linux 下 LaTeX 2018 安装与使用
  3. [SDOI2017]新生舞会
  4. 七牛云图片存储---Java
  5. python错误修复_如何修复python错误(对象不可调用)
  6. 创建Java动态代理
  7. apicloud模块和html,APICloud教程
  8. 【注意力机制】SENet(Squeeze-and-Excitation Networks)详解
  9. matlab multisim,清华大学出版社-图书详情-《仿真软件教程——Multisim和MATLAB》
  10. sudo rosdep init时出现错误: ERROR: cannot download default sources list from
  11. Flir Blackfly S USB3 工业相机:白平衡设置方法
  12. 庆祝小超的家开始筹建
  13. 数据结构之有效的括号
  14. maven的使用-很全
  15. CSS实现鼠标不可点击,样式设置以及不可点击事件的行为
  16. Github项目被fork后如何删除
  17. X-MAS CTF 2018 - Crypto - Hanukkah
  18. 不懂就问--Java基本数据类型与数组(定义了int型二维数组a[6][7]后,数组元素a[3][4]前的数组元素个数)案例分析
  19. 亚马逊、Lazada、ebay、wish、shopee、速卖通、阿里国际、沃尔玛、newegg、mercari测评自养号,卖家如何选择热门产品?来提高店铺产品的权重?
  20. 基于SSH的宠物商城网站设计与实现

热门文章

  1. 2017计算机家庭拥有量,中国数字鸿沟报告.doc
  2. 蓝天计算机培训怎么样,呼和浩特蓝天计算机培训班好不好
  3. 织梦搜索结果列表如何制作
  4. FMEA软件之SunFMEA全面提升产品质量与可靠性
  5. js运算符之逗号运算符
  6. COOKIES注入拿站
  7. SGame 连接选项
  8. 【集训DAY4】Forging【期望DP】
  9. 如何获取.JTL文件
  10. 2017.12.29T19-B3-U3I/Ojiangyi