共享變量
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()