【學習筆記3】Convolutional Pose Mashines在FashionAI中的應用——我的深度學習首秀

春學期開學至今這一個多月裏,除了有序推進自己的科研任務,非專業的我還和協會志同道合的小夥伴跟着羅老師以參加比賽的方式在深度學習計算機視覺領域裏進行實戰演練。我們參加的是天池FashionAI服飾關鍵點定位全球挑戰賽,今天(4月21日)是初賽截止的日子,憑藉有限的精力和資源我們最終以test_b數據集不包含遮擋點NE(Normalized Error)7.49%的成績排名70/2321,順利進入複賽。雖然在複賽隊伍裏,我們的成績並不拔尖,我也知道未來我們要做的還有很多很多,但是這是我第一次參賽,CPM(Convolutional Pose Machines)也是我第一個通篇讀懂、調試、修改、完善的深度學習模型。和本科時候第一次參加電子設計大賽一樣,第一次永遠是最痛苦最煎熬的,但也是收穫最大進步最顯著的。從當初面試時的什麼也不懂,到如今能夠獨當一面成爲一名還算不錯的深度學習煉丹師,碰了不少壁,踩了不少坑,但是我很享受這種鑽研進步的過程。羅老師說,任重而道遠,是的,還有很多要做,我也還有很多要學。那麼就先寫博客做一個階段性的總結吧。

一、CPM——卷積姿態機

論文傳送門:Convolutional Pose Machines》

作者源碼傳送門:https://github.com/shihenw/convolutional-pose-machines-release

我們在比賽中用到的tensorflow實現的源碼傳送門:https://github.com/timctho/convolutional-pose-machines-tensorflow

關於CPM的機理,這篇博客講的已經很好了,CPM的結構簡單,結構上覆用很多,配合代碼很快就能看懂,雖然我這個小白還是看了半個月,一句一句地推敲纔讀通了網絡。在這裏就不再多說原理,我想說一下我通過實踐對CPM的一些理解,可能不準確,僅代表個人意見,歡迎各位指正。

優點:

  1. CPM通過將上一個stage預測的heatmap和當前stage提取的特徵一起concate,有一種殘差的思想,通過stack多個stage來refine預測的heatmap。Baseline挺高,在不同數據集上魯棒性很強。
  2. 實踐證明,CPM在學習關鍵點關聯性上有先天的優勢。在天池提供的數據集上,兩個領口中間(neckline_left,neckline_right)就應該有中線點(center_front),左肩點(shoulder_left)對面就應該有右肩點(shoulder right)。因此很少有點明顯跑偏到無關背景中的現象,哪怕有也是一些確實有可能混淆的角點。身邊的有個好朋友也參加了這個比賽,他們先通過檢測提取出bbox然後在bbox上預測關鍵點,他們起初點跑飛的現象依然很嚴重,來諮詢我的時候,我直接說CPM應該能很大程度解決這個問題,於是他們轉戰CPM,最終獲得了NE八點幾的結果,也成功闖進複賽。因此,CPM不太會有明顯的點跑飛現象,它可以很好的學習關鍵點之間的關聯性。至少我這裏的實踐情況如此。
  3. CPM的中繼監督優化,單獨計算每個stage的loss,很好地解決了梯度彌散現象,因此多個stage網絡也能訓得動。

缺點:

  1. CPM網絡雖然簡單,但是結果複用、連續的卷積顯得有些“囉嗦”,訓練起來也很慢。當然網絡性能好,硬件資源跟得上,這些也都不是啥大問題。
  2. CPM是沒有Hourglass那樣的多尺度特性的,因此需要在數據增廣的時候加入scale的增廣,而且實踐證明,尺度的增廣對於CPM來說是十分重要的。因爲test上有很多全身照,人已經非常小,而我們只需要根據任務要求提取上衣或者裙子的關鍵點,所以需要網絡從很小的區域提取圖像特徵。因此,尺度的增廣對於沒有多尺度特性的CPM來說是必要的。
  3. CPM具有殘差的思想,通過多個stage不斷refine預測結果,這種refine只能說是微調位置以及鞏固強化heatmap對關鍵點的響應。但是一旦第一個stage發生很明顯的預測不準確,或是根本沒有響應關鍵點,那麼後面的refine也是無濟於事。

綜上所述,CPM具有很好域遷移的魯棒性,baseline挺高,但是它的缺點也決定了僅僅依靠CPM的baseline很難達到非常好的效果,即使加入完善的數據增廣、加入檢測給預測增加一個很強的constrain,也只能是漲一些點,要想躋身排行榜前列,需要結合一些更先進的算法,關於這一點,我們也在仔細研究。

二、我的煉丹修煉

深度學習煉丹過程是痛苦的,一種trick的效果驗證的等待週期很長,先要代碼實現,然後放到GPU上訓練,等很長的時間一個模型訓練完,然後做出結果,雖然有可視化的圖片給出直觀的感覺,但是還是需要提交一波結果讓官方審覈才放心,於是又得等待一天只有兩次的測評。關鍵的是,我是個非常非常非常明顯的急性子,等得我真的是......當然,我目前盲目的訓練方法也存在問題,有很多彎路是完全可以規避的,這個後面會說。

不過,煉丹的過程卻又是很有趣的,當結果顯示一個小trick的加入讓網絡漲了哪怕只有半個百分點的時候,別提多高興了。很多個trick都是之前從論文裏看到的,知道機理卻從沒實踐過,現在通過第一次嘗試,對一些trick也有了更深的瞭解。後面就大致說一下我訓練CPM baseline的過程,多少也能夠表明訓練一個網絡都要做哪些事。有一點我是確信的,就是下一個網絡,我絕不會再花這麼久才做出第一個結果了(我的第一次結果提交是在4月4號,也就是說我差不多花了一個月)。

1、Datagenerator——數據生成器

我的師兄經常說數據預處理是訓練一個網絡的過程中最麻煩的,而且這個過程針對每個數據集的操作還不一樣,因此針對不同網絡需要寫不同的數據生成器,所以,會做數據預處理,會寫數據生成器,是深度學習實踐的第一步。因此深度學習行業裏有個崗位叫“Data provider”,它是專門做數據預處理的一個崗位。

將圖片Feed進網絡之前,一般需要做如下幾個步驟數據預處理、數據增廣、編寫數據迭代器。我在CPM的實踐過程中的數據生成器是團隊小夥伴寫的,大致做了如下操作:

  • 數據預處理。根據大賽提供的csv文件提取標籤,生成包含所有圖片名字的list,以及包含圖片所有信息的dict,並按照一定百分比將訓練集劃分爲訓練集和驗證集。這一步蠻簡單的。
  • 數據增廣。數據增廣是一個很玄妙的學問:增廣弱了不好,訓練集規模又不夠大,無法涵蓋所有場景,test上的accuracy自然也不會高;增廣太強呢也不好,一方面,增大了訓練集的規模,需要增加網絡訓練的epoch,訓練時間加長,另一方面過分地涵蓋所有場景,同時又讓訓練的loss降到很低,網絡很容易在我們設置的增廣場景內過擬合,test一旦出現一個新奇的玩意兒,可能就一塌糊塗了,還不如不加增廣的好。所以,增廣的到底該怎麼加,每種增廣的幅度加多少,需要針對特定任務特定數據集認真確定,沒辦法一概而論。那麼我在FashionAI的數據集中用的增廣有這些:
  1. 尺度增廣。在CPM缺點那一塊提到了,CPM不具有提取多尺度特徵的特性,而我們有需要網絡有尺度上的魯棒性,因此尺度增廣是十分重要的。
  2. 旋轉增廣。test圖片裏的美女們經常擺pose嘛,pose一擺,關鍵點整體就偏移了一個角度,因此加入旋轉的增廣也是很重要的。不過,旋轉沒必要做到upside down這種程度,±30°、±45°足矣。要是直接upside down,我估計腳會被預測手,手會被預測稱腳......
  3. 亮度、對比度、色度增廣。test圖片場景亮度變化很大,有的是在白天拍的,有的是在晚上拍的,有的是晚上拍的穿黑衣服,有的是穿着黃衣服背景還是差不多色兒的牆壁,因此對網絡在亮度、對比度、色度上的要求也很高。當然這個增廣也得有個度,沒必要亮到自己看着都刺眼,也沒必要暗到自己肉眼都看不着。我是用PIL的ImageEnhance函數庫做的,區間設置爲[0.5~1.8]。
  4. 其他增廣的trick,由於涉及到小夥伴們還沒發表的論文,時機成熟後再和大家分享。
  • 數據迭代器。數據迭代器很簡單,一個while...和yield的組合就可以實現,在調用的時候通過next()函數,程序會自動返回到while中繼續生成下一個batch的數據。

綜上所述,一個簡單的random batch的datagenerator的函數體大概如下:

def generator(self, batch_size=16, normalize=False, sample_set='train'):
        """ Auxiliary Generator
        """
        while True:
            train_img = np.zeros((batch_size, 256, 256, 3), dtype=np.float32)
            i = 0
            while i < batch_size:
                if sample_set == 'train':
                    name = random.choice(self.train_set)
                elif sample_set == 'valid':
                    name = random.choice(self.valid_set)
                img = self.open_img(name)
                
                ......
                data processing
                ......

                ......
                data augmentation
                ......

                train_img[i] = img.astype(np.float32)
                i = i + 1
            yield train_img

在主函數調用的時候用:

generator = dataset.generator(batchSize=FLAGS.batch_size, norm=False, sample='train')
batch_img_np = next(generator)

2、learning rate decay存在的問題

大家可以先看這篇乾貨:https://zhuanlan.zhihu.com/p/33107481?utm_medium=social&utm_source=wechat_session&wechatShare=1。谷歌爸爸都已經證明了增加Batch Size的同時保持學習率的策略既可以保證不掉點,還可以減少參數更新的次數。當然,我們的硬件資源有限,顯存就那麼點,沒辦法把batch size設置成那麼大,沒辦法還是在用decayed learning rate。

關於learning rate decay網絡上博客很多,這裏就不再贅述了。learning rate decay設計的初衷就是爲了讓網絡在開始訓練的時候可以用一個較大的學習率迅速調節網絡參數,之後再網絡的後期通過一個小的學習率fine tune網絡參數,使網絡下降到全局或者局部最優,解決了固定學習率網絡訓練後期在全局或局部最優點附近震盪等問題。但是learning rate decay的參數很難調,decay rate和decay step很難調到和網絡相匹配,decay週期長了,網絡後期還在以一個較大的值在持續訓練,可能出現過擬合甚至跳出全局/局部最優點造成loss回升;decay週期短了,網絡還沒有收斂完全,learning rate就非常非常小了,網絡參數就更新不動了。這兩種情況在實踐過程中我都出現過。所以說,learning rate decay存在很嚴重的網絡匹配問題。

同樣的原因,我們的解決方法時機成熟再和大家分享。

3、適當的fine tune很重要

fine tune就是在網絡訓練的後期以一個合適的小學習率更新網絡參數,使網絡更好地擬合訓練集,在全局/局部最優點處收斂得更好。實踐證明,我們通過fine tune讓模型在test a上增長了一個多點。

4、理解tensorflow命名空間

和小夥伴在寫BN代碼的時候總是會出現命名空間複用的問題,那時候不懂命名空間,一氣之下乾脆把bug相關的變量定義從tf.get_variable全部替換成了tf.Variable,並且名字都設置成了None,最後辛辛苦苦訓練了一天多的網絡保存的checkpoint在load進test網絡的時候發生變量不存在的錯誤,訓好的網絡參數一點用都沒有了,白白浪費了很多時間。

因此,以後管理變量儘量都用scope管理好,在不同的代碼塊用不同的scope管理代碼。比如CPM中每個stage都定義一個單獨的scope。並且用tf.get_variable定義時,每個變量定義一個自己唯一的名字,這樣保存的checkpoint才能根據變量名成功地加載參數,也規範了網絡的變量管理。

5、切忌“盲訓”,要建立自己的validation機制

我們在訓練的時候沒有根據大賽官方的評價標準建立自己的驗證機制,每做一次新的嘗試,都要等待經過漫長的等待時間獲得官方給出的test結果,這種盲目的時間浪費了我們大量的時間。如果在訓練的過程中就建立和大賽官方標準一樣的NE評價機制,就能直接在訓練過程中通過觀察驗證集的NE值得到新的trick的性能,這樣能減少浪費的時間,並且有據可依地嘗試各種方法。做比賽嘛,要過擬合,也要在官方評價指標過擬合。

三、總結

上述是我自己在訓練CPM的基礎模型的過程中遇到的一些問題,對於大神來說可能不算什麼,但對於第一次訓練完整深度學習模型的我來說,都是第一次遇見。過程中確實走了不少彎路、碰了不少壁、踩了不少坑。在此總結一番,便於自己今後學習翻閱,也和大家一起交流分享。還有一些trick我會繼續總結好再和大家一起分享,代碼我也會在後面開源。未來還有很多要學,那就繼續學下去吧。

最後,對於文中的錯誤,還請大家指正。



-------------------------------------------

Youzhi Gu, master student

Foresight Control Center
College of Control Science & Engineering
Zhejiang University
Email: [email protected],[email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章