tf.name_scope与tf.variable_scope用法区别

本文由网络上一些回答和博文汇总而成。

要将这个问题解释清楚,得结合tensorflow中创建变量的两种方式tf.get_variable()和tf.Variable()一起说明。

在tf.name_scope下:

  • tf.get_variable()创建的变量名不受tf.name_scope的影响,即创建的变量的name没有name_scope定义的前缀。而且,在未指定共享变量时,如果重名会报错。

tf.name_scope与tf.variable_scope用法区别_第1张图片

  • tf.Variable()会自动检测有没有变量重名,如果有则会自行处理。

tf.name_scope与tf.variable_scope用法区别_第2张图片

要共享变量,需要使用tf.variable_scope()

 

解析1: https://www.zhihu.com/question/54513728/answer/515912730

  1. 对于使用tf.Variable来说,tf.name_scope和tf.variable_scope功能一样,都是给变量加前缀,相当于分类管理,模块化。
  2. 对于tf.get_variable来说,tf.name_scope对其无效,也就是说tf认为当你使用tf.get_variable时,你只归属于tf.variable_scope来管理共享与否。

来看一个例子:

with tf.name_scope('name_sp1') as scp1:
    with tf.variable_scope('var_scp2') as scp2:
        with tf.name_scope('name_scp3') as scp3:
            a = tf.Variable('a')
            b = tf.get_variable('b')

等同于:

with tf.name_scope('name_sp1') as scp1:
    with tf.name_scope('name_sp2') as scp2:
        with tf.name_scope('name_scp3') as scp3:
            a = tf.Variable('a')

with tf.variable_scope('var_scp2') as scp2:
        b = tf.get_variable('b')

 

要注意的是:

with tf.variable_scope('scp', reuse=True) as scp:
    a = tf.get_varialbe('a') #报错

with tf.variable_scope('scp', reuse=False) as scp:    
     a = tf.get_varialbe('a')
    a = tf.get_varialbe('a') #报错

都会报错,因为reuse=True是,get_variable会强制共享,如果不存在,报错;reuse=Flase时,会强制创造,如果已经存在,也会报错。

如果想实现“有则共享,无则新建”的方式,可以:

with tf.variable_scope('scp', reuse=tf.AUTO_REUSE) as scp:    
     a = tf.get_variable('a') #无,创造
     a = tf.get_variable('a') #有,共享

 

当你写一个建图模块时(e.g. LSTM_block() ),你不知道用户是否会共享此模块,因此你可以只用tf.variable_scope来分组模块内变量,用tf.get_variable来为共享提供可能,而不能用tf.Variable。

举个例子:我们想构建一个NewAutoEncoder, 包含了一个encoder和2个decoder, 这2个decoder是共享的。

首先,新建一个Dense层:

def Dense(x, x_dim, y_dim, name, reuse=None):

    with tf.variable_scope(name, reuse=reuse):
        w = tf.get_variable('weight', [x_dim, y_dim])
        b = tf.get_variable('bias', [y_dim])
        y = tf.add(tf.matmul(x, w), b)
    return y


def Encoder(x, name):

    with tf.variable_scope(name, reuse=None):
        x = tf.nn.relu(Dense(x, 784, 1000, 'layer1', reuse=False))
        x = tf.nn.relu(Dense(x, 1000, 1000, 'layer2', reuse=False))
        x = Dense(x, 1000, 10, 'layer3', reuse=False)
    return x

def Decoder(x, name, reuse=None):

    with tf.variable_scope(name, reuse=reuse):
        x = tf.nn.relu(Dense(x, 10, 1000, 'layer1', reuse=False))
        x = tf.nn.relu(Dense(x, 1000, 1000, 'layer2', reuse=False))
        x = tf.nn.sigmoid(Dense(x, 1000, 784, 'layer3', reuse=False))
    return x

def build_network(x):
    batchsz = 32
    x_ph = tf.placeholder(tf.float32, [batchsz, 784], name='input')
    z_ph = tf.placeholder(tf.float32, [1, 10], name='z')

    x = Encoder(x_ph, 'Encoder')
    x_hat = Decoder(x, 'Decoder1', reuse=None)
    x_hat2 = Decoder(z_ph, 'Decoder2', reuse=True)

    # ...

解读:所有的模块都要使用tf.variable_scope带name参数封装,如Dense(), Encoder(), Decoder()。对于明确不会共享的模块,如本例中的Encoder, reuse参数可以不提供。

注意:当多个tf_variable_scope嵌套时,如果中间某层开启了reuse=True, 则内层自动全部共享,即使内层设置了reuse=False。而且,一旦使用tf.get_variable_scope().reuse_variables()打开了当前域共享,就不能关闭了!

 

总结: 1. `tf.variable_scope`和`tf.get_variable`必须要搭配使用(全局scope除外),为share提供支持。

    2. `tf.Variable`可以单独使用,也可以搭配`tf.name_scope`使用,给变量分类命名,模块化。

    3.  `tf.Variable`和`tf.variable_scope`搭配使用不伦不类,不是设计者的初衷

 

TensorFlow基础:共享变量 https://www.jianshu.com/p/ab0d38725f88 

作用域中的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
    # Exited the reusing scope, back to a non-reusing one.
    assert tf.get_variable_scope().reuse == False

一个作用域可以作为另一个新的作用域的参数,如:

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()打开一个已经存在的作用域时,就会跳转到这个作用域。

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:
            assert foo_scope2.name == "foo"  # Not changed.

 

你可能感兴趣的:(深度学习)