Tensorflow是一個編程模型,幾乎成爲了一種編程語言(裏面有變量、有操做......)。 Tensorflow編程分爲兩個階段:構圖階段+運行時。 Tensorflow構圖階段其實就是在對圖進行一些描述性語言,跟html很像,很適合用標記性語言來描述。 Tensorflow是有向圖,是一個有向無環圖。張量爲邊,操做爲點,數據在圖中流動。 Tensorflow爲每一個結點都起了惟一的一個名字。html
import tensorflow as tf a = tf.constant(3) # name=Const:0 b = tf.Variable(4) # name=Variable:0 print(a.name, b.name)
如上所示,即使你沒有指明變量的name屬性,tensorflow也會給它起個默認名字。python
在C++中有namespace的概念,命名空間的好處就是減小了命名衝突,咱們能夠在命名空間中使用較簡易的標識符。爲了便於用戶定義變量的name,tensorflow也提出了name_scope編程
with tf.name_scope("my"): a = tf.constant(3) # my/Const:0 b = tf.add(a, b) # my/Add:0 print(a.name, b.name) # 使用get_variable卻無論用 c = tf.get_variable("c", shape=1, dtype=tf.int32, initializer=tf.constant_initializer(2)) # c:0 print(c.name)
如上所示,在name_scope中的屬性,會用相似文件路徑的方式來定義變量的name屬性 可是關於name_scope須要明白兩點:編程語言
總而言之,name_scope做用比較單一,僅僅是爲了更改變量的name屬性,便於命名變量。而variable_scope做用就很豐富了,它不只可以改變變量的name屬性,還可以實現變量管理功能。函數
with tf.variable_scope("ha"): a = tf.constant(2, name="myconstant") # ha/myconstant:0 b = tf.get_variable("b", shape=1, dtype=tf.int32, initializer=tf.constant_initializer(2)) # ha/b:0 print(a.name, b.name)
在改變變量name屬性這方面,variable_scope和name_scope基本沒有差異,惟一的區別就是get_variable不會受到name_scope的影響,卻會受到variable_scope的影響。測試
variable_scope更加劇要的功能是實現變量管理,其中最突出的一點就是變量共享spa
# 下面咱們來驗證一下變量共享機制 def get_share_variable(reuse): with tf.variable_scope("share", reuse=reuse): a = tf.get_variable("a", shape=(1), dtype=tf.int32) return a one = get_share_variable(False) two = get_share_variable(True) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run([one, two, tf.assign(one, [2])]))
再上面的例子中,經過reuse屬性能夠控制variable_scope中的變量是否須要從新建立,若是指定reuse=false,則必然會執行新建變量的操做。 上面代碼one和two輸出值都變成了2,這說明它倆引用的是同一個對象。 使用variable_scope實現變量共享須要注意如下幾點:設計
變量共享機制很是重要。一個很是經常使用的場景就是:訓練完成以後保存模型,加載模型以後整個圖已經創建好了,這時就須要經過variable_scope機制複用已經建好的圖,而後測試。code
爲了驗證以上兩點,請看下例:htm
複用不曾建立過的變量會報錯
with tf.variable_scope("ha", default_name="what", reuse=True): try: m = tf.get_variable("m") except Exception as ex: print(ex) # Variable ha/m does not exist, or was not created with tf.get_variable(). Did you mean to set reuse=tf.AUTO_REUSE in VarScope?
它建議咱們使用reuse=tf.AUTO_REUSE,這個屬性值的含義表示:若是變量存在則複用,不存在則建立之。
之前,reuse屬性的取值爲True和False,沒有tf.AUTO_REUSE。可是在tensorflow將來的版本中,有可能會把reuse的取值弄成枚舉類型。這就略微有點小坑了,不知AUTO_REUSE的使用場景是否對得起這麼不優雅的設計。
下面驗證第二點,必須指明變量的形狀和類型才能夠複用
with tf.variable_scope("ha", default_name="what", reuse=tf.AUTO_REUSE): try: m = tf.get_variable("m") print(m.name) except Exception as ex: print(ex) # ValueError: Shape of a new variable (ha/m) must be fully defined, but instead was <unknown>. 這個錯誤是在說:建立變量必須指明變量的類型
variable_scope的主要做用是變量共享。 說到變量共享,不得不說tf.get_variable()函數。tf.Variable()是構造函數,必定會建立新的變量。tf.get_variable則能夠直接訪問已經建立的變量(只能在variable_scope中且reuse=True或者AUTO_REUSE的狀況下),也能夠建立新的變量(在variable_scope內部或者外面均可以,如果內部,則必須reuse=FALSE或者AUTO_REUSE)。
經過以上過程能夠發現,get_variable跟variable_scope很是合得來。get_variable不必定非在variable_scope中使用,可是不在variable_scope中使用,它就只能用來建立變量而沒法複用變量了,由於只有variable_scope才擁有reuse屬性。
# reuse變量的惟一方式就是使用name_scope x = tf.Variable(3, False, name='x') print(x.name, x.shape) # x:0 () y = tf.get_variable("x", shape=x.shape) print(y.name, y.shape) # x_1:0 ()
使用get_variable時也有一些微操做,好比指定trainable屬性指明該變量是否能夠訓練。
with tf.variable_scope("ha", default_name="what", reuse=tf.AUTO_REUSE): # 當variable_scope reuse變量時,依舊能夠對變量進行一些微操做:設置trainable=False,表示這個節點不可訓練 # 當獲取變量時,dtype類型必須對應正確 a = tf.get_variable("b", trainable=False, dtype=tf.int32) print(tf.trainable_variables("ha"))
相比name_scope功能的單一,tensorflow對variable_scope玩了不少花樣:
爲了對比說明問題,下面用嵌套的方式來實現做用域。
with tf.variable_scope("one"): """ 使用name_scope只會影響變量的名字,它要解決的問題是變量重名問題 """ with tf.name_scope("two"): x = tf.constant(3) # one/two/Const:0 print(x.name) # variable_scope.name是根目錄的名字 print(tf.get_variable_scope().name, tf.get_variable_scope().original_name_scope) # 輸出爲:one one/ with tf.variable_scope("three"): x = tf.constant(3) # one/three/Const:0 print(x.name) print(tf.get_variable_scope().name, tf.get_variable_scope().original_name_scope) # 輸出爲one/three one/three/
可見,name_scope對於tf.get_variable_scope()來講幾乎是不可見的,但卻會對變量的命名產生影響,但卻僅僅對變量名產生影響。
函數不會阻隔with做用域
# 使用函數依舊不會影響做用域 def ha(): x = tf.Variable(3) # ha_3/Variable:0 print(x.name) with tf.variable_scope("ha"): # 這個變量做用域已經定義過好幾回了,它的實際名字變成了ha_3 ha()
Tensorflow中每一個結點的name都不會重複,若是重複了怎麼辦?
# 若是重複定義變量 a = tf.constant(2, name='a') # a:0 b = tf.constant(2, name='a') # a_1:0 print(a.name, b.name) # 若是重複定義name_scope with tf.name_scope("my"): a = tf.constant(2) # my_1/Const:0 print(a.name) """ 可見tensorflow對於一切重名的東西都會在末尾加上下劃線+數字 """ with tf.name_scope("my_4"): a = tf.constant(2) print(a.name) # my_4/Const:0 with tf.name_scope("my"): a = tf.constant(2) print(a.name) # my_2/Const:0 with tf.name_scope("my_4"): a = tf.constant(2) # my_4_1/Const:0 print(a.name)
經過以上例子能夠發現,tensorflow對於命名重複問題使用如下規則解決: 一、要使用的name不存在,能夠直接使用 二、要使用的name已經存在,執行下列循環:
i=1 while 1: now_name="%s_%d"%(name,i) if exists(now_name): i+=1 else: return now_name