【TF/Guide筆記】 02. Variable
? ? 開篇第一句話就耐人尋味,"A tf.Variable represents a tensor whose value can be changed by running ops on it",不考慮寫文檔的人理解不到位(巨頭公司應(yīng)該不至于)的話,光是計算圖的定義就跟我以前理解的不一樣。
? ? 以前我們設(shè)計的時候是op和variable交替連接構(gòu)成一張計算圖,這樣的好處是很容易分清哪些op是互相獨(dú)立的,可以op級的并行計算。在這樣的設(shè)計里,必然要認(rèn)定variable是只讀的,這樣作為輸入的時候可以被多個op同時讀取,但其實(shí)只讀的問題很大,很多時候級聯(lián)的梯度必然得加到同一個tensor上,如果逐步展開的話就會增加大量無用的內(nèi)存開銷,最終只能特化了InplaceAdd,并且祈禱不會碰上出bug的情況。
? ? 但如果計算圖里只有op,而大部分op在設(shè)計之初就是原地操作的話,雖然理論上這種op只能串聯(lián)運(yùn)行了,但是感覺絕大多數(shù)情況下還是靠tensor內(nèi)的并行來加速的,并不影響多數(shù)場景下的加速。而且原地操作占多數(shù)的話,就會節(jié)省很多中間變量的存儲和讀寫,按理說帶來的好處是更大的。
? ? 而且這樣一來就可以理解人家的循環(huán)和control flow是怎么做出來的了,光是在op上操作的話,不會帶來大量的variable,搞再多也沒事。
? ? 至于他這樣搞會不會帶來一些計算順序上的問題,說實(shí)在的以前我就覺得對計算圖算拓?fù)涫莻€蠻蠢的事,因?yàn)樽蠲髅靼装椎耐負(fù)湫蚓褪怯脩魧懴碌拇a,頂多在此基礎(chǔ)上用output去判斷一下哪些是無用節(jié)點(diǎn)就夠了,甚至于用戶寫的代碼其實(shí)還變相的告訴了你哪些操作可以原地做而哪些需要開辟新空間,core根本不用考慮的那么復(fù)雜。
tf.debugging.set_log_device_placement(True),雖然名字起了很長,但用起來感覺就是glog的flag,log印級別調(diào)成了計算圖一級罷了
基本可以看作Variable和Tensor有相同的操作,但Variable不能reshape,Variable支持原地assign
Variable內(nèi)部包了tensor,它內(nèi)部的tensor應(yīng)該是不能共享的,或者說Variable內(nèi)部的東西只有它自己有所有權(quán),不管是怎么構(gòu)造來的。這樣的確方便管理
Variable的生命周期與py obj的周期相同,想上去應(yīng)該就是利用了py的語義,沒有引用的時候自動釋放了內(nèi)存。不過這里的是否沒有引用,還得看op在使用Variable定義的時候是不是拿到了所有權(quán)
聲明Variable的時候可以加參數(shù)trainable,說明它內(nèi)部應(yīng)該是默認(rèn)有data和diff兩個tensor,這跟我們以前的設(shè)計差不多
可以手動指定Variable所在的device,這個應(yīng)該也受益于原地操作的設(shè)計,但或許會給op的實(shí)現(xiàn)帶來很多麻煩,不過只要人力足夠這些都不是問題
不指定device的時候它會自己找合適的,估計就是連續(xù)tensor優(yōu)先進(jìn)GPU吧,這玩意應(yīng)該也寫不出很復(fù)雜的策略
使用了set_log_device_placement之后會發(fā)現(xiàn),tf里的所有操作最終都對應(yīng)到了計算圖的運(yùn)行上,甚至連tf.constant都不例外,不過這里使用的是eager execute,估計本身就是非常輕量的,不像我們原來跑個圖至少兩把鎖