cascade down_Cascaded CNN 方法寻找人脸关键点
Cascaded CNN 方法尋找人臉關鍵點
論文筆記
閱讀論文
第一階段閱讀論文,大約兩天大體閱讀完論文 Deep Convolutional Network Cascade for Facial Point Detection。感覺還是比較缺乏論文閱讀經驗,但是比以前快了很多。主要閱讀論文 intro、method 和 modeling。作者的思維比較奇特,把損失函數放在 experiment 部分,我找了好久沒找到。
編寫代碼
尋找同學幫助,發現代碼變化太快,舊經驗有些跟不上。嘗試瞎貓撞死耗子的策略,瞎寫,顯然不能成功,浪費 4+ 天時間。
靜下心,閱讀 Caffe 框架代碼,C++ 不熟悉,讀 C++ 代碼沒經驗。硬著頭皮讀,不得法,痛苦,事倍功半;晚上,腦子突然靈光一閃,讀繼承關系和頭文件(因為 C 的頭文件只是函數聲明,而宏定義可以臨時找),有效,思路清晰。一天時間寫完代碼。
NaN 和收斂失敗
計算結果 J(theta) 是 NaN,天!各種 Debug,找了 3+ 天,代碼中沒發現和數值相關的 BUG。也許是數值計算方法的問題?不能,這是框架寫的代碼。后來發是學習率調太大。之前已經調小過,無效,沒想到還要繼續調小。
再次驗證,收斂失敗。這是什么原因?后來發現是 loss 的設計存在問題,沒有做 normalization。細節在這里。收斂成功。
算法效果驗證
最直接的方法當然是輸出坐標點,可惜一點都不直觀。寫了一堆代碼用來在圖上做各種標記,代碼混亂成翔(后來抽取到 我的 github)。從輸出來看,總體位置還算靠譜,但是效果并不好,雖然還沒量化,但是我知道肯定不好,不用算了。
我天真的覺得是 overfit 了。在 train set 做個測試,underfit。
突然想到會不會是 BUG 導致所有輸出都是一樣的?檢查了輸出的坐標,雖然比較相近,但是確實是不同的,所以應該不是 BUG。這說明,沒有提取到足夠的 inter-face 特征?這個地方要想想。
單點驗證
其實我沒有完全按照論文實現。論文結構太復雜,存在 3 個級聯,第一個級聯有 3 個網絡做平均。作者的說法是第一個級聯最重要,所以我只實現了第一個級聯的其中一個網絡。有可能沒有完全按照結構設計導致的問題?
另外一個思路是,用一個 kernel 去掃描 5 個不同的面部特征真的靠譜么?我也許試試五個 kernel?一時間沒有思路為何 underfit。先做一個 left eye 試試吧。我快速 10000 輪迭代做出個 model,輸出一百個圖像來人力比較,第一印象是單點的確比多點要準確。看一下損失:
左眼坐標網絡損失:I0920 16:27:52.355422 11912 solver.cpp:294] Iteration 10000, Testing net (#0)
I0920 16:27:52.606781 11912 solver.cpp:343] Test net output #0: loss = 0.00317065 (* 1 = 0.00317065 loss)
臉部坐標網絡損失:I0920 16:19:16.628931 48513 solver.cpp:294] Iteration 10000, Testing net (#0)
I0920 16:19:16.885615 48513 solver.cpp:343] Test net output #0: loss = 0.0263838 (* 1 = 0.0263838 loss)
從數據來看,確實只做一個坐標效果會比較好。
重讀論文
我想我一定是弄錯論文某些細節了,我決定重新讀一遍這篇論文。重新閱讀論文過程中,我產生了新的想法。
之前的 network 只有一個 kernel,而作者提出的方案是 locally weight-sharing,開始的時候不甚明了,直接忽略了。我看了 Convolutional Neural Networks 突然想通了 weight-sharing 指的是什么意思。Convolutional layers consist of a rectangular grid of neurons. It requires that the previous layer also be a rectangular grid of neurons. Each neuron takes inputs from a rectangular section of the previous layer; the weights for this rectangular section are the same for each neuron in the convolutional layer. Thus, the convolutional layer is just an image convolution of the previous layer, where the weights specify the convolution filter.
Fully-Connected layer 的輸入和輸出的尺寸都是固定的,每一個神經元對應一個輸出。根據 Andrew NG 的 UFLDL,我產生了這種觀念:卷積層只有一個神經元,這個神經元就是 kernel,是 weight 的矩陣。我突然發覺這種觀念可能有問題。
我現在的理解是這樣的,不知道有沒有錯。一般看到,kernel 只有一個,而 convolution layer 的輸入是沒有大小限制的,而輸出也固定,根據圖像大小產生不同大小的 feature map。如果換個角度看,convolution layer 是一個 (N?m+1)×(N?m+1) 個 m×m 的 kernel 的神經元,每個神經元對應著自己的感受域,產生一個輸出:如果這樣定義,convolution layer 也是輸入輸出大小固定的。而 weight-sharing 也很好理解了,就是這 (N?m+1)×(N?m+1) 個 kernel 現在變成了同一個,他們 share weight。而文章提出的方法就是,不再使用整個 feature map 做 weight-sharing,用同一個 kernel,而是分區域使用不同的 kernel。
輸入區域似乎也和我想的不一樣,原文的 input range 是臉部區域 + 一個百分比...,我覺得我當時沒看到是不是不太合適....
看完我大概是怎么一個思路:先修改輸入區域;
實現 locally weight-sharing 看看效果;
進一步提高再實現 cascaded 結構,這是后話。
調整輸入范圍
根據上次閱讀論文的想法,先測試左眼的檢測,進行數據清洗,只截取左眼。結果發現,雖然輸出的 cost 變小了,但是看圖片依然是 underfit。
進行 64 樣本的測試,發現依舊是 underfit,這實在詭異,難道是 Bug?那么測試 1 樣本試試,還是不準。輸出預測值和坐標試試....咦,數據績小,所以幾乎完美重合,那么打印怎么會有那么巨大的位置錯誤,這只能解釋為我的程序哪里寫錯了。
理理思路,程序的邏輯大概是:
Created with Rapha?l 2.1.2Create DBLE DataLayerCNNLE Feature Extract
很可能是某個數值忘記加減,導致的偏移。檢查輸出值后發現,輸出的訓練坐標和預測坐標是幾乎相同的。這就說明:訓練數據生成錯了
訓練圖像框錯了
測試后發現,確實是自己 normalize 監督信號的時候把監督信號弄錯了。在選取 sub-region 時候并不需要 normalize 坐標,只有 resize 才需要,大腦故障了。調整后發現,無論是損失函數,還是肉眼觀察結果,比起之前大大靠譜,非常好。
總結
以上是生活随笔為你收集整理的cascade down_Cascaded CNN 方法寻找人脸关键点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 曝佳能在开发全像素四核对焦全画幅相机 解
- 下一篇: 8 无法识别raid盘_王者荣耀防沉迷规