zoukankan      html  css  js  c++  java
  • tensorflow基础【6】-共享变量与作用域

    共享变量

    tf.Variable 创建唯一变量:当系统检测到命名冲突会自动处理,保证了变量的唯一性,也就是不可复用,

    ######################### Variable 无法共享 #########################
    v1 = tf.Variable(tf.random_normal((2, 3)), name='v1')
    print(v1)       # <tf.Variable 'v1:0' shape=(2, 3) dtype=float32_ref>
    v2 = tf.Variable(tf.random_normal((3, 3)), name='v1')
    print(v2)       # <tf.Variable 'v1_1:0' shape=(3, 3) dtype=float32_ref>   ### name 冲突自动处理

    通俗的说就是不能有两个变量一模一样

    tf.get_variable 创建共享变量所谓的共享变量,不是 共享文件的共享,也不是编程中公共变量的共享,

    这里的共享是指可以把变量 A 直接赋值给变量 B,即变量 B 共享了 变量 A,通俗的说就是连个变量一模一样; 

    实际上 get_variable 是获取指定属性(name)的已存在变量,如果可获取,即共享了变量,如果指定属性的变量不存在,就新建一个。

    ######################### get_variable 共享变量 #########################
    ############# 证明 get_ariable 的共享是有条件的 #############
    
    ### test1:用 tf.Variable 创建一个变量
    # 1. 用 get_variable 无法获取这个已存在的变量,提示你在瞎搞
    # 2. 用 get_variable 新建一个同名的变量,名字冲突会自动处理
    v3 = tf.Variable(tf.random_normal((3, 3)), name='v3')
    print(v3)       # <tf.Variable 'v3:0' shape=(3, 3) dtype=float32_ref>
    # v4 = tf.get_variable(name='v3')         ### 报错 ValueError: The initializer passed is not valid. It should be a callable with no arguments and the shape should not be provided or an instance of `tf.keras.initializers.*' and `shape` should be fully defined.
    v5 = tf.get_variable(name='v3', shape=(2, 2))
    print(v5)       # <tf.Variable 'v3_1:0' shape=(2, 2) dtype=float32_ref>
    
    ### test2:用 tf.get_variable 创建一个变量
    # 1. 用 get_variable 也无法获取这个已存在的变量,提示已经存在,可见不是在获取,而是在新建
    # 2. 用 get_variable 新建一个同名的变量,显然也会提示已存在
    gv1 = tf.get_variable(name='gv1', shape=(2, 3))
    print(gv1)      # <tf.Variable 'gv1:0' shape=(2, 3) dtype=float32_ref>
    # gv2 = tf.get_variable(name='gv1')      ### 报错 ValueError: Variable gv1 already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:
    # gv3 = tf.get_variable(name='gv1', shape=(2, 2))
    
    #### 结论:直接使用 get_ariable 无法共享变量

    小结

    1. 共享变量就是两个变量一模一样

    2. tf.get_variable 无法获取 tf.Variable 创建的变量,因为 tf.Variable 创建的是唯一变量,无法共享

    3. tf.get_variable 无法直接获取 tf.get_variable 创建的变量,因为共享变量需要一定的条件

    变量作用域

    tensorflow 有一个默认的变量作用域,当然我们可以自己创建新的作用域

    ##### 默认变量作用域
    print(tf.get_variable_scope().name)         #
    
    ##### 显式地创建一个变量作用域
    with tf.variable_scope('scope1'):
        print(tf.get_variable_scope().name)     # scope1
    
    with tf.variable_scope('scope2') as scope:
        print(tf.get_variable_scope().name)     # scope2

    tf.get_variable 共享变量的条件是作用域内变量可共享

    ############# 探索 get_ariable 共享变量的方法 #############
    ### test1:用 tf.Variable 创建一个变量
    # 1. 使该作用域的变量可复用后,用 get_variable 无法获取这个已存在的变量,提示变量已存在
    v11 = tf.Variable(tf.random_normal((2, 3)), name='v11')
    # tf.get_variable_scope().reuse_variables()       ### 作用域内的变量可复用
    # v12 = tf.get_variable(name='v11')
    
    ### test2:用 tf.get_variable 创建一个变量
    # 1. 使该作用域的变量可复用后,用 get_variable 可以获取这个已存在的变量
    gv11 = tf.get_variable(name='gv11', shape=(2, 3))
    print(gv11)     # <tf.Variable 'gv11:0' shape=(2, 3) dtype=float32_ref>
    tf.get_variable_scope().reuse_variables()       ### 作用域内的变量可复用
    gv12 = tf.get_variable(name='gv11')
    print(gv12)     # <tf.Variable 'gv11:0' shape=(2, 3) dtype=float32_ref>
    print(gv11 is gv12)     # True

    小结

    1. tf.Variable 创建唯一变量,无论什么情况,都不可共享

    2. tf.get_variable 只能共享 tf.get_variable 创建的变量

    3. tf.get_variable 共享变量的条件是 作用域内变量可复用

    作用域内变量可复用

    有多种方法,如下

    ##### 作用域内的变量可复用-method1
    with tf.variable_scope('test1') as test:
        v1 = tf.get_variable('v1', shape=(2, 3))
        tf.get_variable_scope().reuse_variables()       ### 作用域内的变量可复用
        v2 = tf.get_variable('v1')
        print(v1 is v2)         # True
    
    ##### 作用域内的变量可复用-method2
    with tf.variable_scope('test2') as test:
        v3 = tf.get_variable('v3', shape=(2, 3))
        test.reuse_variables()              ### 作用域内的变量可复用
        v4 = tf.get_variable('v3')
        print(v3 is v4)         # True
    
    ##### 作用域内的变量可复用-method3
    with tf.variable_scope('test3') as test:
        v5 = tf.get_variable('v5', shape=(2, 3))
    with tf.variable_scope(test, reuse=True):           ### 作用域内的变量可复用
        v6 = tf.get_variable('v5')
        print(v5 is v6)         # True

    小结

    1. 需要使用 同时使用 get_variable 和 variable_scope

    2. 在同一个 variable_scope 内,不需要指定 reuse=True,但需要用 scope.reuse_variables() 或者 tf.get_variable_scope().reuse_variables()

    3. 在不同的 variable_scope 内, 第一个不需要指定reuse=True,但后面需要指定。

    get_variable 机制

    get_variable 会判断指定属性的变量是否存在,如果存在,并且该变量空间的 reuse=True,那么就共享之前的变量,否则新建一个,

    但是如果没有指定 reuse=True,会提示命名冲突

    变量作用域进阶

    多重作用域

    作用域中的 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
            # with tf.variable_scope("bar2"):
            #     # Now sub-scope inherits the reuse flag.
            #     assert tf.get_variable_scope().reuse == False       # AssertionError
        # Exited the reusing scope, back to a non-reusing one.
        assert tf.get_variable_scope().reuse == False

    可以看到在 bar2 作用域内,reuse==False 报错了,因为这个父域是True。

    作用域的调用

    作用域名字可以作为参数

    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('scope1'):
        w1 = tf.Variable(1, name='w1')
        w2 = tf.get_variable(name='w2', initializer=2.)
    
    with tf.variable_scope('scope1', reuse=True):  # 另一种方式
        w1_p = tf.Variable(1, name='w1')
        w2_p = tf.get_variable(name='w2', initializer=2.) 

    用as 或者直接用名字都可作为参数。 但是有区别,后面会总结。

    作用域跳转

    不管作用域如何嵌套,当使用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:
            print(tf.get_variable_scope().name) # foo
            assert foo_scope2.name == "foo" # Not changed
          with tf.variable_scope('foo') as foo_scope3:
            print(tf.get_variable_scope().name) # bar/baz/foo
            assert foo_scope3.name == "foo" # AssertionError

    
    

    这里可以看到,直接用名字没有跳转,而用as跳转成功。 

    多重作用域下的变量

    变量都是通过作用域/变量名来标识,作用域可以像文件路径一样嵌套。

    # encoding:utf-8
    __author__ = 'HP'
    import tensorflow as tf
    
    with tf.variable_scope('s1'):
        x1 = tf.get_variable('data1', [3, 4])
        print(x1)                   # <tf.Variable 's1/data1:0' shape=(3, 4) dtype=float32_ref>
        tf.get_variable_scope().reuse_variables()
    
        with tf.variable_scope('s11'):
            # x2 = tf.get_variable('data1')           # ValueError: Variable s1/s11/data1 does not exist
            # print(x2)
            pass
    
            with tf.variable_scope('s1'):
                # x3 = tf.get_variable('data1')       # ValueError: Variable s1/s11/s1/data1 does not exist
                # print(x3)
                pass
    
        with tf.variable_scope('s1', reuse=True):
            x4 = tf.get_variable('data1')       # ValueError: Variable s1/s1/data1 does not exist
            print(x4)
            pass
    
    with tf.variable_scope('s1', reuse=True):
        x5 = tf.get_variable('data1')
        print(x5)                       # <tf.Variable 's1/data1:0' shape=(3, 4) dtype=float32_ref>

     with tf.variable_scope('s2'):
       with tf.variable_scope('s1', reuse=True):
     print(tf.get_variable_scope().name) # s2/s1
       # x6 = tf.get_variable('data1') # Variable s2/s1/data1 does not exist
       # print(x6)

     

    可以看到 变量 就像文件一样,这个文件夹内的a文件和另外文件夹内的a文件不是一个文件。

    综上得出如下结论:

    1. 如果直接用名字,只能在同级作用域下跳转,如上例。 

    2. 如果用as, 可以在任何地方跳转到该作用域

      // 可以这么理解:如果直接用名字,是相对路径,相当于是在当前目录下创建了一个该名字的文件夹,

      // 而as是绝对路径,不管在哪调用,都能指定该路径。

    命名空间

    命名空间,也是一种作用域

    name_scope 仅对普通operation 有用,对 get_variable 无效,

    variable_scope 不仅对普通operation 有效,也对 get_variable 有效

    先上代码

    with tf.name_scope('name_test'):
        n1 = tf.constant(1, name='cs1')
        n2 = tf.Variable(tf.zeros([1]), name='v1')
        ww1 = tf.multiply(n2, [1])
    
        nv1 = tf.get_variable(name='nv1', initializer=1.0)
    
    with tf.variable_scope('v_test'):
        v_n1 = tf.constant(2, name='cs2')
        v_n2 = tf.Variable(tf.zeros([1]), name='v2')
        ww2 = tf.multiply(v_n2, [1])
    
        v1 = tf.get_variable(name='vv1', initializer=2.0)
    
    ### name_scope
    print('n1', n1.name)        # n1 name_test/cs1:0
    print('n2', n2.name)        # n2 name_test/v1:0
    print('nv1', nv1.name)      # nv1 nv1:0                 # 注意和前两个不同,name_scope 对 get_variable 无效
    
    print('ww1', ww1.name)      # ww name_test/Mul:0        # 注意也加上了name_scope
    
    ### variable_scope
    print('v_n1', v_n1.name)    # v_n1 v_test/cs2:0
    print('v_n2', v_n2.name)    # v_n2 v_test/v2:0
    print('v1', v1.name)        # v1   v_test/vv1:0         # 注意和前两个相同,name_scope 对 get_variable 有效
    print('ww2', ww2.name) # ww2 v_test/Mul:0 # 注意也加上了variable_scope

    变量的名称是指针名,变量的name是地址。

    共享变量用法进阶

    在重复使用(即 非第一次使用)时,设置 reuse=True 来 再次调用 该共享变量作用域(variable_scope)。但是这种方法太繁琐了。

     简单方法

    def myfunc():
        with tf.variable_scope('test', reuse=tf.AUTO_REUSE):
            w = tf.get_variable('data', [2, 2])
        return w
    
    for i in range(3):
        print(myfunc())
    
    # <tf.Variable 'test/data:0' shape=(2, 2) dtype=float32_ref>
    # <tf.Variable 'test/data:0' shape=(2, 2) dtype=float32_ref>
    # <tf.Variable 'test/data:0' shape=(2, 2) dtype=float32_ref>

     相关API

    with tf.variable_scope('V1') as variable_scope:
        a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))
        a2 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2')
    
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        print(variable_scope)                            # <tensorflow.python.ops.variable_scope.VariableScope object at 0x000000000D5F67F0>
        print(variable_scope.name)                       # V1
        print(tf.get_variable_scope())                   # <tensorflow.python.ops.variable_scope.VariableScope object at 0x000000000D5F67B8>
        print(tf.get_variable_scope().original_name_scope)      #
        print(tf.get_variable_scope().reuse)             # False
        print(tf.get_variable_scope().name)              #
        print(a1.name)      # V1/a1:0
        print(a2.name)      # V1/a2:0

    获取当前环境的作用域  tf.get_variable_scope()

    参考资料

    https://www.cnblogs.com/MY0213/p/9208503.html

    https://blog.csdn.net/lucky7213/article/details/78967306

    https://blog.csdn.net/u012436149/article/details/53081454

    https://blog.csdn.net/u010867294/article/details/78695487

    https://blog.csdn.net/jeryjeryjery/article/details/79242684

    http://www.cnblogs.com/Charles-Wan/p/6200446.html

  • 相关阅读:
    什么是操作系统
    去除按钮点击的边框
    unsupported time zone specified undefined
    w3c JS测试
    视频播放器
    document.write
    HTML4到HTML5
    MPU6050
    NRF24L01模块配置
    4-Four-Seeing hands
  • 原文地址:https://www.cnblogs.com/yanshw/p/10532722.html
Copyright © 2011-2022 走看看