[AI開發]小型資料集解決實際工程問題——交通擁堵、交通事故實時告警

周見智發表於2020-01-16

這篇文章其實主要是想介紹在深度學習過程中如何使用小型資料集,這種資料集樣本數量一般在1000以下,有時候甚至只有幾百。一般提到神經網路,大家都會說資料量越豐富,準確性越高,但是實際工作中,可能收集不了大量的訓練樣本,那麼這時候該如何利用有限的資料集去實現我們想要的功能,並且還能得到相對不錯的效果呢?本篇文章以擁堵(事故)檢測為例,為大家介紹小型資料集在深度學習中的應用,這是一個二分類的分類任務,最終分類結果為“擁堵(疑似事故)”和“正常”,分別包含大約500個樣本(包含訓練、驗證和最後拿來測試模型的樣本)。下面是最終效果:

上圖顯示路況由“通暢”慢慢變成“擁堵”,然後再由“擁堵”變為“通暢”,頂部顯示判斷擁堵的機率(1.0最高),可以看到在兩種狀態切換過程中,並不是平滑切換,而是有一個來回抖動的過渡期。下圖顯示發生追尾車禍時出現擁堵的過程:

上圖剛開始車輛行駛緩慢,檢測結果不斷在兩種狀態之間切換,之後出現追尾事故,發生擁堵,檢測狀態穩定。實際使用過程中,我們需要增加一個狀態快取邏輯,去避免這種來回抖動的問題。

 

小型資料集存在的問題

機器學習包括現在流行的深度學習(關於兩者的區別後面打算專門寫一篇文章介紹一下),都是在已有資料集中學習規律,然後再將學習到的經驗應用到其他資料上,這種經驗應用效果的好壞我們稱之為“泛化能力”的強弱。如果一個演算法學習過大量資料,充分找到了其中規律,那麼它的泛化能力可能就比較強,因為見多識廣;相反,如果用於學習的資料集不大,那麼就不會見多識廣了,泛化能力就比較弱,小型資料集就存在這種缺陷。

神經網路的訓練過程就是找到合適的引數,讓神經網路的預測值和實際值誤差最小,如果一個神經網路很複雜,層數多,那麼相應需要訓練的引數也就多,這時候訓練時需要的資料集就必須大一些,否則很難將每個引數調成相對最好的值。

對於小型資料集,有兩種方式可以去嘗試規避它的缺陷,一種就是使用遷移學習(transfer learning),在已經訓練好的複雜模型(引數)基礎上,做一些調整,讓其適應自己的任務,這種方式的原理就是使用一部分預訓練的模型引數,引數訓練無需從零開始,這就可以避免前面提到的資料集太小引數調整困難的問題。另外一種方式就是使用簡單網路,不要使用類似ResNet、Inception等系列這些比較複雜的卷積網路,這些網路適用於大型資料集,引數多,如果資料量不夠,很難訓練好它,我們可以根據需要自定義網路結構,比如本篇文章我自定義了一個類似AlexNet的網路結構,5個卷積層外加3個全連線層,相對來說要簡單很多。

 

遷移學習

前面說過,神經網路學習的過程其實就是找到最合適的引數,讓網路的預測結果和實際結果之間的誤差儘量最小,這個過程一般以最佳化損失函式的方式來完成(比如尋找損失函式的最小值),為了簡化說明,假設我們神經網路最終的損失函式為Loss=W^2-2W+1,形狀是一個拋物線:

如上圖所示,當W=1時,Loss的值最小,也就是說我們需要透過不斷訓練,去調整引數W,使其儘量靠近W=1的位置。神經網路在初始化時,引數W的值是隨機初始化的,假設隨機初始化W=5,那麼我們需要一步一步去調整W,使其讓左慢慢移動(比如使用梯度下降最佳化演算法),最終W有可能不能剛好落到W=1的位置,但是如果非常接近就已經足夠好了,比如W=1.1的時候。注意這裡,我們初始化的W=5,它往W=1的位置移動時,距離為4,如果我們每步走的步長(學名叫學習率)比較小,比如為0.0001,那麼調整W的次數就需要非常多了(比如4/0.0001),這時候就說明訓練很困難。那麼如何快速學習、能讓W儘快落到W=1的位置呢?答案就在W初始化這一步,我們可以不隨機初始化W,而是使用之前訓練好的W來初始化,如下圖:

如上圖,如果我們初始化W=3,那麼使其往W=1的位置移動的次數就要少很多了(2/0.001次),這樣相比隨機初始化W的做法要好很多了。

遷移學習的做法其實說白了就是上面提到初始化W的過程。如果從零開始訓練一個網路,那麼W可能初始化為5(甚至更大w=10),如果使用遷移學習的方法訓練一個網路,那麼W可以初始化為3,這個3就是預訓練好的引數,然後我們根據實際情況看是否需要再繼續調整W(甚至直接使用初始化的W即可,不用再調了)。

遷移學習的前提是,這個預訓練的模型要和我們待解決的問題有一定的聯絡,比如預訓練的模型使用的資料集是各種自然花朵的照片,主要用於花型識別,而我們要解決的問題是手工繪圖分類,那麼這兩種任務其實聯絡不是很大(自然花朵和手工繪圖特徵相差明顯),這時候遷移學習沒什麼意義(或者說價值不大),這個時候如果使用遷移學習,那麼上面W初始化的值可能就不是3了,很可能是20,那麼還不如隨機初始化W那種方法有效。

Tensorflow2.0中遷移學習的實現過程很簡單,有很多內建的網路結構,比如ResNet、Inception系列等等,例項化對應網路型別的物件,載入預訓練的權重值,然後擷取該網路的一部分(主要是前面提取特徵的卷積層),然後在擷取的網路之上再新增自定義的分類層,主要是全連線層就行了。最後凍結擷取下來的層(不用更新引數),直接用小型資料集訓練新增的層引數即可。根據實際情況,我們有時候還需要解凍擷取下來的若干層,讓其參與一起訓練,這個要看具體情況

 

使用簡單網路

對於我們本篇文章的二分類問題,我們只需要定義一個相對簡單的網路結構就可以了,比如類似AlexNet的網路結構(甚至LeNet-5可能也可以),然後我們使用已有的小型資料集從零開始訓練這個網路即可。因為網路足夠簡單,所以相對更容易訓練好。

本次任務中,我們判斷道路擁堵與否,是不需要顏色資訊的,因此在自定義的簡單網路結構中,我們增加了一個Lambda層,該層能將輸入進行一些變換,產生輸出,不需要訓練任何引數。這裡Lambda層主要負責去色功能,將輸入的RGB圖片轉成灰度圖片,然後再參與後面的特徵提取環節。下面是我自定義的簡單網路結構:

如上圖所示,網路開始一個Lambda層,直接將輸入的RGB圖片(224*224*3)轉換成灰度圖片(224*224*1),然後緊接著5個卷積層(包含其他池化、歸一化等層),最後加2個全連線層(神經元分別為4096和1000),最後是我們的輸出層,包含2個神經元,輸出一個2維向量,代表每個分類的機率。注意這裡的二分類,我們也可以使用一個神經元,但是需要將輸出層的softmax啟用函式換成sigmoid函式,後者能將任何輸入對映到0~1之間,0和1分別代表2個不同分類,同時在模型訓練時我們需要選擇另外一個損失函式binary_crossentropy(二分交叉熵損失函式)代替現在的categories_crossentropy損失函式(分類交叉熵損失函式)。機器學習中損失函式主要是用來衡量損失大小,也就是實際值和預測值之間的誤差。再看看我們訓練過程,loss值和accuracy的變化過程:

效果還不錯,驗證準確率最後可以到達95%,再來看看100多張測試集上的效果:

可以看到測試集上的準確率在95.8%,已經不錯了。

上面這個截圖主要是為了說明如何使用小型資料集,可能網路設計、資料集豐富性上還不夠完善,後面在實際工程中使用時,還需要根據需要增加部分場景的訓練素材(同樣,少量即可)。

 

資料集的‘數量’和‘質量’

深度學習中的資料集不僅對數量有要求,對質量同樣有要求。數量一般是越大越好,同樣要求樣本標註準確,比如目標檢測資料集,要求標註的矩形方框大小、位置都要儘量合理,能完整將目標包含進來,同樣資料集應該儘可能包含各種場景,也就是資料集的豐富性要高,就是前面提到的“見多識廣”。對於監督學習而言,主要是透過訓練素材得到X->Y的對映關係,如果你給出的訓練樣本本身不具備X->Y的對映關係,或者說這種對映關係沒有任何規律、甚至摻雜了很多錯誤對映關係,那麼資料集在怎麼大,都沒有什麼用處,因為你這是在愚弄神經網路,會把它整懵逼了,最後得不償失。對於深度學習來講,資料集的數量、質量都同等重要。

相關文章