Tensorflow是一个编程模型,几乎成为了一种编程语言(里面有变量、有操做......)。 Tensorflow编程分为两个阶段:构图阶段+运行时。 Tensorflow构图阶段其实就是在对图进行一些描述性语言,跟html很像,很适合用标记性语言来描述。 Tensorflow是有向图,是一个有向无环图。张量为边,操做为点,数据在图中流动。 Tensorflow为每一个结点都起了惟一的一个名字。html
import tensorflow as tf a = tf.constant(3) # name=Const:0 b = tf.Variable(4) # name=Variable:0 print(a.name, b.name)
如上所示,即使你没有指明变量的name属性,tensorflow也会给它起个默认名字。python
在C++中有namespace的概念,命名空间的好处就是减小了命名冲突,咱们能够在命名空间中使用较简易的标识符。为了便于用户定义变量的name,tensorflow也提出了name_scope编程
with tf.name_scope("my"): a = tf.constant(3) # my/Const:0 b = tf.add(a, b) # my/Add:0 print(a.name, b.name) # 使用get_variable却无论用 c = tf.get_variable("c", shape=1, dtype=tf.int32, initializer=tf.constant_initializer(2)) # c:0 print(c.name)
如上所示,在name_scope中的属性,会用相似文件路径的方式来定义变量的name属性 可是关于name_scope须要明白两点:编程语言
总而言之,name_scope做用比较单一,仅仅是为了更改变量的name属性,便于命名变量。而variable_scope做用就很丰富了,它不只可以改变变量的name属性,还可以实现变量管理功能。函数
with tf.variable_scope("ha"): a = tf.constant(2, name="myconstant") # ha/myconstant:0 b = tf.get_variable("b", shape=1, dtype=tf.int32, initializer=tf.constant_initializer(2)) # ha/b:0 print(a.name, b.name)
在改变变量name属性这方面,variable_scope和name_scope基本没有差异,惟一的区别就是get_variable不会受到name_scope的影响,却会受到variable_scope的影响。测试
variable_scope更加剧要的功能是实现变量管理,其中最突出的一点就是变量共享spa
# 下面咱们来验证一下变量共享机制 def get_share_variable(reuse): with tf.variable_scope("share", reuse=reuse): a = tf.get_variable("a", shape=(1), dtype=tf.int32) return a one = get_share_variable(False) two = get_share_variable(True) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run([one, two, tf.assign(one, [2])]))
再上面的例子中,经过reuse属性能够控制variable_scope中的变量是否须要从新建立,若是指定reuse=false,则必然会执行新建变量的操做。 上面代码one和two输出值都变成了2,这说明它俩引用的是同一个对象。 使用variable_scope实现变量共享须要注意如下几点:设计
变量共享机制很是重要。一个很是经常使用的场景就是:训练完成以后保存模型,加载模型以后整个图已经创建好了,这时就须要经过variable_scope机制复用已经建好的图,而后测试。code
为了验证以上两点,请看下例:htm
复用不曾建立过的变量会报错
with tf.variable_scope("ha", default_name="what", reuse=True): try: m = tf.get_variable("m") except Exception as ex: print(ex) # Variable ha/m does not exist, or was not created with tf.get_variable(). Did you mean to set reuse=tf.AUTO_REUSE in VarScope?
它建议咱们使用reuse=tf.AUTO_REUSE,这个属性值的含义表示:若是变量存在则复用,不存在则建立之。
之前,reuse属性的取值为True和False,没有tf.AUTO_REUSE。可是在tensorflow将来的版本中,有可能会把reuse的取值弄成枚举类型。这就略微有点小坑了,不知AUTO_REUSE的使用场景是否对得起这么不优雅的设计。
下面验证第二点,必须指明变量的形状和类型才能够复用
with tf.variable_scope("ha", default_name="what", reuse=tf.AUTO_REUSE): try: m = tf.get_variable("m") print(m.name) except Exception as ex: print(ex) # ValueError: Shape of a new variable (ha/m) must be fully defined, but instead was <unknown>. 这个错误是在说:建立变量必须指明变量的类型
variable_scope的主要做用是变量共享。 说到变量共享,不得不说tf.get_variable()函数。tf.Variable()是构造函数,必定会建立新的变量。tf.get_variable则能够直接访问已经建立的变量(只能在variable_scope中且reuse=True或者AUTO_REUSE的状况下),也能够建立新的变量(在variable_scope内部或者外面均可以,如果内部,则必须reuse=FALSE或者AUTO_REUSE)。
经过以上过程能够发现,get_variable跟variable_scope很是合得来。get_variable不必定非在variable_scope中使用,可是不在variable_scope中使用,它就只能用来建立变量而没法复用变量了,由于只有variable_scope才拥有reuse属性。
# reuse变量的惟一方式就是使用name_scope x = tf.Variable(3, False, name='x') print(x.name, x.shape) # x:0 () y = tf.get_variable("x", shape=x.shape) print(y.name, y.shape) # x_1:0 ()
使用get_variable时也有一些微操做,好比指定trainable属性指明该变量是否能够训练。
with tf.variable_scope("ha", default_name="what", reuse=tf.AUTO_REUSE): # 当variable_scope reuse变量时,依旧能够对变量进行一些微操做:设置trainable=False,表示这个节点不可训练 # 当获取变量时,dtype类型必须对应正确 a = tf.get_variable("b", trainable=False, dtype=tf.int32) print(tf.trainable_variables("ha"))
相比name_scope功能的单一,tensorflow对variable_scope玩了不少花样:
为了对比说明问题,下面用嵌套的方式来实现做用域。
with tf.variable_scope("one"): """ 使用name_scope只会影响变量的名字,它要解决的问题是变量重名问题 """ with tf.name_scope("two"): x = tf.constant(3) # one/two/Const:0 print(x.name) # variable_scope.name是根目录的名字 print(tf.get_variable_scope().name, tf.get_variable_scope().original_name_scope) # 输出为:one one/ with tf.variable_scope("three"): x = tf.constant(3) # one/three/Const:0 print(x.name) print(tf.get_variable_scope().name, tf.get_variable_scope().original_name_scope) # 输出为one/three one/three/
可见,name_scope对于tf.get_variable_scope()来讲几乎是不可见的,但却会对变量的命名产生影响,但却仅仅对变量名产生影响。
函数不会阻隔with做用域
# 使用函数依旧不会影响做用域 def ha(): x = tf.Variable(3) # ha_3/Variable:0 print(x.name) with tf.variable_scope("ha"): # 这个变量做用域已经定义过好几回了,它的实际名字变成了ha_3 ha()
Tensorflow中每一个结点的name都不会重复,若是重复了怎么办?
# 若是重复定义变量 a = tf.constant(2, name='a') # a:0 b = tf.constant(2, name='a') # a_1:0 print(a.name, b.name) # 若是重复定义name_scope with tf.name_scope("my"): a = tf.constant(2) # my_1/Const:0 print(a.name) """ 可见tensorflow对于一切重名的东西都会在末尾加上下划线+数字 """ with tf.name_scope("my_4"): a = tf.constant(2) print(a.name) # my_4/Const:0 with tf.name_scope("my"): a = tf.constant(2) print(a.name) # my_2/Const:0 with tf.name_scope("my_4"): a = tf.constant(2) # my_4_1/Const:0 print(a.name)
经过以上例子能够发现,tensorflow对于命名重复问题使用如下规则解决: 一、要使用的name不存在,能够直接使用 二、要使用的name已经存在,执行下列循环:
i=1 while 1: now_name="%s_%d"%(name,i) if exists(now_name): i+=1 else: return now_name