基礎(chǔ)知識(shí)
下面就自底向上詳細(xì)介紹一下 TensorFlow 的系統(tǒng)架構(gòu)歪脏。最下層是網(wǎng)絡(luò)通信層和設(shè)備管理層虫啥。網(wǎng)絡(luò)通信層包括 gRPC(google Remote Procedure Call Protocol)和遠(yuǎn)程直接數(shù)據(jù)存惹还选(Remote Direct Memory Access, RDMA)跷究,這都是在分布式計(jì)算時(shí)需要用到的洛退。設(shè)備管理層包括 TensorFlow 分別在 CPU、 GPU夹抗、 FPGA 等設(shè)備上的實(shí)現(xiàn)外莲,也就是對(duì)上層提供了一個(gè)統(tǒng)一的接口,使上層只需要處理卷積等邏輯兔朦,而不需要關(guān)心在硬件上的卷積的實(shí)現(xiàn)過(guò)程偷线。
其上是數(shù)據(jù)操作層,主要包括卷積函數(shù)沽甥、激活函數(shù)等操作声邦。再往上是圖計(jì)算層,也是我們要了解的核心摆舟,包含本地計(jì)算圖和分布式計(jì)算圖的實(shí)現(xiàn)亥曹。再往上是 API 層和應(yīng)用層
Tensorflow的特點(diǎn)
TensorFlow是符號(hào)式編程。將圖的定義和圖的運(yùn)行完全分開恨诱。因此媳瞪, TensorFlow 被認(rèn)為是一個(gè)“符號(hào)主義”的庫(kù)。相比于命令式編程來(lái)說(shuō)不易理解和調(diào)試照宝,但是運(yùn)行速度相對(duì)很快蛇受。
符號(hào)式計(jì)算一般是先定義各種變量,然后建立一個(gè)數(shù)據(jù)流圖厕鹃,在數(shù)據(jù)流圖中規(guī)定各個(gè)變量之間的計(jì)算關(guān)系兢仰,最后需要對(duì)數(shù)據(jù)流圖進(jìn)行編譯乍丈,但此時(shí)的數(shù)據(jù)流圖還是一個(gè)空殼兒,里面沒(méi)有任何實(shí)際數(shù)據(jù)把将,只有把需要運(yùn)算的輸入放進(jìn)去后轻专,才能在整個(gè)模型中形成數(shù)據(jù)流,從而形成輸出值察蹲。
TensorFlow 中涉及的運(yùn)算都要放在圖中请垛,而圖的運(yùn)行只發(fā)生在會(huì)話(session)中。開啟會(huì)話后洽议,就可以用數(shù)據(jù)去填充節(jié)點(diǎn)叼屠,進(jìn)行運(yùn)算;關(guān)閉會(huì)話后绞铃,就不能進(jìn)行計(jì)算了镜雨。因此,會(huì)話提供了操作運(yùn)行和 Tensor 求值的環(huán)境儿捧。
import tensorflow as tf
# 創(chuàng)建圖
a = tf.constant([1.0, 2.0])
b = tf.constant([3.0, 4.0])
c = a * b
# 創(chuàng)建會(huì)話
sess = tf.Session()
# 計(jì)算 c
print sess.run(c) # 進(jìn)行矩陣乘法荚坞,輸出[3., 8.]
sess.close()
Tensorflow的運(yùn)行原理(編程模型)
下面這張圖是一個(gè)簡(jiǎn)單的回歸模型。圖中包含輸入(input)菲盾、塑形(reshape)颓影、 Relu 層(Relu layer)、 Logit 層(Logit layer)懒鉴、 Softmax诡挂、交叉熵(cross entropy)、梯度(gradient)临谱、 SGD 訓(xùn)練(SGD Trainer)等部分璃俗。
它的計(jì)算過(guò)程是,首先從輸入開始悉默,經(jīng)過(guò)塑形后城豁,一層一層進(jìn)行前向傳播運(yùn)算。 Relu 層(隱藏層)里會(huì)有兩個(gè)參數(shù)抄课,即 Wh1和 bh1唱星,在輸出前使用ReLu(Rectified Linear Units)激活函數(shù)做非線性處理。然后進(jìn)入 Logit 層(輸出層)跟磨,學(xué)習(xí)兩個(gè)參數(shù) Wsm和 bsm间聊。用 Softmax 來(lái)計(jì)算輸出結(jié)果中各個(gè)類別的概率分布。用交叉熵來(lái)度量?jī)蓚€(gè)概率分布(源樣本的概率分布和輸出結(jié)果的概率分布)之間的相似性抵拘。然后開始計(jì)算梯度哎榴,這里是需要參數(shù) Wh1、 bh1、 Wsm和 bsm叹话,以及交叉熵后的結(jié)果。隨后進(jìn)入 SGD 訓(xùn)練墩瞳,也就是反向傳播的過(guò)程驼壶,從上往下計(jì)算每一層的參數(shù),依次進(jìn)行更新喉酌。也就是說(shuō)热凹,計(jì)算和更新的順序?yàn)?bsm、 Wsm泪电、 bh1和 Wh1般妙。
Tensor(張量)代表了數(shù)據(jù)流圖中的邊,而 Flow(流動(dòng))這個(gè)動(dòng)作就代表了數(shù)據(jù)流圖中節(jié)點(diǎn)所做的操作相速。
邊
TensorFlow 的邊有兩種連接關(guān)系:數(shù)據(jù)依賴和控制依賴碟渺。實(shí)線邊表示數(shù)據(jù)依賴,代表數(shù)據(jù)突诬,即張量苫拍。在機(jī)器學(xué)習(xí)算法中,張量在數(shù)據(jù)流圖中從前往后流動(dòng)一遍就完成了一次前向傳播(forword propagation)旺隙,而殘差從后向前流動(dòng)一遍就完成了一次反向傳播(backword propagation)绒极。
虛線邊,稱為控制依賴蔬捷÷⑻幔可以用于控制操作的運(yùn)行,這被用來(lái)確保happens-before 關(guān)系周拐,這類邊上沒(méi)有數(shù)據(jù)流過(guò)铡俐,但源節(jié)點(diǎn)必須在目的
節(jié)點(diǎn)開始執(zhí)行前完成執(zhí)行。常用代碼如下:
tf.Graph.control_dependencies(control_inputs)
節(jié)點(diǎn)
節(jié)點(diǎn)又稱為算子妥粟,它代表一個(gè)操作(operation高蜂, OP),一般用來(lái)表示施加的數(shù)學(xué)運(yùn)算罕容,也可以表示數(shù)據(jù)輸入(feed in)的起點(diǎn)以及輸出(push out)的終點(diǎn).或者是讀取/寫入持久變量(persistent variable)的終點(diǎn)
這些代碼在C:\Users\14192\Anaconda3\Lib\site-packages\tensorflow\python\ops中备恤。(因?yàn)槲野惭b了anaconda,所以包的路徑都是anaconda的子路徑)
其余概念
- 圖:操作任務(wù)描述成有向無(wú)環(huán)圖。首先創(chuàng)建節(jié)點(diǎn)锦秒,然后創(chuàng)建節(jié)點(diǎn)之間的關(guān)聯(lián)
- 會(huì)話: 會(huì)話是啟動(dòng)圖的第一步露泊,提供執(zhí)行操作的一些方法。過(guò)程是:建立會(huì)話旅择,此時(shí)會(huì)生成一張空?qǐng)D惭笑,在會(huì)話中添加節(jié)點(diǎn)和邊,形成一張圖,然后執(zhí)行沉噩。相關(guān)代碼在C:\Users\14192\Anaconda3\Lib\site-packages\tensorflow\python\client\session.py中捺宗。
import tensorflow as tf
# 創(chuàng)建一個(gè)常量運(yùn)算操作,產(chǎn)生一個(gè) 1×2 矩陣
matrix1 = tf.constant([[3., 3.]])
# 創(chuàng)建另外一個(gè)常量運(yùn)算操作川蒙,產(chǎn)生一個(gè) 2×1 矩陣
matrix2 = tf.constant([[2.],[2.]])
# 創(chuàng)建一個(gè)矩陣乘法運(yùn)算 蚜厉,把 matrix1 和 matrix2 作為輸入
# 返回值 product 代表矩陣乘法的結(jié)果
product = tf.matmul(matrix1, matrix2)
#會(huì)話:
#傳入一些 Tensor,這個(gè)過(guò)程叫填充(feed)畜眨;
#返回的結(jié)果類型根據(jù)輸入的類型而定昼牛,這個(gè)過(guò)程叫取回(fetch)。
with tf.Session() as sess:
result = sess.run([product])
print( result)
- 設(shè)備:一塊可以用來(lái)運(yùn)算并且擁有自己的地址空間的硬件康聂,如 GPU 和 CPU贰健。TensorFlow 為了實(shí)現(xiàn)分布式執(zhí)行操作,充分利用計(jì)算資源恬汁,可以明確指定操作在哪個(gè)設(shè)備上執(zhí)行伶椿。
with tf.Session() as sess:
# 指定在第二個(gè) gpu 上運(yùn)行
with tf.device("/gpu:1"):
matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.],[2.]])
product = tf.matmul(matrix1, matrix2)
- 變量
變量(variable)是一種特殊的數(shù)據(jù),它在圖中有固定的位置氓侧,不像普通張量那樣可以流動(dòng)悬垃。例如,創(chuàng)建一個(gè)變量張量甘苍,使用 tf.Variable()構(gòu)造函數(shù)尝蠕,這個(gè)構(gòu)造函數(shù)需要一個(gè)初始值,初始值的形狀和類型決定了這個(gè)變量的形狀和類型载庭。
state = tf.Variable(0, name="counter")
TensorFlow 還提供了填充機(jī)制看彼,可以在構(gòu)建圖時(shí)使用 tf.placeholder()臨時(shí)替代任意操作的張量,在調(diào)用 Session 對(duì)象的 run()方法去執(zhí)行圖時(shí)囚聚,使用填充數(shù)據(jù)作為調(diào)用的參數(shù)靖榕,調(diào)用結(jié)束后,填充數(shù)據(jù)就消失顽铸。
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)]
- 內(nèi)核:可以理解為進(jìn)程茁计。操作(operation)是對(duì)抽象操作(如 matmul 或者 add)的一個(gè)統(tǒng)稱,而內(nèi)核(kernel)則是能夠運(yùn)行在特定設(shè)備(如 CPU谓松、 GPU)上的一種對(duì)操作的實(shí)現(xiàn)星压。因此,同一個(gè)操作可能會(huì)對(duì)應(yīng)多個(gè)內(nèi)核鬼譬。
常用API匯總
可視化時(shí)需要在程序中給必要的節(jié)點(diǎn)添加摘要(summary)娜膘,摘要會(huì)收集該節(jié)點(diǎn)的數(shù)據(jù),并標(biāo)記上第幾步优质、時(shí)間戳等標(biāo)識(shí)竣贪,寫入事件文件(event file)中军洼。 tf.summary.FileWriter 類用于在目錄中創(chuàng)建事件文件,并且向文件中添加摘要和事件演怎,用來(lái)在 TensorBoard 中展示匕争。