是一个类,tensorflow.python.ops.variables.Variable
,其构造函数原型为
def __init__(
self,
initial_value: Any = None,
trainable: bool = True,
collections: Any = None,
validate_shape: bool = True,
caching_device: Any = None,
name: Any = None,
variable_def: Any = None,
dtype: Any = None,
expected_shape: Any = None,
import_scope: Any = None,
constraint: Any = None
) -> Any
创建一个初始值为 initial_value
的变量。
Params:(仅关注几个常用的)
initial_value
– 变量初始值,是一个 Tensor
或者 可转换为 Tensor
的 python 对象;trainable
– 可否训练;collections
– 一个 List[graph collections keys],变量将会加入这些 collections
,列表默认为 [GraphKeys.GLOBAL_VARIABLES]
;name
– Optional(可选) 变量的名字,默认为 'Variable'
,如果已有同名变量,则新变量 name 为 'Variable_num'
,其中 num
递增;constraint
– 一个可选的投影函数,在被 Optimizer(例如,用于实现层权重的范数约束或值约束)更新之后应用于该变量。该函数必须将代表变量值的未投影张量作为输入,并返回投影值的张量(它必须具有相同的形状)。进行异步分布式训练时,约束条件不安全。例子:
a = tf.Variable(
initial_value=[1.0, 2.0],
trainable=True,
name='va',
dtype=tf.float32
)
print(a) #
函数,原型为:
def get_variable(
name: Any,
shape: Any = None,
dtype: Any = None,
initializer: Any = None,
regularizer: Any = None,
trainable: Any = None,
collections: Any = None,
caching_device: Any = None,
partitioner: Any = None,
validate_shape: bool = True,
use_resource: Any = None,
custom_getter: Any = None,
constraint: Any = None,
synchronization: VariableSynchronization = VariableSynchronization.AUTO,
aggregation: VariableAggregation = VariableAggregation.NONE
) -> Any
通过变量名来获取或创建一个变量。
Params:(仅关注几个常用的)
name
– 必填 变量的名字,如果已有同名变量,则报错(variable_scope(reuse=True)
除外);shape
– 变量形状;dtype
– 数据类型;本来猜测 initializer
中的 dtype
可能只决定随机值,最终类型由此参数决定,但 initializer
中的 dtype
似乎并不起作用;initializer
– 初始化器,如 tf.tf.random_uniform_initializer(minval=1, maxval=10)
;regularizer
– 可能是传入一个正则化器,如 `tf.contrib.layers.l2_regularizer(0.1)';synchronization
– 以后再说(应该挺有用的);例子:
a = tf.get_variable(
name='v',
shape=[1, 2],
dtype=tf.float64,
initializer=tf.random_uniform_initializer(
minval=1,
maxval=10,
dtype=tf.int32
) # initializer 里的 dtype 没什么卵用
)
print(a) # ``
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(a)) # [[3.98646081 3.30710938]]
def __init__(
self,
name: Any,
default_name: Any = None,
values: Any = None
) -> None
初始化上下文管理器。
Params:
name
– 传递给 OP 函数的 name 参数;default_name
– 如果 name 参数为 None 则使用默认的名称;values
– 要传递给 op 函数的张量参数列表(不清楚);这篇博文 讲得不错。
例子:
with tf.name_scope(name='ns'):
a = tf.Variable(0.0)
b = tf.Variable(0.0)
c = a + b
print(a) #
print(b) #
print(c) # Tensor("ns/add:0", shape=(), dtype=float32)
def __init__(
self,
name_or_scope: Any,
default_name: Any = None,
values: Any = None,
initializer: Any = None,
regularizer: Any = None,
caching_device: Any = None,
partitioner: Any = None,
custom_getter: Any = None,
reuse: Any = None,
dtype: Any = None,
use_resource: Any = None,
constraint: Any = None,
auxiliary_name_scope: bool = True
) -> Any
初始化上下文管理器。
Params:
name_or_scope
– string
or VariableScope
: 要打开的 scope;default_name
– 如果参数 name_or_scope
是 None
, 则启用默认名;values
– 要传递给 op 函数的张量参数列表(不清楚);reuse
– True
, None
, or tf.AUTO_REUSE
;
True
,该 scope 及其 sub-scope(reuse=None)开启 reuse 模式,get_variable(name='v')
将获取已有的 name == v
的变量;tf.AUTO_REUSE
, get_variable(name='v')
创建新变量 if v
不存在 esle 获取已有变量 v
;None
,则继承其 parent-scope 的 reuse flag;Returns:
A scope that can be captured and reused. 可以作为参数传递给 tf.variable_scope()
;
例子
with tf.variable_scope('vs') as scope:
a = tf.get_variable(name='a', shape=[2, 3], initializer=tf.random_uniform_initializer(0.0, 1.0))
print(a) #
with tf.variable_scope(scope, reuse=True): # 需要指明 reuse
b = tf.get_variable(name='a')
print(a is b) # True
# 两个定义是等价的
v = tf.Variable(tf.constant(1.0, shape=[1]), name='v')
v = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
print(v) #
tf.Variable()
的 name
是可选的;而 tf.get_variable()
的 name
是必填的;tf.Variable()
会在变量名后加 _n
其中 n
递增;而 tf.get_variable()
会报错(最后一个例子特殊,如果已存在 tf.Variable()
创建的同名变量,则遵循 +1 规则);例子
a = tf.Variable(tf.constant(1.0, shape=[1]), name='v')
b = tf.Variable(tf.constant(1.0, shape=[1]), name='v')
print(a) #
print(b) #
a = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
b = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
# ValueError: Variable v already exists, disallowed.
a = tf.Variable(1.0, name='v')
b = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
c = tf.Variable(1.0, name='v1')
d = tf.get_variable(name='v1', shape=[1], initializer=tf.constant_initializer(1.0))
print(a) #
print(b) #
print(c) #
print(d) #
只有在 tf.get_variable()
& tf.get_variable()
的情况下重名才报错,其他情况遵循 +1 规则。
with tf.name_scope('ns'):
a = tf.Variable(tf.constant(1.0, shape=[1]), name='v')
b = tf.Variable(tf.constant(1.0, shape=[1]), name='v')
print(a) #
print(b) #
with tf.variable_scope('vs'):
a = tf.Variable(tf.constant(1.0, shape=[1]), name='v')
b = tf.Variable(tf.constant(1.0, shape=[1]), name='v')
print(a) #
print(b) #
此时,tf.variable_scope()
== tf.name_scope()
with tf.name_scope('ns'):
a = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
# b = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
print(a) #
# print(b) # Err
tf.name_scope()
对 tf.get_variable()
不起作用。
with tf.variable_scope(
'vs',
initializer=tf.constant_initializer(1.0),
regularizer=tf.contrib.layers.l2_regularizer(0.01)
):
a = tf.Variable(0.0, name='v')
b = tf.get_variable(name='v', shape=[1])
print(a) #
print(b) #
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(a)) # 0.0
print(sess.run(b)) # [1.]
图 1 说明 a
的初始化是自己的 initial_value,regularizer 也未作用到 a
上。而 b
得到了这两个默认属性。
def forward(input_tensor):
with tf.variable_scope('vs', reuse=tf.AUTO_REUSE, initializer=tf.constant_initializer(3.0)):
w = tf.get_variable(name='w', shape=[1])
return input_tensor * w
a = tf.get_variable(name='input', shape=[1], initializer=tf.constant_initializer(2.0))
b = forward(a)
c = forward(b)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(a)) # [2.]
print(sess.run(b)) # [6.]
print(sess.run(c)) # [18.]
![]() |
![]() |
---|---|
get_variavble() |
Variavble() |
可以看到,w
为 tf.get_variable()
时得到了 reuse,非常方便。而 w
为 tf.Variable()
则不 reuse。
结论
tf.get_variable()
和tf.variable_scope()
一起可以发挥强大灵活的作用。而tf.Variable()
只把tf.variable_scope()
当作简化的tf.name_scope()
使用。
2.2
和 2.3
可以看到,tf.name_scope()
和 tf.variable_scope()
下,tf.Variable()
的名字都会加上前缀 scope
;2.4
说明tf.name_scope()
对 tf.get_variable()
不起作用;tf.name_scope()
更像是 tf.variable_scope()
的阉割版,从形参上看,前者较为简单,被后者完全覆盖;tf.variable_scope()
的形参中存在大量针对变量的参数(几乎是 name_scope + get_variable 参数的合集),如 initializer
和 regularizer
等,可以指定 scope
内创建的变量的默认属性;tf.Variable()
一样,空间重名 +1,(tf.variable_scope()
不使用 tf.get_variable()
时)with tf.name_scope('s'):
a = tf.Variable(0.0, name='v')
c = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
with tf.name_scope('s'):
b = tf.Variable(0.0, name='v')
print(a) #
print(b) #
print(c) #
with tf.variable_scope('s'):
a = tf.Variable(0.0, name='v')
c = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
with tf.variable_scope('s'):
b = tf.Variable(0.0, name='v')
# d = tf.get_variable(name='v', shape=[1], initializer=tf.constant_initializer(1.0))
print(a) #
print(b) #
print(c) # ,变量重名 +1
# print(d) # Err,对于 b = Variable() 而言,s+1,对于 d = tf.get_variable() 而言,s 内变量重名报错
Note1 可以看到,当用于 tf.Variable()
时,tf.variable_scope()
和 tf.name_scope()
没什么区别,重名的话都会使空间名自动 +1,即使混用,也一样;
Note2 发现一个很有意思的现象:
在第三个 scope 中,a 和 c 竟然不是同一个 scope,{a:s_2, c:s},可见,当
tf.variable_scope()
用于tf.get_variable()
,空间会另起炉灶(这个新炉灶不会+1)。
且新炉灶的第一个tf.get_variable()
前有tf.Variable()
创建的重名变量的话,则命名重复 +1。
所以,tf.variable_scope()
下,tf.get_variable()
和tf.Variable()
混用时,实际上是各自独立的。
总结
当使用
tf.Variable()
时,tf.name_scope()
和tf.variable_scope()
没什么区别;
当使用tf.get_variable()
时,tf.name_scope()
不起作用。
tf.variable_scope()
下,tf.get_variable()
和tf.Variable()
混用时,实际上是各自独立的