3、TensorFlow基礎(一) 設計思想與編程模型


1、TensorFlow系統架構

  如圖為TensorFlow的系統架構圖:

    

 

  TensorFlow的系統架構圖,自底向上分為設備層和網絡層、數據操作層、圖計算層、API層、應用層,其中設備層和網絡層,數據操作層,圖計算層是TensorFlow的核心層。

  網絡通信層和設備層:

    網絡通信層包括個gRPC(google Remote Procedure Call Protocol)和遠程直接數據存取(Remote DirectMemory Access,RDMA),這都是在分布式計算時需要用到的。設備管理層包括 TensorFlow 分別在 CPU、GPU、FPGA 等設備上的實現,也就是對上層提供了一個統一的接口,使上層只需要處理卷積等邏輯,而不需要關心在硬件上的卷積的實現過程。

  數據操作層:

    主要包括卷積函數、激活函數等操作

  圖計算層:

    包含本地計算圖和分布式計算圖的實現

  API 層和應用層

    編程語言的實現與應用

2、設計理念

  TensorFlow的設計理念主要體現在兩個方面

   (1)、將圖定義和圖運算完全分開。
 TensorFlow 被認為是一個“符號主義”的庫。我們知道,編程模式通常分為命令式編程(imperative style programming)和符號式編程(symbolic style programming)。命令式編程就是編寫我們理解的通常意義上的程序,很容易理解和調試,按照原有邏輯執行。符號式編程涉及很多的嵌入和優化,不容易理解和調試,但運行速度相對有所提升。現有的深度學習框架中,Torch 是典型的命令式的,Caffe、MXNet 采用了兩種編程模式混合的方法,而 TensorFlow 完全采用符號式編程。

  符號式計算一般是先定義各種變量,然后建立一個數據流圖,在數據流圖中規定各個變量間的計算關系,最后需要對據流圖進行編譯,但此時的數據流圖還是一個空殼兒,里面沒有任何實際數據,只有把需要運算的輸入放進去后,才能在整個模型中形成數據流,從而形成輸出值。

  例如:

 t = 8+ 9 
print(t)

  在傳統的程序操作中,定義了 t 的運算,在運行時就執行了,並輸出 17。而在 TensorFlow

中,數據流圖中的節點,實際上對應的是 TensorFlow API 中的一個操作,並沒有真正去運行:

import tensorflow as tf
t = tf.add(8,9)
print(t)
#輸出  Tensor{"Add_1:0",shape={},dtype=int32}

  (2)、TensorFlow 中涉及的運算都要放在圖中,而圖的運行只發生在會話(session)中。開啟會話后,就可以用數據去填充節點,進行運算;關閉會話后,就不能進行計算了。因此,會話提供了操作運行和 Tensor 求值的環境。

  例如:

import tensorflow as tf
#創建圖
a = tf.constant([1.0,2.0])
b = tf.constant([3.0,4.0])
c = a * b
#創建會話
sess  = tf.Session()
#計算c
print(sess.run(c))#進行矩陣乘法,輸出[3.,8.]
sess.close()

3、TensorFlow編程模型 

  TensorFlow 是用數據流圖做計算的,因此我們先創建一個數據流圖(也稱為網絡結構圖),
如圖 下圖 所示,看一下數據流圖中的各個要素。

  圖 講述了 TensorFlow 的運行原理。圖中包含輸入(input)、塑形(reshape)、Relu 層(Relulayer)、Logit 層(Logit layer)、Softmax、交叉熵(cross entropy)、梯度(gradient)、SGD 訓練(SGD Trainer)等部分,是一個簡單的回歸模型。

  它的計算過程是,首先從輸入開始,經過塑形后,一層一層進行前向傳播運算。Relu 層(隱藏層)里會有兩個參數,即 W h1 和 b h1 ,在輸出前使用 ReLu(Rectified Linear Units)激活函數做非線性處理。然后進入 Logit 層(輸出層),學習兩個參數 W sm 和 b sm 。用 Softmax 來計算輸出結果中各個類別的概率分布。用交叉熵來度量兩個概率分布(源樣本的概率分布和輸出結果的概率分布)之間的相似性。然后開始計算梯度,這里是需要參數 W h1 、b h1 、W sm 和 b sm ,以及交叉熵后的結果。隨后進入 SGD 訓練,也就是反向傳播的過程,從上往下計算每一層的參數,依次進行更新。也就是說,計算和更新的順序為 b sm 、W sm 、b h1 和 W h1 。

                                

  顧名思義,TensorFlow 是指“張量的流動”。TensorFlow 的數據流圖是由節點(node)和邊edge)組成的有向無環圖(directed acycline graph,DAG)。TensorFlow 由 Tensor 和 Flow 兩部分組成,Tensor(張量)代表了數據流圖中的邊,而 Flow(流動)這個動作就代表了數據流圖中節點所做的操作

  3.1、邊

    TensorFlow 的邊有兩種連接關系:數據依賴和控制依賴。其中,實線邊表示數據依賴代表數據,即張量。任意維度的數據統稱為張量。在機器學習算法中,張量在數據流圖中從前往后流動一遍就完成了一次前向傳播(forword propagation),而殘差 從后向前流動一遍就完成了一次反向傳播(backword propagation)。

  注:在數理統計中,殘差是指實際觀測值於訓練的估計值之間的差

    還有一種特殊邊,一般畫為虛線邊,稱為控制依賴(control dependency),可以用於控制操作的運行,這被用來確保 happens-before 關系,這類邊上沒有數據流過,但源節點必須在目的節點開始執行前完成執行。常用代碼:

tf.Graph.control_dependencies(control_inputs)

  Tensorflow支持的張量的數據屬性:

  

  有關圖及張量的實現的源代碼均位於 tensorflow-1.1.0/tensorflow/python/framework/ops.py

 

  3.2、節點

     圖中的節點又稱為算子,它代表一個操作(operation,OP),一般用來表示施加的數學運算,也可以表示數據輸入(feed in)的起點以及輸出(push out)的終點,或者是讀取/寫入持久變量(persistent variable)的終點。下表列舉了一些 TensorFlow 實現的算子。算子支持表所示的張量的各種數據屬性,並且需要在建立圖的時候確定下來。

   

   與操作相關的代碼位於 tensorflow-1.1.0/tensorflow/python/ops/目錄下。以數學運算為例,代碼為上述目錄下的 math_ops.py,里面定義了 add、subtract、multiply、scalar_mul、div、divide、truediv、floordiv 等數學運算,每個函數里面調用了 gen_math_ops.py 中的方法,這個文件是在編譯(安裝時)TensorFlow 時生成的,位於 Python 庫 site-packages/tensorflow/python/ops/gen_math_ops.py 中,隨后又調用了 tensorflow1.1.0/tensorflow/core/kernels/下面的核函數實現。再例如,數據運算的代碼位於 tensorflow-1.1.0/tensorflow/python/ops/array_ops.py 中,里面定義了concat、split、slice、size、rank 等運算,每個函數都調用了 gen_array_ops.py 中的方法,這個文件也是在編譯TensorFlow 生成的,位於Python 庫site-packages/tensorflow/python/ops/gen_array_ops.py中,隨后又調用了 tensorflow-1.1.0/tensorflow/core/kernels/下面的核函數實現。

  3.3、圖

    把操作任務描述成有向無環圖。那么,如何構建一個圖呢?構建圖的第一步是創建各個節

點。具體如下:

import tensorflow as tf
# 創建一個常量運算操作,產生一個 1×2 矩陣
matrix1 = tf.constant([[3., 3.]])
# 創建另外一個常量運算操作,產生一個 2×1 矩陣
matrix2 = tf.constant([[2.],[2.]])
# 創建一個矩陣乘法運算 ,把 matrix1 和 matrix2 作為輸入
# 返回值 product 代表矩陣乘法的結果
product = tf.matmul(matrix1, matrix2)

  3.4、會話

    啟動圖的第一步是創建一個 Session 對象。會話(session)提供在圖中執行操作的一些方法。一般的模式是,建立會話,此時會生成一張空圖,在會話中添加節點和邊,形成一張圖,然后執行。要創建一張圖並運行操作的類,在 Python 的 API 中使用 tf.Session,在 C++ 的 API 中使用tensorflow::Session。示例如下:

with tf.Session() as sess:
result = sess.run([product])
print result

  在調用 Session 對象的 run()方法來執行圖時,傳入一些 Tensor,這個過程叫填充(feed);返回的結果類型根據輸入的類型而定,這個過程叫取回(fetch)。

  與會話相關的源代碼位於 tensorflow-1.1.0/tensorflow/python/client/session.py。

  會話是圖交互的一個橋梁,一個會話可以有個圖,會話可以修改圖的結構,也可以往圖中注入數據進行計算。因此,會話主要有兩個 API 接口:Extend 和 Run。Extend 操作是在 Graph中添加節點和邊,Run 操作是輸入計算的節點和填充必要的數據后,進行運算,並輸出運算結果。

   3.5、設備

    設備(device)是指一塊可以用來運算並且擁有自己的地址空間的硬件,如 GPU 和 CPU。TensorFlow 為了實現分布式執行操作,充分利用計算資源,可以明確指定操作在哪個設備上執行。具體如下:

with tf.Session() as sess:
# 指定在第二個 gpu 上運行
    with tf.device("/gpu:1"):
        matrix1 = tf.constant([[3., 3.]])
        matrix2 = tf.constant([[2.],[2.]])
        product = tf.matmul(matrix1, matrix2)        

  與設備相關的源代碼位於 tensorflow-1.1.0/tensorflow/python/framework/device.py

  3.6、變量

   ·  變量(variable)是一種特殊的數據,它在圖中有固定的位置,不像普通張量那樣可以流動。例如,創建一個變量張量,使用 tf.Variable()構造函數,這個構造函數需要一個初始值,初始值的形狀和類型決定了這個變量的形狀和類型:

# 創建一個變量,初始化為標量 0
state = tf.Variable(0, name="counter")
#創建一個常量張量:
input1 = tf.constant(3.0)

  TensorFlow 還提供了填充機制,可以在構建圖時使用 tf.placeholder()臨時替代任意操作的張量,在調用 Session 對象的 run()方法去執行圖時,使用填充數據作為調用的參數,調用結束后,填充數據就消失。代碼示例如下:

 

input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = tf.multiply(input1, input2)
with tf.Session() as sess:
    print sess.run([output], feed_dict={input1:[7.], input2:[2.]})
# 輸出 [array([ 14.], dtype=float32)]

  與變量相關的源代碼位於 tensorflow/tensorflow/python/ops/variables.py。

  3.7、內核

    我們知道操作(operation)是對抽象操作(如 matmul 或者 add)的一個統稱,而內核(kernel)則是能夠運行在特定設備(如 CPU、GPU)上的一種對操作的實現。因此,同一個操作可能會對應多個內核。

  當自定義一個操作時,需要把新操作和內核通過注冊的方式添加到系統中

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM