TensorFlow-Slim
mob 发布于 2021-03-01
TensorFlow-Slim是一个轻量级的库,用于定义、训练和评估TensorFlow中的复杂模型。tf slim的组件可以与本机tensorflow以及其他框架自由混合。

注:TF Slim的最新版本1.1.0使用tf1.15.2 py2、tf2.0.1、tf2.1和tf2.2进行了测试。

TF Slim是一个使神经网络的定义、训练和评估变得简单的库:

允许用户通过消除样板代码简洁地定义模型。这是通过使用参数范围和许多高级层和变量来实现的。这些工具提高了可读性和可维护性,降低了复制和粘贴超参数值时出错的可能性,并简化了超参数调整。

通过提供常用的正则化器使开发模型变得简单。

一些广泛使用的计算机视觉模型(如VGG、AlexNet)已在slim中开发,并可供用户使用。它们既可以用作黑盒,也可以以各种方式扩展,例如,通过向不同的内部层添加“多个头”。

Slim可以很容易地扩展复杂模型,并通过使用预先存在的模型检查点来热启动训练算法。


TF Slim的各种组件是什么?

TF-Slim由几个独立存在的部分组成。其中包括以下主要部分(详细说明如下)。
arg_scope:提供一个名为arg\u scope的新范围,允许用户为该范围内的特定操作定义默认参数。
数据:包含tfslim的数据集定义、数据提供程序、并行读取器和解码实用程序。
评估:包含评估模型的例程。
层:包含用于使用tensorflow构建模型的高级层。
学习:包含训练模型的例程。
损失:包含常用的损失函数。
指标:包含流行的评估指标。
nets:包含流行的网络定义,如VGG和AlexNet模型。
队列:提供了一个上下文管理器,用于轻松安全地启动和关闭QueueRunner。
正则化器:包含权重正则化器。
变量:为变量创建和操作提供方便的包装器。


定义模型

通过结合TensorFlow-Slim的变量、层和作用域,可以使用tfslim简洁地定义模型。这些元素的定义如下。

变量

在原生tensorflow中创建变量需要预定义的值或初始化机制(例如,从高斯流中随机采样)。此外,如果需要在特定设备(如GPU)上创建变量,则必须明确说明该规范。为了减少创建变量所需的代码,tfslim在中提供了一组瘦包装函数变量.py允许调用者轻松定义变量。
例如,要创建一个权重变量,使用截断正态分布对其进行初始化,使用l2\u损失对其进行正则化,并将其放置在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中,有两种类型的变量:正则变量和局部(瞬态)变量。绝大多数变量都是常规变量:一旦创建,就可以使用保存程序将它们保存到磁盘上。局部变量是那些仅在会话期间存在且未保存到磁盘的变量。

tfslim通过定义模型变量进一步区分变量,模型变量是表示模型参数的变量。模型变量在学习过程中进行训练或微调,在评估或推理过程中从检查点加载。示例包括由slim.fully_connected或者slim.conv2d图层。非模型变量是学习或评估过程中使用的所有其他变量,但实际执行推理时不需要这些变量。例如,全局步骤是在学习和评估期间使用的一个变量,但它实际上不是模型的一部分。同样,移动平均线变量可能反映模型变量,但移动平均线本身不是模型变量。

模型变量和规则变量都可以通过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提供了一个方便的函数,用于将模型变量添加到其集合中:

 my_model_variable = CreateViaCustomCode()

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

虽然张量流运算的集合相当广泛,但神经网络的开发人员通常会根据更高层次的概念来考虑模型,如“层”、“损失”、“度量”和“网络”。一个层,例如卷积层、完全连接层或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)
为了减少重复复制这些代码的需要,tfslim提供了许多在更抽象的神经网络层定义的方便操作。例如,将上面的代码与相应TF Slim代码的调用进行比较:

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

TensorFlow-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


TensorFlow-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的重复操作可以使其更干净:

 net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3')
net = slim.max_pool2d(net, [2, 2], scope='pool2')
请注意斯利姆。重复它不仅可以在线应用相同的参数,而且还可以聪明地展开作用域,以便分配给超薄.conv2d附加下划线和迭代编号。更具体地说,上述示例中的作用域将命名为“conv3/conv3_1”、“conv3/conv3_2”和“conv3/conv3_3”。

此外,斯利姆特遣部队slim.stack公司运算符允许调用方使用不同的参数重复应用相同的操作,以创建一个堆栈或层塔。slim.stack调用也创建了一个新的tf.U范围对于创建的每个操作。例如,创建多层感知器(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三次将函数的一次调用的输出传递给下一次调用。但是,每次调用中的隐藏单元数从32变为64,再变为128。类似地,可以使用堆栈来简化由多个卷积组成的塔:


mob
关注 私信
文章
61
关注
0
粉丝
0