版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。


[参考文献]:

1.scope 命名方法

2.name&variable scope

3.tf.variable_scope和tf.name_scope的用法


1.scope是干什么的

顾名思义“scope”的意思是“范围”,那么name_scope和variable_scope就是针对name所做的范围定义。典型的 TensorFlow 可以有数以千计的节点,在构建各op的过程中,命名要做到不重复,那么在编写程序的时候就要特别注意,例如“x”、“y”、”W”、”B”甚至“weight”等经常使用的变量/常量命名就很可能会重复,否则就要增加一个字符串来表示不同的op所属,例如在x前加train成为train_x,在x前加scan成为scan_x等等,一方面表明此变量、常量所属“范围”的标识,这个name_scope和variable_scope就是干这个事情的,另一方面是从name上保证此变量命名的唯一性。有了这个scope的存在,其中描述的变量和常量就会在机器当中自动给添加前缀描述,作为对各个变量、常量的区分。在这里的编程和以前使用C、C++不同之处就是,C/C++当中的变量名实际相当于我们这里的XXX.name()而不是XXX,计算机区分的是XXX.name()。简单说,有了scope,那么在tensorflow当中就是用op/tensor名来划定范围,实现对变量或者常量名的唯一性定义,避免冲突。

2.scope是怎么干的

接下来我们要分析的问题是:究竟name_scope()和variable_scope()对可以产生变量的tf.get_variable()和tf.Variable()会有什么不同?为了一探究竟,接下来做一些测试:

2.1 tf.name_scope对tf.get_variable()的影响

import tensorflow as tf

with tf.name_scope("a_name_scope") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
 
var1:0
[ 1.]

[结论]:

name_scope()没有对 tf.get_variable()产生的变量增加“范围”。于是,如果再有相同的变量名生成,即便name_scope使用了新的名字“a_name_scope_new”,仍旧会破坏“唯一性”,从而导致出错“该变量已经定义过了!”,试验一下:

with tf.name_scope("a_name_scope_new") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
 
---------------------------------------------------------------------------

ValueError: Variable var1 already exists, disallowed. Did you mean to set reuse=True in VarScope?

【结论】:

果然出错了!“Variable var1 already exists, disallowed.”,说明name_scope没有对get_variable()增加“范围”。那我现在还想生成一个新的变量var2而且要让其内容与var1相同怎么办?

with tf.name_scope("a_name_scope") as myscope:
#initializer = tf.constant_initializer(value=1)
var2 = tf.get_variable(name='var2', dtype=tf.float32, initializer=var1)
#var2=var1
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # var2:0
print(sess.run(var2)) # [ 1.]
 
var1:0
[ 1.]
var2:0
[ 1.]
 

【结论】:

看结果,的确生成了新的变量var2。如果我不想生成新的变量var2,而只想做个变量的名称更改怎么办?注意,这里就和C、C++有不同了。
 
  • 1
with tf.name_scope("a_name_scope") as myscope:
var3=var1
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var3.name) # var1:0
print(sess.run(var3)) # [ 1.]
 
var1:0
[ 1.]
var1:0
[ 1.]
 

【结论】:

虽然有一个变量var3,但是其name和值都是与var1相同的,计算机认的是name,认为这两个是完全一样的,并不是新建,只是引用,我们可以理解为是C语言中的指针,指针的名字可以千奇百怪,但是其指向的地址内容才是其真正的归属。所以,这个变量var3你可以随时设置,不会引起重复性、唯一性的错误——“Variable var1 already exists, disallowed.”。
 
  • 1

变量的名称只是指针名,变量的name是地址

with tf.name_scope("a_name_scope") as myscope:
var3=var1
 

【结论】:

的确没有引起错误提示。
 

2.2 variable_scope对get_variable的影响

那么接着分析,既然name_scope对get_variable没有增加“范围”,那variable_scope呢?
 
with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
 

【结论】:variable_scope对get_variable有命名的影响

看到var1指向的内容被新建了,其name变成了“a_variable_scope/var1:0”,也就是说对计算机而言这已经是一个新的内容了,需要一个新的内存来存储,这个和之前的var1.name = var1:0已经不是一个东西了.同时,我们想要找到之前的var1的name已经是不能够了,这个完全就是C/C++指针的意思,指针指向了一个新的内存,如果不使用一个新的指针指向旧的地址,那么就会导致旧地址的内容无法检索了。验证一下:
 
  • 1
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var3.name) # var1:0
print(sess.run(var3)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
var1:0
[ 1.]
 

【结论】: 变量名就是指针,变量的name属性是地址

var3是前面对旧的var1的内容的指针,虽然在前面var1指向了新建的内容(a_variable_scope/var1:0),但是原有内容的指针给了var3,所以现在仍旧可以通过指针找到旧地址内容。前面看到了,使用variable_scope能够产生新的变量,即增加了“范围”标识的变量,那么这个能否再次执行产生新的变量呢?也就是说,新产生的name为(a_variable_scope/var1:0)的地址能否再次被新建?
 
with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
 
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)
ValueError: Variable a_variable_scope/var1 already exists, disallowed. Did you mean to set reuse=True in VarScope?
 

【结论】:get_variable取值的唯一性仍旧需要保证

可见虽然variable_scope可以增加name“范围”,但是get_variable取值的唯一性仍旧需要维护,否则就会出错,你是不可以任性新建的。那我现在就是想重用此变量,我就是想更改一个变量名而已,行吗?当然行,之前我们就采用了直接变量名赋值就行了“var3=var1”,这样变量名改为了var3,但是其name仍旧是var1的name,从c理解就是,指针随便建,地址唯一不变,街道名你随便改,可是街道你不能随便拆改。那还有一种材料中介绍的方法,就是使用reuse_variables(),但是一旦重用的对象本身不存在就会报错。这里说的对象不是“指针”,而是指针地址,而且是带有variable_scope指定的“范围”的指针地址。
 
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # var2:0
print(sess.run(var2)) # [ 1.]
print(var3.name) # var1:0
print(sess.run(var3)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
var2:0
[ 1.]
var1:0
[ 1.]
 

【分析】:

看看上面三个变量,如果在 tf.variable_scope(“a_variable_scope”)下则会增加“范围”——(a_variable_scope),显然,var1是已存在的对象,而var2虽然也是有已有的地址,但是如果在 tf.variable_scope当中使用get_variable来获取则会新建一个name为:(a_variable_scope/var2:0),所以var2不能当做是已有地址的变量来被重用,否则会出错。var1是可以被重用的,因为他的确是一个已有的范围内的地址。

with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
myscope.reuse_variables()
var2 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_variable_scope/var1:0
print(sess.run(var2)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
a_variable_scope/var1:0
[ 1.]
 

**【结论】:**var1被var2重用了

with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
myscope.reuse_variables()
var2 = tf.get_variable(name='var2', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_variable_scope/var1:0
print(sess.run(var2)) # [ 1.]
 
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

ValueError: Variable a_variable_scope/var7 does not exist, or was not created with tf.get_variable(). Did you mean to set reuse=None in VarScope?
 

【结论】:

在上面var1被var2重用,这个是正确的,但是紧接着想重新新建一个就会立马报错的,说明这个重用操作“myscope.reuse_variables()”在with范围内都是生效的。如果name_scope下使用reuse_variables()则会报错。
 
with tf.name_scope("a_name_scope") as myscope:
initializer = tf.constant_initializer(value=1)
myscope.reuse_variables()
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer) with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
 
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)
AttributeError: 'str' object has no attribute 'reuse_variables'
 

2.3 name_scope()对variable的影响

with tf.name_scope("a_name_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[2], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
 
a_variable_scope/var1:0
[ 1.]
a_name_scope_5/var2:0
[ 2.]
 

【结论】:

很棒!name_scope对variable有效,新增了“范围”名。那这个范围名是否与get_variable一样有唯一性?
 
with tf.name_scope("a_name_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[2], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
 
a_variable_scope/var1:0
[ 1.]
a_name_scope_6/var2:0
[ 2.]
 

【结论】:

从上面结果看,唯一性仍旧保证了,原因是自动的将var2.name从(a_name_scope_1/var2:0)变为了(a_name_scope_2/var2:0).这里使用了“变为”这个词实际是错误的,因为根本不是变为,而是新建了一个name 为(a_name_scope_2/var2:0)的变量,这个变量和前面的那个变量的名都为var2但是name属性却是不同的。
 

2.4 variable_scope对variable的影响

with tf.variable_scope("my_variable_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[initializer.value], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
a_variable_scope/var1:0
[ 1.]
my_variable_scope/var2:0
[ 1.]
 

【结论】:

variable_scope对variable有效,而且从下面的运行结果看,唯一性可以得到保证,新建了一个新的变量,这点和name_scope一致。
 
  • 1
with tf.variable_scope("my_variable_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[initializer.value], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
 
a_variable_scope/var1:0
[ 1.]
my_variable_scope_1/var2:0
[ 1.]
 

总结:

[1]. name_scope 对 get_variable新建变量的name属性无影响;对variable新建变量的name属性增加了“范围”标识。

[2]. variable_scope对get_variable新建变量的name属性和variable新建变量的name属性都增加了“范围”标识。

[3]. get_variable新建变量如果遇见重复的name则会因为重复而报错。

[4]. variable新建的变量如果遇见重复的name则会自动修改前缀,以避免重复出现。

name_scope与variable_scope 详解的更多相关文章

  1. 基础 | batchnorm原理及代码详解

    https://blog.csdn.net/qq_25737169/article/details/79048516 https://www.cnblogs.com/bonelee/p/8528722 ...

  2. TextCNN 代码详解(附测试数据集以及GitHub 地址)

    前言:本篇是TextCNN系列的第三篇,分享TextCNN的优化经验 前两篇可见: 文本分类算法TextCNN原理详解(一) 一.textCNN 整体框架 1. 模型架构 图一:textCNN 模型结 ...

  3. Batchnorm原理详解

    Batchnorm原理详解 前言:Batchnorm是深度网络中经常用到的加速神经网络训练,加速收敛速度及稳定性的算法,可以说是目前深度网络必不可少的一部分. 本文旨在用通俗易懂的语言,对深度学习的常 ...

  4. 深度学习基础(CNN详解以及训练过程1)

    深度学习是一个框架,包含多个重要算法: Convolutional Neural Networks(CNN)卷积神经网络 AutoEncoder自动编码器 Sparse Coding稀疏编码 Rest ...

  5. 超详细的Tensorflow模型的保存和加载(理论与实战详解)

    1.Tensorflow的模型到底是什么样的? Tensorflow模型主要包含网络的设计(图)和训练好的各参数的值等.所以,Tensorflow模型有两个主要的文件: a) Meta graph: ...

  6. 无所不能的Embedding6 - 跨入Transformer时代~模型详解&代码实现

    上一章我们聊了聊quick-thought通过干掉decoder加快训练, CNN-LSTM用CNN作为Encoder并行计算来提速等方法,这一章看看抛开CNN和RNN,transformer是如何只 ...

  7. 中文NER的那些事儿2. 多任务,对抗迁移学习详解&代码实现

    第一章我们简单了解了NER任务和基线模型Bert-Bilstm-CRF基线模型详解&代码实现,这一章按解决问题的方法来划分,我们聊聊多任务学习,和对抗迁移学习是如何优化实体识别中边界模糊,垂直 ...

  8. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  9. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

随机推荐

  1. RestTemplate的GET与POST

    发送GET请求: //设置请求头HttpHeaders headers = new HttpHeaders(); headers.add("token",PostUtils.get ...

  2. 碰到的TypeError--记录

    TypeError: object of type 'Response' has no len()   我在写爬虫的时候,通过requests获取到了网址的html文件,一开始是用content保存下 ...

  3. java8 lamb表达式对List排序

    场景一:List<Long> 或其他泛型,非对象 List<Long> ids = new ArrayList(); ids.add(100000001L); ids.add( ...

  4. [Python] Codecombat 攻略 地牢 Kithgard (1-22关)

    首页:https://cn.codecombat.com/play语言:Python 第一界面:地牢 Kithgard(22关) 时间:1-3小时 内容:语法.方法.参数.字符串.循环.变量等 网页: ...

  5. 你的一举一动,我可都看着!Linux超骚技巧三分钟Get

    今天看到一个超级叼的linux命令,可以完整记录屏幕上的命令与输出结果. 有人问这有什么叼的,不就是保存历史操作记录吗?我看看日志也能看出来. 不不不,我要说的“完整记录”包括第几秒执行什么命令,就像 ...

  6. python_并发编程——多进程

    from multiprocessing import Process import os def func1(): print('子进程1',os.getpid()) #子进程:获取当前进程的进程号 ...

  7. PL/sql配置相关

    可以安装oracle之后,打开PL/sql之后,自动找到oracle的路径以及数据库连接.   或者:安装oracle客户端,手动在PL/sql中配置oic以及oracle主目录的位置,并且配置好C: ...

  8. oracle数据库锁表

    在团队开发一个项目的时候,避免不了两个或两个以上的人同时操作某一数据库中的同一张表,这时候,如果一个用户没有提交事务,或者忘记提交事务,那么其他用户就不能对这张表进行操作了,这是很烦人的事情,下面是查 ...

  9. Ubuntu16.04 install hadoop-2.8.1.tar.gz Cluster Setup

    环境说明: ip地址 用户名称 机器名称 机器角色 192.168.3.150 donny  donny-Lenovo-B40-80 Master + Salve 192.168.3.167 cqb ...

  10. Kubernetes 学习24 helm入门

    一.概述 1.我们此前在使用kubernetes中,无论我们使用无状态的应用程序,比如myapp,nginx.以及有状态的tomcat,redis,etcd,...等等,他们部署在k8s之上会有这样的 ...