tf.variable_scope( )和tf.get_variable( )在jupyter中的使用

写本篇博客的初衷:因本人使用tf.variable_scope()变量域在jupyter多次运行程序时,经常会遇到:
Variable …… already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:……
此报错,在查看网上多篇博客和资料后,都没有能够明确解释tf.variable_scope()和jupyter运行机制之间的关系。因此本人在经过深刻钻研和实验后,决定探究如何在jupyter中正确使用tensorflow变量域,及两者之间存在的关系。

当我们新建一个jupyter文档后,在文档中运行下面的代码:

import tensorflow as tf

with tf.variable_scope("conv"):
    # Create variable named "conv/weights".
    weights = tf.get_variable("weights", [5, 5, 32, 32], initializer=tf.random_normal_initializer())
    # Create variable named "conv/biases".
    biases = tf.get_variable("biases", [32], initializer=tf.constant_initializer(0.0))


# tf.trainable_variables()用来获取所有的可训练变量,即之前运用jupyter运行程序时,系统内存中保存的所有变量
vs = tf.trainable_variables()
print("There are %d train_able_variables in the Graph: " % len(vs))
for v in vs:
    print(v.name)

输出:

There are 2 train_able_variables in the Graph: 
conv/weights:0
conv/biases:0

可见,通过上面的程序,我们创建了两个分别名为conv/weights和conv/biases的变量,此时我们把上面的代码复制到下面的框中,再重新运行一遍,看看输出什么结果。

import tensorflow as tf

with tf.variable_scope("conv"):
    # Create variable named "conv/weights".
    weights = tf.get_variable("weights", [5, 5, 32, 32], initializer=tf.random_normal_initializer())
    # Create variable named "conv/biases".
    biases = tf.get_variable("biases", [32], initializer=tf.constant_initializer(0.0))


# tf.trainable_variables()用来获取所有的可训练变量,即之前运用jupyter运行程序时,系统内存中保存的所有变量
vs = tf.trainable_variables()
print("There are %d train_able_variables in the Graph: " % len(vs))
for v in vs:
    print(v.name)

输出:

ValueError                                Traceback (most recent call last)
<ipython-input-2-aa5fff98c0f6> in <module>()
      3 with tf.variable_scope("conv"):
      4     # Create variable named "conv/weights".
----> 5     weights = tf.get_variable("weights", [5, 5, 32, 32], initializer=tf.random_normal_initializer())
      6     # Create variable named "conv/biases".
      7     biases = tf.get_variable("biases", [32], initializer=tf.constant_initializer(0.0))
……………………
ValueError: Variable conv/weights already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:

  File "<ipython-input-1-aa5fff98c0f6>", line 5, in <module>
    weights = tf.get_variable("weights", [5, 5, 32, 32], initializer=tf.random_normal_initializer())
  File "/Users/zhuhai/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2862, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "/Users/zhuhai/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2802, in run_ast_nodes
    if self.run_code(code, result):

出现了错误,系统提示我们,变量conv/weights已经存在,问我们是否要设置reuse=True,即通过将准许重复使用的标志位置为真,来重复使用该变量。同时错误提示还告诉我们变量conv/weights原始定义的位置。

由此,我们可以得出:当我们初次运行上面这段程序时,系统中没有在conv变量域下定义的两个变量weights和biases,所以系统自动创建了这两个变量,并将它们命名为conv/weights和conv/biases。当我们再次运行时,系统报错,告诉我们变量已存在,还给我们提出了解决办法,即通过将reuse标志位置为真。下面我们来试一下,加入reuse=True后程序的运行结果:

import tensorflow as tf
#在tf.variable_scope()中,已经内置了reuse标志位形参,不填,默认为False
with tf.variable_scope("conv", reuse=True):
    # Create variable named "conv/weights".
    weights = tf.get_variable("weights", [5, 5, 32, 32], initializer=tf.random_normal_initializer())
    # Create variable named "conv/biases".
    biases = tf.get_variable("biases", [32], initializer=tf.constant_initializer(0.0))


# tf.trainable_variables()用来获取所有的可训练变量,即之前运用jupyter运行程序时,系统内存中保存的所有变量
vs = tf.trainable_variables()
print("There are %d train_able_variables in the Graph: " % len(vs))
for v in vs:
    print(v.name)

输出:

There are 2 train_able_variables in the Graph: 
conv/weights:0
conv/biases:0

可以看到,在添加reuse=True后,我们再次运行程序,输出了和第一次运行程序相同的结果,说明我们进行了变量共享。

总结:我们第一次运行程序是创建变量(提示:如果第一次运行程序时就加上reuse=True,程序运行依然有错,因为变量还没有创建,不能重复使用,读者可自行试验);第二次运行程序,报错,提示没有将重复使用标志位置为真,就重复使用了变量;第三次运行程序,我们加上reuse=True后,程序内存中储存的变量依然是第一次运行后所创建的变量,并没有重新创建新变量,即我们通过使用variable scope变量域,和tf.get_variable()函数,实现了变量共享。

下面我们将上面的变量域的名字由conv改为conv1,同时去掉reuse=True,看一下会输出什么。

import tensorflow as tf
#在tf.variable_scope()中,已经内置了reuse标志位形参,不填,默认为False
with tf.variable_scope("conv1"):
    # Create variable named "conv/weights".
    weights = tf.get_variable("weights", [5, 5, 32, 32], initializer=tf.random_normal_initializer())
    # Create variable named "conv/biases".
    biases = tf.get_variable("biases", [32], initializer=tf.constant_initializer(0.0))


# tf.trainable_variables()用来获取所有的可训练变量,即之前运用jupyter运行程序时,系统内存中保存的所有变量
vs = tf.trainable_variables()
print("There are %d train_able_variables in the Graph: " % len(vs))
for v in vs:
    print(v.name)

输出:

There are 4 train_able_variables in the Graph: 
conv/weights:0
conv/biases:0
conv1/weights:0
conv1/biases:0

可见输出了四个变量,前两个是我们之前创建的conv/weights和conv/biases变量,后两个是我们本次程序运行创建的conv1/weights和conv1/biases变量。

总结:
1、在jupyter中每定义一个新的变量,系统内存就会开辟一个以该变量的名字命名的存储空间,用来存储该变量。变量在内存中的存储只与其名字一一对应。
2、tf.get_variable()函数,当内存中一个变量已存在时,将该变量域的reuse置为True,可实现变量重复使用,即变量共享;当内存中一个变量不存在时,将reuse置为False,可创建变量。
3、tf.variable_scope( )的形参——reuse标志位,起作用的范围是整个变量域内定义的所有变量。

下面我们将上面程序复制到下面,用tf.Variable()函数来定义变量,其它都不变,看看会输出什么。

import tensorflow as tf
#在tf.variable_scope()中,已经内置了reuse标志位形参,不填,默认为False
with tf.variable_scope("conv1"):
    # Create variable named "conv/weights".
    weights = tf.Variable(tf.random_normal([5, 5, 32, 32]), name="weights")
    # Create variable named "conv/biases".
    biases = tf.Variable(tf.zeros([32]), name="biases")


# tf.trainable_variables()用来获取所有的可训练变量,即之前运用jupyter运行程序时,系统内存中保存的所有变量
vs = tf.trainable_variables()
print("There are %d train_able_variables in the Graph: " % len(vs))
for v in vs:
    print(v.name)

输出:

There are 6 train_able_variables in the Graph: 
conv/weights:0
conv/biases:0
conv1/weights:0
conv1/biases:0
conv1_2/weights:0
conv1_2/biases:0

总结:我们没有改变变量域和变量的名字,但是系统还是又创建了两个变量,conv1_2/weights和conv1_2/biases,可见,tf.Variable()的功能是:不管之前是否创建过该变量,系统都会自动给变量分配新的名字,开辟新的存储空间,创建新的变量。

本文系作者原创,转载请注明出处。

猜你喜欢

转载自blog.csdn.net/Liven_Zhu/article/details/80218611