tf.name_scope() 和 tf.variable_scope()
儘管tensorflow支援 name_scope 和 Variable,但更推薦使用 variable_scope 和 get_variable,這麼做方便進行變數名稱管理和實現權值變數共享
1 tf.name_scope()
with tf.name_scope('ns1') as ns: ns_v1 = tf.Variable(initial_value=[1.0], name='v') ns_gv1 = tf.get_variable(name='v', shape=[2,3]) ns_v2 = tf.Variable(initial_value=[1.0], name='v') print('ns_v1', ns_v1) print('ns_gv1', ns_gv1) print('ns_v2', ns_v2)
ns_v1 <tf.Variable 'ns1/v:0' shape=(1,) dtype=float32_ref> ns_gv1 <tf.Variable 'v:0' shape=(2, 3) dtype=float32_ref> ns_v2 <tf.Variable 'ns1/v_1:0' shape=(1,) dtype=float32_ref>
結果:在 tf.name_scope() 裡邊:
- 使用 tf.Variable() 建立的變數,會自動地在 name 前面加上 scope name
- 使用 tf.get_variable() 建立的變數,並不受 name_scope 的影響
2 tf.variable_scope()
with tf.variable_scope('vs1') as vs:
vs_v1 = tf.Variable(initial_value=[1.0], name='v')
vs_gv1 = tf.get_variable(name='v', shape=[2,3])
print('vs_v1', vs_v1)
print('vs_gv1', vs_gv1)
vs_v1 <tf.Variable 'vs1/v:0' shape=(1,) dtype=float32_ref> vs_gv1 <tf.Variable 'vs1/v_1:0' shape=(2, 3) dtype=float32_ref>
可以看到 tf.variable_scope 和 tf.name_scope 的區別:
使用 tf.Variable() 和使用 tf.get_variable() 建立的變數,都會自動地在 name 前面加上 variable scope name
3 reuse 實現變數共享
在開始之前,先來看看 python 中怎麼判斷兩個變數指向的物件是不是一樣的。我們直接使用 is 關鍵字來判斷就行了,注意不能使用 == 來判斷,和 java, C++ 中不同,python 中的 == 只是判斷左右兩邊的內容是否一致,而不是判斷左右兩邊是不是同一個物件。
a = [1,2,3]
b = [1,2,3]
c = a
print('a is b: ', a is b)
print('a is c: ', a is c)
c[0] = 555 # 修改 c,a也會變化:因為 a 和 c 指向同一個物件
b[1] = 666 # 修改 b, a不受影響:因為 a 和 b 指向兩個不同的物件
print('a:', a)
print('b:', b)
print('c:', c)
a is b: False
a is c: True
a: [555, 2, 3]
b: [1, 666, 3]
c: [555, 2, 3]
上面的結果顯示,a 和 c 是指向記憶體中的同一個物件的,如果修改c的內容,a 也會一起變。而 b 雖然和 a 的內容一模一樣,但是他們並不是一個物件,如果修改 b 的內容,並不會影響到 a。
在 TensorFlow 中,我們是通過變數的 name 來區別不同的物件。 tf.variable_scope() 中的 reuse 就是是我們為了實現變數的共享。
在上面,我們已經建立了一個 variable_scope 它的 name='vs1';在 'vs1' 裡邊,我們建立了一個變數:name='v'.
with tf.variable_scope('vs1') as vs:
vs_gv2 = tf.get_variable(name='v2', shape=[2,3])
print('vs_gv2', vs_gv2)
with tf.variable_scope('vs1', reuse=True) as vs:
vs_gv3 = tf.get_variable(name='v', shape=[2,3])
print('vs_gv3', vs_gv3)
print('vs_gv3 is vs_gv1: ', vs_gv3 is vs_gv1)
vs_gv2 <tf.Variable 'vs1/v2:0' shape=(2, 3) dtype=float32_ref> vs_gv3 <tf.Variable 'vs1/v_1:0' shape=(2, 3) dtype=float32_ref> vs_gv3 is vs_gv1: True
上面發現了沒有,當我們要在同一個 variable_scope 下面‘定義’一個已經存在的變數 name='v' 的時候,需要設定 reuse=True,實際上兩次‘定義’指向同一個記憶體物件。
4 例項
def fc(X, out_size):
in_size = X.shape[1]
W = tf.get_variable('weight', shape=[in_size, out_size], initializer=tf.truncated_normal_initializer())
b = tf.get_variable('bias', shape=[out_size],initializer=tf.zeros_initializer())
h_fc = tf.nn.relu(tf.nn.xw_plus_b(X,W,b), name='relu')
return h_fc
batch_size = 128
feature_size = 50
fc1_size = 64
fc2_size = 32
X_input = tf.placeholder(dtype=tf.float32, shape=[batch_size, feature_size], name='X_input')
with tf.variable_scope('fc1') as vs:
h_fc1 = fc(X_input, out_size=fc1_size)
with tf.variable_scope('fc2') as vs:
h_fc2 = fc(h_fc1, out_size=fc2_size)
all_vars = tf.global_variables()
for i in range(len(all_vars)):
print('var {}:'. format(i), all_vars[i])
var 0: <tf.Variable 'fc1/weight:0' shape=(50, 64) dtype=float32_ref> var 1: <tf.Variable 'fc1/bias:0' shape=(64,) dtype=float32_ref> var 2: <tf.Variable 'fc2/weight:0' shape=(64, 32) dtype=float32_ref> var 3: <tf.Variable 'fc2/bias:0' shape=(32,) dtype=float32_ref>
在神經網路的結構定義的時候,我們應該養成比較好的習慣,在定義每個層的時候都放在一個 tf.variable_scope() 裡邊。
在定義整個模型的時候,也應該把整個模型放在一個 tf.variable_scope('your_model_name') 裡邊,這樣做有個好處就是後期你想要微調某些層或者把多個小模型聯合成一個大模型的時候都可以很輕鬆地實現。
---- suffer now and live the rest of your life as a champion ----