版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013745804/article/details/80428618

————————————————

引子

前面写过一篇博文《TensorFlow学习笔记(六)》,其内容主要介绍的就是name_scope/variable_scope的使用,不过并没有明确地对这二者的使用场景进行区分,所以本文将清晰地给出name_scope / variable_scope的应用场景。

文章比较长,如果时间不够的话,那就直接看总结啦~

主要用法

我们知道,在TensorFlow中,常常会定义一堆节点,如果我们不能对此进行有效地管理,那么这些节点很可能会使我们心如乱麻,并且再也不想看这些杂乱的代码。

name_scope / variable_scope 正是为了更有效地管理节点而产生的两个操作(op)。

  • name_scope:用于对变量设置命名域,从而让变量按照其关系组成一个个scope,并不会对tf.get_variable()创建的变量名字产生影响;
  • variable_scope:绝大部分情形下,与tf.get_variable()配合使用,实现变量共享。

示例

我们下面举几个简单的例子:

a)利用name_scopetf.Variable创建的变量加上命名域:

with tf.name_scope("scope_1"):
v1 = tf.Variable([1], name="v1", dtype=tf.float32)
v2 = tf.get_variable("v2", [1])
print v1
print v2

此时输出结果为:

<tf.Variable 'scope_1/v1:0' shape=(1,), dtype=float32_ref>
<tf.Variable 'v2:0' shape=(1,) dtype=float32_ref>

从这里我们可以得出下列结论:

  • name_scope并不会对 tf.get_variable() 创建的变量添加命名域;
  • name_scope并不能用于实现变量共享。

b)结合使用variable_scopetf.get_variable()实现变量共享:

实验一
with tf.variable_scope("scope_1"):
v1 = tf.Variable([1], name="v1", dtype=tf.float32)
with tf.variable_scope("scope_1"):
v2 = tf.Variable([1], name="v1", dtype=tf.float32)

此时的输出结果为:

<tf.Variable 'scope_1/v1:0' shape=(1,), dtype=float32_ref>
<tf.Variable 'scope_1_1/v1:0' shape=(1,), dtype=float32_ref>

这个实验说明了tf.Variable()遇到重名变量时,将自动重命名,而不会发生冲突。在这个实验中,我们是在同一个scope中定义的同名变量,可是为什么不是修改最内层的变量名呢?也即为什么输出结果不是下面这样呢?

<tf.Variable 'scope_1/v1:0' shape=(1,), dtype=float32_ref>
<tf.Variable 'scope_1/v1_1:0' shape=(1,), dtype=float32_ref>

这是TensorFlow的一种很巧妙的手段,因为tf.Variable()被设计为提供给库编写者使用的一个接口,所以我们修改scope的话更加有利。为什么这么说?比如,我们运行下面的代码:

net = fully_connected(input_tensor, shape)
net = fully_connected(net, shape)

这个时候我们对fully_connected()函数的两次调用均没有给出scope,那这个时候我们的全连接层中的变量应该如何命名呢?这就与上面的实验情形类似了,TFLearn的fully_connected()函数是使用tf.Variable()实现的,所以一般情况下,将会使用默认的“FullyConnected”这一scope作为命名域,当我们第二次调用fully_connected()函数时,自动改变命名域为“FullyConnected_1”,而不是修改命名域内部的变量名,是不是比直接改最内层的变量名要合理许多?

那如果我们改变最内层的变量名,假设我们的函数fn()在scope中定义了“scope/v1, scope/v2”,那么,我们接下来将重命名为“scope/v1_1, scope/v2_1”,这样的话,那不是都在同一个scope中了么?到时候在TensorBoard中将显得乱七八糟~

对了,tf.Variable()在解决冲突时,总是重命名最外层的scope哟~验证如下:

with tf.variable_scope("scope_top"):
with tf.variable_scope("scope_bot"):
v1 = tf.Variable([1], name="v1", dtype=tf.float32)
with tf.variable_scope("scope_top"):
with tf.variable_scope("scope_bot"):
v2 = tf.Variable([1], name="v1", dtype=tf.float32)
vs=tf.trainable_variables()
for v in vs:
print v

此时,我们的输出为:

<tf.Variable 'scope_top/scope_bot/v1:0' shape=(1,), dtype=float32_ref>
<tf.Variable 'scope_top_1/scope_bot/v1:0' shape=(1,), dtype=float32_ref>

这样的话,如果我们调用一些基本的Layers来定义自己的Layer,比如说叫做layer_udef,且默认命名域为“Layer_Udef”,那么重复使用layer_udef时,得到的是“Layer_Udef”、“Layer_Udef_1”…这就很符合我们的预期咯。

实验二

实验一中,我们发现使用tf.Variable()并不能获取已经定义变量,换句话说,不能达到共享变量的目的,那我们能否用tf.get_variable()函数获取tf.Variable()定义的变量呢

with tf.variable_scope("scope_1"):
v1 = tf.Variable([1], name="v1", dtype=tf.float32)
print v1
with tf.variable_scope("scope_1", reuse=True):
v2 = tf.get_variable("v1", [1])

输出为:

<tf.Variable 'scope_1/v1:0' shape=(1,) dtype=float32_ref>
...
ValueError: Variable scope_1/v1 does not exist, or was not created with tf.get_variable().

相信大家都有疑惑,不是已经有了scope_1/v1变量么?为什么说它不存在呢?因为tf.Variable()所定义的变量并不是用于共享的,虽然它对于tf.get_variable()是可见的:

with tf.variable_scope("scope_1"):
v1 = tf.Variable([1], name="v1", dtype=tf.float32)
with tf.variable_scope("scope_1"):
v2 = tf.get_variable("v1", [1])

此时输出为:

<tf.Variable 'scope_1/v1:0' shape=(1,) dtype=float32_ref>
<tf.Variable 'scope_1/v1_1:0' shape=(1,) dtype=float32_ref>

那到底为什么tf.Variable()定义的变量不能共享呢?

这就涉及到tf.Variable()和tf.get_variable()的设计理念了:个人认为,tf.Variable()主要是为库的编写者设计,或者,我们可以用它来编写自己的需要重复定义的Layers,这样就不用操心变量之间的冲突了,这一点我们在实验一中已经说明过了。所以,当我们想要从最底层开始定义自己的层时,使用tf.Variable()吧~

实验三

说了这么多,那到底怎样才能成功地共享变量呢?

with tf.variable_scope("scope_1"):
v1 = tf.get_variable("v1", [1])
with tf.variable_scope("scope_1", reuse=True):
v2 = tf.get_variable("v1", [1])
vs = tf.trainable_variables()
for v in vs:
print v

此时我们的输出为:

<tf.Variable 'scope_1/v1:0' shape=(1,) dtype=float32_ref>

也就是说,变量“scope_1/v1”被共享咯~

总结

现将本文总结如下:

    name_scope并不会对tf.get_variable()定义的变量的命名产生影响;
    如果要从底层变量开始定义库函数的话,使用tf.Variable()是一种较好的选择;
    tf.Variable()定义的变量并不能被共享;
    如果想要实现变量共享,那就同时使用variable_scope和tf.get_variable()吧~

【转载】 TensorFlow之name_scope/variable_scope的更多相关文章

  1. tensorflow里面共享变量、name_scope, variable_scope等如何理解

    tensorflow里面共享变量.name_scope, variable_scope等如何理解 name_scope, variable_scope目的:1 减少训练参数的个数. 2 区别同名变量 ...

  2. Tensorflow函数——tf.variable_scope()

    Tensorflow函数——tf.variable_scope()详解 https://blog.csdn.net/yuan0061/article/details/80576703 2018年06月 ...

  3. tensorflow中的name_scope, variable_scope

    在训练深度网络时,为了减少需要训练参数的个数(比如LSTM模型),或者是多机多卡并行化训练大数据.大模型等情况时,往往就需要共享变量.另外一方面是当一个深度学习模型变得非常复杂的时候,往往存在大量的变 ...

  4. tensorflow 中 name_scope 及 variable_scope 的异同

    Let's begin by a short introduction to variable sharing. It is a mechanism in TensorFlow that allows ...

  5. tensorflow 中 name_scope和variable_scope

    import tensorflow as tf with tf.name_scope("hello") as name_scope: arr1 = tf.get_variable( ...

  6. Tensorflow 之 name/variable_scope 变量管理

    name/variable_scope 的作用 充分理解 name / variable_scope TensorFlow 入门笔记 当一个神经网络比较复杂.参数比较多时,就比较需要一个比较好的方式来 ...

  7. [转载]Tensorflow 的reduce_sum()函数的axis,keep_dim这些参数到底是什么意思?

    转载链接:https://www.zhihu.com/question/51325408/answer/125426642来源:知乎 这个问题无外乎有三个难点: 什么是sum 什么是reduce 什么 ...

  8. [图解tensorflow源码] [转载] tensorflow设备内存分配算法解析 (BFC算法)

    转载自 http://weibo.com/p/1001603980563068394770   @ICT_吴林阳 tensorflow设备内存管理模块实现了一个best-fit with coales ...

  9. [转载]tensorflow中使用tf.ConfigProto()配置Session运行参数&&GPU设备指定

    tf.ConfigProto()函数用在创建session的时候,用来对session进行参数配置: config = tf.ConfigProto(allow_soft_placement=True ...

  10. [转载]Tensorflow中reduction_indices 的用法

    Tensorflow中reduction_indices 的用法 默认时None 压缩成一维

随机推荐

  1. .net core .net5 asp.net core mvc 与quartz.net 3.3.3 新版本调用方式

    参照了:https://www.cnblogs.com/LaoPaoEr/p/15129899.html 1.项目Nuget引用Quartz.AspNetCore和Quartz.Extensions. ...

  2. 为什么boolean 类型的字段不建议使用is开头?

    对于非boolean类型的参数,getter和setter方法命名的规范是以get和set开头 对于boolean类型的参数,setter方法是以set开头,但是getter方法命名的规范是以is开头 ...

  3. SpringMVC 流程?

    a.用户发送请求至前端控制器 DispatcherServlet. b.DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器. c.处理器映射器找到具体的处理器 ...

  4. c++ win32 纤程

    Win32纤程是一种轻量级的协程机制,它能够在同一个线程中实现多个线程执行的效果,从而提高了程序的并发性和可伸缩性. 在C++中,可以使用Win32 API中的fiber来实现纤程.以下是一个使用纤程 ...

  5. springboot支持http2

    现在http/3都出来了,但是很多项目还是没有采用https,这个是说不过去的. http3在2022/06/06 正式发布,具体见https://www.163.com/dy/article/H9B ...

  6. 京东云上centos8.2 安装 consul1.11.1

    做个笔记下 -- 前言 部分内容有参考网友的,但是地址不记得了! 安装内容基本参考官网的和上一个网友的 官网地址: https://www.consul.io/downloads 以下是使用root方 ...

  7. python重拾第十天-协程、异步IO

    本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 引子 到目前为止,我们已经学了网络并发编程的2个套路, 多进程,多线程,这哥俩的优势和劣势都非常的明显,我们一起来回顾 ...

  8. Nuxt3 的生命周期和钩子函数(六)

    title: Nuxt3 的生命周期和钩子函数(六) date: 2024/6/30 updated: 2024/6/30 author: cmdragon excerpt: 摘要:本文深入解析了Nu ...

  9. ElasticSearch不区分字母大小写搜索

    0.停止使用该索引的服务(避免新加了数据没备份) 1.备份filesearch索引(检查备份的索引和原索引数据条数是否一致) 1 POST http://127.0.0.1:9200/_reindex ...

  10. 【Error】mysql的error.log中ranges: 268 max_threads: 4 split: 268 depth: 2是什么意思?

    2021-12-08T09:36:39.612332+08:00 44213799 [Note] [MY-011825] [InnoDB] Parallel scan: 4 2021-12-08T09 ...