1. 程式人生 > >TensorFlow之變數(Variable)

TensorFlow之變數(Variable)

訓練模型時,需要使用變數(Variables)儲存和更新引數。Variables是包含張量(tensor)的記憶體緩衝。變數必須要先被初始化(initialize),而且可以在訓練時和訓練後儲存(save)到磁碟中。之後可以再恢復(restore)儲存的變數值來訓練和測試模型。 

  • 1、變數op能夠持久化儲存,普通張量不行
  • 2、定義一個變數時,在會話中必須初始化
  • 3、name引數:在tensorboard使用時顯示名字,可以讓相同op名字進行區分
     

變數的建立

 建立當一個變數時,將你一個張量作為初始值傳入建構函式Variable()。TensorFlow提供了一系列操作符來初始化張量,值初始的英文常量或是隨機值。像任何一樣Tensor,建立的變數Variable()可以用作圖中其他操作的輸入。此外,為Tensor該類過載的所有運算子都被轉載到變數中,因此您也可以通過對變數進行算術來將節點新增到圖形中。

x = tf.Variable(5.0,name="x")
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")

呼叫tf.Variable()向圖中添加了以下幾個操作:

  • 一個variable op儲存變數值。
  • 初始化器op將變數設定為其初始值。這實際上是一個tf.assign操作。
  • 初始值的ops,例如 示例中biases變數的zeros op 也被新增到圖中。

變數的初始化

 

  • 變數的初始化必須在模型的其它操作執行之前先明確地完成。最簡單的方法就是新增一個給所有變數初始化的操作,並在使用模型之前首先執行那個操作。最常見的初始化模式是使用便利函式 initialize_all_variables()將Op新增到初始化所有變數的圖形中。
init_op = tf.global_variables_initializer()

with tf.Session() as sess:
  sess.run(init_op)
  • 還可以通過執行其初始化函式op來初始化變數,從儲存檔案還原變數,或者簡單地執行assign向變數分配值的Op。實際上,變數初始化器op只是一個assignOp,它將變數的初始值賦給變數本身。assign是一個方法,後面方法的時候會提到

 

with tf.Session() as sess:
    sess.run(w.initializer)

 

  • 還可以通過另一個變數賦值

你有時候會需要用另一個變數的初始化值給當前變數初始化,由於tf.global_variables_initializer()初始化所有變數,所以需要注意這個方法的使用。就是將已初始化的變數的值賦值給另一個新變數!

weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),name="weights")

w2 = tf.Variable(weights.initialized_value(), name="w2")

w_twice = tf.Variable(weights.initialized_value() * 0.2, name="w_twice")

所有變數都會自動收集到建立它們的圖形中。預設情況下,建構函式將新變數新增到圖形集GraphKeys.GLOBAL_VARIABLES。方便函式 global_variables()返回該集合的內容。

變數的屬性

Variable.name:返回變數的名字

weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),name="weights")
print(weights.name)

Variable.op:返回op

weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35))
print(weights.op)

變數的方法

 

  • assign:為變數分配一個新值。
w = tf.Variable(5.0,name="x")
w.assign(w + 1.0)
  • eval:在會話中,計算並返回此變數的值。這不是一個圖形構造方法,它不會向圖形新增操作。方便列印結果。eval的作用和sess.run的作用相似
v = tf.Variable([1, 2])
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    # 指定會話
    print(v.eval(sess))
    # 使用預設會話
    print(v.eval())

佔位符--tf.placeholder()

 只是一個佔位符,佔位符並沒有初始值,只是在必要時分配記憶體, 
在TensorFlow中,資料並不會儲存為 integer, float, 或 string. 這些值都封裝在 tensor 物件中,因此不能直接定義並使用一個變數例如x,因為你設計的模型可能需要受不同的資料集與不同的引數。所以TF使用placeholder()來傳遞一個tensor到session.run()中,並與feed_dict{}結合一起使用。 
feed_dict{}是一個字典,在字典中需要給每一個用到的佔位符取值。在訓練神經網路時,需要大批量的訓練樣,如果每一次迭代選取的資料都需要常量表示,那麼TensorFlow的計算圖會非常大。因為每計算一個常量 ,TensorFlow會增加一個結點,所以說,擁有幾百萬次迭代的神經網路會擁有龐大的計算圖,如果使用佔位符的話,就可以很好的解決這一點,它只會擁有佔位符這一個結點。
 

import tensorflow as tf
import numpy as np

x = tf.placeholder(tf.string)
init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    output = sess.run(x, feed_dict={x: 'Hello World'})
    print(output)

變數的作用域

tensorflow提供了變數作用域和共享變數這樣的概念,有幾個重要的作用。

  • 讓模型程式碼更加清晰,作用分明

變數作用域

通過tf.variable_scope(<scope_name>)建立指定名字的變數作用域

with tf.variable_scope("itcast"):
  print("----")

加上with語句就可以在整個itcast變數作用域下就行操作。

  • 巢狀使用:變數作用域可以巢狀使用
with tf.variable_scope("itcast") as itcast:
    with tf.variable_scope("python") as python:
      print("----")

變數作用域下的變數

 在同一個變數作用域下,如果定義了兩個相同名稱的變數(這裡先用tf.Variable())會怎麼樣呢?

with tf.variable_scope("itcast") as scope:
    a = tf.Variable([1.0,2.0],name="a")
    b = tf.Variable([2.0,3.0],name="a")

 我們通過tensoflow提供的計算圖介面觀察,如下圖所示

我們發現儘管在程式碼中取了同樣的名字,其實tensorflow並沒有當作同一個,而是另外又增加了一個a_1,來表示b的圖。

變數範圍

 當每次在一個變數作用域中建立變數的時候,會在變數的name前面加上變數作用域的名稱。

with tf.variable_scope("itcast"):
    a = tf.Variable(1.0,name="a")
    b = tf.get_variable("b", [1])
    print(a.name,b.name)

 結果為:

(u'itcast/a:0', u'itcast/b:0')

對於巢狀的變數作用域來說

with tf.variable_scope("itcast"):
    with tf.variable_scope("python"):
        python3 = tf.get_variable("python3", [1])
assert python3.name == "itcast/python/python3:0"
var2 = tf.get_variable("var",[3,4],initializer=tf.constant_initializer(0.0))