拔了智齒,疼滴想屎。

拔了兩顆右邊的智齒,術後反應有點大,嗓子巨痛,疼痛使我思考,思考起了用了這麼久的Tensorflow,那它的架構到底是啥樣的????????????????

看了一遍google的論文:

TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systemsarxiv.org

稍微總結一下。

一、編程模式和基本概念

本著嚴謹的原則,說些廢話:

大家應該都知道,tensorflow的計算是由一個用戶畫出的有向計算圖(和高中學過的數據流圖類似)來描述的,而一張計算圖就代表著數據流的計算過程,在這張計算圖中,有的節點可以保持不變,有的節點可以進行更新,並且可以有循環和分支結構。如果使用python介面,可以像這樣碼代碼來構建計算圖:

編程模式通常分為命令式編程(imperative style programs)和符號式編程(symbolic style programs)。

命令式編程容易理解和調試,命令語句基本沒有優化,按原有邏輯執行。符號式編程涉及較多的嵌入和優化,不容易理解和調試,但運行速度有同比提升,Tensorflow使用的是符號式編程,這應該也是一開始Tensorflow不支持動態計算圖的原因吧。

1.Edges and Tensors:

1.1. edge:

在tensorflow的計算圖中有兩種邊,一種就是表示數據流流向的邊,從一些節點的輸出到另一些節點的輸入;另一種邊表示control dependenices,強行翻譯的話就是控制依賴,通過這種邊我們可以實現對節點運行順序的控制,源節點必須要在目標節點之前運行,所以當我們的運算圖中存在依賴關係時,可以使用這種控制方式確保數據流的正確性。

我們可以這樣來使用control dependencies:

with g.control_dependencies([a, b, c]):n # `d` and `e` will only run after `a`, `b`, and `c` have executed.n d = ...n e = ...n

在這段代碼中,d和e這兩個op必須在a、b、c三個op都執行之後再執行。

還可以嵌套:

with g.control_dependencies([a, b]):n # Ops constructed here run after `a` and `b`.n with g.control_dependencies([c, d]):n # Ops constructed here run after `a`, `b`, `c`, and `d`.n

還可以傳入None來消除依賴:

with g.control_dependencies([a, b]):n # Ops constructed here run after `a` and `b`.n with g.control_dependencies(None):n # Ops constructed here run normally, not waiting for either `a` or `b`.n with g.control_dependencies([c, d]):n # Ops constructed here run after `c` and `d`, also not waitingn # for either `a` or `b`.n

1.2. tensor:

在edge中流動的數據就是tensor,可以是任意維度的array,但是在構建計算圖時就需要指定元素的類型,比如tf.float16, tf.float32, tf.float64, tf.uint8, tf.int8, tf.int16, tf.int32, tf.int64, tf.string, tf.bool, tf.complex64等之類。

2.Operations and Kernels:

2.1. operation:

op有自己的名字和代表的計算過程(例如加法、矩陣乘法),在計算圖中一個節點node就是一個op,op可以有自己的attributes,一種常用的使用attributes的情況是,我們在使用比如tf.add這個方法的時候需要通過dtype參數指定數據類型,attributes的存在是為了使得op可以實現多態(比如元素類型為int的tensor之間的加法和元素類型為float的tensor之間的加法)。

2.2. kernel:

kernel是可以在某種設備(CPU或者GPU)上運行的,一個具體操作的實現。

3.Sessions

我們寫的程序通過Session和Tensorflow系統進行交互,當創建一個session時,計算圖是一張白紙,session介面提供extend方法來向計算圖中添加邊和節點;另外一個session介面提供的重要方法就是run,提供給run一些需要輸出的節點名稱和一個feed dict,Tensorflow系統就會計算所有與輸出節點有關的節點的數值。

4.Variables

在大多數計算中,計算圖會不止一次地被執行,但是大多數tensor的生命周期只在一次執行中。Variable是一種特殊的operation,它返回的是一個句柄(handle,我覺得這裡的handle應該不是windows編程里的那個handle,應該是更加像c++指針里的概念),該句柄指向一個永久性的可變tensor。在Tensorflow構建的機器學習模型中,模型參數都是用由Variables方法創建的tensor中的。

二、實現

Tensorflow系統的主要組成部分是:

前端:client

後端:distributed master、worker services和kernel implements。

client通過session與master進行交互,master通過worker service指導具體的device進行計算。

在單機單卡和單機多卡時,client、master和worker都運行在同一個進程里;

在實現分散式時,不同的進程運行在不同的機器上,相同目的的進程組成一個job,不同的jobs由一個cluster scheduling system來管理。大概關係如下圖所示:

三、梯度計算

common sense:深度學習存在這樣一個過程,對損失函數的參數求梯度,通過SGD來進行參數更新。那一個深度學習框架必不可少的部分就是如何進行自動求導,也就是如何根據用戶代碼來自動計算梯度。

先用華盛頓大學CSE599G1的PPT大概表示一下自動求導的可行性:

根據前向傳播的計算圖,可以構建出BP時的計算圖,在Tensorflow中利用的也是這種方式,假設有一個tensor,稱為C,C在前向傳播時依賴於另一個tensor,稱之為I,當從C向I進行BP時,首先找出由I向C前向傳播的路徑,再反過來,反向傳播路徑上數據流經過的每一個節點都會被加入到Tensorflow的計算圖中,在該條反向傳播的路徑上根據鏈式法則構建梯度。

圖中從前向傳播計算圖指向反向傳播計算圖的箭頭表示的是在反向傳播時需要用到的正向傳播數據流。

在Tensorflow中我們一般這樣來使用自動求導機制:

loss = output - labelnall_trainable = tf.trainable_variables()noptimizer = tf.train.AdamOptimizer(learning_rate)n# 通過下面兩行代碼實現反向計算圖的構建和train這個op的定義ngrad = tf.gradients(loss, all_trainable) ntrain_op = optimizer.apply_gradients(zip(grad, all_trainable))n

四、控制流

儘管不含有任何控制流的數據流圖已經有足夠的模型表達能力,但是有時如果加入循環和條件語句,可以更加高效準確地表示一個機器學習演算法。

這個部分白皮書里寫的有丶難懂。。我打算在官網看看手冊里的幾個函數。

條件語句之tf.cond:

cond(n pred,n true_fn=None,n false_fn=None,n strict=False,n name=None,n fn1=None,n fn2=Nonen)nn# 例子nz = tf.multiply(a, b)nresult = tf.cond(x < y, lambda: tf.add(x, z), lambda: tf.square(y))n

看起來有點像三元運算符的用法,可以在構建計算圖時加入條件分支,使得機器學習模型可以更加多元化。

循環語句之tf.while_loop:

while_loop(n cond,n body,n loop_vars,n shape_invariants=None,n parallel_iterations=10,n back_prop=True,n swap_memory=False,n name=Nonen)n

在cond為true時,循環執行body。無知使我醜陋,沒見過人用呀。在使用循環時,每次迭代(不得不說開發Tensorflow的團隊真的很嚴謹,用了each iteration of a loop這種表述)都有一個tag來唯一標識,每次迭代的狀態都由一個frame來表示。通過這種方式,使得多個迭代可以同時進行(個人理解是,一個batch的數據進來,不同的數據滿足不同的條件,各個數據之間的循環情況是分開的,所以可以同時進行)。

之前介紹的control dependencies應該也屬於控制流的一部分,只不過control dependencies控制的是不同數據流,如果計算圖中存在依賴關係則是個很好用的工具,比如模型中的op1想使用更新操作op2更新後的參數,就可以將op2加入依賴項,這樣以來,op2必須在op1前被執行。

總結

其實還有一個很重要的部分是Tensorflow的分散式,打算另開一個地方寫一篇深度學習與分散式結合的學習心得,還有一些很關鍵的概念比如parameter server,都需要先進行學習,拔了智齒後一兩天的生活有丶難啊。


推薦閱讀:

【博客存檔】深度學習之Neural Image Caption
[乾貨|實踐] TensorBoard可視化
YJango的前饋神經網路--代碼LV1

TAG:深度学习DeepLearning | TensorFlow |