文档章节

tf.name_scope() 和 tf.variable_scope() 的用法和玄机

刘小米_思聪
 刘小米_思聪
发布于 2017/12/22 03:12
字数 2035
阅读 372
收藏 0

一. name_scope 和 variable_scope的用途

用途1: 共享变量

TensorFlow (TF) 中,name_scope 和 variable_scope 主要是因为 变量共享 的需求。为什么要共享变量?举个简单的例子:例如,当我们研究生成对抗网络GAN的时候,判别器的任务是如果接收到的是生成器生成的图像,判别器就尝试优化自己的网络结构来使自己输出0,如果接收到的是来自真实数据的图像,那么就尝试优化自己的网络结构来使自己输出1。也就是说,生成图像和真实图像经过判别器的时候,要共享同一套变量,所以TensorFlow引入了变量共享机制。

变量共享主要涉及两个函数: 

  • tf.get_variable(<name>, <shape>, <initializer>)
  • tf.variable_scope(<scope_name>)

即就是必须要在tf.variable_scope的作用域下使用tf.get_variable()函数。这里用tf.get_variable( ) 而不用tf.Variable( ),是因为前者拥有一个变量检查机制,会检测已经存在的变量是否设置为共享变量,如果已经存在的变量没有设置为共享变量,TensorFlow 运行到第二个拥有相同名字的变量的时候,就会报错(详见本文的RNN应用例子章节)。

  • 两个创建变量的方式。如果使用tf.Variable() 的话每次都会新建变量。但是大多数时候我们是希望重用一些变量,所以就用到了get_variable(),它会去搜索变量名,有就直接用,没有再新建。
  • 名字域。既然用到变量名了,就涉及到了名字域的概念。通过不同的域来区别变量名,毕竟让我们给所有变量都取不同名字还是很辛苦。
  • 这就是为什么会有scope 的概念。name_scope 作用于操作,variable_scope 可以通过设置reuse 标志以及初始化方式来影响域下的变量。

“共享变量” 的应用场景:RNN应用例子

在tf.variable_scope的作用域下,通过get_variable()使用已经创建的变量,实现了变量的共享。在 train RNN 和 test RNN 的时候, RNN 的 time_steps 会有不同的取值, 这将会影响到整个 RNN 的结构, 所以导致在 test 的时候, 不能单纯地使用 train 时建立的那个 RNN. 但是 train RNN 和 test RNN 又必须是有同样的 weights biases 的参数. 所以, 这时, 就是使用 reuse variable 的好时机.

例子:首先定义train 和 test 的不同参数.

class TrainConfig:
    batch_size = 20
    time_steps = 20
    input_size = 10
    output_size = 2
    cell_size = 11
    learning_rate = 0.01


class TestConfig(TrainConfig):
    time_steps = 1
    
train_config = TrainConfig()
test_config = TestConfig()

然后让 train_rnn 和 test_rnn 在同一个 tf.variable_scope('rnn') 之下.

并且定义 scope.reuse_variables(), 使我们能把 train_rnn 的所有 weights, biases 参数全部绑定到 test_rnn 中.

这样, 不管两者的 time_steps 有多不同, 结构有多不同, train_rnn W, b 参数更新成什么样, test_rnn 的参数也更新成什么样.

with tf.variable_scope('rnn') as scope:
    sess = tf.Session()
    train_rnn = RNN(train_config)
    scope.reuse_variables()
    test_rnn = RNN(test_config)
    sess.run(tf.global_variables_initializer())

RNN 例子的完整代码可以看这里.

因为想要达到变量共享的效果, 就要在 tf.variable_scope()的作用域下使用 tf.get_variable() 这种方式产生和提取变量. 不像 tf.Variable() 每次都会产生新的变量, tf.get_variable() 如果遇到了已经存在名字的变量时, 它会单纯的提取这个同样名字的变量,如果不存在名字的变量再创建.

但在重复使用的时候, 一定要在代码中强调 scope.reuse_variables(),如下面代码所示,否则系统将会报错, 以为你是不小心重复使用到了一个变量.

with tf.variable_scope("a_variable_scope") as scope:
    initializer = tf.constant_initializer(value=3)
    var3 = tf.get_variable(name='var3', shape=[1], dtype=tf.float32, initializer=initializer)
    scope.reuse_variables()
    var3_reuse = tf.get_variable(name='var3',) # var3_reuse
    var4 = tf.Variable(name='var4', initial_value=[4], dtype=tf.float32)
    var4_reuse = tf.Variable(name='var4', initial_value=[4], dtype=tf.float32) # var4_reuse
    
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(var3.name)            # a_variable_scope/var3:0
    print(sess.run(var3))       # [ 3.]
    print(var3_reuse.name)      # a_variable_scope/var3:0
    print(sess.run(var3_reuse)) # [ 3.]
    print(var4.name)            # a_variable_scope/var4:0
    print(sess.run(var4))       # [ 4.]
    print(var4_reuse.name)      # a_variable_scope/var4_1:0
    print(sess.run(var4_reuse)) # [ 4.]
    

不强调reuse_variables()而报错的例子:

  1. 如果把 tf.Variable 改成 tf.get_variable,直接调用两次,就会报错:

    result1 = my_image_filter(image1)
    result2 = my_image_filter(image2)
    # Raises ValueError(... conv1/weights already exists ...)

    为了解决这个问题,TF提出了 tf.variable_scope 函数:它的主要作用是,在一个 variable_scope 作用域下内共享一些变量。实现方式可以有如下几种用法:

    1)

    with tf.variable_scope("image_filters") as scope:
        result1 = my_image_filter(image1)
        scope.reuse_variables() # or 
        #tf.get_variable_scope().reuse_variables()
        result2 = my_image_filter(image2)

    2)

    with tf.variable_scope("image_filters1") as scope1:
        result1 = my_image_filter(image1)
    with tf.variable_scope(scope1, reuse = True)
        result2 = my_image_filter(image2)

注意最好不要采用的方式:设置 reuse 标识为 False,然后在需要的时候设置 reuse 标识为 True。

 

可视化用途:画tensorboard流程图时封装

当然对我们而言name_scope还有个更直观的用处就是:在tensorboard 里可视化的时候用name_scope进行封装后会更清晰. 通常情况下,tf.variable_scope 和 tf.name_scope 配合,能画出非常漂亮的tensorboard流程图,但是他们两个之间又有着细微的差别,那就是 name_scope 只能管住操作 Ops 的名字,而管不住变量 Variables 的名字,看下例:

with tf.variable_scope("foo"):
    with tf.name_scope("bar"):
        v = tf.get_variable("v", [1])
        x = 1.0 + v
assert v.name == "foo/v:0"
assert x.op.name == "foo/bar/add"

参考:https://www.zhihu.com/question/54513728/answer/177901159

Tensorflow变量共享,参考:http://www.cnblogs.com/Charles-Wan/p/6200446.html

参考:http://sentiment-mining.blogspot.com/2016/12/tensorflow-name-scope-variable-scope.html

参考:https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-12-scope/

 

二. TensorFlow中name scope和variable scope区别

为了在代码的任何部分可以使用某一个已经创建的变量,TF引入了变量共享机制共享变量,而不是传一个变量的引用。

I. TF中创建变量的方式有两种:tf.get_variable()和tf.Variable()

  • tf.get_variable(“vname”)方法,在创建变量时,如果这个变量vname已经存在,直接使用这个变量,如果不存在,则重新创建;
  • tf.Variable()在创建变量时,一律创建新的变量,如果这个变量已存在,则后缀会增加0、1、2等数字编号予以区别。

例子:在 tf.name_scope() 的框架下使用这两种方式, 结果如下.

import tensorflow as tf

with tf.name_scope("a_name_scope"):
    initializer = tf.constant_initializer(value=1)
    var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
    var2 = tf.Variable(name='var2', initial_value=[2], dtype=tf.float32)
    var21 = tf.Variable(name='var2', initial_value=[2.1], dtype=tf.float32)
    var22 = tf.Variable(name='var2', initial_value=[2.2], dtype=tf.float32)


with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    print(var1.name)        # var1:0
    print(sess.run(var1))   # [ 1.]
    print(var2.name)        # a_name_scope/var2:0
    print(sess.run(var2))   # [ 2.]
    print(var21.name)       # a_name_scope/var2_1:0
    print(sess.run(var21))  # [ 2.0999999]
    print(var22.name)       # a_name_scope/var2_2:0
    print(sess.run(var22))  # [ 2.20000005]

可以看出使用 tf.Variable() 定义变量的时候, 虽然var2, var21, var22的 name 一样, 但是为了不重复变量名, Tensorflow 为它们做了附加的区分,因为输出的变量名是不一样的. 所以, 本质上tensorflow令 var2var21var22 成为不一样的变量.

这样做的目的是,搭配上不同的作用域类型,可以实现变量共享机制

II. TF中有两种作用域类型

  1. 命名域 (name scope),通过tf.name_scope 或 tf.op_scope创建;
  2. 变量域 (variable scope),通过tf.variable_scope 或 tf.variable_op_scope创建;
  • 这两种作用域,对于使用tf.Variable()方式创建的变量,具有相同的效果,都会在变量名称前面,加上域名称。 
  • 对于通过tf.get_variable()方式创建的变量,只有variable scope名称会加到变量名称前面,而name scope不会作为前缀。例如 print(v1.name)   # var1:0

例子:

 with tf.name_scope("my_name_scope"):

    v1 = tf.get_variable("var1", [1], dtype=tf.float32)

    v2 = tf.Variable(1, name="var2", dtype=tf.float32)

    a = tf.add(v1, v2)

print(v1.name)  # var1:0

print(v2.name)  # my_name_scope/var2:0

print(a.name)   # my_name_scope/Add:0

小结:name_scope不会作为tf.get_variable变量的前缀,但是会作为tf.Variable的前缀。

例子:

with tf.variable_scope("my_variable_scope"):

    v1 = tf.get_variable("var1", [1], dtype=tf.float32)

    v2 = tf.Variable(1, name="var2", dtype=tf.float32)

    a = tf.add(v1, v2)

print(v1.name)  # my_variable_scope/var1:0

print(v2.name)  # my_variable_scope/var2:0

print(a.name)   # my_variable_scope/Add:0

小结:在variable_scope的作用域下,tf.get_variable()和tf.Variable()都加了scope_name前缀。因此,在tf.variable_scope的作用域下,通过get_variable()可以使用已经创建的变量,实现了变量的共享。

 

© 著作权归作者所有

刘小米_思聪
粉丝 58
博文 60
码字总数 43955
作品 0
西安
其他
私信 提问
TensorFlow 作用域与操作符的受限范围

variablescope 影响变量和操作符 namescope 只影响操作符 with tf.namescope(""),使用空字符串将作用域返回到顶层 tf.variablescope("") 相当于添加一个空层...

阿豪boy
2018/07/19
4
0
tensorflow中的“tf.name_scope()”有什么用?

tf.name_scope()命名空间的实际作用 (1)在某个tf.namescope()指定的区域中定义的所有对象及各种操作,他们的“name”属性上会增加该命名区的区域名,用以区别对象属于哪个区域; (2)将不...

HeroHY
09/01
23
0
[专题2]tensorflow model save and restore 模型的保存和恢复(2)

二、进阶 Question: After you train a model in Tensorflow: 1. How do you save the trained model? 2. How do you later restore this saved model? 在入门过程中是使用了saver = tf.tr......

斐波那契的数字
2017/12/11
0
0
TensorFlow入门(八)tensorboard 的一个简单示例

关于 tensorboard 的一点心得 1.一定要学会使用 tf.variablescope() 和 tf.namescope(),否则稍微复杂一点的网络都会乱七八糟。你可以通过上图中的 graph 来看看自己构建的网络结构。 2.使用 ...

jerr__y
2017/11/21
0
0
强化学习笔记2-Python/OpenAI/TensorFlow/ROS-程序指令

强化学习笔记2-Python/OpenAI/TensorFlow/ROS-程序指令 TensorFlow TensorFlow是Google的一个开源软件库,广泛用于数值计算。它使用可在许多不同平台上共享和执行的数据流图。 它被广泛用于构...

优惠码发放
06/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Docker 可视化管理 portainer

官网安装指南: https://portainer.readthedocs.io/en/latest/deployment.html docker-compose.yml 位置,下载地址:https://downloads.portainer.io/docker-compose.yml...

Moks角木
28分钟前
2
0
Spring Security 实战干货:必须掌握的一些内置 Filter

1. 前言 上一文我们使用 Spring Security 实现了各种登录聚合的场面。其中我们是通过在 UsernamePasswordAuthenticationFilter 之前一个自定义的过滤器实现的。我怎么知道自定义过滤器要加在...

码农小胖哥
31分钟前
3
0
常见分布式事务解决方案

1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单、松耦合的服务,这样可以降低开发难度、增强扩展性、便于敏捷开发。当前被越来越多的开发者推崇,很多互联网行业巨头、开源...

asdf08442a
31分钟前
2
0
influxdb continuous queries(cq)从入门到放弃

从前一篇influxdb的文章prometheus基于influxdb的监控数据持久化存储方案完成之后,就一直在折腾influxdb发布测试和生产环境的问题,经过接近2个月的验证,最终发现使用influxdb自带cq的方案...

狗陈
42分钟前
7
0
7.线程通信

在现实生活中,如果一个人团队正在共同完成任务,那么他们之间应该有通信,以便正确完成任务。 同样的比喻也适用于线程。 在编程中,要减少处理器的理想时间,我们创建了多个线程,并为每个线...

Eappo_Geng
48分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部