TensorFlow的系統(tǒng)結(jié)構(gòu)以C API為界惕艳,將整個(gè)系統(tǒng)分為「前端」和「后端」兩個(gè)子系統(tǒng)。前端系統(tǒng)扮演了Client的角色蒙兰,完成計(jì)算圖的構(gòu)造镜沽,通過(guò)轉(zhuǎn)發(fā)Protobuf格式的GraphDef
給后端系統(tǒng)的Master,并啟動(dòng)計(jì)算圖的執(zhí)行過(guò)程桨吊。
最終威根,Master將圖進(jìn)行分裂,通過(guò)RegisterGraph
接口视乐,將GraphDef
的子圖片段注冊(cè)到Worker上洛搀。因此,GraphDef
是描述計(jì)算圖的知識(shí)模型佑淀,整個(gè)TensorFlow的計(jì)算過(guò)程都是圍繞GraphDef
所展開(kāi)的留美。
TensorFlow計(jì)算的單位是OP,它表示了某種抽象計(jì)算伸刃。本章首先闡述NodeDef, OpDef
的元數(shù)據(jù)模型谎砾,然后通過(guò)一個(gè)簡(jiǎn)單的例子,講述元數(shù)據(jù)的流動(dòng)過(guò)程捧颅。
元數(shù)據(jù)
OP表示某種抽象計(jì)算景图,它擁有0個(gè)或多個(gè)「輸入/輸出」,及其0個(gè)或多個(gè)「屬性」碉哑。其中挚币,輸入/輸出以Tensor的形式存在亮蒋。
在系統(tǒng)實(shí)現(xiàn)中,OP的元數(shù)據(jù)使用Protobuf格式的OpDef
描述忘晤,實(shí)現(xiàn)前端與后端的數(shù)據(jù)交換宛蚓,及其領(lǐng)域模型的統(tǒng)一。
OpDef定義
OpDef定義包括OP的名字设塔,輸入輸出列表凄吏,屬性列表,優(yōu)化選項(xiàng)等闰蛔。其中痕钢,屬性常常用于描述輸入/輸出的類型,大小序六,默認(rèn)值任连,約束,及其OP的其他特性例诀。
OP命名
OP通過(guò)名字索引随抠,因此必須保證OP的名字全局唯一。按照規(guī)范繁涂,OP的名字采用「駝峰」的命名風(fēng)格拱她,而Python前端則使用「小寫下劃線」的命名風(fēng)格。后者也常常稱為「OP構(gòu)造器」扔罪,也是公開(kāi)給用戶的編程接口(API)秉沼。
另外,以下劃線開(kāi)頭的OP被系統(tǒng)內(nèi)部實(shí)現(xiàn)保留矿酵。例如唬复,_Send, _Recv
,它們用于設(shè)備間通信的OP全肮;_Source, _Sink
標(biāo)識(shí)計(jì)算圖的開(kāi)始節(jié)點(diǎn)和結(jié)束節(jié)點(diǎn)敞咧。
輸入/輸出
OP的輸入/輸出以Tensor的形式存在,存在如下4種情況辜腺。
- 0個(gè)Tensor
- 零輸入
- 零輸出
- 1個(gè)Tensor
- 類型確定
- 類型不確定
- 多個(gè)Tensor
- 類型相同
- 類型不相同
相對(duì)于OP的屬性妄均,OP的輸入是動(dòng)態(tài)的,其值每次迭代(Step)時(shí)哪自,都會(huì)發(fā)生變化。
屬性
OP可以擁有「屬性集」禁熏,用于描述OP輸入輸出的類型壤巷,大小,默認(rèn)值瞧毙,約束胧华,及其其他OP的特征寄症。其中,計(jì)算圖構(gòu)造時(shí)矩动,屬性值(AttrValue)被確定(由NodeDef攜帶有巧,通過(guò)GraphDef傳遞給后端執(zhí)行系統(tǒng))。
也就是說(shuō)悲没,OP的「屬性定義」與「屬性值設(shè)置」是兩個(gè)分離的過(guò)程篮迎。其中,屬性定義在OP注冊(cè)時(shí)確定示姿,通過(guò)AttrDef描述甜橱;屬性值設(shè)置在計(jì)算圖構(gòu)造時(shí)確定(OP添加到計(jì)算圖時(shí)),由AttrValue描述栈戳。
相對(duì)于OP的輸入岂傲,OP的屬性則是靜態(tài)的。OP屬性值在計(jì)算圖構(gòu)造期間確定子檀,包括輸入輸出的類型镊掖,大小,形狀等褂痰,在計(jì)算迭代過(guò)程之中不會(huì)發(fā)生變化亩进。
NodeDef定義
OP索引
NodeDef
通過(guò)op
從OpRegistry
中索引OpDef
。
輸入列表
通過(guò)input
指定節(jié)點(diǎn)的輸入列表脐恩,它也是構(gòu)造計(jì)算圖最重要的知識(shí)所在镐侯。它存在2種情況,分別表示普通邊與控制依賴邊驶冒。
按照約定苟翻,為了解析方便,input
列表前面存儲(chǔ)普通邊骗污,隨后存儲(chǔ)控制依賴邊崇猫。
node:src_output
表示此邊為普通邊,承載Tensor的數(shù)據(jù)流需忿。其中诅炉,node
為前驅(qū)節(jié)點(diǎn)的名稱,src_output
為前驅(qū)節(jié)點(diǎn)輸出邊的索引屋厘。特殊地涕烧,當(dāng)src_output
為0時(shí),可以略去0
汗洒。
^node
表示該邊為控制依賴邊议纯。其中,node
為前驅(qū)節(jié)點(diǎn)的名稱溢谤。
設(shè)備規(guī)范
通過(guò)device
可以支持用戶自定義設(shè)備分配方案瞻凤。例如憨攒,
-
"@other/node"
: 與other/node
節(jié)點(diǎn)分配在同一設(shè)備; -
"/job:worker/replica:0/task:1/gpu:3"
:完整規(guī)范 -
"/job:worker/gpu:3"
:部分規(guī)范 -
""
:空規(guī)范
屬性值列表
在計(jì)算圖的構(gòu)造期阀参,OP屬性值得以確定肝集,包括輸入/輸出的類型,Shape等信息蛛壳。OP的屬性值承載于OpDef
的attr
屬性列表之中杏瞻。
符號(hào)編程
TensorFlow的計(jì)算過(guò)程是一個(gè)延遲計(jì)算,是一種典型的基于符號(hào)的編程范式炕吸。從計(jì)算時(shí)間軸看伐憾,計(jì)算過(guò)程基本分為2個(gè)階段:
- 圖構(gòu)造期:負(fù)責(zé)計(jì)算圖的構(gòu)造;
- 圖執(zhí)行期:負(fù)責(zé)計(jì)算圖的執(zhí)行赫模。
其中树肃,在系統(tǒng)初始化時(shí),系統(tǒng)實(shí)現(xiàn)對(duì)所有OP進(jìn)行掃描注冊(cè)瀑罗,并保存于OpRegistry
之中胸嘴。
注冊(cè)O(shè)P
理論上,OP的注冊(cè)發(fā)生在系統(tǒng)初始化階段斩祭。后端系統(tǒng)劣像,可以使用REGISTER_OP
實(shí)用宏注冊(cè)O(shè)P。前端系統(tǒng)摧玫,也存在類似的OP注冊(cè)機(jī)制耳奕。
使用REGISTER_OP
注冊(cè)O(shè)P過(guò)程,實(shí)際上是一個(gè)REGISTER_OP
描述到OpDef
表示的翻譯過(guò)程诬像。OpDefBuilder
通過(guò)鏈?zhǔn)秸{(diào)用Input
, Output
, Attr
方法分別構(gòu)造OP的輸入屋群、輸出列表,及其屬性列表坏挠。最后芍躏,通過(guò)調(diào)用Finalize
成員函數(shù),經(jīng)過(guò)解析字符串表示降狠,將其翻譯為OpDef
的內(nèi)在表示对竣,最后注冊(cè)到OpRegistry
之中。
例如榜配,REGISTER_OP("ZerosLike")
向系統(tǒng)注冊(cè)了一個(gè)zeros_like
的OP否纬,在運(yùn)行時(shí)實(shí)現(xiàn)了OpDef
的翻譯表達(dá)。
構(gòu)造OP
在前端蛋褥,用戶使用OP構(gòu)造器實(shí)現(xiàn)OP的構(gòu)造烦味,并將OP注冊(cè)到計(jì)算圖中。在計(jì)算圖構(gòu)造期間,OP的輸入/輸出的類型谬俄,Shape得以確定,OP屬性值也得以確定弃理。
計(jì)算圖的構(gòu)造過(guò)程溃论,實(shí)際上就是GraphDef
定義過(guò)程。其中痘昌,OP的屬性值承載于NodeDef
钥勋,計(jì)算圖構(gòu)造期間,NodeDef
的屬性值得以確定辆苔。
在計(jì)算圖執(zhí)行啟動(dòng)時(shí)算灸,通過(guò)調(diào)用Session.run
,將整個(gè)GraphDef
傳遞給后端驻啤,并啟動(dòng)計(jì)算圖的執(zhí)行菲驴。例如,存在如下的計(jì)算圖構(gòu)造過(guò)程:
tensor = tf.constant([1, 2], name="n1")
zeros = tf.zeros_like(tensor, name="n2")
ZerosLike
的上游節(jié)點(diǎn)為n1
骑冗,其src_output=0
輸出邊流入ZerosLike
赊瞬。此時(shí),ZerosLike
的屬性T
的值自動(dòng)推演為DT_INT32
贼涩,兩個(gè)節(jié)點(diǎn)構(gòu)造了一個(gè)簡(jiǎn)單的計(jì)算圖巧涧。
執(zhí)行OP
在計(jì)算圖執(zhí)行期間,輸入由上游OP流入得以確定遥倦,根據(jù)特定設(shè)備類型谤绳,輸入輸出類型,多態(tài)選擇合適的Kernel實(shí)現(xiàn)袒哥,并啟動(dòng)Kernel的計(jì)算過(guò)程缩筛。
例如,如果zeros_like
上游輸入為[1, 2, 3, 4]
统诺,進(jìn)過(guò)zeros_like
的OP運(yùn)算歪脏,輸出為[0, 0, 0, 0]
。
開(kāi)源技術(shù)書
https://github.com/horance-liu/tensorflow-internals