原作者:Kirill Panarin
譯者:胡雯思
來源:medium.com
<https://towardsdatascience.com/dog-breed-classification-hands-on-approach-b5e4f88c333e>
幾天前,我發現了由Kaggle主辦的一個「狗狗品種識別」挑戰賽。 這個比賽的目標是建立一個模型,使能夠通過「觀察」狗狗的圖像來對狗進行品種分類。 我開始思考一些可行的建模方法以及這些模型可能實現的準確度。 據我所知,利用像TensorFlow這樣的流行機器學習框架、開源數據集以及用於圖像識別的預訓練模型,可以很好地完成這個任務,而不需要花費太多的時間和資源。 我將再次分享我使用TensorFlow構建狗狗品種分類器的端到端流程。
小編建議:
以下內容請配合作者在GitHub的repo觀看<https://github.com/stormy-ua/dog-breeds-classification>
一個好的訓練數據集能幫助我們向建立穩健模型邁出重要的一步。 我們手頭擁有的數據是史丹福大學的狗狗數據集,包含120個品種的狗的共20K張圖像。 數據集中的每個圖像都被標註了一種狗的品種。 但是正如我們注意到,僅僅120個不同品種共20K個圖像(相當於每個品種約200個圖像)是不足以用來訓練深度神經網絡的。 儘管卷積神經網絡(CNN)是目前用於圖像分類的最好的機器學習模型,在這種情況下,沒有足夠的訓練樣例來訓練它,我們是無法從這個數據集中通過機器學習得到足夠的通用模型來識別不同的犬種。這很有可能導致模型對少量訓練樣例的過度擬合,因此測試集的準確性會很低。 針對這種情況,我們有兩種可行的方法來減輕訓練樣例過少帶來的不足:
將狗狗數據集與另一個更大的圖像數據集(比如ImageNet),並用這些合併後的樣例來訓練一個CNN。
取一個已經預先用更大數據集訓練好的深度神經網絡模型,在其中附加一個額外的「分類標頭」,即額外的幾個帶有Softmax層的完全連接層 。
第一種方法有兩大缺點:需要我們進行分析的數據量比原始數據集要大得多,對這個新的大數據集的訓練需要佔用更多的時間和資源。
第二種方法似乎更有可能實現,模型的訓練需要用原始數據集進行,並且由於只有幾個完全連接層的「分類標頭」,模型的訓練將不需要佔用大量時間和資源。
以上這種將有帶「分類標頭」的預訓練模型附加到較小的數據集上的方法,我們稱為轉移學習。
簡而言之,利用大數據集訓練的深層神經網絡的底層層級可以捕獲一個圖像的低級圖元(例如輪廓和簡單形狀),它學到的這些知識對於所有圖像是通用的並且可以被「轉移」到任何圖像識別問題中。
假設一個圖像被輸入到Inception模型中。 Inception模型的輸出經過幾個完全連接(FC)層,最後經由softmax輸出該圖像屬於每一個類別的概率。 只有FC層代表「分類標頭」必須接受訓練。 而初始模型在已經預定義的模型參數下保持凍結。
下一步是下載狗狗數據集,並通過Google Inception模型進行預訓練。 從repo的根目錄處執行setup/setup.sh腳本命令將幫助我們下載所有內容,提取並放入適當的目錄。 一旦下載並提取狗狗數據集,我們將會得到一組包含圖像和注釋的文件夾。 TensorFlow有一個漂亮的數據集API,可以更好地幫助我們處理TF記錄數據格式問題。 這個想法是把所有的訓練樣例和他們的注釋一起保存在一個文件中,所有的例子都以protobuf序列化的形式存儲。 TensorFlow數據集API可以高效地處理這種數據格式,並在訓練過程中儘可能多地加載所需的示例,同時使用最少的磁碟I / O操作和內存要求。 有一個python腳本,可以將原始的狗狗數據集轉換為TF記錄文件,準備用於訓練:
這個命令必須從repo的根目錄執行。數據集轉換可能需要約1小時。每個圖像都被輸入到Inception模型中,並且輸出的圖像將與其他圖像和其他注釋一起存儲。 這簡化了訓練,因為我們不需要在訓練期間為每個例子計算初始輸出,而是已經預先計算好以便使用。 TF記錄文件的結果將在data/stanford.tfrecords中。 setup.sh腳本還會下載並提取TensorFlow圖形的Google Inception模型並將其凍結。 凍結意味著模型中所有的變量都被替換為常量並嵌入到圖形本身中,因此不需要將檢查點文件與圖形一起攜帶,就可以將模型加載到TensorFlow會話中並開始使用它。 Inception模型可用於frozen/inception/classify_image_graph_def.pb.
下一步是實際執行培訓。 首給模型起一個獨一無二的名字。 其次應該配置這些層級中完整連接的層數和單元數量。 這些都可以在src/common/consts.py模塊中配置。
默認情況下一般有2個完全連接的層級分別為1024單元和120單元。輸入層有2048個單位,與Inception模型最後一層的單位數相等。
我們可以實用src/training/train.py中的代碼進行培訓。 學習速度,時代數量和每批量大小可以在腳本中配置:
此外,我們可以啟動TensorBoard對訓練進行監控:
這裡有三個可用的度量標準:
成本,測試集上的錯誤以及訓練集上的錯誤。
默認情況下,錯誤率是按照訓練集中有3000個例子來計算的。我用了以下的超參數訓練模型:
小批量大小= 64
學習率= 0.0001
時代數= 5000
以下是我在TensorBoard獲得的這三個指標的數字:
執行5K個時期需要約1小時。 訓練結束後,指標具有以下值:
成本= 0.1
測試錯誤= 2.7%
訓練錯誤= 2.5%
在測試和訓練集中,這兩個錯誤都相當低。 由於訓練集上的誤差與測試集上的誤差大致相同,因此訓練集沒有明顯的過度訓練現象。
一旦模型被訓練好,其優化參數就存儲在./checkpoints目錄中的檢查點文件中。 為了有效地重新使用該模型進行推斷分析,將其作為一個凍結的TensorFlow圖,再將參數嵌入到圖本身中是非常好的。 這可以使用src/freeze/freezy.py來完成:
將Inception模型和「分類標頭」模型加載到同一個TensorFlow會話中,並將它們組合到一個單一的計算圖中,以便將來自Inception模型的輸出直接輸入到「分類標頭」模型的輸入中。 綁定完成後,腳本會將文件系統中圖形中的複合模型序列化。 此時,由於在訓練期間計算的模型參數仍然位於檢查點文件中,所以圖表還沒有被凍結。
使用TensorFlow freeze_graph函數凍結上一步生成的圖形。 它實際上從檢查點文件中取出模型參數並將它們注入到圖形變量中。 圖形變量輪流轉換為常量。 生成的文件將轉到帶有模型名稱的./frozen目錄。
一旦凍結的模型準備好,我們就可以對任意圖像進行分類了。 src/inference/classify.py腳本能夠對存儲在文件系統上的狗圖像進行分類,或者可以將其用作HTTP資源。 在幕後,它加載凍結圖並將圖像輸入到該圖中。 這裡有兩個例子說明如何推理「Airedale Terrier」(萬能㹴)和「Shih-Tzu」(西施犬、獅子狗):
如果你只是想了解推理分析是如何進行的,有一個docker container <https://hub.docker.com/r/kirillpanarin/dog_breed_classification/> 包含了所有的代碼和冷凍模型包裝。 它使用Python筆記本做推斷。 它實際上擁有所有的設置,甚至在docker container本身進行培訓。 可以使用以下命令啟動:
一旦container開始導航到瀏覽器<http://localhost:8888/notebooks/Inference.ipynb>,你將能夠進行你自己的圖像分類。
我提議我們應該仔細研究機器學習模型未能正確進行分類的例子。
腳本src/analysis/training_perf_analysis.py能夠為所有訓練實例生成具有預測和實際品種的CSV文件
通過從training_confusion.csv加載數據,可以繪製混淆矩陣:
在這裡對如此多品種進行詳細的分析是困難的。 讓我們試著找出30個錯誤分類的品種(Confusion.ipynb提供了一個如何做到這一點的例子):
可以看出,這對「Silky Terrier / Yorkshire Terrier」(絲毛梗/約克夏梗)在錯誤分類數量方面領先。如果我們看看這兩種狗的樣子,就能夠理解這是為什麼了:
如果你認為自己是一個愛狗人士,你可以問問你的模型你是什麼品種的狗 : )
在我的情況下,我得到了以下答案:
正如我們所看到的,即使你沒有足夠的訓練圖像和/或計算資源,如果你有預訓練好的深度神經網絡和像TensorFlow一樣的現代機器學習庫,你也可以訓練出穩健的圖像分類器。
往期精彩回顧
點擊「閱讀原文」查看數據應用學院核心課程