在本文中我們將對TensorFlow中的一些基本概念做一個簡單的介紹,希望進一步了解這些概念及其實現的讀者,可以參考官方的白皮書(主要是15年的)以及TensorFlow官網的一些文檔。需要注意的是,這些資料中的部分內容對於TensorFlow2.0來說已經不適用了,讀者在閱讀的時候需要留意。
1. TensorFlow常見基本概念
1.1 計算圖
計算圖(computation graph)是一個有向圖(directed graph),是對TensorFlow中計算任務的抽象描述,也稱為數據流圖(data flow graph)。TensorFlow使用計算圖將計算表示成了獨立的指令之間的依賴關係,在計算圖中,節點表示計算單元(即一個獨立的運算操作),圖中的邊表示計算使用或產生的數據。在TensorFlow1.x版本中,當我們使用TensorFlow低級API進行編程時,我們首先需要定義好計算圖,然後創建TensorFlow會話(session)來執行計算圖。
在TensorFlow1.x版本中採用的是靜態圖機制,我們需要預先定義好計算圖,然後再可以反覆的調用它(1.x版本有提供Eager Execution接口,讓用戶可以使用動態圖)。TensorFlow2.0則採用了動態圖機制(1.x版本的Eager Execution在2.0中成為了默認的執行方式),我們可以像執行普通的python程序一樣執行TensorFlow的代碼,而不再需要自己預先定義好靜態圖,調試代碼也更加容易。TensorFlow1.x的靜態圖機制一直被用戶所詬病,調整為動態圖機制是TensorFlow2.0一個最重大的改進,並且其也提供了一些方法來保留靜態計算圖的一些優勢。
1.2 會話
在1.x版本中,會話(session)是客戶端程序與TensorFlow系統進行交互的接口,我們定義好的計算圖必須在會話中執行。當會話被創建時會初始化一個空的圖,客戶端程序可以通過會話提供的「Extend」方法向這個圖中添加新的節點來創建計算圖,並通過「tf.Session」類提供的「run」方法來執行計算圖。大多數情況下我們只需要創建一次會話和計算圖,之後我們可以在會話中反覆執行整個計算圖或者其中的某些子圖。
TensorFlow2.0採用了動態圖機制,我們不需要在會話中執行計算圖了,「tf.Session」類被放到了兼容模塊「tensorflow.compat.v1」中,這個模塊里有完整的TensorFlow1.x的API。為了保留靜態圖的優勢(例如性能優化和可移植性等),TensorFlow2.0提供了「tf.function」方法,使用「tf.function」修飾的python函數,TensorFlow可以將其作為單個圖來運行。
1.3 運算操作和運算核
計算圖中的每一個節點就是一個運算操作(operation,通常簡稱op),每一個運算操作都有名稱,並且代表了一種類型的抽象運算,例如「MatMul」代表矩陣的乘法。每個運算操作都可以有自己的屬性,但是所有的屬性都必須被預先設置,或者能夠在創建計算圖時根據上下文推斷出來。 通過設置運算操作的屬性可以讓運算操作支持不同的張量(tensor)元素類型,例如讓向量加法操作運算只接受浮點類型的張量。運算核(kernel)是一個運算操作在某個具體的硬體(比如CPU或GPU)上的實現,在TensorFlow中可以通過註冊機制加入新的運算操作或者為已有的運算操作添加新的運算核。
TensorFlow的部分運算操作
1.4 張量
張量(tensor)可以看作是一個多維的數組或列表,它是對矢量和矩陣的更高維度的泛化,張量由「tf.Tensor」類定義。計算圖中的一個運算操作可以獲得零個或多個張量作為輸入,運算後會產生零個或多個張量輸出。這些張量在計算圖的邊中流動(flow),從一個節點(運算操作)到另一個節點,TensorFlow也因此而得名。
張量具有以下兩個屬性:
- 數據類型(同一個張量中的每個元素都具有相同的數據類型,例如float32、int32以及string)
- 形狀(即張量的維數以及每個維度的大小)
TensorFlow中張量的形狀示例
TensorFlow中有一些特殊的張量,以下是一些主要的特殊張量:
- tf.Variable(變量,TensorFlow中的張量一般都不會被持久化保存,參與一次運算操作後就會被丟棄了。變量(variable)是一種特殊的運算操作,它可以將一些需要持久化保存的張量存儲在內存或顯存中,並會返回一個可以對該變量所引用的張量進行一系列特定操作的句柄,例如Assign和AssignAdd(等同於「+=」)等。模型的參數是保存在變量中的,在模型的訓練過程中,參數在不斷地更新。變量的值可以修改,但是維度不可以變。)
- tf.constant(常量,常量定義時必須初始化值,且定義後其值和維度不可再改變。)
- tf.placeholder(占位符,在執行「session.run()」方法時傳入具體的值,TensorFlow2.0中不再使用,但依然可以在「tensorflow.compat.v1」模塊中找到。)
- tf.SparseTensor(稀疏張量)
2. 從1.x到2.0的變化
TensorFlow 2.0在1.x的基礎上做了重新設計,重點放在了提升開發人員的工作效率上,確保2.0版本更加的簡單易用。TensorFlow 2.0為了提升易用性做了很多改進,例如對API做了精簡,刪除了冗餘的API,使得API更加一致(例如統一了TensorFlow和tf.keras的循環神經網絡和優化器等),以及由靜態計算圖轉變為了動態計算圖等(這使得代碼的編寫和調試變得更加容易)。接下來我們看看TensorFlow 2.0的一些主要變化。
2.1. API精簡
很多TensorFlow 1.x的API在2.0中被去掉或者改變了位置,還有一些則被新的API給替換掉了。官方提供了一個轉換工具,可以用來將1.x版本的代碼升級到2.0,其主要的工作其實就是修改這些有變更的API。不過使用該工具不一定能夠轉換成功,轉換成功後的代碼也並不一定能夠正常運行,很多時候還是需要人工修改。
2.2. Eager execution
Eager execution(動態圖機制)是TensorFlow 從1.8版本開始正式加入的,但只是作為一種可選操作,在TensorFlow 2.0之前,TensorFlow默認的模式都是Graph execution(靜態圖機制),TensorFlow 2.0將Eager execution做為了默認模式。在該模式下用戶能夠更輕鬆的編寫和調試代碼,可以使用原生的Python控制語句,大大降低了學習和使用TensorFlow的門檻。在TensorFlow 2.0中,圖(graph)和會話(session)都變成了底層實現,而不需要用戶關心了。
2.3. 取消全局變量
TensorFlow 1.x非常依賴隱式全局命名空間。當我們調用「tf.Variable」創建變量時,該變量就會被放進默認的圖中,即使我們忘記了指向它的python變量,它也會留在那裡。當我們想恢復這些變量時,我們必須知道該變量的名稱,如果我們沒法控制這些變量的創建,也就無法做到這點。TensorFlow 1.x中有各種機制旨在幫助用戶再次找到他們所創建的變量,而在2.0中則取消了所有這些機制,支持默認的機制:跟蹤變量。當我們不再用到創建的某個變量時,該變量就會被自動回收。
2.4. 使用函數而不是會話
在TensorFlow 1.x中,我們使用「session.run()」方法執行計算圖,「session.run()」方法的調用類似於函數調用:指定輸入數據和調用的方法,最後返回輸出結果。為了保留靜態圖的一些優勢,例如性能優化以及重用模塊化的TensorFlow函數等,在TensorFlow2.0中,我們可以使用「tf.function()」來修飾python函數以將其標記為即時(Just-In-Time)編譯,從而TensorFlow可以將其作為單個圖來執行。
3. TensorFlow2.0的架構
Tensorflow作為全球最受歡迎、使用最為廣泛的機器學習平台之一,在其發展的三年時間裡,也是機器學習和人工智慧發展最為迅猛的三年。TensorFlow2.0是一個重要的里程碑,其重心放在了簡單性和易用性上,儘量降低用戶使用的門檻。在TensorFlow成長的這幾年裡,TensorFlow團隊為其添加了許多的組件,在TensorFlow2.0里,這些組件被打包成了一個全面的平台,它支持從訓練到部署的標準化的機器學習流程。如圖2-1所示是TensorFlow2.0架構的簡化概念圖。
ensorFlow2.0架構的簡化概念圖
接下來我們結合上圖介紹一下TensorFlow2.0的基本工作流程以及對應可以使用的API,在2.3節里我們會根據TensorFlow的官方文檔重點介紹一下「tf.data」和「tf.keras」這兩個API,讓讀者快速入門TensorFlow2.0的使用。其它的API,讀者可以結合官方的文檔在本書後續的項目實戰中慢慢熟悉和掌握。
3.1. 使用tf.data加載數據
我們使用tf.data創建的輸入管道來讀取訓練數據,並可以通過tf.feature_column來指定特徵列或者交叉特徵。
3.2. 使用tf.keras或Premade Estimators構建、訓練和驗證模型
tf.keras作為TensorFlow的核心高級API,其已經和TensorFlow的其餘部分緊密集成,使用tf.keras可以簡單、快捷的構建我們的模型。另外tf.estimator中打包了一些標準的模型供我們直接使用,例如邏輯回歸、提升樹以及隨機森林等。當我們不想從頭開始訓練一個模型時(例如這個模型的訓練可能非常耗時),我們可以使用TensorFlow Hub模塊來進行遷移學習。
3.3. 使用eager execution運行和調試模型,以及使用tf.function充分利用計算圖的優勢
前面已經介紹過,在eager execution模式下,我們可以更加方便的編寫和調試代碼,在TensorFlow2.0中該模式是默認開啟的。我們可以使用tf.function來將python程序轉換為TensorFlow的靜態計算圖,這樣就可以保留TensorFlow1.x版本中的靜態計算圖的一些優勢。
3.4. 使用Distribution Strategies進行分布式訓練
對於大規模的機器學習訓練任務,tf.distribute.Strategy API旨在讓用戶只需要對現有的模型和代碼做最少的更改,就可以實現分布式的訓練。TensorFlow支持CPU、GPU以及TPU等硬體加速器,我們可以將訓練任務分配到單節點/多加速器以及多節點/多加速器。
3.5. 使用SavedModel存儲模型
在TensorFlow中有兩種模型存儲的格式,一個是檢查點(checkpoints),另一個是SavedModel,前者依賴於創建模型的原始碼,而後者則與創建模型的原始碼無關,因此標準化後的SavedModel可以作為TensorFlow Serving、TensorFlow Lite、TensorFlow.js或者其它程式語言的交換格式。