TensorFlow-重新學習第3天

共享變量

#! -*- coding: utf-8 -*-
import tensorflow.compat.v1 as tf


def main():
    """
    共享變量實踐
    1. 爲什麼需要共享變量
        在某些情況下,一個模型需要使用其他模型創建的變量,
        兩個模型一起訓練(比如對抗網絡)
    """
    var1 = tf.Variable(1.0, name='firstvar')
    var2 = tf.Variable(2.0, name='firstvar')
    var3 = tf.Variable(3.0, name='firstvar')
    var4 = tf.Variable(4.0)
    var5 = tf.Variable(5.0)
    print('var1: ', var1.name)
    print('var2: ', var2.name)
    print('var3: ', var3.name)
    print('var4: ', var4.name)
    print('var5: ', var5.name)
    """
    結果:
        var1:  firstvar:0
        var2:  firstvar_1:0
        var3:  firstvar_2:0
        var4:  Variable:0
        var5:  Variable_1:0
    分析:
        1. `tf.Vairiable()`只能創建新的變量;
        2. 如果創建同名變量,tf會默認給新的變量加索引。
           所以,雖然定義的變量使用使用了相同的名稱,
           但其實創建的是三個不同的變量,一個變量的改
           變不會影響其他變量的值;
        3. 如果tf.Variable()創建變量時不指定名稱,則系統
           會自動指定名稱。
    """

    var1 = tf.get_variable(
        name='firstvar',
        shape=[1],
        dtype=tf.float32,
        initializer=tf.constant_initializer())
    print('var1: ', var1.name)
    """
    結果:
        var1:  firstvar_3:0
    分析:
        1. 使用`tf.get_variable()`生成的變量是以指定的`name`
        屬性爲 唯一標識,並不是定義的變量名稱。使用時一般通過
        `name`屬性定位到具體位置,並將其共享到其他模型中。
        2. 由於變量var1在前面使用Variable函數生成過一次,
        所以系統自動變成了firstvar_3:0
    """

    """
    var1 = tf.get_variable(
        name='firstvar',
        shape=[1],
        dtype=tf.float32,
        initializer=tf.constant_initializer())
    """
    """
    結果:
        ValueError: Variable var1 already exists, disallowed.
    分析:
        程序發生了崩潰,使用`get_variable()`只能定義一次指定名稱的變量。
    """

    """
    `get_variable()`一般會配合`variable_scope`一起使用,以實現共享變量
    """
    with tf.variable_scope('test1'):
        var1 = tf.get_variable(
            name='firstvar', 
            shape=[1],
            dtype=tf.float32,
            initializer=tf.constant_initializer(0.3))
    print('var1: ', var1.name)

    with tf.variable_scope('test2'):
        var2 = tf.get_variable(
            name='firstvar', 
            shape=[1],
            dtype=tf.float32,
            initializer=tf.constant_initializer(0.3))
    print('var2: ', var2.name)
    """
    結果:
       	var1:  var1:  test1/firstvar:0
        var1:  var2:  test2/firstvar:0
    分析:
        var1和var2都使用firstvar的名字來定義。從輸出結果可以看出,
        生成的兩個變量var1和var2是不同的,他們作用在不同的scope下,
        這就是scope的作用。
    """

    with tf.variable_scope('test1'):
        with tf.variable_scope('test2'):
            var2 = tf.get_variable(
                name='firstvar',
                shape=[1],
                dtype=tf.float32,
                initializer=tf.constant_initializer())
    print('var2: ', var2.name)
    """
    結果:
        var1:  test1/test2/firstvar:0
    分析:
        `variable_scope`支持嵌套
    """

    # 如何實現共享變量呢?
    """
    使用`variable_scope`的`reuse`參數來實現共享變量功能
    reuse=True 表示使用已經定義過的變量,此時`get_variable`
    不會再創建新的變量,而是去 `圖` 中被get_variable所
    創建過的變量中找與`name`相同的變量。
    """

    with tf.variable_scope('test1', reuse=True):
        var3 = tf.get_variable(
            name='firstvar',
            shape=[1],
            dtype=tf.float32,
            initializer=tf.constant_initializer())
    print('var3: ', var3.name)
    """
    結果:
        var3:  test1/firstvar:0
    分析:
        var3與var1輸出的名字是一樣的,此時就實現了變量共享。
    """

    with tf.variable_scope('test1', reuse=True):
        with tf.variable_scope('test2'):
            var4 = tf.get_variable(
                name='firstvar',
                shape=[1],
                dtype=tf.float32,
                initializer=tf.constant_initializer())
    print('var4: ', var4.name)
    """
    結果:
        var4:  test1/test2/firstvar:0
    分析:
        var4的名字與var2的名字相同,這表明var4與var2公用了
        一個變量。可以看到,雖然scope test2沒有指定reuse=True,
        但上層空間test1指定了resuse=True,即variable_scope
        的reuse具有繼承關係。
    """

	"""
    `variable_scope`和`get_variable`都有初始化的功能,且作用域
    的初始化方法能夠被繼承
    """
    with tf.variable_scope('test1', reuse=tf.AUTO_REUSE, initializer=tf.constant_initializer(0.4)):
        var1 = tf.get_variable('secondvar', shape=[2], dtype=tf.float32)
        with tf.variable_scope('test2', reuse=tf.AUTO_REUSE):
            var2 = tf.get_variable('secodvar', shape=[2], dtype=tf.float32)
            var3 = tf.get_variable('var3', shape=[2], dtype=tf.float32, initializer=tf.constant_initializer(0.3))
    print('var1: ', var1)
    print('var2: ', var2)
    print('var3: ', var3)
    """
    結果:
        var1:  <tf.Variable 'test1/firstvar:0' shape=(1,) dtype=float32, numpy=array([0.4], dtype=float32)>
        var2:  <tf.Variable 'test1/test2/firstvar:0' shape=(1,) dtype=float32, numpy=array([0.4], dtype=float32)>
        var3:  <tf.Variable 'test1/test2/var3:0' shape=(1,) dtype=float32, numpy=array([0.3], dtype=float32)>
    分析:
        1. 在`variable_scope`中使用`tf.AUTO_REUSE`爲reuse屬性賦值
           因爲之前已經使用`test1/firstvar:0`和`test1/test2/firstvar:0`
           定義過變量。`tf.AUTO_REUSE`可以實現第一次調用`variable_scope`
           時傳入的reuse值爲False,再次調用`variable_scope`時,傳入的
           reuse值自動變爲True。
        2. 將test1作用域初始化爲4.0,var1沒有初始化時,初始值繼承test1作用域的初始化值。
        3. test2作用域沒有定義初始化方法,var2的初始值也爲4.0,表明test2作用域的初始值
           繼承了test1作用域的初始值。
        4. test1/test2作用域下的var3定義了初始化方法,則不再繼承作用域的初始化方法。
    """



if __name__ == '__main__':
    main()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章