tf之变量与作用域
共享变量
tf.Variable 创建唯一变量:当系统检测到命名冲突会自动处理,保证了变量的唯一性,也就是不可复用,
######################### Variable 无法共享 #########################
v1 = tf.Variable(tf.random_normal((2, 3)), name='v1')
print(v1) # <tf.Variable 'v1:0' shape=(2, 3) dtype=float32_ref>
v2 = tf.Variable(tf.random_normal((3, 3)), name='v1')
print(v2) # <tf.Variable 'v1_1:0' shape=(3, 3) dtype=float32_ref> ### name 冲突自动处理
通俗的说就是不能有两个变量一模一样
tf.get_variable 创建共享变量:所谓的共享变量,不是 共享文件的共享,也不是编程中公共变量的共享,
这里的共享是指可以把变量 A 直接赋值给变量 B,即变量 B 共享了 变量 A,通俗的说就是连个变量一模一样;
实际上 get_variable 是获取指定属性(name)的已存在变量,如果可获取,即共享了变量,如果指定属性的变量不存在,就新建一个。
######################### get_variable 共享变量 #########################
############# 证明 get_ariable 的共享是有条件的 ############# ### test1:用 tf.Variable 创建一个变量
# 1. 用 get_variable 无法获取这个已存在的变量,提示你在瞎搞
# 2. 用 get_variable 新建一个同名的变量,名字冲突会自动处理
v3 = tf.Variable(tf.random_normal((3, 3)), name='v3')
print(v3) # <tf.Variable 'v3:0' shape=(3, 3) dtype=float32_ref>
# v4 = tf.get_variable(name='v3') ### 报错 ValueError: The initializer passed is not valid. It should be a callable with no arguments and the shape should not be provided or an instance of `tf.keras.initializers.*' and `shape` should be fully defined.
v5 = tf.get_variable(name='v3', shape=(2, 2))
print(v5) # <tf.Variable 'v3_1:0' shape=(2, 2) dtype=float32_ref> ### test2:用 tf.get_variable 创建一个变量
# 1. 用 get_variable 也无法获取这个已存在的变量,提示已经存在,可见不是在获取,而是在新建
# 2. 用 get_variable 新建一个同名的变量,显然也会提示已存在
gv1 = tf.get_variable(name='gv1', shape=(2, 3))
print(gv1) # <tf.Variable 'gv1:0' shape=(2, 3) dtype=float32_ref>
# gv2 = tf.get_variable(name='gv1') ### 报错 ValueError: Variable gv1 already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:
# gv3 = tf.get_variable(name='gv1', shape=(2, 2)) #### 结论:直接使用 get_ariable 无法共享变量
小结
1. 共享变量就是两个变量一模一样
2. tf.get_variable 无法获取 tf.Variable 创建的变量,因为 tf.Variable 创建的是唯一变量,无法共享
3. tf.get_variable 无法直接获取 tf.get_variable 创建的变量,因为共享变量需要一定的条件
变量作用域
tensorflow 有一个默认的变量作用域,当然我们可以自己创建新的作用域
##### 默认变量作用域
print(tf.get_variable_scope().name) # 空 ##### 显式地创建一个变量作用域
with tf.variable_scope('scope1'):
print(tf.get_variable_scope().name) # scope1 with tf.variable_scope('scope2') as scope:
print(tf.get_variable_scope().name) # scope2
tf.get_variable 共享变量的条件是作用域内变量可共享
############# 探索 get_ariable 共享变量的方法 #############
### test1:用 tf.Variable 创建一个变量
# 1. 使该作用域的变量可复用后,用 get_variable 无法获取这个已存在的变量,提示变量已存在
v11 = tf.Variable(tf.random_normal((2, 3)), name='v11')
# tf.get_variable_scope().reuse_variables() ### 作用域内的变量可复用
# v12 = tf.get_variable(name='v11') ### test2:用 tf.get_variable 创建一个变量
# 1. 使该作用域的变量可复用后,用 get_variable 可以获取这个已存在的变量
gv11 = tf.get_variable(name='gv11', shape=(2, 3))
print(gv11) # <tf.Variable 'gv11:0' shape=(2, 3) dtype=float32_ref>
tf.get_variable_scope().reuse_variables() ### 作用域内的变量可复用
gv12 = tf.get_variable(name='gv11')
print(gv12) # <tf.Variable 'gv11:0' shape=(2, 3) dtype=float32_ref>
print(gv11 is gv12) # True
小结
1. tf.Variable 创建唯一变量,无论什么情况,都不可共享
2. tf.get_variable 只能共享 tf.get_variable 创建的变量
3. tf.get_variable 共享变量的条件是 作用域内变量可复用
作用域内变量可复用
有多种方法,如下
##### 作用域内的变量可复用-method1
with tf.variable_scope('test1') as test:
v1 = tf.get_variable('v1', shape=(2, 3))
tf.get_variable_scope().reuse_variables() ### 作用域内的变量可复用
v2 = tf.get_variable('v1')
print(v1 is v2) # True ##### 作用域内的变量可复用-method2
with tf.variable_scope('test2') as test:
v3 = tf.get_variable('v3', shape=(2, 3))
test.reuse_variables() ### 作用域内的变量可复用
v4 = tf.get_variable('v3')
print(v3 is v4) # True ##### 作用域内的变量可复用-method3
with tf.variable_scope('test3') as test:
v5 = tf.get_variable('v5', shape=(2, 3))
with tf.variable_scope(test, reuse=True): ### 作用域内的变量可复用
v6 = tf.get_variable('v5')
print(v5 is v6) # True
小结
1. 需要使用 同时使用 get_variable 和 variable_scope
2. 在同一个 variable_scope 内,不需要指定 reuse=True,但需要用 scope.reuse_variables() 或者 tf.get_variable_scope().reuse_variables()
3. 在不同的 variable_scope 内, 第一个不需要指定reuse=True,但后面需要指定。
get_variable 机制
get_variable 会判断指定属性的变量是否存在,如果存在,并且该变量空间的 reuse=True,那么就共享之前的变量,否则新建一个,
但是如果没有指定 reuse=True,会提示命名冲突
变量作用域进阶
多重作用域
作用域中的 resuse 默认是 False,调用函数 reuse_variables() 可设置为 True,
一旦设置为True,就不能返回到False,并且该作用域的子空间 reuse 都是True。
如果不想重用变量,那么可以退回到上层作用域,相当于 exit 当前作用域
with tf.variable_scope("root"):
# At start, the scope is not reusing.
assert tf.get_variable_scope().reuse == False
with tf.variable_scope("foo"):
# Opened a sub-scope, still not reusing.
assert tf.get_variable_scope().reuse == False
with tf.variable_scope("foo", reuse=True):
# Explicitly opened a reusing scope.
assert tf.get_variable_scope().reuse == True
with tf.variable_scope("bar"):
# Now sub-scope inherits the reuse flag.
assert tf.get_variable_scope().reuse == True
# with tf.variable_scope("bar2"):
# # Now sub-scope inherits the reuse flag.
# assert tf.get_variable_scope().reuse == False # AssertionError
# Exited the reusing scope, back to a non-reusing one.
assert tf.get_variable_scope().reuse == False
可以看到在 bar2 作用域内,reuse==False 报错了,因为这个父域是True。
作用域的调用
作用域名字可以作为参数
with tf.variable_scope("foo") as foo_scope: # 名字
v = tf.get_variable("v", [1])
with tf.variable_scope(foo_scope): # 参数
w = tf.get_variable("w", [1])
with tf.variable_scope(foo_scope, reuse=True):
v1 = tf.get_variable("v", [1])
w1 = tf.get_variable("w", [1])
assert v1 is v
assert w1 is w
with tf.variable_scope('scope1'):
w1 = tf.Variable(1, name='w1')
w2 = tf.get_variable(name='w2', initializer=2.) with tf.variable_scope('scope1', reuse=True): # 另一种方式
w1_p = tf.Variable(1, name='w1')
w2_p = tf.get_variable(name='w2', initializer=2.)
用as 或者直接用名字都可作为参数。 但是有区别,后面会总结。
作用域跳转
不管作用域如何嵌套,当使用with tf.variable_scope()打开一个已经存在的作用域时,就会跳转到这个作用域。
with tf.variable_scope("foo") as foo_scope:
assert foo_scope.name == "foo"
with tf.variable_scope("bar"):
with tf.variable_scope("baz") as other_scope:
assert other_scope.name == "bar/baz"
with tf.variable_scope(foo_scope) as foo_scope2:
print(tf.get_variable_scope().name) # foo
assert foo_scope2.name == "foo" # Not changed
with tf.variable_scope('foo') as foo_scope3:
print(tf.get_variable_scope().name) # bar/baz/foo
assert foo_scope3.name == "foo" # AssertionError
这里可以看到,直接用名字没有跳转,而用as跳转成功。
多重作用域下的变量
变量都是通过作用域/变量名来标识,作用域可以像文件路径一样嵌套。
# encoding:utf-8
__author__ = 'HP'
import tensorflow as tf with tf.variable_scope('s1'):
x1 = tf.get_variable('data1', [3, 4])
print(x1) # <tf.Variable 's1/data1:0' shape=(3, 4) dtype=float32_ref>
tf.get_variable_scope().reuse_variables() with tf.variable_scope('s11'):
# x2 = tf.get_variable('data1') # ValueError: Variable s1/s11/data1 does not exist
# print(x2)
pass with tf.variable_scope('s1'):
# x3 = tf.get_variable('data1') # ValueError: Variable s1/s11/s1/data1 does not exist
# print(x3)
pass with tf.variable_scope('s1', reuse=True):
x4 = tf.get_variable('data1') # ValueError: Variable s1/s1/data1 does not exist
print(x4)
pass with tf.variable_scope('s1', reuse=True):
x5 = tf.get_variable('data1')
print(x5) # <tf.Variable 's1/data1:0' shape=(3, 4) dtype=float32_ref>
with tf.variable_scope('s2'):
with tf.variable_scope('s1', reuse=True):
print(tf.get_variable_scope().name) # s2/s1
# x6 = tf.get_variable('data1') # Variable s2/s1/data1 does not exist
# print(x6)
可以看到 变量 就像文件一样,这个文件夹内的a文件和另外文件夹内的a文件不是一个文件。
综上得出如下结论:
1. 如果直接用名字,只能在同级作用域下跳转,如上例。
2. 如果用as, 可以在任何地方跳转到该作用域
// 可以这么理解:如果直接用名字,是相对路径,相当于是在当前目录下创建了一个该名字的文件夹,
// 而as是绝对路径,不管在哪调用,都能指定该路径。
命名空间
命名空间,也是一种作用域
name_scope 仅对普通operation 有用,对 get_variable 无效,
variable_scope 不仅对普通operation 有效,也对 get_variable 有效
先上代码
with tf.name_scope('name_test'):
n1 = tf.constant(1, name='cs1')
n2 = tf.Variable(tf.zeros([1]), name='v1')
ww1 = tf.multiply(n2, [1]) nv1 = tf.get_variable(name='nv1', initializer=1.0) with tf.variable_scope('v_test'):
v_n1 = tf.constant(2, name='cs2')
v_n2 = tf.Variable(tf.zeros([1]), name='v2')
ww2 = tf.multiply(v_n2, [1]) v1 = tf.get_variable(name='vv1', initializer=2.0) ### name_scope
print('n1', n1.name) # n1 name_test/cs1:0
print('n2', n2.name) # n2 name_test/v1:0
print('nv1', nv1.name) # nv1 nv1:0 # 注意和前两个不同,name_scope 对 get_variable 无效 print('ww1', ww1.name) # ww name_test/Mul:0 # 注意也加上了name_scope ### variable_scope
print('v_n1', v_n1.name) # v_n1 v_test/cs2:0
print('v_n2', v_n2.name) # v_n2 v_test/v2:0
print('v1', v1.name) # v1 v_test/vv1:0 # 注意和前两个相同,name_scope 对 get_variable 有效
print('ww2', ww2.name) # ww2 v_test/Mul:0 # 注意也加上了variable_scope
变量的名称是指针名,变量的name是地址。
共享变量用法进阶
在重复使用(即 非第一次使用)时,设置 reuse=True 来 再次调用 该共享变量作用域(variable_scope)。但是这种方法太繁琐了。
简单方法
def myfunc():
with tf.variable_scope('test', reuse=tf.AUTO_REUSE):
w = tf.get_variable('data', [2, 2])
return w for i in range(3):
print(myfunc()) # <tf.Variable 'test/data:0' shape=(2, 2) dtype=float32_ref>
# <tf.Variable 'test/data:0' shape=(2, 2) dtype=float32_ref>
# <tf.Variable 'test/data:0' shape=(2, 2) dtype=float32_ref>
相关API
with tf.variable_scope('V1') as variable_scope:
a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))
a2 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2') with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(variable_scope) # <tensorflow.python.ops.variable_scope.VariableScope object at 0x000000000D5F67F0>
print(variable_scope.name) # V1
print(tf.get_variable_scope()) # <tensorflow.python.ops.variable_scope.VariableScope object at 0x000000000D5F67B8>
print(tf.get_variable_scope().original_name_scope) # 空
print(tf.get_variable_scope().reuse) # False
print(tf.get_variable_scope().name) # 空
print(a1.name) # V1/a1:0
print(a2.name) # V1/a2:0
获取当前环境的作用域 tf.get_variable_scope()
参考资料
https://www.cnblogs.com/MY0213/p/9208503.html
https://blog.csdn.net/lucky7213/article/details/78967306
https://blog.csdn.net/u012436149/article/details/53081454
https://blog.csdn.net/u010867294/article/details/78695487
https://blog.csdn.net/jeryjeryjery/article/details/79242684
http://www.cnblogs.com/Charles-Wan/p/6200446.html
tf之变量与作用域的更多相关文章
- js学习之变量、作用域和内存问题
js学习之变量.作用域和内存问题 标签(空格分隔): javascript 变量 1.基本类型和引用类型: 基本类型值:Undefined, Null, Boolean, Number, String ...
- 深入理解 JavaScript 变量的作用域和作用域链
一个变量的作用域(scope)是程序源代码中定义这个变量的区域.简单的说,作用域就是变量与函数的可访问范围.全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义.局部变量是在函数体内 ...
- js变量及其作用域(附例子及讲解)
Javascript和Java.C这些语言不同,它是一种无类型.弱检测的语言.它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变量 工具/原料 Ch ...
- javascript变量的作用域
javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象 讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...
- Js中变量的作用域
一.理解函数作用域需要理解以下几点: 1.函数变量的作用域有全局变量和局部变量两种,全局变量写在函数的最前面,局部变量写在函数体内,局部变量省略了var 也就默认成为了全局变量! 2.函数 ...
- 《征服 C 指针》摘录2:C变量的 作用域 和 生命周期(存储期)
在开发一些小程序的时候,也许我们并不在意作用域的必要性.可是,当你书写几万行,甚至几十万行的代码的时候,没有作用域肯定是不能忍受的. C 语言有如下 3 种作用域. 1.全局变量 在函数之外声明的变量 ...
- JavaScript变量和作用域
认识JavaScript中的变量 JavaScript中的变量有两种类型,一种是基本类型.一种是引用类型. 基本数据类型:Defined,Null,Boolean,Number,String.注意St ...
- JavaScript笔记:变量及其作用域
一.变量的定义及声明 在javascript中变量仅仅是用来保存值的一个占位符而已,定义变量时要使用关键字var后跟一个变量名,如下所示: var message; //定义一个变量message,像 ...
- JavaScript变量的作用域和函数的作用域的区别
变量作用域和函数作用域都涉及到变量值的变化,本文旨在让大家明白他们之间的区别 变量的作用域: 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接 ...
随机推荐
- Shell脚本管理
sh test.sh../test.sh与source test.sh.. test.sh执行命令的区别:sh是启用子shell执行而source或点是在当前窗口执行export A=123:定义全局 ...
- 关于JAVA项目中的常用的异常处理情况总结
1. JAVA异常处理 在面向过程式的编程语言中,我们可以通过返回值来确定方法是否正常执行.比如在一个c语言编写的程序中,如果方法正确的执行则返回1.错误则返回0.在vb或delphi开发的应用程序中 ...
- Vue音乐项目笔记(四)(搜索页面提取重写)
1.如何通过betterScroll组件实现上拉刷新 https://blog.csdn.net/weixin_40814356/article/details/80478440 2.搜索页面跳转单曲 ...
- LOJ6072苹果树
虽然结合了很多算法,但是一步一步地推一下还不算太难的一道题. 首先考虑枚举枚举有用的苹果的集合,然后去算生成树个数. 先考虑怎么计算生成树个数. 发现可以使用matrix-tree. 所有有用点可以和 ...
- 20165309 实验一 Java开发环境的熟悉
20165309 实验一 Java开发环境的熟悉 一.实验内容及步骤 (一)命令行下Java程序开发 在Linux下用ctrl+alt+T打开终端,用mkdir创建文件夹后cd进入. 在vim下键入如 ...
- 移动端自动化测试-Mac-IOS-Appium环境搭建
第一步 安装JDK,本机如果带有1.7及以上版本的,则可忽略此安装步骤. 百度下载JDK,并配置环境变量 vim ~/.bash_profile 检查是否安装成功 java -version 第二步 ...
- python-day97--git协同开发
1.协同开发流程 - 在dev的基础上创建三个开发的分支 -每个人都在自己的分支中进行开发 -第一个人开发完成之后把review分支从云端版本库中拉下来 -将个人的分支与review分支合并(确保re ...
- leetcode-algorithms-20 Valid Parentheses
leetcode-algorithms-20 Valid Parentheses Given a string containing just the characters '(', ')', '{' ...
- Redis(window版本)安装及使用
1.打开redis官网http://redis.io/点击Download 2.往下拉,找到Windows,由图片中的文字可以看出Redis项目不正式支持Windows. 但是,Microsoft开放 ...
- 在Shell中使用alias
以前在Linux跳机上登录其他服务器(ssh IP),为了方便,把很多服务器的IP和业务名称touch到了用户主目录下,这样方便了好多,每次ls -l 出来下就可以了,然后复制,粘贴就方便了.如下图. ...