- TensorFlow從零開始學
- 侯倫青等
- 3674字
- 2020-05-22 17:14:35
2.3 TensorFlow2.0的使用
2.3.1 “tf.data”API
除GPU和TPU等硬件加速設備外,高效的數據輸入管道也可以很大程度地提升模型性能,減少模型訓練所需要的時間。數據輸入管道本質是一個ELT(Extract、Transform和Load)過程:
●Extract:從硬盤中讀取數據(可以是本地的,也可以是云端的)。
●Transform:數據的預處理(如數據清洗、格式轉換等)。
●Load:將處理好的數據加載到計算設備(例如CPU、GPU及TPU等)。
數據輸入管道一般使用CPU來執行ELT過程,GPU等其他硬件加速設備則負責模型的訓練,ELT過程和模型的訓練并行執行,從而提高模型訓練的效率。另外ELT過程的各個步驟也都可以進行相應的優化,例如并行地讀取和處理數據等。在TensorFlow中可以使用“tf.data”API來構建這樣的數據輸入管道。
這里使用的是一個花朵圖片的數據集,如圖2-13所示,除一個License文件外,主要是五個分別存放著對應類別花朵圖片的文件夾,其中“daisy(雛菊)”文件夾中有633張圖片,“dandelion(蒲公英)”文件夾中有898張圖片,“roses(玫瑰)”文件夾中有641張圖片,“sunflowers(向日葵)”文件夾中有699張圖片,“tulips(郁金香)”文件夾中有799張圖片。

圖2-13 解壓后的數據集
接下來開始實現代碼,導入需要使用的包:

pathlib提供了一組用于處理文件系統路徑的類。導入需要的包后,可以先檢查一下TensorFlow的版本:

獲取所有圖片樣本文件的路徑:

輸出結果如圖2-14所示。

圖2-14 文件路徑輸出結果
接下來統計圖片的類別,并給每一個類別分配一個類標:

輸出結果如圖2-15所示,daisy(雛菊)、dandelion(蒲公英)、roses(玫瑰)、sunflowers(向日葵)和tulips(郁金香)的類標分別為0、1、2、3和5。

圖2-15 圖片類標的輸出結果
處理完類標之后,接下來需要對圖片本身做一些處理,這里定義一個函數,用來加載和預處理圖片數據。

完成對類標和圖片數據的預處理之后,使用“tf.data.Dataset”來構建和管理數據集:

輸出結果如圖2-16所示。

圖2-16 構建的數據集
在第35行和第41行代碼中,“from_tensor_slices”方法使用張量的切片元素構建數據集,“tf.data.Dataset”類還提供了“from_tensor”,直接使用單個張量來構建數據集,以及“from_generator”方法使用生成器生成的元素來構建數據集。
在第39行代碼中,我們使用了“tf.data.Dataset”的“map”方法,該方法允許自定義一個函數,該函數會將原數據集中的元素依次進行處理,并將處理后的數據作為新的數據集,處理前和處理后的數據順序不變。例如這里我們自己定義了一個“load_and_preprocess_image”函數,將“path_ds”中的圖片路徑轉換成了經過預處理的圖像數據,并保存在了“image_ds”中。
最后使用“tf.data.Dataset”的“zip”方法將圖片數據和類標數據壓縮成“(圖片,類標)”對。數據集中的部分數據可視化結果如圖2-17所示。

圖2-17 數據集中部分數據的可視化

接下來用創建的數據集訓練一個分類模型,這個例子的目的是讓讀者了解如何使用我們創建的數據集,簡單起見,直接使用“tf.keras.applications”包中訓練好的模型,并將其遷移到我們的花朵分類任務上來。這里使用的是“MobileNetV2”模型。

當我們執行第59行代碼后,訓練好的“MobileNetV2”模型會被下載到本地,該模型是在ImageNet數據集上訓練的。因為我們想把該訓練好的模型遷移到花朵分類問題中來,所以第61行代碼將該模型的參數設置為不可訓練和更新。
接下來打亂一下數據集,以及定義好訓練過程中每個批次(Batch)數據的大小。

在第64行代碼中,我們使用“tf.data.Dataset”類的“shuffle”方法將數據集進行打亂。第66行代碼使用“repeat”方法讓數據集可以重復獲取,通常情況下,若一個訓練回合(Epoch)只對完整的數據集訓練一遍,則可以不需要設置“repeat”。“repeat”方法可以設置參數,例如“ds.repeat(2)”是讓數據集可以重復獲取兩遍,即在一個訓練回合中,可以使用兩遍數據集。若不加參數的話,則默認可以無限次重復獲取數據集。
第68、69行代碼設置了訓練過程中一個批次數據的大小。在第71行代碼中,我們使用“tf.data.Dataset.prefetch”方法讓ELT過程中的“數據準備和預處理(EL)”和“數據消耗(T)”過程并行。
由于“MobileNetV2”模型接收的輸入數據是歸一化在[-1,1]之間的數據,而在第31行代碼中對數據進行了一次歸一化處理后,其范圍是[0,1],所以需要將數據映射到[-1,1]。

接下來定義模型,由于預訓練好的“MobileNetV2”返回的數據維度為“(32,6,6,1280)”,其中“32”是一個批次(Batch)數據的大小,“6,6”代表輸出的特征圖的大小為6×6,“1280”代表該層使用了1280個卷積核。為了適應花朵分類任務,需要在“MobileNetV2”返回數據的基礎上再增加兩層網絡層。

全局平均池化(Global Average Pooling,GAP)是對每一個特征圖求平均值,將該平均值作為該特征圖池化后的結果,因此經過該操作后數據的維度變為(32,1280)。由于花朵分類任務是一個5分類的任務,因此需要再使用一個全連接(Dense),將維度變為(32,5)。
接著我們編譯一下模型,同時指定使用的優化器和損失函數:

“model.summary()”可以輸出模型各層的參數概況,如圖2-18所示。

圖2-18 模型各層的參數概況
最后使用“model.fit”訓練模型:

這里參數“epochs”指定需要訓練的回合數,“steps_per_epoch”代表每個回合要取多少個批次數據,通常“steps_per_epoch”的大小等于我們數據集的大小除以批次的大小后上取整。關于模型的訓練部分,我們在2.3.2節中會詳細介紹。
在本節中我們簡單了解了“tf.data”API的使用,在后面章節的項目實戰部分還會用到該API來構建數據輸入管道,包括圖片數據和文本數據等。
2.3.2 “tf.keras”API
Keras是一個基于Python編寫的高層神經網絡API,強調用戶友好性、模塊化及易擴展等,其后端可以采用TensorFlow、Theano及CNTK,目前大多是以TensorFlow作為后端引擎的。考慮到Keras優秀的特性及它的受歡迎程度,TensorFlow將Keras的代碼吸收進來,并將其作為高級API提供給用戶使用。“tf.keras”不強調原來Keras的后端可互換性,而是在符合Keras標準的基礎上讓其與TensorFlow結合得更緊密(例如支持TensorFlow的Eager Execution模式,支持“tf.data”,以及支持TPU訓練等)。“tf.keras”提高了TensorFlow的易用性,同時也保持了TensorFlow的靈活性和性能。
1.基本模型的搭建和訓練
可以使用“tf.keras.Sequential”來創建基本的網絡模型。通過這種方式創建的模型又稱為順序模型,因為這種模型是由多個網絡層線性堆疊而成的。
首先,導入需要的包:

然后,創建一個順序模型:

上面的代碼中,在定義這個順序模型的同時添加了相應的網絡層,除此之外也可以使用“add”方法逐層添加:

“tf.keras.layers”用于生成網絡層,包括全連接層(tf.keras.layers.Dense())、Dropout層(tf.keras.layers.Dropout),以及卷積網絡層(如二維卷積:tf.keras.layers.Conv2D)等。創建好網絡結構后,要對網絡進行編譯:

在編譯模型的時候需要設置一些必需參數,例如“optimizers”用來指定我們想使用的優化器及設定優化器的學習率,如Adam優化器“tf.keras.optimizer.Adam”、SGD優化器“tf.keras.optimizer.SGD”等,在第15行代碼中使用的是Adam優化器,并設置學習率為“0.001”。
“loss”參數用來設置模型的損失函數(又稱目標函數),例如均方誤差損失函數(mean_squared_error)、對數損失函數(binary_ crossentropy),以及多分類的對數損失函數(categorical_crossentropy),等等。
“metrics”用來設定模型的評價函數,模型的評價函數與損失函數相似,不過評價函數只用來顯示給用戶查看,并不用于模型的訓練。除了自帶的一些評價函數外,這里還可以使用自定義評價函數。
編譯好模型之后就可以開始訓練了,這里使用NumPy生成一組隨機數作為訓練數據:

第20行和第21行代碼隨機生成樣本數據和類標。第25行代碼使用“model.fit”來執行模型的訓練,其中參數“data”和“labels”分別為訓練數據和類標,“epochs”為訓練的回合數(一個回合即在全量數據集上訓練一次),“batch_size”為訓練過程中每一個批次數據的大小。輸出結果如圖2-19所示。

圖2-19 輸出結果
在訓練模型的工程中,為了更好地調節參數,方便模型的選擇和優化,通常會準備一個驗證集。這里隨機生成一個驗證集:

輸出結果如圖2-20所示。

圖2-20 增加驗證集后的輸出結果
和圖2-19相比,這里多了“val_loss”和“val_accuracy”,分別為驗證集上的損失和準確率。
在上面的例子中,我們直接在NumPy數據上訓練模型,也可以使用“tf.data”將其轉為數據集后再傳遞給模型去訓練:

模型訓練好之后,我們希望用驗證集去對模型進行評估,這里可以使用“model.evaluate”對模型進行評估:

結果如圖2-21所示。

圖2-21 模型評估結果
最后,使用“model.predict”對新的數據進行預測:

結果如圖2-22所示。

圖2-22 使用訓練好的模型預測新的數據
2.搭建高級模型
(1)函數式API
可以使用“tf.keras.Sequential”來搭建基本的網絡結構,但更多的時候我們面臨的是比較復雜的網絡結構,例如,模型可能有多輸入或多輸出、模型中的某些網絡層需要共享等,此時就需要用到函數式API。
實現一個簡單的例子:

接下來使用上面定義的網絡層來創建模型:

(2)實現自定義的模型類和網絡層
通過繼承“tf.keras.Model”和“tf.keras.layers.Layer”可以實現自定義的模型類和網絡層為我們構建自己的網絡結構提供了非常好的靈活性。例如定義一個簡單的前饋神經網絡模型:,

我們需要在“__init__”方法中定義好模型中所有的網絡層,并作為模型類的屬性。在“call”方法中可以定義模型的正向傳遞過程。之后就可以調用這個模型。

以上是我們自定義一個簡單的網絡模型的例子,通過繼承“tf.keras.layers.Layer”類還可以實現自定義的網絡層。
3.回調函數
回調函數會在模型的訓練階段被執行,可以用來自定義模型訓練期間的一些行為,例如輸出模型內部的狀態等。我們可以自己編寫回調函數,也可以使用內置的一些函數,例如:
●tf.keras.callbacks.ModelCheckpoint:定期保存模型。
●tf.keras.callbacks.LearningRateScheduler:動態地改變學習率。
●tf.keras.callbacks.EarlyStopping:當模型在驗證集上的性能不再提升時終止訓練。
●tf.keras.callbacks.TensorBoard:使用TensorBoard來監測模型。
回調函數的使用方式如下:

4.模型的保存和恢復
使用“model.save()”和“tf.keras.models.load_model()”來保存和加載由“tf.keras”訓練的模型:

通過“model.save()”保存的是一個完整的模型信息,包括模型的權重和結構等。除保存完整的模型外,還可以單獨保存模型的權重參數或者模型的結構。

- 后稀缺:自動化與未來工作
- 一本書玩轉數據分析(雙色圖解版)
- 自動檢測與傳感技術
- C語言寶典
- 走近大數據
- 精通LabVIEW程序設計
- Linux系統管理員工具集
- Linux Shell Scripting Cookbook(Third Edition)
- MongoDB 4 Quick Start Guide
- Learning Cassandra for Administrators
- 網管員世界2009超值精華本
- MySQL Management and Administration with Navicat
- 工業機器人技術
- Mastering Machine Learning with R
- Architectural Patterns