在上篇博客中已經詳細的介紹了tf的安裝,下面就讓我們正式進入tensorflow的使用,介紹以下tf的特征。
首先tf有它獨特的特征,我們在使用之前必須知曉:
- 使用圖 (graph) 來表示計算任務,tf把計算都當作是一種有向無環圖,或者稱之為計算圖。
- 計算圖是由節點(node)和邊(edge)組成的,節點表示運算操作,邊就是聯系運算操作之間的流向/流水線。
- 使用張量( tensor) 表示數據,張量用來表示在節點間流動的數據,可想,如果沒有數據傳輸,計算圖僅表示一個關系,無實際意義。
- 在被稱之為
會話(Session)
的上下文 (context) 中執行圖,計算圖和數據之后,接下來便是要執行計算圖,Session是tf使用的交互式接口。 - 通過
變量 (Variable)
維護狀態,這就是參數,在運行計算圖的過程中並不是所有的數據都要保存,我們僅僅保存的是Variable,而且是不斷的被更新。 - 使用 feed 和 fetch 可以為任意的操作(arbitrary operation) 賦值或者從其中獲取數據.
以上是tf的基本特征,這在上篇博客的例子中可以清晰的看到。另外,更值得一提的是tensorboard,用以可視化計算圖或監控tf的運行過程,這在caffe中是比較缺乏的,非常值得學習。可以用下面的一段話概括這個過程:
TensorFlow 是一個編程系統, 使用圖(graph)來表示計算任務。圖中的節點(node)被稱之為 op (operation 的縮寫)。一個 op 通過邊(edge)獲得 0 個或多個 Tensor
, 執行計算, 產生 0 個或多個 Tensor。
每個 Tensor 是一個類型化的多維數組。例如, 你可以將一小組圖像集表示為一個四維浮點數數組, 這四個維度分別是 [batch, height, width, channels]。
一個 TensorFlow 圖描述了計算的過程。為了進行計算, 圖必須在會話(Session)
里被啟動,同時,圖中必須為建立的節點喂入數據(feed),會話
將圖的op分發到諸如 CPU 或 GPU之類的設備
上, 同時提供執行 op 的方法。這些方法執行后, 將產生的 tensor(或Variable) 返回,根據需要取回數據(fetch)。在 Python 語言中, 返回的 tensor 是 numpy ndarray
對象; 在 C 和 C++ 語言中, 返回的 tensor 是tensorflow::Tensor
實例。
從圖的角度來看這個過程,其實就是在構建圖和執行圖,構建圖,描述的是節點運算之間的關系;而執行圖,則是在會話中執行這個運算關系,這很好的幫我們理解tf的原理。
下面分別介紹這幾個關鍵的特征,從而達到承上啟下的作用。
- 計算圖
TensorFlow 支持 C, C++, Python 編程語言。目前, TensorFlow 的 Python 庫更加易用, 它提供了大量的輔助函數來簡化構建圖的工作, 這些函數尚未被 C 和 C++ 庫支持。因此大部分的我們都是使用python語言,這在很多框架上已然被證明。既然已經說了計算圖分成兩步,那分別介紹以下它們。
- 構建圖
構建圖的第一步, 是創建源操作 op (source op)。 源操作不需要任何輸入,例如常量(Constant)。
源操作的輸出被傳遞給其它節點做運算。Python 庫中, 操作構造器的返回值代表被構造出的操作的輸出, 這些返回值可以傳遞給其它操作構造器作為輸入。TensorFlow Python 庫有一個默認圖 (default graph), 操作構造器可以為其增加節點。這個默認圖對許多程序來說已經足夠用了。閱讀 Graph 類文檔來了解如何管理多個圖。
import tensorflow as tf # 創建一個常量操作, 產生一個 1x2 矩陣. 這個操作代表一個節點 # 加到默認圖中. # 構造器的返回值代表該常量操作的返回值. matrix1 = tf.constant([[3., 3.]]) # 創建另外一個常量操作, 產生一個 2x1 矩陣. matrix2 = tf.constant([[2.],[2.]]) # 創建一個矩陣乘法 matmul 操作, 把 'matrix1' 和 'matrix2' 作為輸入. # 返回值 'product' 代表矩陣乘法的結果. product = tf.matmul(matrix1, matrix2)
默認圖現在有三個節點, 兩個 constant()
操作, 和一個matmul()
操作。關系已經建立了,下面就要第二步了。
- 啟動圖
構造階段完成后, 才能啟動圖。啟動圖的第一步是創建一個 Session
對象, 如果無任何創建參數, 會話構造器將啟動默認圖。例如我們之前的那個例子,直接
sess = tf.Session()
啟動默認圖。之后就要執行計算圖,with塊執行完后,會自動關閉會話,如下:
with tf.Session() as sess: result = sess.run([product]) print (result)
另外,上文有提到"同時,圖中必須為建立的節點喂入數據,會話
將圖的op分發到諸如 CPU 或 GPU之類的設備
上, 同時提供執行 op 的方法",這也就是分布式執行,以充分利用可用的計算資源(如 CPU 、 GPU)。一般不需要顯式指定使用 CPU 還是 GPU, TensorFlow 能自動檢測。如果檢測到 GPU, TensorFlow 會盡可能地利用找到的第一個 GPU 來執行操作。如果機器上有超過一個可用的 GPU, 除第一個外的其它 GPU 默認是不參與計算的。為了讓 TensorFlow 使用這些 GPU, 你必須將 op 明確指派給它們執行。 with...device
語句用來指派特定的 CPU 或 GPU 執行操作:
with tf.Session() as sess: with tf.device("/gpu:1"): matrix1 = tf.constant([[3., 3.]]) matrix2 = tf.constant([[2.],[2.]]) product = tf.matmul(matrix1, matrix2)
設備用字符串進行標識,目前支持的設備包括:
“/cpu:0”
: 機器的 CPU。“/gpu:0”
: 機器的第一個 GPU, 如果有的話。“/gpu:1”
: 機器的第二個 GPU。- 以此類推......
2.交互式使用
上面的示例使用一個會話 Session
來 啟動圖, 並調用 Session.run()
方法執行操作。為了便於使用諸如 IPython 之類的 Python 交互環境, 可以使用 InteractiveSession
代替 Session
類, 使用 Tensor.eval()
和 Operation.run()
方法代替 Session.run()。
這樣相當於運行我們想要的關系圖,不是默認的整個計算圖,這之間的依賴或者參數傳遞關系tf會自動找到。
# 進入一個交互式 TensorFlow 會話. import tensorflow as tf sess = tf.InteractiveSession() x = tf.Variable([1.0, 2.0]) a = tf.constant([3.0, 3.0]) # 使用初始化器 initializer op 的 run() 方法初始化 'x' x.initializer.run() # 增加一個減法 sub op, 從 'x' 減去 'a'. 運行減法 op, 輸出結果 sub = tf.subtract(x, a) print (sub.eval())
3.Fetch
為了取回操作的輸出內容, 可以在使用 Session
對象的 run()
調用執行圖時, 傳入一些 tensor, 這些 tensor 會幫助你取回結果。在之前的例子里, 我們只取回了單個節點 state
, 但是你也可以取回多個 tensor:
import tensorflow as tf import numpy as np with tf.Session() as sess: with tf.device("/cpu:0"): a = tf.constant(3.0) b = tf.constant(2.0) c = tf.constant(5.0) intermed = tf.add(b, c) mul = tf.multiply(a, intermed) result = sess.run([mul, intermed]) print (result)
需要獲取的多個 tensor 值,在 op 的一次運行中一起獲得(而不是逐個去獲取 tensor)。
4.Feed
上述示例在計算圖中引入了 tensor, 以常量或變量的形式存儲。TensorFlow 還提供了 feed 機制, 該機制 可以臨時替代圖中的任意操作中的 tensor 可以對圖中任何操作提交補丁, 直接插入一個 tensor。feed 使用一個 tensor 值臨時替換一個操作的輸出結果。你可以提供 feed 數據作為 run()
調用的參數。feed 只在調用它的方法內有效, 方法結束, feed 就會消失。最常見的用例是將某些特殊的操作指定為 "feed" 操作, 標記的方法是使用 tf.placeholder() 為這些操作創建占位符。
import tensorflow as tf import numpy as np with tf.Session() as sess: with tf.device("/cpu:0"): a = tf.placeholder(tf.float32) b = tf.placeholder(tf.float32) output = tf.multiply(a, b) print (sess.run([output], feed_dict={a:[7.], b:[2.]}))