一文看懂如何搭建AI应用:10周学会深度学习,还赢下5千美元
春節后第一個休息日,量子位給大家準備了一個不一樣的故事。
在這個故事里,主人公David Brailovsky(就叫阿D吧)參加了一場計算機視覺比賽。這個挑戰賽要求基于卷積神經網絡(CNN),做出一個識別紅綠燈的人工智能應用模型。
于是阿D花了10周的時間,從0開始,一點一滴摸索著,搭建、調試、訓練和一個深度學習系統。而且還在最后的比賽中一舉奪魁,贏了5000美元。
主人公把這個有點逆襲的過程,原原本本的寫了下來。量子位也希望對人工智能感興趣的朋友仔細看一看。不用擔心,并不是AI專家才能理解這篇文章。因為全文重點在與搭建一個人工智能應用模型的思路和方法,而不是拘泥于技術實現。
從實踐應用的角度出發,搭建一個AI模型,并不是從0開始寫代碼的過程。
最初,是選擇一些功能近似的既有模型,然后進行微調,從而把既有模型的能力,從原來的任務“遷移”到新任務上。然后使用數據進行訓練,訓練過程中嘗試不同的調整,以觀察哪些調整可以起效,哪些調整沒有效果。
這個過程中重要的一步,是把幾個較低精度的模型組合在一起,反而得到了較高精度的輸出結果。隨后,測試并且獲得較好的效果。
如前所述,下文沒有過于晦澀的技術內容,量子位選擇推薦這篇,是因為有助于理解如何在實踐中利用人工智能解決問題。
那么,我們就跟著阿D的講述就開始吧。
正文分割線
△?一個基于深度學習的交通燈識別分類器Demo
左上角是根據圖片給出的判斷
挑戰
我最近在一個交通燈識別挑戰賽中贏得了第一名,這是由一家公司組織的計算機視覺競賽。挑戰的目標是識別行車載攝像頭拍下的圖像中,交通燈的狀態。
在任何給定的圖像中,要做出這樣一個人工智能應用模型(分類器):可以輸出場景中是否有交通燈,以及它是紅色還是綠色。 且應該僅識別行駛方向上的交通燈。
上面的三張圖像,就是需要預測的三類可能的情況:沒有交通燈,紅色或綠色交通燈。
挑戰要求解決方案基于卷積神經網絡,這是一種在使用深度神經網絡進行圖像識別領域非常流行的方法。 參賽的算法模型,會被依照準確性以及模型的大小兩個維度進行評分。 較小的模型得分更高。 此外,獲勝所需的最低準確度為95%。
主辦方提供了18659個經過標記的圖像作為訓練數據。每個圖像都標記為上面提到的三個類別之一。
軟件和硬件
我用Caffe深度學習框架(可以理解為一組工具包)來訓練模型。主要原因是Caffe里有各種各樣的預訓練模型。
在分析結果、數據探索和特殊腳本的工作中,我使用了Python,NumPy以及Jupyter Notebook。
我還用了亞馬遜的GPU實例(g2.2xlarge)用于訓練模型。最后的費用是263美元之巨。用來訓練和運行模型的代碼和文件在GitHub上。
最終分類器
最終的分類器在主辦方的測試集上,實現了94.955%的精度,模型大小為7.84 MB。作為比較,GoogLeNet的模型大小為41MB,VGG-16的模型大小528MB。
主辦方大發慈悲同意把94.955%當作95%看待,讓我通過最低要求。
追求更高精度的過程中,伴隨大量的試驗和錯誤。 其中一些我知道背后的邏輯,有些只是“碰碰運氣”。我將講述一些在模型中試圖改進的事情,有的搞定了有的沒搞定。
搞定的部分
遷移學習
我從嘗試微調一個模型起步,這是一個在ImageNet圖像數據庫上用GoogLeNet架構預訓練的模型。很快,這就讓我得到> 90%的準確性!
不過,主辦方在挑戰的官方頁面中提到,通過微調GoogLeNet模型應該可以達到93%的精度。我也不知道我哪里出了問題。
SqueezeNet
SqueezeNet:具有AlexNet(圖像分類模型)級精度,但參數少50倍,模型尺寸小于0.5MB。
由于競爭獎勵使用小模型的解決方案,早期我決定尋找一個緊湊的網絡模型,盡可能少的參數,仍然可以產生良好的效果。 但大多數最近發布的網絡非常深,有很多參數。
SqueezeNet似乎是一個非常好的選擇,它也有一個在ImageNet上訓練好的預訓練模型,可用在Caffe的Model Zoo(類似手機上的應用商店)中方便取用。
△?SqueezeNet網絡架構
網絡通過以下方式保持緊湊:
-
主要使用1x1卷積過濾,輔助一些3x3
-
減少3x3過濾的輸入通道數
有關更多詳細信息,我建議閱讀Lab41的博客。
在一些來回調整學習率后,我能夠微調預訓練模型以及從零開始訓練,并且準確度能夠達到很好的92%!很酷!
旋轉圖像
大多數圖像是水平橫置的,如上所示,但約2.4%是垂直的,另外還有好多種不同的方向。如下所示。
雖然這些在數據集中占比不大,但我們仍希望自己的模型也能對他們進行正確分類。
不幸的是,在jpeg圖像中沒有指定方向的EXIF數據。起初,我考慮做一些啟發式算法來識別天空和相應地翻轉圖像,但這似乎沒那么簡單。
然后我改讓圖像按照固定角度旋轉。最開始我嘗試訓練網絡隨機以0°,90°,180°,270°進行旋轉。這沒什么改善。但是,當我對每個圖像進行四次旋轉而得的預測取平均值時,改善出現了!
92% → 92.6%。
澄清一下:上面提到的“預測取平均值”,我的意思是平均了每個類在4個圖像變化中產生的模型的概率。
過采樣修剪
在訓練期間,SqueezeNet網絡默認首先在輸入圖像上執行隨機修剪,我沒有對這個進行改動。 這種類型的數據增加使網絡更好地泛化。
類似地,當生成預測時,我對輸入圖像進行了一些修剪以及平均結果。 我使用5個修剪:4個角和一個中心。 有現成的免費Caffe代碼來完成這個任務。
92% → 92.46%
旋轉圖像與過采樣修剪帶來了非常輕微的改進。
以較低的學習率進行附加訓練
所有模型在一定點后開始過擬合。我注意到這點,是看到驗證集損失開始在某一點上升。
40000迭代之后驗證集損失開始上升
我在那個點停止了訓練,因為模型可能不再泛化了。這意味著學習率沒有時間衰減到零。 我試圖恢復訓練過程,在模型開始過擬合時,把學習率調低10倍。 這大概提高了0-0.5%的精度。
更多的訓練數據
起初,我將數據分成3組:訓練集(64%),驗證集(16%)和測試集(20%)。幾天后,我認為放棄36%的數據可能太多了。我合并了訓練和驗證集,并使用測試集來檢查我的結果。
我重新訓練了一個模型,加入“圖像旋轉”和“低速率附加訓練”,并得到了如下提升:
92.6% → 93.5%
在訓練數據中重新標簽錯誤
當分析分類器對驗證集的錯誤時,我注意到一些錯誤的置信度非常高。 換句話說,模型確定它是一件事(例如綠燈),而訓練數據說明是相反的情況(例如紅燈)。
注意,在上面的圖中,最右邊的欄是相當高的。 這意味著有大量的錯誤有著> 95%的置信度。 當仔細檢查這些情況時,我發現這些通常錯誤是源自訓練集的地面實況(ground-truth),而不是訓練好的模型。
我決定在訓練集中修復這些錯誤。 應該是這些錯誤混淆了模型,使其更難以進行歸納。 即使最終測試集在地面實況中有錯誤,一個更泛化的模型在所有圖像中,更有可能達到更高的精度。
我手動標記了709張圖像,當時我的一個模型產生了錯誤。 這改變了709張圖像中337張的地面實況。 這個手工活耗時一小時,我還用了python腳本來提升效率。
以上是重新標記和重新訓練模型后的結果。看起來好多了!
這對模型的提升度為:
93.5% → 94.1%
組合模型
使用幾個模型在一起并平均其結果也提高了精度。 我在訓練過程中對參與整體的模型進行了不同類型的修改。 使用從頭開始訓練的模型(即使自身準確度較低),結合精細調教過的預處理模型,我們獲得了顯著改進的結果。可能這種方式學習到了更多的特征。
最后我們組合了3個模型,精度為94.1%,94.2%和92.9%,合在一起精度為94.8%。
沒搞定的部分
沒搞定的太多了!希望其中的一些想法在別處有用。
與過擬合戰斗
當試圖處理過度擬合時,我嘗試了幾個事情,沒有一個產生顯著的改進:
-
增加網絡中的丟失率
-
更多數據增強(隨機移位,縮放,傾斜)
-
分配更多的訓練數據:使用90/10分隔而不是80/20
平衡數據集
數據集不是非常平衡:
-
19%的圖像標有沒有交通燈
-
53%的是紅燈
-
28%的是綠燈
我試圖使用過采樣較不常見的類來平衡數據集,但沒有發現任何改進。
區分晝夜
我的直覺是,識別交通燈在白天和夜間是非常不同的。我想也許我可以幫助這個模型,把它分成兩個更簡單的問題。
通過觀察它們的平均像素強度,將圖像分為白天和黑夜是相當容易的:
你可以看到一個非常自然的圖像分離,低平均值即暗圖像,在夜間拍攝,明亮的圖像,在白天拍攝。
我試過兩種方法,都沒有改善結果:
-
為白天圖像和夜間圖像訓練兩個單獨的模型
-
訓練網絡預測6種分類而不是3種,方法也是預測是白天還是晚上
使用SqueezeNet的更好的變體
我用兩個改進的SqueezeNet變體進行了一點嘗試。第一次使用殘留連接和第二次訓練與密集→稀疏→密集訓練。沒什么用。
交通燈定位
在閱讀deepsense.io的一篇關于他們如何贏得鯨魚識別挑戰的文章后,我試圖訓練一個定位器,即首先識別交通燈在圖像中的位置,然后在一個小區域識別交通燈狀態。
我花費數小時用sloth來注釋約2000張圖片。當試圖訓練一個模型,它過擬合得非常快,可能是因為沒有足夠的標簽數據。 也許這個方法可行,如果我能標注更多的圖像。
在困難案例上訓練分類器
通過挑選分類器置信度小于97%的數據,我跳出30%“難度更高”的圖片。然后我試圖只用這些圖片訓練分類器。沒什么改善。
不同的優化算法
我短暫的使用Caffe的Adam結算期,取代線性降低學習率的SGD,但是沒有看到任何改進。
向組合中添加更多模型
由于組合的方法證明有效,我曾嘗試把規模擴大一倍。我試著改變不同的參數來產生不同的模型,并將它們添加到組合中:初始種子,dropout rate,不同的訓練數據(分組方法不同),訓練中不同的檢查點。這些都沒有帶來顯著的改善。
最終分類器細節
我的分類器,最后由三個單獨訓練的網絡組合而成。它們給每個類的概率,進行加權后的平均值作為輸出。所有這三個網絡都基于SqueezeNet,但各自經過了不同的訓練。
一號模型 - 以過采樣進行預訓練的網絡
訓練基于重新打標簽的訓練集(修復地面實況錯誤之后)。這個微調過的模型,基于ImageNet上一個預訓練的SqueezeNet模型。
訓練期間的數據增強:
-
隨機水平鏡像
-
送入網絡之前隨機裁剪227×227大小的補丁
測試時,對每個圖像進行10各不同的變體預測,然后取計算平均值作為最終預測。這10種不同的變體預測是:
-
5次227×227大小的裁剪:四個角各一次,圖片中央一次
-
對每一個裁剪,都生成一個水平鏡像
驗證集的模型精度:94.21%
模型大小:~2.6 MB
二號模型 - 增加旋轉不變性
和一號模型非常類似,只不過增加的是圖像旋轉。在訓練時間期間,圖像隨機旋轉90°,180°,270°或根本不旋轉。 在測試時,一號模型中描述的10個變體中的每一個通過旋轉90°,180°和270°而產生三個變體。 共有40個變量被我們的模型分類和平均在一起。
驗證集的模型精度:94.1%
模型大小:~2.6 MB
三號模型 - 從頭開始訓練
這個模型不是微調得來,而是從零開始訓練。即便他的準確性低一些,但是從訓練集上學到了不同的特性。用在一個組合里面時,這可能是有用的。
訓練和測試期間的數據增強與一號模型相同:鏡像和裁剪。
驗證集的模型精度:92.92%
模型大小:~2.6 MB
把模型組合在一起
每個模型輸出三個值,表示圖像屬于三個類中的每一個的概率。我們用以下權重平均它們的輸出:
-
一號模型:0.28
-
二號模型:0.49
-
三號模型:0.23
我通過對可能的值進行網格搜索并在驗證集上測試來找到權重的值。它們對驗證集,可能有點過度擬合,但也許不是太多,因為這是一個非常簡單的操作。
驗證集的模型精度:94.83%
模型大小:~7.84 MB
在Nexar測試集上的精度:94.955% [撒花]
模型錯誤示例
棕櫚樹上因為眩光產生的綠點,讓模型錯誤的判斷這是一個綠燈信號。
模型把直行的紅燈判斷成綠燈。這種路口不止一個交通燈的情況有點棘手。
圖中右側有一個亮起綠燈的信號燈,但是模型認為沒有交通信號燈。
結語
這是我第一次在一個實際案例中應用深度學習!效果這么好讓我很高興。在這個過程中我學到了很多很多。以后有機會再跟大家交流更多~
除了這篇,今天還推送了另外一篇學習AI的文章,推薦繼續閱讀:
秘籍:如何用廉價硬件玩轉深度學習,成本不到1000美元
One more thing …
量子位的微信群已有不少關注和研究人工智能的朋友,從中國到美國,從金融到醫療……
如果你也想參與討論,結識同好,請添加量子位小助手的微信號:qbitbot,然后做個自我介紹,說明職業或研究領域和方向,小助手會拉你進群~
原文發布時間:2017-02-05
總結
以上是生活随笔為你收集整理的一文看懂如何搭建AI应用:10周学会深度学习,还赢下5千美元的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql运维管理-mysqldump
- 下一篇: Pymetrics开源公平性感知机器学习