TF-Slim是tensorflow中用来定义、训练与评估的轻量级库,tf-slim的组件与tf.contrib.learn相似能够将你从复杂的原生tensorflow解放出来。
你需要导入import tensorflow.contrib.slim as slim

为什么要用TF-Slim?

tf-slim能够将搭建、训练、评估神经网络变的简单:

  1. 通过使用参数域(argument scoping)与更多的高抽象层(layer)与变量,允许用户定义更加紧凑的模型,而不像原生tensorflow那样冗余。这个工具增加了代码的可读性与可维护性,减少像粘贴复制参数产生的错误,简化了参数的使用
  2. 通过提供常用的正则化方式使得开发模型变的简单
    3.内置了常用的视觉模型(VGG、Alextnet…),你可以把它当做一个黑盒子使用,并且也可以根据自己的需求进行修改
  3. Slim使得扩展复杂的模型变的简单,最令人兴奋的是你可以使用已经存在的checkpoints,去训练模型,做迁移学习
TF-Slim有哪些组件?
  1. arg_scope
  2. data
  3. evaluation
  4. layers
  5. learning
  6. losses
  7. metrics
  8. nets
  9. queues
  10. regularizers
  11. variables

Variables

如果使用原生tensorflow创建一个variables,你需要给它一个预定义值,或者初始化机制(如:在高斯模型中随机取值),而且如果一个变量你想要把它创建在GPU上 ,你需要更加相信的指定。为了解放这个过程,TF-Slim提供了一个包裹函数使得我们更加简单的定义变量
例如:下面这个例子,不仅指定了初始化方式、使用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中有两类变量,局部变量与全局变量,全局变量一旦被创建,就可以通过saver保存到磁盘中,而局部变量只存在session生命周期中,一点session关闭则就会被清除,不能保存到磁盘中。
TF-Slim进一步区分变量类型,定义了模型变量,模型变量指的是模型中的参数。模型变量是学习过程中被训练的或者被微调的,在评估模型与推理模型的时候,能够通过checkpoint文件加载到计算图(Graph)中。例如:slim.fully_connected o(创建全连接函数)与slim.conv2d (卷积操作)创建的变量就是模型变量

# 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来管理您的模型变量,那该怎么办呢?
TF-Slim提供了一个简单便利的方式添加到模型变量集合中

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

Layers

TF-Slim另外一个高度抽象的方法就是Layers组件,如果使用原生tensorflow创建一个:

  1. 创建权重与偏置变量
  2. 将输入变量与权重做卷积操作
  3. 加上偏置
  4. 应用激活函数,输出
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)

上面是定义一个卷积层的基础步骤,如果创建多个呢?比如说vgg-16?为了减少重复代码,TF-Slim提供了更简单的方式去定义一个卷积。

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

为了搭建神经网络,TF-Slim提供了一些标准的实现方式

这里写图片描述
TF-Slim也提供了两个元运算( meta-operations),repeat与stack,这两个函数将会更加的精简代码。比如在搭建vgg网络过程中,会有很多3*3相同的网络结构,你需要这样定义:

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

但是如果使用slim的话,你只需要这样定义:

net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3')
net = slim.max_pool2d(net, [2, 2], scope='pool2')

在inception网络的Inception-Model中,经常碰到的是相同网络结构,但是参数不同,你可能会这样定义:

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

如果使用stack方法的话,你只需要这样定义:

slim.stack(x, slim.conv2d, [(32, [3, 3]), (32, [1, 1]), (64, [3, 3]), (64, [1, 1])], scope='core')

Scopes

除了name_scope与variable_scope之外,TF-Slim还新添加了一个新的scoping机制叫做arg_scope。允许用户指定一个或多个操作和一组参数,这些参数将传递给arg_scope中定义的每个操作。比如定义三个卷积层,每层都使用L2正则化方式,权重初始化方式都采用标准差为0.01,从高斯函数中随机取值

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

不难看出,有很多设置是重复的,所以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还支持嵌套,如下设置全局的激活函数为relu,在全链接层设置局部激活函数为None

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

Losses

TF-Slim也内置了损失函数,

# 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)
`

Training Loop

TF-Slim提供了一个简单但是强大的工具去训练模型,包括一个训练方法能够重复的计算损失、梯度并且保存模型到磁盘中还有几个可以手动操作梯度的简单方法。例如:一旦我们指定了模型、损失函数、优化策略,我们可以调用 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 可以确保每次去执行损失函数, the update_ops
#会被运行,并且也会执行梯度的计算.
train_op = slim.learning.create_train_op(total_loss, optimizer)
logdir = ... # checkpoints 文件位置
slim.learning.train(train_op,logdir,number_of_steps=1000,save_summaries_secs=300,save_interval_secs=600)

train_op提供给slim.learning.train将会自动的计算损失与梯度下降。logdir的指定用来存储checkpoints与event文件。我们可以限制梯度下降的步数为任何值。比如上面我们限制为1000步。最后save_summaries_secs=300,是指定tensorboard中,多少次存储一个summary,300秒就是5分钟。我们经常会碰到训练中断,为了避免重头训练,可以设置save_interval_secs=600,表示10分钟保存一次模型。

Fine-Tuing已经存在的模型

模型被训练完以后,可以使用tf.train.Saver保存模型,也可以利用它从checkpoints文件中加载模型
例如:把变量从checkpoint文件中加载到模型中

# 创建变量
v1 = tf.Variable(..., name="v1")
v2 = tf.Variable(..., name="v2")
restorer = tf.train.Saver()
restorer = tf.train.Saver([v1, v2])
with tf.Session() as sess:# 从磁盘中加载模型restorer.restore(sess, "/tmp/model.ckpt")print("Model restored.")

checkpoint文件就是模型的元数据文件,里面记载了保存模型的历史与最新模型的名称,通过ckpt=tf.train.get_checkpoint_state('./checkpoints/')方法,可以得到最近一次ckpt文件的名称。saver.restore(sess, ckpt.model_checkpoint_path)把变量加载进来,这种方式需要重新运算模型,构造静态图,当然也有一种直接把静态图也加载进来,就不需要模型代码了saver = tf.train.import_meta_graph(ckpt.model_checkpoint_path+'.meta'),通过加载模型元数据可以直接恢复静态图。

恢复部分模型

有的时候模型很大比如说残差网络,动辄几百层,也许你只想观察某一层,而不想把所有的变量都加载进来,那么slim也提供了一个简单的方式

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

评估 Models

一旦我们训练了一个模型,我们想看看模型在实践中表现得如何。这是通过选择一组评价指标来完成的,这些评价指标将对模型的性能进行评分,而评估代码实际上是加载数据,执行模型,将结果与一组真实值进行比较,并记录评估得分。这个步骤可以进行一次或定期重复。网上大多都是粘贴复制,根本没有进行测试,甚至连代码能不能运行都不知道,也就是翻译一番而已,我的环境是tensoflow1.8,执行mre_value_op, mre_update_op = slim.metrics.streaming_mean_relative_error(predictions, labels)一直报错

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)
mre_value_op, mre_update_op = slim.metrics.streaming_mean_squared_error(predictions, labels)
pl_value_op, pl_update_op = slim.metrics.percentage_less(mean_relative_errors, 0.3)

先以mre_value_op, mre_update_op = slim.metrics.streaming_mean_relative_error(predictions, labels)为例,我翻阅了源码具体操作如下absolute_errors = math_ops.abs(predictions - labels),其实就是取绝对值,那么这个可能在评价回归模型比较有用,分类模型就没啥用处了。同理squared_error = math_ops.square(labels - predictions)也就是取平方。

对于streaming_mean_relative_error,我测试一直报错TypeError: streaming_mean_relative_error() missing 1 required positional argument: 'normalizer',源码如下:一起分析一下

  relative_errors = array_ops.where(math_ops.equal(normalizer, 0.0), array_ops.zeros_like(labels),math_ops.div(math_ops.abs(labels - predictions), normalizer))return mean(relative_errors, weights, metrics_collections,updates_collections, name or 'mean_relative_error')

总结的来说,就是需要设置一个normalizer参数,这个参数要与labels shape相同,如果normalizer为0,则这个label就设置为0,否则就是lable与prediction绝对值与normalizer的商。
这个用法我没体会到哪里会用到。也许当你阅读sllim英文文档时候,会搞不明白他们的含义,经过我们源码讨论一波,你是不是稍微有点感觉了?
最常用的还是,准确率,精准率,召回率,这点slim还是比较良心的

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),
})

如果你的代码运行不了,提示AttributeError: module 'tensorflow.contrib.metrics' has no attribute 'precision',那是因为tensorflow 1.8 直接把方法放到tensorflow.metrics中了,你可以降低版本,或者重新安装一下slim。欢迎关注我的微信公共号,一起讨论学习吧

还在用原生Tensorflow吗?试试TF-Slim吧相关推荐

  1. tensorflow兼容处理 tensorflow.compat.v1 tf.contrib

    20201130 问题提出: v1版本中tensorflow中contrib模块十分丰富,但是发展不可控,因此在v2版本中将这个模块集成到其他模块中去了.在学习tensorflow经常碰到tf.con ...

  2. TensorFlow介绍之TF数据流图

    TensorFlow介绍之TF数据流图 1. TF数据流图 1.1案例:TensorFlow实现一个加法运算 示例代码: def tensorflow_demo():""" ...

  3. Tensorflow学习之tf.keras(一) tf.keras.layers.Model(另附compile,fit)

    模型将层分组为具有训练和推理特征的对象. 继承自:Layer, Module tf.keras.Model(*args, **kwargs ) 参数 inputs 模型的输入:keras.Input ...

  4. tensorflow中的tf.summary.image

    tensorflow中的tf.summary.image tf.summary.image(name,#生成的节点的名称.也将作为TensorBoard中的系列名称tensor,#uint8或者flo ...

  5. 记录 之 tensorflow函数:tf.data.Dataset.from_tensor_slices

    tf.data.Dataset.from_tensor_slices(),是常见的数据处理函数,它的作用是将给定的元组(turple).列表(list).张量(tensor)等特征进行特征切片.切片的 ...

  6. tensorflow 启动Session(tf.Session(),tf.InteractivesSession(),tf.train.Supervisor().managed_session() )

    (1)tf.Session() 计算图构造完成后, 才能启动图. 启动图的第一步是创建一个 Session 对象. 示例程序: #coding:utf-8 import tensorflow as t ...

  7. TensorFlow 2.0 - tf.saved_model.save 模型导出

    文章目录 1. tf.saved_model.save 2. Keras API 模型导出 学习于:简单粗暴 TensorFlow 2 1. tf.saved_model.save tf.train. ...

  8. TensorFlow 2.0 - tf.data.Dataset 数据预处理 猫狗分类

    文章目录 1 tf.data.Dataset.from_tensor_slices() 数据集建立 2. Dataset.map(f) 数据集预处理 3. Dataset.prefetch() 并行处 ...

  9. Tensorflow 学习二 tf.Session().run

    以下为tf.Session().run 说明,其接受的fetches参数可以有多种类型. def run(self, fetches, feed_dict=None, options=None, ru ...

最新文章

  1. golang标准库http服务器处理流程
  2. springboot 添加拦截器之后中文乱码_springboot中配置了拦截器后,拦截器无效的解决方案之一...
  3. 零基础不建议学前端_web前端培训心得:零基础怎样学好web前端
  4. ElasticSearch聚合查询
  5. 树莓派 python 无人机_DIY一个基于树莓派和Python的无人机视觉跟踪系统
  6. ISO 审批通过 Ada 2012 语言标准
  7. 2017.10.17笔记
  8. CMOS和TTL的区别?
  9. numpy 常见 用法 取自np100题
  10. Windows XP优化指南
  11. cad卸载_IT运维:CAD卸载不彻底,无法重装?
  12. 阿里云Centos7安装mysql5.7
  13. 用树莓派连电脑显示屏
  14. 开源大数据处理系统/工具大全
  15. 【ZZULIOJ】1023: 大小写转换
  16. 什么是 Pandas?
  17. 软考-架构师-第七章-系统规划 第二节 可行性研究与效益分析 (读书笔记)
  18. 城市信息学其三-智能地理可实现个性化和可持续的未来城市交通
  19. 决策树之建立一棵树(代码模板)防止过拟合、剪枝参数
  20. C语言实现BMP图片的放大缩小-24位

热门文章

  1. 2022年大学应届生破千万,就业形势严峻,打工人准备好了吗?
  2. 今天许多的家庭有计算机英语,用英语写我的家庭作文3篇
  3. 618 线上摆摊 | 看直播 领京豆
  4. 卡巴斯基互联网安全套装(kis 官方
  5. Java面试宝典最新整理 下篇(持续更新中)
  6. 论文笔记---SSH
  7. video dispose
  8. 经历了几天台湾地震的影响,MSN终于可以上了~~~
  9. ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number
  10. learining user's intrinsic and extrinsic interests for point of interest recommendation IJCAI17