您現在的位置是:首頁 > 運動

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

由 極市平臺 發表于 運動2021-10-08
簡介第二點就是隨機裁剪crop增大目標範圍,主要是初步驗證的時候發現泛化效果不好,經過簡單資料分析,發現訓練集的關鍵點區域面積集中在2000附近:再看看目標場景採集的幾百張圖片的關鍵點區域面積分布,範圍是2000-12000,且峰值在6000-

公交地圖和標準地圖有什麼區別

作者丨Fire

編輯丨極市平臺

一、需求背景

這天接到個新需求,需要實時檢測自然場景下目標人體的關鍵點位置。

從演算法工程師的角度來拆解下需求:

1、檢測人體關鍵點位置,就是人體姿態估計任務嘛;

2、要實時,那麼就是終端部署,服務端那傳輸延時就不考慮了。對了咱們硬體不大行,所以肯定是要輕量級模型的,解析度也不能太大,剪枝量化蒸餾三件套也要做好打算;

3、“自然場景下的目標人體”,意思就是場景下可能有多人,但是我們只需要一個目標的關鍵點,要考慮如何區分(這點後面再展開說)。

二、方案探索

2。1 初見

之前的專案經驗主要是人臉相關的分類、檢測、分割以及OCR等,雖然沒做過人體姿態估計,但是需求分析完,我的第一感覺是“應該很簡單”,這份底氣來自於之前做過的人臉關鍵點檢測專案,當時的經驗是,處理好資料、使用合適的Loss,隨便用個剪枝後的輕量級模型都可以達到很高的精度,而且在嵌入式板子上能跑到10ms以下(都不需要PFLD之類的)。而人臉關鍵點有68點,人體也就17個點,不是簡單多了。

於是直接拿出之前人臉關鍵點的程式碼,修改億點點細節(調整模型輸出、準備訓練資料、修改DataLoader等),用少部分資料先跑跑看看。資料就用COCO和MPII就差不多了,後續可以自己從網上爬取一些來擴充,當然如果有目標場景的資料就更好了。

工欲善其事,必先抓只小白鼠。也就是需要一個評測指標,分類常用Accuracy、F1,檢測常用mAP,而人體姿態估計又有所不同,請教了谷哥(Google),

一般是用PCK(PCKh)和OKS+mAP,簡單來說,前者就是計算predict和label點的距離再經過head size normalize,後者就是用類似於目標檢測中IOU的OKS計算相似度,然後再算AP。

雖然前者在學術界目前已經很少使用(主要是刷榜刷得太高了),但是我們場景只需要單人,加上工程化簡單,肯定是選擇PCK,且考慮資料不一定都有head的標註,以及我們場景目標大小比較一致,最終決定使用自定義PCK,160解析度下,距離小於5則算正確,其實PCK也算作一種acc,所以後面用acc指代。

第一次跑完,驗證集acc達到了 0。81,感覺還行,於是開始往丹爐瘋狂加料(加資料、加Data balance、微調loss、不同關鍵點loss設定不同weight、懷疑特徵提取不夠甚至把FastSCNN的backbone都拿來了、各種調參等等),一頓操作下來,終於有了一點提升:val-acc達到了0。9869。

這麼高,看來是成了,部署上板測試之前,習慣性在自己電腦上先跑跑,準備好視覺化demo一看,傻眼了,除了head之類的比較準,手稍微一動就很容易檢測不到。

一腔熱血終於被冰冷的現實擊潰,看來這個“應該很簡單”的任務並不簡單。。。自己挖的坑,跪著也要填完。稍微總結下失敗的教訓,然後準備老老實實從零開始。

人臉關鍵點檢測直接回歸座標點的效果好,很大原因在於特徵分佈比較集中。首先是人臉大小比較一致,其次是人臉是剛體,各個關鍵點相對位置也比較固定,最後是除了側臉,基本不會遮擋,目標特徵也比較清晰。相較之下,人體大小分佈就不一致,且各個關節活動範圍很大,相對位置不固定,還存在各種位置遮擋和服裝遮擋的情況,相比來說任務難了很多。同時由於關鍵點的分佈範圍太廣,單純用全連線層去迴歸,很有可能出現某一部分神經元訓練的比較好,另一部分比較差,也就導致泛化能力很差。

2。2 反思

直接回歸關鍵點的思路行不通,那就開啟國門睜眼看世界——看看現在的主流方案。這篇2020年的綜述就挺不錯的:Deep Learning-Based Human Pose Estimation: A Survey。如同華山派著名的氣宗和劍宗之爭,人體姿態估計也有不同的派別,而且打得更熱鬧,還分了兩個方向:

目標學習形式:

直接回歸點座標 VS 迴歸Heatmap

整體檢測流程:

Top-Bottom VS Bottom-Up

原來早期的人體姿態估計就是直接回歸關鍵點,看來我也只是在重複前輩的路而已。後來發現效能不好,於是改為迴歸heatmap的方式來訓練。簡單來說就是把原圖縮小几倍得到特徵圖,這個特徵圖有關鍵點的位置值就是1、背景就是0,因為只設1太稀疏了,所以把1改為一個高斯核,這樣也符合實際語義。

確定好學習形式後,再看看檢測流程。上面我的方案其實就屬於Top-Bottom,也就是先檢測人,再裁剪出來對每個人去檢測關鍵點;而Bottom-Up則相反,直接檢測出所有的關鍵點,再依次組合成一個個人。這裡和目標檢測中的one-stage和two-stage其實有點神似,一般來說,Top-Bottom方式精度高,但是速度慢一點,而Bottom-Up速度快,但是精度差一點。

同時瞭解了一下目前一些優秀的開源方案(主要側重一些相對輕量級模型,因此就不包含HRNet之流了):

AlphaPose、OpenPose、Lightweight OpenPose、BlazePose、Simple Baselines、Fast Human Pose Estimation、Global Context for Convolutional Pose Machines、Simple and Lightweight Human Pose Estimation

等,那就來吧。

2。3 嘗試

2。3。1 淺嘗輒止

對上面提到的各種潛在可行方案,分別進行測試。

修改上文的我的人臉關鍵點回歸模型(Top-Bottom),把輸出改為heatmap,相應調整資料處理和loss,訓練完效果一般,val-acc85;

AlphaPose、OpenPose都屬於比較大的模型,且GPU速度也只是勉強實時,我們是端側+CPU+低效能板子,估計1秒以上了,所以暫時不考慮,同時發現有個Lightweight OpenPose(Bottom-Up)的專案,直接拿來上板跑了下,360ms,有點希望;

BlazePose,這裡直接用了TNN的模型,同時發現他們還開源了騰訊光流實驗室的一個姿態估計模型(Top-Bottom),比BlazePose要好,於是直接測試了後者,上板200ms,且除了轉換後的模型沒有什麼其他資料;

Simple Baselines(Top-Bottom),用預訓練模型訓練,val-acc在0。95左右還行,就是換成輕量級網路後(mobilenet-v3),精度掉到0。9左右,且視覺化很差;

Fast Human Pose Estimation(Top-Bottom),相比於沙漏網路,stage砍半,channel砍半,就沒其它改變了;使用了蒸餾,loss是兩部分,一部分是老師的預測結果,一部分是GT;效果還行,720ms略慢;

Global Context for Convolutional Pose Machines(Top-Bottom),提供的預訓練模型,視覺化效果還行,400ms左右;

Simple and Lightweight Human Pose Estimation(Top-Bottom),視覺化效果還行,250ms;

2。3。2 集中火力

經過綜合考慮,最後選擇了Lightweight OpenPose來做最佳化。

一是它是Bottom-Up的模型,不需要額外訓練人體檢測器(對應額外的資料處理成本、模型訓練成本以及推理耗時);二是視覺化來看,它的精度也是屬於表現最好的幾個。

要了解Lightweight OpenPose,那麼就需要先提下OpenPose,它使用了VGG作為特徵提取,加上兩個header,分別輸出關鍵點的heatmap和PAF的heatmap,透過多個stage迭代最佳化(每個stage的輸入和輸出都是這兩個heatmap),最後透過MSE進行最佳化。關鍵點的heatmap好理解,PAF是什麼呢?這是論文提出的part affinity fields,一般翻譯為親和力向量場,它代表了兩個關鍵點之間的連線資訊,個人覺得可以直觀理解為關鍵點之間的骨骼資訊,實現的時候是求兩個關鍵點之間的單位向量(代表了方向),然後給對應的heatmap位置賦值。最後把多人檢測問題轉化為二分圖匹配問題,並用匈牙利演算法求得相連關鍵點最佳匹配。

而Lightweight OpenPose作者測試發現原openpose的refinement stage的5個階段,從第一個refinement stage1之後,正確率沒有提升多少,但是運算量就加大了。並且還發現了refinement stage網路的關鍵點定位(heatmap)和關鍵點組合(pafs)兩部分的兩條分支運算,有不少操作是一樣的,造成運算冗餘。於是主要進行了以下最佳化:

新的網路設計。只採用initial stage+refinement stage兩個階段網路。(此處,我覺得到refinement stage2階段的價效比比較高,refinement stage1的正確率還是有點低,儘管運算量不大。但是refinement stage2再加了約19GFLOPs的同時正確率就提高了3%左右,價效比更好。)

更換輕量級backbone。用MobileNet替換,並用空洞卷積最佳化網路。並且進行了一系列對比實驗,發現MoblieNet v1比MobileNet v2效果居然更好。

refinement stage中的關鍵點定位(heatmap)和關鍵點組合(pafs)部分的網路權值共享,減少操作計算量。最後兩個卷積層才分出兩個分支分別用來預測關鍵點的定位(heatmap)和關鍵點組合(pafs)。

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

原openpose的refinement stage中都是使用7x7的卷積核。作者卻使用了三個連續的1x1, 3x3, 3x3的卷積核來代替7x7,並且最後的3x3是使用了空洞卷積, dilation=2。另外由於用3個卷積核代替原來的一個卷積核,網路層數變得很深,所以作者又加上了一個residual連線。

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

研究了下Lightweight OpenPose原始碼,繼續開始往丹爐瘋狂加料(改backbone、剪枝、加資料、調解析度、蒸餾、各種調參等等),一頓操作下來,得到了模型:速度80ms,acc0。95(對應的蒸餾teacher acc0。98)

速度勉強能接受,精度還行,但是視覺化測試稍微有點不準,可能跟資料也有一定關係。

三、峰迴路轉

3。1 轉機

就在我猶豫要不要繼續深入最佳化Lightweight OpenPose的時候,無意間刷到了這樣一篇文章:《實時檢測17個人體關鍵點,谷歌SOTA姿態檢測模型,手機端也能執行》。文章介紹了谷歌今年五月開源的一個輕量級人體姿態估計模型MoveNet,在tfjs有對應的api。

眾裡尋他千百度,驀然回首,那人卻在燈火闌珊處。這不就是上天為我準備的嗎?趕緊用網頁端測試了下,感覺還行,加上之前有轉bodypix的tfjs模型到tf模型的經驗,準備直接下模型本地跑跑,幸運的是,這次的MoveNet不僅有tfjs模型,還有tflite模型,這下方便多了。

透過官方部落格的隻言片語以及Netron視覺化網路,對模型有了初步瞭解,官方宣稱是基於CenterNet做的修改,但是修改了很多(The prediction scheme loosely follows CenterNet, with notable changes that improve both speed and accuracy)。具體來說,使用了mobilenetv2+fpn作為backbone,輸出四個header,最後經過後處理輸出一個最靠近圖片中心的人的關鍵點。由此可知,它也是屬於Bottom-Up的流派,同時透過關鍵點回歸的範圍進行加權,只輸出最靠近中心的一個人的關鍵點,和我們的場景絕佳匹配,因為就Lightweight OpenPose而言,其餘人的PAF資訊其實也是多餘的。

先測測速度吧,首先嚐試上板安卓直接載入tflite模型,報錯Didn‘t find op for builtin opcode ’RESIZE_BILINEAR‘ version ’3‘,之前用的org。tensorflow:tensorflow-lite:2。0。0,嘗試2。3。0後可以了。速度150ms左右一幀,連續跑在120ms左右。然後嘗試一些推理框架(比如Tengine、NCNN、MNN等),這裡我習慣使用TNN。結果tflite轉tnn和pb轉tnn均failed,debug看是不支援ARG_MAX運算元,這是後處理裡面的,於是自己簡單寫了個去掉後處理的mobilenetv2+fpn+4個header的模型轉tnn,上板測試80ms左右。

考慮到Lightweight OpenPose已經優化了很多,繼續壓榨空間有限,且上文提到有冗餘輸出,而這個MoveNet直接就能跑到80多ms,且只輸出一個人的關鍵點,還有谷歌背書,因此痛下決心,準備拋棄Lightweight OpenPose採用MoveNet的方案,嘗試復現它。同時我還準備了Plan B:如果復現不了,就直接匯出tflite的backbone權重,然後新建一個pytorch模型載入權重,得到模型推理輸出後透過C++程式碼實現後處理。這樣的缺點是沒法用自己資料訓練,無法迭代最佳化,且直接使用官方提供的預訓練模型視覺化來看精度也沒有達到特別高。

3。2 復現

好吧,那就開始準備擼起袖子復現MoveNet了。

只根據一個模型結構要復現一個模型訓練,說難不難,說簡單也不簡單。模型結構搭建照貓畫虎即可,關鍵是資料如何構造、Loss如何選擇沒有任何資訊,甚至還隱藏了大量細節,比如高斯核的構造、loss權重的設定、最佳化器等各種超引數設定。道阻且長,行則將至,只能一步一個腳印了。

事先說明,以下所有分析均是主觀猜想,只是經過實驗驗證效果也不錯,不代表谷歌官方原始實現就一定是這樣,僅供參考。

3。2。1 模型結構

要復現一個模型並不難,很多模型有論文、有官方程式碼或者有其他人復現的程式碼、哪怕是各種專欄部落格的拆解分析,都能幫助很多,遺憾的是,MoveNet都沒有,唯一能參考的只有兩個東西:谷歌官方部落格的介紹,以及TFHub提供的訓練好的模型。這也是這篇文章分享的初衷。

觀察模型結構,主要分為三部分:backbone、header、後處理。

1。Backbone前面說過了很簡單,即mobilenetv2+fpn,為了保證可控性和靈活性,我沒有使用現成的一些mobilenetv2的實現,而是自己一層層自己搭起來的(其實也沒有太大必要,後續換backbone我也是直接在現成的模型程式碼上改的);

2。Header的構建就更簡單了,輸入backbone的特徵圖,經過各自的幾個卷積層,最後輸出各自維度的特徵圖即可,難點在於要理解每一個header的含義,整體結構參考如下:

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

經過不斷的分析、猜想、測試,現在直接分享得到的結論吧。四個header我們分別命名head_heatmap,head_center,head_reg,head_offset以便說明:

head_heatmap的維度是[N,K,H,W],n是batchsize,訓練時自己指定,預測時一般為1;K代表關鍵點數量,比如17;H、W就是對應的特徵圖了,這裡輸入是192x192,降取樣4倍就是48x48;它所代表的意義就是當前影象上所有人的關鍵點的heatmap,注意是所有人的;

head_center的維度是[N,1,H,W],這裡的1代表的是當前影象上所有人的中心點的heatmap,你可以簡單理解為關鍵點,因為只有一個,所以通道為1;它所代表的意義官方部落格說是arithmetic mean,即每一個人的所有關鍵點的算術平均數,但是我實測這樣效果並不好,我自己最終是取得所有關鍵點得最大外接矩形的中心點,當存在一些較遠的關鍵點的時候,可能算術平均數可以很好的訓練大部分距離近的點,但是對較遠的點效果差點,而我比較關注手腕這種較遠的點,按我這麼取對每一個點學習起來差不多,這個就仁者見仁智者見智了,以自己場景實驗結果為準;

head_reg的維度是[N,2K,H,W],K個關鍵點,座標用x,y表示,那麼就有2K個數據,就是對應這裡的2K通道;那麼資料如何構造呢?根據模型結構的拆解,就是在每個人的center座標位置,按2K通道順序依次賦值x1,y1,x2,y2,。。。,這裡的x、y代表的是同一個人的關鍵點相對於中心點的偏移值,原始Movenet用的是特徵圖48尺寸下的絕對偏移值,實測換成相對值(即除以size48轉換到0-1區間)也是可以的,可以稍微加快收斂,不過幾乎沒有區別;

head_offset的維度是[N,2K,H,W],通道意義一樣都是對應K個關鍵點的座標,只不過上面是迴歸偏移值,這裡是offset,含義是我們模型降取樣特徵圖可能存在量化誤差,比如192解析度下x=0和x=3對映到48解析度的特徵圖時座標都變為了0;同時還有迴歸的誤差,這裡一併訓練了;

3。後處理相對來說比較麻煩,因為有各種奇奇怪怪的操作,這一步只有結合Netron視覺化一步步大膽猜測,結合官方部落格認真分析,結構如下,可以看到不是常規的CNN結構。

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

官方介紹如下,也解開了不少疑團。

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

也不賣關子了,直接說明後處理流程吧。

首先對於head_heatmap和head_center,需要求一個sigmoid,這裡也可以寫到網路結構中,主要是保證取值範圍,因為後面要乘位置權重。

然後對於head_center,我們乘以一個位置權重矩陣,大小也是48x48,值可以透過Netron匯出谷歌的設定,透過Numpy+OpenCV載入視覺化可以看出是一箇中心點高亮的高斯核。對於我們檢測出所有的可能的中心點,透過乘以這樣一箇中心位置加權矩陣,可以提高靠近中心的人物權重,因為最終我們只取一個最靠近影象中心的。

乘以權重後,就是常見的argmax操作求出最大值點的座標,這就是最終檢測目標的中心點。拿到這個座標就可以去head_reg的2K個通道對應座標位置取出2K個值,然後加上中心點座標,這就得到粗略的關鍵點位置了。我一開始以為這裡是檢測的主力輸出,但是後續發現,這裡的關鍵點其實很不準的,因為只是粗暴的迴歸座標偏移。

它的實際作用是,對於每一個粗略的關鍵點座標,咱們再生成一個以這個座標點為中心的權重矩陣,這裡也沒用高斯核了,直接0-47等差數列構造即可。

構造好一個粗略關鍵點座標最小、周邊遞增的權重矩陣後,再加上一個常數(比如1。8)防止除0,然後就把一開始的head_heatmap除以這個權重矩陣,再分別透過K個通道求argmax,得到精細化的關鍵點座標。為什麼要這麼做呢?

其實思想很簡單,就是透過粗定位的關鍵點範圍,然後加權取去找最可能屬於當前人物的關鍵點,因為前面說過了我們是Bottom-Up的方案,head_heatmap檢測的是所有人的所有關鍵點。透過這樣一步操作,就可以取出最靠近中心點的人的關鍵點了。

最後再根據座標點去head_offset對應座標位置取出offset的值加上即可。置信度就是head_heatmap的sigmoid後的值。

3。2。2 資料處理

終於分析完模型結構和後處理流程,但是依舊不能開始訓練,因為我們還要喂資料、定目標函式。

資料構造其實弄明白後處理流程後也不難了,一個值得注意的問題是heatmap的高斯核如何構造。一開始我使用的是cv2。GaussianBlur生成的,視覺化看過還行,後來debug發現一個問題,單個點沒影響,但是當存在多個接近的關鍵點時,互相的高斯核極大值會受影響,可能變成比1小的值。於是乾脆拿了CenterNet和Lightweight OpenPose中的高斯核生成來嘗試,前者就是經典的高斯核,後者是按照指數曲線生成的,最終選擇了後者。因為MoveNet後處理中,存在一個乘權重然後取最大值的步驟,為了增加不同點的區分度(比如隔得遠的點置信度為1,近的0。9,這時候應該取近的0。9這個點),那麼應該增大不同距離點的權重差,但是為了減少同一個點的heatmap範圍內變中心點改變(比如同一個高斯核內最大值1,次大0。9,但是0。9更靠近中心,這時候還是應該取1),那麼應該減少相鄰點間隔。在這兩點矛盾的情況下,權重矩陣又是谷歌提供的已知的值,比較合理的一個方案就是選擇指數曲線生成的熱力圖,即增大同一個高斯核中不同點的差值;最後還要注意高斯核的大小半徑,可以當作超引數來調整,建議覆蓋到原圖上分析是否合理,最好根據不同的目標尺寸設定不同的半徑大小。

另外一個細節是,如果只給中心點座標對應的head_reg上那一個點賦值,每次去取回歸值的時候,由於只有一個點,學習起來比較困難,因此我是給周圍一圈也賦值了,只是要注意賦值座標大小要對應加減。

3。2。3 損失函式

一般來說,對於這種heatmap形式的資料,比較常用的是L2 loss,比如Lightweight OpenPose,而CenterNet使用的是Focal loss,其實Focal loss也是從L2 loss最佳化而來,只是根據類別加權處理類別不平衡的問題,根據置信度加權處理難易樣本的問題。

最終我採用的是加權版的MSE,相當於平衡了正負樣本,因為heatmap+高斯核的方式背景佔比很大,但是沒有加Focal loss中的gamma,因為實驗效果不好。這個加權也很好實現,因為我們的label就是取值0-1的矩陣,直接乘以k然後加1,就變成取值1到k+1的範圍,即取值1的位置對應權重k+1,取值0也就是背景對應權重1,這個k可以根據資料情況自己調節,參考取值5-10,參考程式碼如下:

loss = torch。pow((pre-target),2)weight_mask = target*k+1#gamma = torch。pow(torch。abs(target-pre), 2)loss = loss*weight_mask #*gamma

最終head_heatmap和head_center採用了加權MSE,head_reg和head_offset採用了L1 Loss,也是參考的CenterNet。

最後需要考慮的就是不同loss的權重問題,前期除錯的時候由於量級存在差異(head_reg)是絕對座標差值,我是設定的head_heatmap:head_center:head_reg:head_offset=1:1:0。1:1,最終最佳化好之後,直接採用1:1:1:1。

至此,整個MoveNet就已經復現差不多了,跑出來的acc能達到95,再稍微修復了一些bug,優化了一些細節,基本能跑到97了。但是直接跑影片demo視覺化還是不是特別滿意,因此需要以此為baseline,深度最佳化。

四、煉丹之道

既然有了baseline,訓練程式碼也搭建好了,就是喜聞樂見的煉丹環節了。

其實復現MoveNet的過程中就包含了一些最佳化,比如loss選擇、高斯核生成,因為一開始效果不好,你不知道是復現的不對還是沒有最佳化好。這裡資料迭代清洗、一般的資料增強就不多說了,就說一些印象比較深的吧。

我的建議是先透過視覺化分析+實驗驗證確定好資料增強方案,然後再進行模型結構的調整,最後進行loss最佳化以及各種超引數調整,這樣可以一定程度上避免改了東牆測西牆的重複實驗。

首先是資料擴充,谷歌本身除了使用清洗後的COCO資料集,也自己從youtube上爬了一些瑜伽、健身之類的影片然後生成圖片和標註,因為原始COCO、MPII之類的圖片,還是缺少一些瑜伽之類的特殊的姿態的,這就會造成資料不平衡(類似人臉關鍵的中的張嘴閉眼),於是除了考慮程式碼中加入資料平衡,最好的方式也是擴充一些資料,因此我也從B站上下了一些瑜伽、健身、體操、舞蹈等影片標註;

其次是資料增強有兩點值得一提,

一是常見的映象翻轉

,分類任務中翻了就翻了,目標檢測中要把目標框的橫座標同樣翻轉,而人體姿態估計更進一步,對關鍵點橫座標翻轉之後,還要修改對應關鍵點的順序,比如左手腕的圖片水平映象翻轉後,它就不再是左手腕而變成右手腕了,這是一個小坑,不過閱讀一些開原始碼應該也能看到相應的處理;

第二點就是隨機裁剪crop增大目標範圍

,主要是初步驗證的時候發現泛化效果不好,經過簡單資料分析,發現訓練集的關鍵點區域面積集中在2000附近:

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

再看看目標場景採集的幾百張圖片的關鍵點區域面積分布,範圍是2000-12000,且峰值在6000-8000:

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

那麼就可以針對性得調整隨機crop的機率、crop的範圍等,最後得到訓練集資料增強後的分佈如下,可以看到相比原始分佈已經好很多了:

輕量級人體姿態估計模型的修煉之路(附MoveNet復現經驗)

接著就是模型結構的最佳化,谷歌原始方案居然是使用的MobilenetV2,有點奇怪,據個人經驗來說,這幾個常見的輕量級模型效果一般排序是MobileNetV3≈ShuffleNetV2 >= MobilenetV2 >= MobilenetV1 ≈ShuffleNetV1,如果谷歌礙於自家產品不使用Shufflnet能理解,那為什麼不用MobileNetV3呢?分別加上FPN上手跑跑,原始MoveNet使用的FPN分別融合了四個特徵層,而由於網路結構block的差異,MobileNetV3和ShuffleNetV2我均只融合了三個特徵層。經過大量實驗測試,以及一些經驗化剪枝,最後選定的是ShuffleNetV2+FPN,寬度因子為0。75,同時對通道數做了一定的剪枝。

同時把Sigmoid換成了一個近似實現:0。5 * (x/(1+torch。abs(x)))+0。5,訓練精度差不多,且速度略快幾毫秒,而且還順便解決了推理工具結果不對齊的問題。

後來等模型訓練過程中刷到了一篇文章《姿態估計技巧總結》,嘗試了其中一些方案,其中Bone Loss還是有提升的,AID也有輕微提升不過不明顯,Automatic Weighted Loss對此模型沒有明顯效果,嘗試了Mish速度下降很多,也就沒有訓練了。

最後就是後處理的程式碼實現,因為涉及一些矩陣運算,本來是打算用C++版的OpenCV的Mat運算來做的,後來發現其實涉及的矩陣運算也就是一些element-wise操作,且特徵圖大小也就48*48,於是乾脆用一維陣列來做了,一次迴圈就可以搞定乘權重和記錄極大值座標,時間複雜度O(1)。

至此,整個專案也就接近了尾聲,自己挖的坑終於填的七七八八,最終在驗證集、測試集上acc都達到了99%(都這麼高了,也就沒打算蒸餾了),速度在嵌入式CPU上能跑到60+ms。視覺化效果也還不錯,不過依舊有提升空間,鑑於驗證集已經很高了,後續主要的最佳化方向應該是擴充資料了。

五、總結

總結一下,一開始不熟悉人體姿態估計領域,走了一些彎路。同時在方案選擇中也做了不少貌似無用的嘗試,不過也正是對Simple Baselines和Lighweight OpenPose的熟悉,才讓自己有機會深入瞭解人體姿態估計的相關流程,從而根據一個MoveNet的模型檔案就復現出整個訓練流程。最終經過最佳化,精度接近飽和,速度也從原始Movenet純backbone跑80ms提升到了包含後處理整個流程達到60多ms。

最後慣例來個展望吧,時間有限,還有很多可以嘗試的東西,列出一些供參考:

我的場景首先要保證速度可以接受,其次才是精度,因此這套方案的精度還有很大的提升空間,如果是用高階手機來跑、甚至是GPU終端,換用容量更大的backbone,應該可以達到很高的精度;

嘗試一下DSNT、DARK的方案;

嘗試下Adversarial Semantic Data Augmentation for Human Pose Estimation論文提出的A資料增強,mpll資料集評測榜達到94。1%,貌似目前最高的;

量化感知訓練(QAT),因為PyTorch的QAT貌似不支援匯出onnx,也就無法轉換到推理框架使用,因此沒有做。而訓練後量化實際加速很少,掉點明顯,分類任務還好,MoveNet有精細化的heatmap乘以權重的操作,誤差影響更大所以也不考慮;後續可以考慮使用Tensorflow來做QAT,因為本身谷歌MoveNet就是TF訓練的模型;

試試新出的MicroNet,今年的輕量級網路,關注了一段時間最近程式碼也開源了,論文實驗表示甩了Mobilenetv3和ShuffleNetv2一大截,有空可以玩玩;

才疏學淺,有不對的地方歡迎指出,也歡迎友好交流討論。

參考資料

[1]Learning Human Pose Estimation Features with Convolutional Networks

[2]DeepPose Human Pose Estimation via Deep Neural Networks

[3]Joint Training of a Convolutional Network and aGraphical Model for Human Pose Estimation

[4]Joint Training of a Convolutional Network and aGraphical Model for Human Pose Estimation

[5]Convolutional Pose Machine

[6]DeepCut: Joint Subset Partition and Labeling for Multi Person Pose Estimation

[7]Stacked hourglass networks for human pose estimation

[8]Towards Accurate Multi-person Pose Estimation in the Wild

[9]Learning Feature Pyramids for Human Pose Estimation

[10]Multi-Context Attention for Human Pose Estimation

[11]A Cascaded Inception of Inception Network with Attention Modulated Feature Fusion for Human Pose Estimation

[12]Learning to Refifine Human Pose Estimation

[13]Simple Baselines for Human Pose Estimationand Tracking

[14]Deeply Learned Compositional Models for Human Pose Estimation

[15]RMPE: Regional Multi-Person Pose Estimation

[16]Cascaded Pyramid Network for Multi-Person Pose Estimation

[17]Numerical Coordinate Regression with Convolutional Neural Networks

[18]OpenPose: Realtime Multi-Person 2D Pose Estimation using Part Affifinity Fields

[19]Real-time 2D Multi-Person Pose Estimation on CPU: Lightweight OpenPose

[20]Human Pose Estimation with Spatial Contextual Information

[21]Cascade Feature Aggregation for Human Pose Estimation

[22]Rethinking on Multi-Stage Networks for Human Pose Estimation

[23]Spatial Shortcut Network for Human Pose Estimation

[24]Deep High-Resolution Representation Learning for Human Pose Estimation

[25]Simple Pose Rethinking and Improving a Bottom-up Approach for Multi-Person Pose Estimation

[26]Simple and Lightweight Human Pose Estimation

[27]Fast Human Pose Estimation

[28]Global Context for Convolutional Pose Machines

[29]Toward fast and accurate human pose estimation via soft-gated skip connections

[30]Adversarial Semantic Data Augmentation for Human Pose Estimation

[31]Deep Learning-Based Human Pose Estimation: A Survey

[32]實時檢測17個人體關鍵點,谷歌SOTA姿態檢測模型,手機端也能執行:https://xw。qq。com/cmsid/20210725A049IW00

[33]TFBlog:Next-Generation Pose Detection with MoveNet and TensorFlow。js:https://blog。tensorflow。org/2021/05/next-generation-pose-detection-with-movenet-and-tensorflowjs。html

[34]TFHub:movenet/singlepose/lightning:https://tfhub。dev/google/movenet/singlepose/lightning/4

[35]姿態估計技巧總結(2021。9。10更新):https://zhuanlan。zhihu。com/p/34

推薦文章