主要是来辨析tf.get_variable和tf.Variable、tf.variable_scope和tf.name_scope四者。
tf.Variable
- 无scope情况下tf.Variable永远会去创建新变量,且会自动处理name冲突问题,会自动给name+1
a = tf.Variable(tf.constant(0.1, shape=[10]), name='a' )
a2 = tf.Variable(tf.constant(0.1, shape=[10]), name='a' )
print(a is a2) # False
print(a) # <tf.Variable 'a_6:0' shape=(10,) dtype=float32_ref>
print(a2) # <tf.Variable 'a_7:0' shape=(10,) dtype=float32_ref>
tf.get_variable
- 无scope情况下tf.get_variable会去创建新变量,但是不会自动处理name冲突问题,故若name重复了会报错。(看起来和上面运行一样都是去新建变量,但是使用上面tf.Variable出来的变量是无法再去获取到的。而这个可以再获取到。)
# 这样会报错
v = tf.get_variable("v", [1], initializer=tf.constant_initializer(1.0))
v2 = tf.get_variable("v", [1], initializer=tf.constant_initializer(2.0))
tf.name_scope
- tf.name_scope会为tf.Variable,tensor等增加前缀,方便管理变量,并对tf.get_variable无效。
with tf.name_scope("first"):
with tf.name_scope("second"):
v1 = tf.constant(2, name="cons") # first/second/cons:0
v2 = tf.Variable(2, name="var") # first/second/var:0
v3 = tf.multiply(tf.constant(2), tf.constant(3), name="multi") # first/second/multi:0
v4 = tf.get_variable("get_v", [1]) # get_v:0 # 不会有first/second/前缀
注意,name_scope默认不复用,本身调用第二次也会自动name+1的,此时可以加后缀/避免。
image.png
tf.variable_scope
- tf.variable_scope会为两者都添加前缀。但是主要是为了配合tf.get_variable进行变量重用。
- 默认情况(reuse=False)下变量重用关闭,tf.get_variable还是会去创建新变量,若重复则冲突报错。
- 若reuse=True情况下,变量一定重用,tf.get_variable一定会去获取之前已创建过的变量,若没找到则会报错。
-
若reuse=tf.AUTO_REUSE情况下,tf.get_variable会自动判断,变量不存在则新建,存在则获取。
image.png
注意,和name_scope不同,variable_scope默认复用,本身调用第二次并不会自动name+1。但是有例外,那就是除了variable其他的tensor。variable_scope会给其他类型tensor默认也添加一个name_scope,而由上文可知name_scope是默认不复用的。因此发生如下情况:(一般不把非变量写进variable_scope,非变量也不能重获)
image.png
总结
image.png
同时,name_scope与variable_scope不能混用。哪怕在name_scope里tf.Variable了,也无法在之后的variable_scope中tf.get_variable获取到该变量。要想变量共享,则新建或重获的时候都使用tf.get_variable。
源码解析
tf版本有点旧了:https://blog.csdn.net/u012436149/article/details/73555017
image.png
tf1.4.0的版本来看:
利用with语句块,作为上下文管理器,然后重写其中的init(), enter()与exit()方法,做到在进入with语句块之前,先取出并保存当时的旧scope名称为old,然后进入语句块之后,拼接new_name与old构造新scope名称,作为其中变量的前缀名。之后在推出with语句块的时候,依旧写入之前保存的old名称。











网友评论