TensorFlow-Slim 教程(中文版)

TensorFlow-Slim 教程(中文版)


本文翻译自 TensorFlow 的 Slim 模块官方教程

时间:2018-8-23

官方教程(英文版)


TensorFlow-Slim

TF-Slim 是一个对原生的 TensorFlow 函数进行封装的轻量级库,用于在 TensorFlow 中定义,训练和评估复杂模型。tf-slim 的组件可以与 native tensorflow 以及其它框架自由组合(如 tf.contrib.learn)。


导入 Slim 模块

import tensorflow.contrib.slim as slim

为何选择TF-Slim?

TF-Slim是一个简化构建,训练和评估神经网络的库:

  • 允许用户通过消除样板代码来更紧凑地定义模型。这是通过使用 argument scoping 和许多高级的 layers 和 variables 来实现的。这些工具提高了可读性和可维护性,降低了复制和粘贴时超参数值发生错误的可能性,并简化了超参数调整。
  • 通过提供常用的 regularizers 使开发模型变得简单 。
  • 几种广泛使用的计算机视觉模型(例如,VGG,AlexNet)已经开发出来,并且可供用户使用。这些可以用作黑盒子,或者可以以各种方式扩展,例如,通过向不同的内部层添加组件。
  • Slim可以轻松扩展复杂模型,并通过使用预先存在的 checkpoints 来热启动训练算法。

TF-Slim的各种组件有哪些?

TF-Slim由几个设计独立存在的部分组成。这些包括以下主要部分(下面详细说明)。

  • arg_scope: 提供一个新的名称范围 arg_scope,允许用户为该名称范围内的特定操作定义默认参数。
  • data:包含 TF-slim dataset definition, data providers, parallel_reader, and decoding 实用程序。
  • evaluation: 包含评估模型的例程。
  • layers: 包含使用 tensorflow 构建模型的高级图层。
  • learning: 包含训练模型的例程。
  • losses: 包含常用的损失函数。
  • metrics: 包含常用的评估指标。
  • nets: 包含流行的网络定义,如 VGG 和 AlexNet 模型。
  • queues: 提供上下文管理器,可以轻松安全地启动和关闭 QueueRunners。
  • regularizers: 包含权重正则化器。
  • variables: 提供变量创建和操作的便利封装器。

定义模型

通过使用 TF-Slim 的 variables、layers 和 scopes 可以十分简洁地定义模型。下面对各个部分进行了详细描述:

1、变量

在原生的 TensorFlow 创建Variables 需要预定义值或初始化机制(例如,从高斯f分布随机采样)。此外,如果需要在特定设备(如GPU)上创建变量,则必须明确指出 。为了减轻变量创建所需的代码,TF-Slim 在 variables.py 中提供了一组封装函数 ,允许调用者轻松定义变量。

例如,要创建一个 weights 变量,使用截断的正态分布对其进行初始化,使用 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 中,有两种类型的变量:常规变量和局部(瞬态)变量。绝大多数变量都是常规变量:一旦创建,就可以使用保护程序将它们保存到磁盘 。局部变量是仅在会话期间存在且不保存到磁盘的变量。

TF-Slim通过定义模型变量进一步区分变量,模型变量是表示模型参数的变量。模型变量在学习期间被训练或微调,并在评估或推理期间从检查点加载。示例包括由a slim.fully_connected或slim.conv2dlayer 创建的变量。非模型变量是在学习或评估期间使用的所有其他变量,但不是实际执行推理所必需的。例如,它global_step是在学习和评估期间使用的变量,但它实际上不是模型的一部分。同样,移动平均变量可能反映模型变量,但移动平均值本身不是模型变量。

可以通过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的图层创建模型变量或直接通过slim.model_variable函数创建模型变量时,TF-Slim会将变量添加到tf.GraphKeys.MODEL_VARIABLES集合中。如果您有自己的自定义图层或变量创建例程但仍希望TF-Slim管理或了解您的模型变量,该怎么办?TF-Slim提供了一个方便的功能,用于将模型变量添加到其集合中:

my_model_variable = CreateViaCustomCode()

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

图层

虽然TensorFlow操作集非常广泛,但神经网络的开发人员通常会根据更高级别的概念来考虑模型,例如“层”,“损失”,“度量”和“网络”。诸如卷积层,完全连接层或BatchNorm层之类的层比单个TensorFlow操作更抽象,并且通常涉及多个操作。此外,与更原始的操作不同,层通常(但不总是)具有与之关联的变量(可调参数)。例如,神经网络中的卷积层由几个低级操作组成:

创建权重和偏差变量
使用前一层的输入来计算权重
将偏差添加到卷积的结果中。
应用激活功能。
仅使用普通的TensorFlow代码,这可能相当费力:

input = …
以 tf.name_scope(’ conv1_1 ')作为范围:
内核= tf.Variable(tf.truncated_normal([ 3,3,64,128 ],D型细胞= tf.float32,
STDDEV = 1E-1 ),名称= ‘权重’)
CONV = tf.nn.conv2d(输入,内核,[ 1,1,1,1 ],填充= ’ SAME ')
偏置= tf.Variable(tf.constant(0.0,形状= [ 128 ],D型细胞= tf.float32),
可训练= 真,名称= ‘偏压’)
bias = tf.nn.bias_add(conv,biases)
conv1 = tf.nn.relu(偏见,名称=范围)
为了减少重复复制此代码的需要,TF-Slim提供了许多在更抽象的神经网络层定义的方便操作。例如,将上面的代码与相应TF-Slim代码的调用进行比较:

输入 = …
净= slim.conv2d(输入,128,[ 3,3 ],范围= ’ conv1_1 ')
TF-Slim为构建神经网络的众多组件提供标准实现。这些包括:

层 TF-修身
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
退出 slim.dropout
弄平 slim.flatten
MaxPool2D slim.max_pool2d
OneHotEncoding slim.one_hot_encoding
SeparableConv2 slim.separable_conv2d
UnitNorm slim.unit_norm
TF-斯利姆还提供了两个元操作称为repeat以及stack允许用户重复执行相同的操作。例如,请考虑VGG网络中的以下片段, 其层在池化层之间连续执行多个卷积:

净= …
净= slim.conv2d(净,256,[ 3,3 ],范围= ’ conv3_1 ')
净= slim.conv2d(净,256,[ 3,3 ],范围= ’ conv3_2 ')
净= slim.conv2d(净,256,[ 3,3 ],范围= ’ conv3_3 ')
净= slim.max_pool2d(净,[ 2,2 ],范围= ’ POOL2 ')
减少此代码重复的一种方法是通过for循环:

net = …
for i in range(3):
净= slim.conv2d(净,256,[ 3,3 ],范围= ’ conv3_ %d ’ %(I + 1))
净= slim.max_pool2d(净,[ 2,2 ],范围= ’ POOL2 ')
使用TF-Slim的repeat操作可以使这更清洁:

净= slim.repeat(净,3,slim.conv2d,256,[ 3,3 ],范围= ’ conv3 ')
净= slim.max_pool2d(净,[ 2,2 ],范围= ’ POOL2 ')
请注意,slim.repeat不仅在线应用相同的参数,它还足够智能地展开范围,以便为每个后续调用分配的范围slim.conv2d附加下划线和迭代编号。更具体地说,上面示例中的范围将命名为“conv3 / conv3_1”,“conv3 / conv3_2”和“conv3 / conv3_3”。

此外,TF-Slim的slim.stack运算符允许调用者使用不同的参数重复应用相同的操作来创建堆栈或层塔。slim.stack还tf.variable_scope为每个创建的操作创建一个新的。例如,创建多层感知器(MLP)的简单方法:

#详细方式:
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 TF-超薄方式:
slim.stack(X,slim.fully_connected,[ 32, 64, 128 ],范围= ’ FC ')
在此示例中,slim.stack调用slim.fully_connected三次将函数的一次调用的输出传递给下一次。但是,每次调用中隐藏单元的数量从32变为64到128.同样,可以使用堆栈来简化多个卷积的塔:

#冗长的方法:
X = slim.conv2d(X, 32,[ 3, 3 ],范围= '芯/ core_1 ')
X = slim.conv2d(X,32,[ 1,1 ],范围= '芯/ core_2 ')
X = slim.conv2d(X,64,[ 3,3 ],范围= '芯/ core_3 ')
X = slim.conv2d(X,64,[ 1,1 ],范围= '芯/ core_4 ')

#使用堆栈:
slim.stack(X,slim.conv2d,[( 32,[ 3, 3 ]),( 32,[ 1, 1 ]),( 64,[ 3, 3 ]),( 64,[ 1, 1 ])], scope = ’ core ')
领域
除了TensorFlow(name_scope, variable_scope)中的作用域机制类型之外,TF-Slim还添加了一个名为arg_scope的新作用域机制 。这个新范围允许用户指定一个或多个操作以及一组参数,这些参数将传递给中定义的每个操作 arg_scope。通过示例可以最好地说明此功能。请考虑以下代码段:

净= slim.conv2d(输入,64,[ 11,11 ],4,填充= ’ SAME ',
weights_initializer = tf.truncated_normal_initializer(STDDEV = 0.01),
weights_regularizer = slim.l2_regularizer(0.0005),范围= ’ CONV1 ')
净= slim.conv2d(净,128,[ 11,11 ],填充= ’ VALID ',
weights_initializer = tf.truncated_normal_initializer(STDDEV = 0.01),
weights_regularizer = slim.l2_regularizer(0.0005),范围= ’ CONV2 ')
净= slim.conv2d(净,256,[ 11,11 ],填充= ’ SAME ',
weights_initializer = tf.truncated_normal_initializer(STDDEV = 0.01),
weights_regularizer = slim.l2_regularizer(0.0005),范围= ’ conv3 ')
应该清楚的是,这三个卷积层共享许多相同的超参数。两个具有相同的填充,所有三个具有相同的weights_initializer和weight_regularizer。这段代码难以阅读,并且包含许多应该被考虑的重复值。一种解决方案是使用变量指定默认值:

填充= ’ SAME ’
初始化= tf.truncated_normal_initializer(STDDEV = 0.01)
regularizer = slim.l2_regularizer(0.0005)
净= slim.conv2d(输入,64,[ 11,11 ],4,
填充=填充,
weights_initializer =初始化,
weights_regularizer =正则,
范围= ’ CONV1 ')
净= slim.conv2d(净,128,[ 11,11 ],
填充= ’ VALID ',
weights_initializer =初始化,
weights_regularizer =正则,
范围= ’ CONV2 ')
净= slim.conv2d(净,256,[ 11,11 ],
填充=填充,
weights_initializer =初始化,
weights_regularizer =正则,
范围= ’ 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)):
净= slim.conv2d(输入,64,[ 11,11 ],范围= ’ CONV1 ')
净= slim.conv2d(净,128,[ 11,11 ],填充= ’ VALID ',范围= ’ CONV2 ')
净= slim.conv2d(净,256,[ 11,11 ],范围= ’ conv3 ')
如示例所示,使用arg_scope使代码更清晰,更简单,更易于维护。请注意,虽然参数值在arg_scope中指定,但它们可以在本地覆盖。特别是,当padding参数设置为’SAME’时,第二个卷积将使用’VALID’的值覆盖它。

也可以arg_scopes在同一范围内嵌套和使用多个操作。例如:

使用 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 '):
净= slim.conv2d(输入,64,[ 11,11 ],4,填充= ’ VALID ',范围= ’ CONV1 ')
净= slim.conv2d(净,256,[ 5,5 ],
weights_initializer = tf.truncated_normal_initializer(STDDEV = 0.03),
范围= ’ CONV2 ')
net = slim.fully_connected(net,1000,activation_fn = None,scope = ’ fc ')
在这个例子中,第一arg_scope应用相同的weights_initializer 和weights_regularizer参数给conv2d和fully_connected在其范围内的层。在第二个中arg_scope,conv2d仅指定了其他默认参数 。

工作示例:指定VGG16图层
通过组合TF-Slim变量,操作和范围,我们可以编写一个通常非常复杂的网络,只需很少的代码行。例如,可以使用以下代码段定义整个 VGG体系结构:

DEF vgg16(输入):
与 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)):
净= slim.repeat(输入,2,slim.conv2d,64,[ 3,3 ],范围= ’ CONV1 ')
净= slim.max_pool2d(净,[ 2,2 ],范围= ’ POOL1 ')
净= slim.repeat(净,2,slim.conv2d,128,[ 3,3 ],范围= ’ CONV2 ')
净= slim.max_pool2d(净,[ 2,2 ],范围= ’ POOL2 ')
净= slim.repeat(净,3,slim.conv2d,256,[ 3,3 ],范围= ’ conv3 ')
净= slim.max_pool2d(净,[ 2,2 ],范围= ’ pool3 ')
净= slim.repeat(净,3,slim.conv2d,512,[ 3,3 ],范围= ’ CONV4 ')
净= slim.max_pool2d(净,[ 2,2 ],范围= '池4 ')
净= slim.repeat(净,3,slim.conv2d,512,[ 3,3 ],范围= ’ conv5 ')
净= slim.max_pool2d(净,[ 2,2 ],范围= ’ 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 ')
返回网
训练模型
训练Tensorflow模型需要模型,损失函数,梯度计算和训练例程,迭代地计算相对于损失的模型权重的梯度并相应地更新权重。TF-Slim提供常见的损失函数和一组辅助函数,用于运行训练和评估例程。

损失
损失函数定义了我们想要最小化的数量。对于分类问题,这通常是真实分布与跨类别的预测概率分布之间的交叉熵。对于回归问题,这通常是预测值和真值之间的平方和差异。

某些模型,例如多任务学习模型,需要同时使用多个损失函数。换句话说,最终最小化的损失函数是各种其他损失函数的总和。例如,考虑一个模型,该模型预测图像中的场景类型以及每个像素的相机深度。该模型的损失函数将是分类损失和深度预测损失的总和。

TF-Slim提供了一种易于使用的机制,用于通过损耗 模块定义和跟踪损耗函数 。考虑我们想要训练VGG网络的简单情况:

导入 tensorflow 作为 tf
导入 tensorflow.contrib.slim.nets 作为网络
vgg = nets.vgg

#加载图像和标签。
图片,标签 = …

#创建模型。
预测,_ = vgg.vgg_16(图片)

#定义损失函数并获得总损失。
loss = slim.losses.softmax_cross_entropy(预测,标签)
在本例中,我们首先创建模型(使用TF-Slim的VGG实现),然后添加标准分类丢失。现在,让我们转向我们有一个产生多个输出的多任务模型的情况:

#加载图像和标签。
images,scene_labels,depth_labels = …

#创建模型。
scene_predictions,depth_predictions = CreateMultiTaskModel(images)

#定义损失函数并获得总损失。
classification_loss = slim.losses.softmax_cross_entropy(scene_predictions,scene_labels)
sum_of_squares_loss = slim.losses.sum_of_squares(depth_predictions,depth_labels)

#以下两行具有相同的效果:
total_loss = classification_loss + sum_of_squares_loss
total_loss = slim.losses.get_total_loss(add_regularization_losses = False)
在这个例子中,我们有两个损失,我们通过调用slim.losses.softmax_cross_entropy和添加 slim.losses.sum_of_squares。我们可以通过将它们加在一起(total_loss)或通过调用 来获得总损失slim.losses.get_total_loss()。这是怎么回事?当您通过TF-Slim创建损失函数时,TF-Slim会将损失添加到特殊的TensorFlow损失函数集合中。这使您可以手动管理总损失,或允许TF-Slim为您管理它们。

如果您想让TF-Slim为您管理损失但具有自定义丢失功能,该怎么办? loss_ops.py 还有一个函数可以将这种损失添加到TF-Slims集合中。例如:

#加载图像和标签。
images,scene_labels,depth_labels,pose_labels = …

#创建模型。
scene_predictions,depth_predictions,pose_predictions = CreateMultiTaskModel(images)

#定义损失函数并获得总损失。
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)#让TF-Slim知道额外的损失。

#以下两种计算总损失的方法是等效的:
regularization_loss = tf.add_n(slim.losses.get_regularization_losses())
total_loss1 = classification_loss + sum_of_squares_loss + pose_loss + regularization_loss

#(正常化损失默认包含在总损失中)。
total_loss2 = slim.losses.get_total_loss()
在这个例子中,我们可以再次手动产生总损耗函数或让TF-Slim知道额外的损失并让TF-Slim处理损失。

训练循环
TF-Slim为learning.py中的训练模型提供了一套简单但功能强大的工具 。这些功能包括重复测量损耗的Train功能,计算渐变并将模型保存到磁盘,以及用于操作渐变的几个便利功能。例如,一旦我们指定了模型,损失函数和优化方案,我们就可以调用slim.learning.create_train_op并slim.learning.train执行优化:

g = tf.Graph()

#创建模型并指定损失

total_loss = slim.losses.get_total_loss()
optimizer = tf.train.GradientDescentOptimizer(learning_rate)

# create_train_op确保每个我们索要损失时,update_ops
#正在运行和梯度被计算过于应用。
train_op = slim.learning.create_train_op(total_loss,optimizer)
logdir = … #存储检查点的位置。

slim.learning.train(
train_op,
LOGDIR,
number_of_steps = 1000,
save_summaries_secs = 300,
save_interval_secs = 600):
在该示例中,slim.learning.train提供有train_op用于(a)计算损失和(b)应用梯度步骤。logdir指定存储检查点和事件文件的目录。我们可以将所采用的梯度步数限制为任意数量。在这种情况下,我们已经要求 1000采取措施。最后,save_summaries_secs=300表示我们将每5分钟计算一次摘要,并save_interval_secs=600表示我们将每10分钟保存一次模型检查点。

工作示例:培训VGG16模型
为了说明这一点,我们来看一下培训VGG网络的以下示例:

导入 tensorflow 作为 tf
导入 tensorflow.contrib.slim.nets 作为网络

slim = tf.contrib.slim
vgg = nets.vgg

train_log_dir = …
如果 不是 tf.gfile.Exists(train_log_dir):
tf.gfile.MakeDirs(train_log_dir)

使用 tf.Graph()。as_default():
#设置数据加载:
images,labels = …

#定义模型:
predictions = vgg.vgg_16(images, is_training = True)

#指定丢失功能:
slim.losses.softmax_cross_entropy(预测,标签)

total_loss = slim.losses.get_total_loss()
tf.summary.scalar(’ loss / total_loss ',total_loss)

#指定优化方案:
optimizer = tf.train.GradientDescentOptimizer( learning_rate = .001)

# create_train_op确保,当我们评价它得到的损失,
#的update_ops完成和梯度更新计算。
train_tensor = slim.learning.create_train_op(total_loss,optimizer)

#实际上运行训练。
slim.learning.train(train_tensor,train_log_dir)
微调现有模型
从检查点恢复变量的简要回顾
在训练模型之后,可以使用从给定检查点tf.train.Saver() 恢复的模型来恢复它Variables。对于许多情况, tf.train.Saver()提供了一种简单的机制来恢复所有或几个变量。

#创建一些变量。
v1 = tf.Variable( …, name = “ v1 ”)
v2 = tf.Variable(…,name = “ v2 ”)

#添加操作以恢复所有变量。
恢复= tf.train.Saver()

#添加OPS恢复一些变量。
恢复 = tf.train.Saver([V1,V2])

#稍后,启动模型,使用保护程序从磁盘恢复变量,
#做一些与模型一起使用。
使用 tf.Session()作为 sess:
#从磁盘恢复变量。restorer.restore
(sess, “/ tmp / model.ckpt ”)
print( “模型恢复。”)
#做一些与模型一起工作的

有关详细信息,请参阅“ 恢复变量” 和“ 选择要保存和恢复 的变量”部分的“ 变量” 页面。

部分恢复模型
通常需要在全新数据集甚至新任务上微调预训练模型。在这些情况下,可以使用TF-Slim的辅助函数来选择要恢复的变量子集:

#创建一些变量。
v1 = slim.variable( name = “ v1 ”, …)
v2 = slim.variable(name = “ nested / v2 ”,…)

#获取要恢复的变量列表(仅包含’v2’)。这些都是
#等效方法:
variables_to_restore = slim.get_variables_by_name( “ v2 ”)
#或
variables_to_restore = slim.get_variables_by_suffix( “ 2 ”)
#或
variables_to_restore = slim.get_variables( scope = “ nested ”)
#或
variables_to_restore = slim.get_variables_to_restore (包括= [“嵌套” ])
#或
variables_to_restore = slim.get_variables_to_restore( exclude = [ “ v1 ” ])

#创建将用于恢复变量的保护程序。
恢复 = tf.train.Saver(variables_to_restore)

使用 tf.Session()作为 sess:
#从磁盘恢复变量。restorer.restore
(sess,“/ tmp / model.ckpt ”)
print(“模型恢复。”)
#做一些与模型一起工作的

使用不同的变量名恢复模型
从检查点恢复变量时,Saver 将变量名称放在检查点文件中,并将它们映射到当前图形中的变量。上面,我们通过传递一个变量列表来创建一个saver。在这种情况下,从每个提供的变量中隐式获取要在检查点文件中定位的变量的名称var.op.name。

当检查点文件中的变量名称与图中的变量名称匹配时,这很有效。但是,有时,我们希望从检查点恢复模型,该检查点的变量与当前图形中的变量具有不同的名称。在这种情况下,我们必须提供Saver一个字典,从每个检查点变量名称映射到每个图形变量。请考虑以下示例,其中检查点变量名称是通过一个简单的函数获得的:

#假设不是’CONV1 /权重’应从’vgg16 / CONV1 /权重’恢复
DEF name_in_checkpoint( VAR):
返回 ’ vgg16 / ’ + var.op.name

#假设不是’CONV1 /权重’和’器CONV1 /偏压’应从’CONV1 / params1’和’CONV1 / params2’恢复
DEF name_in_checkpoint( VAR:)
如果 “权重” 在 var.op.name:
返回 var.op .name.replace( “权重”, “ params1 ”)
如果 “偏见” 中 var.op.name:
回报 var.op.name.replace( “偏见”, “ params2 ”)

variables_to_restore = slim.get_model_variables()
variables_to_restore = {name_in_checkpoint(VAR):VAR 为 VAR 在 variables_to_restore}
恢复= tf.train.Saver(variables_to_restore)

使用 tf.Session()作为 sess:
#从磁盘恢复变量。restorer.restore
(sess,“/ tmp / model.ckpt ”)
在不同的任务上微调模型
考虑我们拥有预先培训的VGG16模型的情况。该模型在ImageNet数据集上进行了训练,该数据集有1000个类。但是,我们希望将其应用于只有20个类的Pascal VOC数据集。为此,我们可以使用预先训练的模型的值来初始化我们的新模型,不包括最后一层:

#加载Pascal VOC数据
图像,label = MyPascalVocDataLoader( …)
images,labels = tf.train.batch([image,label],batch_size = 32)

#创建模型
预测 = vgg.vgg_16(图像)

train_op = slim.learning.create_train_op(…)

#指定在ImageNet上训练的模型的保存位置。
model_path = ’ / path / to / pre_trained_on_imagenet.checkpoint ’

#指定新模型的生存位置:
log_dir = ’ / path / to / my_pascal_model_dir / ’

#仅恢复卷积层:
variables_to_restore = slim.get_variables_to_restore( exclude = [ ’ fc6 ', ’ fc7 ', ’ fc8 ’ ])
init_fn = assign_from_checkpoint_fn(model_path,variables_to_restore)

#开始训练。
slim.learning.train(train_op,log_dir, init_fn = init_fn)
评估模型。
一旦我们训练了模型(或者甚至在模型忙于训练时),我们希望看到模型在实践中的表现如何。这是通过选择一组评估指标来实现的,评估指标将对模型性能进行评级,实际加载数据的评估代码,执行推理,将结果与基础事实进行比较并记录评估得分。该步骤可以执行一次或周期性地重复。

度量
我们将度量定义为不是损失函数的性能度量(损失在培训期间直接优化),但我们仍然对评估模型的目的感兴趣。例如,我们可能希望最大限度地减少对数损失,但我们感兴趣的指标可能是F1得分(测试准确度)或交叉点联盟得分(不可区分,因此不能用作损失)。

TF-Slim提供了一组度量操作,可以轻松评估模型。抽象地,计算度量值可以分为三个部分:

初始化:初始化用于计算指标的变量。
聚合:执行用于计算指标的操作(总和等)。
完成:(可选)执行任何最终操作以计算度量值。例如,计算方式,分钟,最大值等。
例如,要计算mean_absolute_error,两个变量(count和 total)初始化为零。在聚合期间,我们观察了一组预测和标签,计算它们的绝对差异并将总数加到total。每次我们观察另一个值时, count都会递增。最后,在最终确定期间,total除以count获得均值。

以下示例演示了用于声明度量标准的API。由于度量通常在与训练集(计算损失)不同的测试集上进行评估,因此我们假设我们正在使用测试数据:

images,labels = LoadTestData(…)
predictions = MyModel(图片)

mae_value_op,mae_update_op = slim.metrics.streaming_mean_absolute_error(预测,标签)
mre_value_op,mre_update_op = slim.metrics.streaming_mean_relative_error(预测,标签)
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提供了两个便利功能:

#聚合值并更新两个列表中的操作:
value_ops,update_ops = slim.metrics.aggregate_metrics(
slim.metrics.streaming_mean_absolute_error(预测,标签),
slim.metrics.streaming_mean_squared_error(预测,标签))

#聚合值并更新两个词典中的ops:
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 (预测,标签),
})
工作示例:跟踪多个度量标准
把它们放在一起:

导入 tensorflow 作为 tf
导入 tensorflow.contrib.slim.nets 作为网络

slim = tf.contrib.slim
vgg = nets.vgg

#加载数据
图像,labels = load_data( …)

#定义网络
预测 = vgg.vgg_16(图像)

#选择要计算的指标:
names_to_values,names_to_updates = slim.metrics.aggregate_metric_map({
“ eval / mean_absolute_error ”:slim.metrics.streaming_mean_absolute_error(预测,标签),
“ eval / mean_squared_error ”:slim.metrics.streaming_mean_squared_error(预测,标签) )
})

#使用1000批数据评估模型:
num_batches = 1000

使用 tf.Session()作为 sess:
sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())

用于 BATCH_ID 在 范围(num_batches):
sess.run(names_to_updates.values())

metric_values = sess.run(names_to_values.values())
为指标,值在 拉链(names_to_values.keys(),metric_values):
打印('公制%S具有值:%F ’ %(公制,值))
请注意, metric_ops.py 可以在不使用layers.py 或 loss_ops.py的情况下单独使用

评估循环
TF-Slim提供了一个评估模块(evaluation.py),它包含帮助函数,用于使用metric_ops.py 模块中的指标编写模型评估脚本。其中包括定期运行评估,评估批量数据的指标以及打印和汇总度量结果的功能。例如:

导入张量流为 tf

slim = tf.contrib.slim

#加载数据
图像,labels = load_data( …)

#定义网络
预测 = MyModel(图像)

#选择要计算的指标:
names_to_values,names_to_updates = slim.metrics.aggregate_metric_map({
’ accuracy ':slim.metrics.accuracy(预测,标签),
’ precision ':slim.metrics.precision(预测,标签),
‘召回’:slim.metrics.recall(mean_relative_errors, 0.3),
})

#创建摘要OPS,使得它们也打印出到STD输出:
summary_ops = []
为 METRIC_NAME,metric_value在 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))

#设置全局步骤。
slim.get_or_create_global_step()

output_dir = … #存储摘要的位置。
eval_interval_secs = … #运行评估的频率。
slim.evaluation.evaluation_loop(
‘本地’,
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)
作者
Sergio Guadarrama和Nathan Silberman

引文
“TensorFlow-Slim:用于在TensorFlow中定义,训练和评估复杂模型的轻量级库”S. Guadarrama,N。Silberman,2016年 .https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/slim

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值