包裝再升級?Tensorflow 2.0的重大改變

Jia-Yau Shiau
AI Blog TW
Published in
6 min readMar 19, 2020

綜觀Tensorflow發行的歷史:從2015年的0.x版本、2017年1.x版本到2019年的超級改版的Tensorflow 2.0,一步一步地推展著這套廣為人知的deep learning框架,卻也形成了不同大板號之間概念的變化。這次從1.x到2.x的變化是以往最大的變化,也是整體負評最多的一次(當然一部分是因為現在對手PyTorch實力堅強)。

Tensorflow 2.0 (image credit: Tensorflow)

這篇文章,會用很快的速度帶過Tensorflow 2.0系列跟舊版的變化。主要的內容編排參考官方文檔,再佐以個人的使用經驗與心得。以下文中,會用TF1泛稱Tensorflow 1.x的版本,而TF2代表2.x的版本。

總體改變

吹到不行的Eager Execution

Tensorflow所謂的eager execution或稱eager mode指的就是讓Tensorflow的運作像是Python一樣的逐行執行。在TF1中,Tensorflow依照著靜態圖的概念,所有的語法都需要先定義好圖,再透過tf.Session丟input、計算output。而TF2可以透過eager execution,即時執行並實踐輕易地監控每個tensor的數值。下面這個簡單例子,對於TF1的使用者來說,大概已經是個不可思議的結果了吧!

tf.Tensor( 
[[1 2]
[3 4]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[2 3]
[4 5]], shape=(2, 2), dtype=int32)

你感覺沒錯沒錯,就跟PyTorch很像。

再見了Session

在TF1中,session.run 大概是最有記憶點的一件事,所有關於圖的計算都是透過這個指令去啟動,決定要運算哪些節點。在TF2中引進了更加Python化的接口,也就是直接用Python原生的function取代了session.run 的API。以往透過tf.session 管理的變數或是開口,現在都可以直接透過Python原生function與variable管理。

Eager是一種選項,tf.session則是完全被取代。

隨之而來的AutoGraph

隨著eager execution的產生,衍生而成的需求就是AutoGraph了,也就是如何妥善的在eager與graph間轉換。而隨著session的消失、原生Python function的引入,帶來的就是tf.function了。

tf.function 的魔力在於將所有在eager下的計算,全部自動建好graph,也就是所謂的AutoGraph。因此可以引入圖的各項優勢,最直覺的就是運算速度上的提升。不過由於第一次運行的時候會先建graph,在一開始速度會是比較慢的。另外,如果是小量的計算,也不一定會帶來更快的效能。

Tensorflow自己官方是這樣說的:TF2帶來了方便的eager execution與TF1強大的力量(大概指graph),而使之合併最關鍵的就是tf.function

在Tensorflow的設計下,tf.function 是一個decorator,任何經由@tf.function 裝飾的function可以像原本一樣的被使用,但額外的獲得AutoGraph的效果。

Eager conv: 1.4893367370000306 
Function conv: 1.483031242999914

這個例子可以看出,少量的計算eager跟graph速度差不了多少。

Python化的control flow

在Eager Execution的劇本下,以往常見實作batch normalization與其他關於運算順序實作的 tf.control_dependencies或是控制變化的tf.condtf.while就不再需要了。

現在,只需要用Python原生方法就好。所有的運算都會照著code上的順序,而條件判斷或是迴圈就直接寫的if/elsewhile或是for就可以了。

square_if_positive(2) = 4
square_if_positive(-2) = 0

移除Global變數與Graph Collection

這個解釋起來就有點費心了。簡單來說TF1的使用者會透過name_scopevariable_scope或是graph collection控管自己的變數,而沒有特別控管的變數,會被丟在global下。如果今天想要憑空抓回一個變數,就必須知道它的完整命名,才可以抓回來。Tensorflow的開發者覺得這是一件麻煩的事情,所以就將這一切交給了Python原生管理。不過這也導致另一個麻煩問題:一個不小心沒保留好變數,就會被自動 garbage collected。

因此,大部分的TF2使用者,就算不走Keras的那套訓練模式,還是會把網路寫成Keras的物件。讓Keras物件幫忙管理變數。

API架構性清理

這個就有點瑣碎了,Tensorflow的官方文檔的說法大致是這樣:TF2將tf.apptf.flags、和tf.logging 從Tensorflow中移除,並建議直接使用原生的 absl-py(摁~也是Google開源的)。並且將原本在tf.* 下的許多功能都分包設計,讓整個API架構更有組織。而以往常用的tf.contrib 也是直接從Tensorflow中移除,用另外一個Python包維護。

負評

TF2在網路上掀起很大的論戰,很多人認為TF2只是藉著Tensorflow名氣產生的新框架,不過其實這個就有點見仁見智了。我個人的感覺TF2的確還是Tensorflow,是一個為了在graph base框架上加上eager的嘗試,但目前還在一個尚未非常明朗的狀態,存在一些對原生使用者不利的改變,甚至對新使用者也增加了學習成本。這部分有興趣的可以參考網路上的論戰。

個人最不滿意的是AutoGraph產生的圖,在Tensorboard下的可視結果真的太悽慘。不過我還是買單了TF2,畢竟他帶來了很多優點。

在TF2訓練模型

TF2要建立可訓練的模型有兩種方法,一個是透過完整的Keras.model,用model.fit 的方法訓練模型,另一個方法就是透過tf.GradientTapetf.GradientTape顧名思義像是磁帶般紀錄gradient,再用跟TF1感覺很相似的的apply_gradients更新參數。

這篇文章就先說到這邊,下一篇文章會介紹一些官方建議寫TF2的小原則,以及如何在TF2中透過tf.GradientTape建構一個model。

--

--