在訓練深度網絡時,為了減少需要訓練參數的個數(比如LSTM模型),或者是多機多卡並行化訓練大數據、大模型等情況時,往往就需要共享變量。另外一方面是當一個深度學習模型變得非常復雜的時候,往往存在大量的變量和操作,如何避免這些變量名和操作名的唯一不重復,同時維護一個條理清晰的graph非常重要。因此,tensorflow中用tf.Variable(), tf.get_variable, tf.Variable_scope(), tf.name_scope() 幾個函數來實現:
tf.Variable() 與 tf.get_variable() 的作用與區別:
1)tf.Variable() 會自動監測命名沖突並自行處理,但是tf.get_variable() 遇到重名的變量創建且沒有設置為共享變量時,則會報錯。
import tensorflow as tf; a1 = tf.Variable(tf.random_normal(shape=[2, 3], mean=0, stddev=1), name='a2') a2 = tf.Variable(tf.random_normal(shape=[2, 3], mean=0, stddev=1), name='a2') with tf.Session() as sess: sess.run(tf.initialize_all_variables()) print(a1.name) print(a2.name) # 輸出 a2:0 a2_1:0
import tensorflow as tf; a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1)) a3 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1)) with tf.Session() as sess: sess.run(tf.initialize_all_variables()) print(a1.name) print(a3.name) # 輸出 ValueError: Variable a1 already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:
2) tf.Variable() 和 tf.get_variable() 都是用於在一個name_scope下面獲取或創建一個變量的兩種方式,區別在於: tf.Variable()用於創建一個新變量,在同一個name_scope下面,可以創建相同名字的變量,底層實現會自動引入別名機制,兩次調用產生了其實是兩個不同的變量。tf.get_variable(<variable_name>)用於獲取一個變量,並且不受name_scope的約束。當這個變量已經存在時,則自動獲取;如果不存在,則自動創建一個變量。
import tensorflow as tf; import numpy as np; with tf.name_scope('V1'): a1 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2') with tf.name_scope('V2'): a2 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2') with tf.Session() as sess: sess.run(tf.initialize_all_variables()) print (a1.name) print (a2.name) # 輸出 V1/a2:0 V2/a2:0
import tensorflow as tf; with tf.name_scope('V1'): a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1)) with tf.name_scope('V2'): a2 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1)) with tf.Session() as sess: sess.run(tf.initialize_all_variables()) print (a1.name) print (a2.name) # 輸出 Variable a1 already exists, disallowed. Did you mean to set reuse=True in VarScope? Originally defined at:
3)tf.name_scope() 與 tf.variable_scope(): tf.name_scope():主要用於管理一個圖里面的各種op,返回的是一個以scope_name命名的context manager。一個graph會維護一個name_space的 堆,每一個namespace下面可以定義各種op或者子namespace,實現一種層次化有條理的管理,避免各個op之間命名沖突。 tf.variable_scope() 一般與tf.get_variable()配合使用,用於管理一個graph中變量的名字,避免變量之間的命名沖突。
import tensorflow as tf; import numpy as np; with tf.variable_scope('V1'): 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.variable_scope('V2'): a3 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1)) a4 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2') with tf.Session() as sess: sess.run(tf.initialize_all_variables()) print (a1.name) print (a2.name) print (a3.name) print (a4.name) # 輸出 V1/a1:0 V1/a2:0 V2/a1:0 V2/a2:0
4)當要重復使用變量共享時,可以用tf.variable_scope() 和 tf.get_variable()來實現
import tensorflow as tf with tf.variable_scope('V1', reuse=None): a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1)) with tf.variable_scope('V1', reuse=True): a2 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1)) with tf.Session() as sess: sess.run(tf.initialize_all_variables()) print(a1.name) print(a2.name) #輸出 V1/a1:0 V1/a1:0
上面的代碼在第一個variable_scope中的reuse=None,在之后的variable_scope中若是要共享變量,就要將reuse=True。