定義變量的兩種方式:
tf.Variable()
tf.get_Variable()
import tensorflow as tf
var1 = tf.Variable(1., name='first_var')
print('I am var1: ', var1.name)
var1 = tf.Variable(2., name='first_var')
print('I am var1 too: ', var1.name)
var2 = tf.Variable(3.)
print('I am var2: ', var2.name)
var2 = tf.Variable(4.)
print('I am var2 too: ', var2.name)
# I am var1: first_var:0
# I am var1 too: first_var_1:0
# I am var2: Variable:0
# I am var2 too: Variable_1:0
看到上面的測試代碼,當使用 tf.Variable() 定義變量時,變量是可以重名的,隻是會自動修改其名字,不指定名字時,系統自動配置設定。
tf.get_variable()中形參 name 必須指定
get_var1 = tf.get_variable(name='gv', shape=[])
print('I am get_var1: ', get_var1.name)
# get_var1 = tf.get_variable(name='gv', shape=[])
# print('I am get_var1 too, but I will cause a error: ', get_var1.name)
# I am get_var1: gv:0
# Traceback (most recent call last):
# ValueError: Variable gv already exists, disallowed. Did you mean to set reuse=True
# or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:
# get_var1 = tf.get_variable(name='gv', shape=[])
當使用 tf.get_Variable() 定義變量時,name 必須指定,而且不能重複,不然會報錯
get_variable(name,shape=None, dtype=None, initializer=None, regularizer=None, trainable=True,
collections=None, caching_device=None, partitioner=None, validate_shape=True,
use_resource=None, custom_getter=None, constraint=None)
get_variable值的初始化函數
函數 | 描述 |
tf.constant_initializer(value) | 将變量初始化為給定的常量,初始化一切所提供的值 |
tf.random_normal_initializer(mean,stdd ev) | 将變量初始化為滿足正太分布的随機值,主要參數(正太分布的均值和标準差),用所給的均值和标準差初始化均勻分布 |
tf.truncated_normal_initializer(mean,stddev,seed,dtype) | 将變量初始化為滿足正太分布的随機值,但如果随機出來的值偏離平均值超過2個标準差,那麼這個數将會被重新随機 |
tf.random_uniform_initializer(a,b,seed,dtype) | 從a到b均勻初始化,将變量初始化為滿足平均分布的随機值,主要參數(最大值,最小值) |
tf.uniform_unit_scaling_initializer(factor,seed,dtype) | 将變量初始化為滿足平均分布但不影響輸出數量級的随機值 |
f.zeros_initializer() | 将變量設定為全0;也可以簡寫為tf.Zeros() |
tf.ones_initializer() | 将變量設定為全1;可簡寫為tf.Ones() |
tf.name_scope() 和 tf.variable_scope() 之間的差別
既然 tf.get_variable() 不允許重名,那怎麼辦? 放心吧,總會有辦法解決的。
要解決這個問題,就要引入 tf.variable_scope() ,隔離開 tf.get_variable() 定義的同名變量就可以了
看個例子
with tf.variable_scope('vs1'):
get_var1 = tf.get_variable(name='getVar', shape=[])
with tf.variable_scope('vs2'):
get_var2 = tf.get_variable(name='getVar', shape=[])
with tf.variable_scope('vs3'):
get_var3 = tf.get_variable(name='getVar', shape=[])
with tf.variable_scope('vs4'):
get_var4 = tf.get_variable(name='getVar', shape=[])
print('get_var1', get_var1.name) # get_var1 vs1/getVar:0
print('get_var2', get_var2.name) # get_var2 vs2/getVar:0
print('get_var3', get_var3.name) # get_var3 vs3/getVar:0
print('get_var4', get_var4.name) # get_var4 vs3/vs4/getVar:0
同名的變量在程式中共存,完美解決這個問題。
在看一些代碼的時候, 經常會看到 tf.name_scope() 和 tf.variable_scope(), 那他們兩個到底啥關系呢?
tf.name_scope() 主要是用來管理命名空間的,這樣子讓我們的整個模型更加有條理
tf.variable_scope() 的作用是為了實作變量共享,常和 tf.get_variable() 一起完成變量共享的功能。
with tf.name_scope('ns'):
var1 = tf.Variable(1., tf.float32)
with tf.variable_scope('vs'):
var2 = tf.Variable(2., tf.float32)
get_var = tf.get_variable(name='gv', shape=[])
print('var1', var1.name) # var1 ns/Variable:0
print('var2', var2.name) # var2 ns/vs/Variable:0
print('get_var', get_var.name) # get_var vs/gv:0
從上面的 get_var 的作用範圍,可以看出 tf.get_variable() 不受 tf.name_scope() 的控制
下面就來看看共享變量怎麼操作的。
tf.variable_scope() 中有一個 reuse 的參數,表示使用已經定義過的變量,當然如果使用的變量未定義,就會報錯...
with tf.variable_scope('vs5'):
get_var5 = tf.get_variable(name='getVar_reuse', shape=[])
with tf.variable_scope('vs5', reuse=True):
get_var6 = tf.get_variable(name='getVar_reuse', shape=[])
# get_var7 = tf.get_variable(name='getVar_unknown', shape=[])
print('get_var5', get_var5.name) # get_var5 vs5/getVar_reuse:0
print('get_var6', get_var6.name) # get_var6 vs5/getVar_reuse:0
# print('get_var7', get_var7.name) # 報錯
tf.variable_scope() 和 tf.get_variable() 的初始化變量功能
with tf.variable_scope('vs6', initializer=tf.constant_initializer(1.)):
get_var8 = tf.get_variable(name='getVar8', shape=[1])
with tf.variable_scope('vs7'):
get_var9 = tf.get_variable(name='getVar9', shape=[1])
get_var10 = tf.get_variable(name='getVar10', shape=[1], initializer=tf.constant_initializer(2.))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print('get_var8 = ', get_var8.eval())
print('get_var9 = ', get_var9.eval())
print('get_var10 = ', get_var10.eval())
# get_var8 = [1.]
# get_var9 = [1.]
# get_var10 = [2.]
從上面的測試代碼中可以看出 tf.variable_scope() 和 tf.get_variable() 都有初始化變量的功能,而且如果後者初始化的話,會覆寫前者的初始化值。
看看下面的一個例子,怎麼使内層變量使用另一個作用于的變量
with tf.variable_scope('vs8') as vs8:
get_var11 = tf.get_variable(name='getVar11', shape=[])
print('vs8: ', vs8.name) # vs8: vs8
print('getVar11', get_var11.name) # getVar11 vs8/getVar11:0
with tf.variable_scope('vs9'):
get_var12 = tf.get_variable(name='getVar12', shape=[])
with tf.variable_scope(vs8, reuse=True) as vs8_:
get_var13 = tf.get_variable(name='getVar13', shape=[])
print('vs8_: ', vs8.name) # vs8_: vs8
print('getVar12', get_var12.name) # getVar12 vs9/getVar12:0
print('getVar13', get_var13.name) # getVar13 vs8/getVar13:0
這樣 vs9 空間的就可以使用 vs8 中的變量了。
tf.name_scope() 使用空字元串将作用域傳回到頂層
with tf.variable_scope('vs10'):
get_var14 = tf.get_variable(name='getVar14', shape=[])
with tf.variable_scope('vs11'):
get_var15 = tf.get_variable(name='getVar15', shape=[])
with tf.name_scope(''):
get_var16 = tf.Variable(1., name='getVar16')
with tf.variable_scope(''):
get_var17 = tf.get_variable(name='getVar17', shape=[])
print('getVar14', get_var14.name)
print('getVar15', get_var15.name)
print('getVar16', get_var16.name)
print('getVar17', get_var17.name)
# getVar14 vs10/getVar14:0
# getVar15 vs10/vs11/getVar15:0
# getVar16 getVar16:0
# getVar17 vs10/vs11//getVar17:0 # 中間多個空層