傳統演算法和深度學習的結合和實踐,解讀與優化 deepfake
前言
前一段時間用於人物換臉的deepfake火爆了朋友圈,早些時候Cycle GAN
就可以輕鬆完成換臉任務,其實換臉
是計算機視覺常見的領域,比如Cycle GAN
,3dmm
,以及下文引用的論文均可以使用演算法實現換臉(一定程度上能模仿表情),而不需要使用PS等軟體手工換臉(表情僵硬,不符合視頻上下文),只能說deepfake用一個博取眼球的角度切入了換臉演算法,所以一開始我並沒有太過關注這方面,以為是Cycle GAN
乾的,後來隱約覺得不對勁,因為GAN系列確實在image to image
的領域有著非凡的成績,但GAN的訓練是出了名的不穩定,而且收斂時間長,某些特定的數據集時不時需要有些trick,才能保證效果。但deepfake似乎可以無痛的在各個數據集里跑,深入閱讀開源代碼後(https://github.com/deepfakes/faceswap),發現這東西很多值得一說的地方和優化的空間才有了這一篇文章。
(本文首發於公眾號AI研習社)
本文主要包括以下兩方面:
- 解讀deepfake的model和預處理與後處理的演算法以引用論文。(目前大多文章只是介紹了其中的神經網路,然而這個項目並不是單純的end2end的輸出,所以本文還會涉及其他CV的演算法以及deepfake的介紹)
- 引入膚色檢測演算法,提升換臉的視覺效果。
乾貨和口水齊飛,各位客官可安心食用
DeepFake Model
雖然原作者沒有指出,但從模型和整體方法設計來說,該模型應該是參考了論文https://arxiv.org/abs/1611.09577,其網路結構總體仍是encoder - decoder的形式,但與我們所熟知autoencoder不同的是,他由一個Encoder和兩個Decoder組成,兩個Decoder分別對應imageA和imageB的解碼。
- Encoder部分採用了簡單的堆疊5x5卷積核,採用aplha=0.1的LeakRelu作為激活函數。
- Decoder部分使用了卷積和PixelShuffer來做上採樣,結構上採用了4x4,8x8……64x64這樣逐解析度增加的重建方式(網路整體是類U-net的結構)。
(圖為u-net)
如果你想要復現和改進模型的話,需要主要一點的是,雖然我們期望輸入A臉然後輸出B臉,輸入B臉輸出A臉,但訓練卻不把AB臉作為pair輸進神經網路(輸入A臉,期望在另一端獲得B臉),仍然是像訓練普通autoencoder的一樣,我給出A臉,你要復原A臉,B臉亦然。(用不同的decoder),這樣訓練的結果是decoderA能學會用A的信息復原A,decoderB用B的信息復原B,而他們共用的Encoder呢?則學會了提取A,B的共有特徵,比如眼睛的大小,皮膚的紋理,而解碼器根據得到的編碼,分別找對應的信息復原,這樣就能起到換臉的效果了。
而Encoder獲取到共同的特徵,比單獨學習A/B的特徵,信息要損失得更為嚴重,故會產生更模糊得效果,另一個照片模糊得原因是autoencoder使用得是均方誤差(mse)這一點已經是不可置否的了,後文提及的使用GAN來優化,可以一定程度上緩解模糊的問題。
預處理和後處理
在文處,我就強調了這個不是end2end的東西,接下來就著找介紹deepfake里的預處理和後處理。
我們都知道在CV里用深度學習解決問題前,需要用進行數據增強,然而涉及人臉的數據增強的演算法和平時的有一點點不一樣。
在開源代碼中,作者分別使用了random_transform
,random_warp
兩個函數來做數據增強。但這個兩個函數只是做一些一些有關比例之類的參數的封裝,真正做了轉換的是opencv的warpAffine
,rmap
,兩個函數。下面分別解讀這兩個函數做了些什麼。
首先解讀rmap
其直譯過來就是重映射,其所做的就是將原圖的某一個像素以某種規則映射到新的圖中。利用該函數,可以完成圖像的平移,反轉等功能。
在數據增強中,我們不希望改動數據會影響label的分布,在常見的有監督任務中,數據的標籤由人工打上,如類別,位置等,圖像的扭曲,反轉不會影響到label的分布,但在deepfake中,我們做的是生成任務,作為無監督任務中的一種,其反向轉播的誤差由圖像自己的提供,而要使得數據增強後(代碼中的warped_image
)有對應的樣本(代碼中的target_image
),作者使用了rmap
構造除warped_image
,而使用umeyama
和warpAffine
構造出target_image
。
umeyama
是一種點雲匹配演算法,簡單點來理解就是將源點雲(source cloud)變換到目標點雲(target cloud)相同的坐標系下,包含了常見的矩陣變換和SVD的分解過程,(礙於篇幅本文不作詳解)。調用umeyama
後獲取變換所需的矩陣,最後將原圖和所求得矩陣放進warpAffine
即可獲的增強後對應的target_image。其中warpAffine
的功能就是根據變換矩陣對源矩陣進行變換。
上圖是經過變型處理的warped_image
,下圖是target_image
.
後處理
說完了數據增強部分後,我們來分解後處理。
在deepfake(上述鏈接中)的命令行版本中,有一個-P
參數,選中後可以實時演示圖片的變化過程。在通過預覽這個演變過程中,不難發現進入神經網路的不是整張圖片,也不是使用extract
出來的整個256x256的部分(頭像),而是僅僅只有臉部的小區域(64x64)。因此在預測階段,首先就是截取人臉,然後送進網路,再根據網路的輸出覆蓋原圖部分。
至於將頭像部分傳進網路,也並非不行,臉部還是會可以進行轉換,但背景部分也會變得模糊,且很難修復,因此我們只選擇臉部替換。
在臉部替換後,會出現如下問題:
- 膚色差異,即使是同種人,也會有細微的差異。
- 光照差異,每張照片的光照環境不同
- 假臉邊界明顯
前兩者的造成原因一是客觀差異,二是和數據集的大小相關,作為想給普通的用戶用,數據集太大了,用戶承受不起,數據集太小,神經網路學習不多。
至於最後一點則是前兩者造成的,但這一點可以通過降低解析度緩解。這也是很多網上小視頻假臉邊界不明顯的原因,因為很少會有一張臉占屏幕80%的畫面。但如果你直接用在256x256的頭像圖上則邊界效果明顯(如下圖)
(原圖,下文所有圖片的原圖都是這個,由官方提供)
該圖使用的是官方提供的預訓練權重和數據。接下來在試試低尺寸下的視覺效果
使用64x64後,相對來說,邊界效果沒那明顯了。
至於另外的兩個問題,官方給出了下面的幾種後處理方法緩減:
smooth_mask
這個方法解釋其實起來很簡單,你神經網路輸出的圖像不是很模糊嗎?要模糊變清晰很難,但清晰變糊還不簡單嗎?直接用高斯模糊將邊界進行處理,從而讓過度看起來自然。
adjust_avg_color
這個方法背後的理論同樣很簡單,假設A圖要換成B圖,那麼做法就是A圖加上自身和B圖的每一個像素的均值的差值,算是作為一種色彩的調和。
(左圖未經處理,右圖經過上述兩種方法處理。)
以上兩種便是deepfake默認的處理方式。下面介紹另外一種圖像編輯常用的演算法,這種演算法作為deepfake的後備選項,由參數-S
控制。
泊松融合
此外,deepfake給出了基於泊松融合演算法 的來進行後處理,泊松融合的大致思想提供一個一個mask
矩陣,背景區域為0,ROI區域(region of insteresing 這裡就是指臉部,下文同一簡稱ROI)的區域為255,演算法通過該矩陣得知拿一步分是融合的部分,然後通過計算梯度,用梯度場作為指示,修改ROI的像素值,使得邊界與原圖更為貼切。
(圖片源於網路)
deepfake中的泊松融合可以選擇兩種模式。一種以人臉矩形框為邊界,另一種以人的特徵點(即人臉輪廓和眼睛輪廓)為邊界。
(左圖未經處理,右圖在整個替換區域進行泊松融合)
事實上,這裡得補充一點,人臉檢測和定位如果不想自己實現,一般有兩種實現方法(在本地實現),一種是使用dlib庫提供的api,另一種是使用opencv。dlib,face_recongize的模型比opencv的精度要高的,但要自己下載模型(模型比較大),且這個庫的編譯在windows上比較麻煩,但對於特徵點檢測,opencv沒有現成的特徵點檢測的介面。如果有童孩不想依賴dlib,這裡提供一種方法來代替在泊松融合時的特徵點定位問題。(人臉檢測可以使用opencv即可)
膚色檢測
顯然,我們選擇人臉的特徵點的位置信息,目的時為了只替換人臉,這樣可以盡量將信息損失(模糊)局限於人臉部分,而其他部分則保留原圖的清晰度,而我們剛才說過了,deepfake並不將全圖放進神經網路,而是將人臉部分(由人臉檢測演算法確定),定位後的ROI是以人臉為主的矩形,這時唯一的膚色就只有人臉部分了,不用太過擔心其餘噪音干擾。
如果再人臉定位這一步出錯,那麼使用膚色檢測還是人臉特徵點兩種方法,都不會有太大差別。因此,使用膚色檢測在這種場景上,在效果上一定程度能代替人臉特徵點檢測這種方法。
下面解釋膚色檢測如何使用。總的來說,膚色檢測一般常見RGB,HSV和YCrCb空間的檢測,所謂的YCrCb空間,Y代表的是亮度,Cr 與Cb代表的都是色度,而HSV空間H代表色調,S飽和度,V亮度,RGB則是常見的紅綠藍空間。
下面只介紹RGB空間下的膚色檢測,無需依賴其他庫,手寫即可,亦可以達到不錯的效果。
規則部分:
- R>G and R>B and |R - G| > 15
- 在(1)滿足下,(R > 95) and (G > 40) and (B > 20) and (max(R, G, B) - min(R, G, B) > 15)
- 在(1)滿足,(2)不滿足下,(R > 220) and (G > 210) and (B > 170),則可認為該像素是膚色。
( 左圖未經處理,右圖經過膚色模型構造mask矩陣,再進行泊松融合)
可以優化的空間
最後說說deepfake可以優化的空間。
deepfake出現後也有很多工作對deepfake進行優化,包括使用GAN的,這些優化的針對生成圖像的質量,但目前看質量沒有太大的提升,同時幾乎沒有工作是針對模型的訓練速度和圖像的後處理。
本文最後提出的膚色檢測代替原來人臉特徵點檢測的,算是一種補充。
我也曾經嘗試過一些模型壓縮的演算法,雖然在原始數據下可以恢復精度,但遷移的能力差(因為參數少了)。而deepfake的目的是做成一款app,(已經有了,叫fakeapp,在deepfake的基礎上添加了GUI),那麼就不能不考慮軟體的體積,fakeapp共1.8G,以及沒有GPU的普通用戶在自己數據集上遷移的時間。
在Reddit上,作者是指出,在GPU上模型訓練要幾小時,而CPU要近3天,這已經超出很多人的忍受範圍了。
深度學習走入尋常百姓家,尤其是有自定製需求的深度學習,仍然任重道遠。
推薦閱讀:
※利用點雲掃描技術增強FM視覺功能
※【生成高清人臉】ProgressiveGAN 筆記
※圖像檢索之Large-Scale Image Retrieval with Attentive Deep Local Features
※【技術綜述】從alexnet到resnet,初探深度學習演算法玩攝影
※Rocket Training: 一種提升輕量網路性能的訓練方法
TAG:計算機視覺 | 深度學習DeepLearning |