0
本文作者: 孔令雙 | 2018-03-02 11:53 |
雷鋒網(wǎng) AI 研習(xí)社按:本文為知乎主兔子老大為雷鋒網(wǎng) AI 研習(xí)社撰寫的獨家稿件。
前一段時間用于人物換臉的deepfake火爆了朋友圈,早些時候Cycle GAN就可以輕松完成換臉任務(wù),其實換臉是計算機視覺常見的領(lǐng)域,比如Cycle GAN ,3dmm,以及下文引用的論文均可以使用算法實現(xiàn)換臉(一定程度上能模仿表情),而不需要使用PS等軟件手工換臉(表情僵硬,不符合視頻上下文),只能說deepfake用一個博取眼球的角度切入了換臉?biāo)惴?,所以一開始我并沒有太過關(guān)注這方面,以為是Cycle GAN干的,后來隱約覺得不對勁,因為GAN系列確實在image to image領(lǐng)域有著非凡的成績,但GAN的訓(xùn)練是出了名的不穩(wěn)定,而且收斂時間長,某些特定的數(shù)據(jù)集時不時需要有些trick,才能保證效果。但deepfake似乎可以無痛的在各個數(shù)據(jù)集里跑,深入閱讀開源代碼后(https://github.com/deepfakes/faceswap),發(fā)現(xiàn)這東西很多值得一說的地方和優(yōu)化的空間才有了這一篇文章。
本文主要包括以下幾方面:
解讀deepfake的model和預(yù)處理與后處理的算法以引用論文。(目前大多文章只是介紹了其中的神經(jīng)網(wǎng)絡(luò),然而這個項目并不是單純的end2end的輸出,所以本文還會涉及其他CV的算法以及deepfake的介紹);
引入膚色檢測算法,提升換臉的視覺效果。
干貨和口水齊飛,各位客官可安心食用。
雖然原作者沒有指出,但從模型和整體方法設(shè)計來說,該模型應(yīng)該是參考了論文https://arxiv.org/abs/1611.09577,其網(wǎng)絡(luò)結(jié)構(gòu)總體仍是encoder - decoder的形式,但與我們所熟知autoencoder不同的是,他由一個Encoder和兩個Decoder組成,兩個Decoder分別對應(yīng)imageA和imageB的解碼。
Encoder部分用了簡單的堆疊5x5卷積核,采用aplha=0.1的LeakRelu作為激活函數(shù)。Decoder部分使用了卷積和PixelShuffer來做上采樣,結(jié)構(gòu)上采用了4x4,8x8……64x64這樣逐分辨率增加的重建方式(網(wǎng)絡(luò)整體是類U-net的結(jié)構(gòu))。
(圖為u-net)
如果你想要復(fù)現(xiàn)和改進模型的話,需要主要一點的是,雖然我們期望輸入A臉然后輸出B臉,輸入B臉輸出A臉,但訓(xùn)練卻不把AB臉作為pair輸進神經(jīng)網(wǎng)絡(luò)(輸入A臉,期望在另一端獲得B臉),仍然是像訓(xùn)練普通autoencoder的一樣,我給出A臉,你要復(fù)原A臉,B臉亦然。(用不同的decoder),這樣訓(xùn)練的結(jié)果是decoderA能學(xué)會用A的信息復(fù)原A,decoderB用B的信息復(fù)原B,而他們共用的Encoder呢?則學(xué)會了提取A,B的共有特征,比如眼睛的大小,皮膚的紋理,而解碼器根據(jù)得到的編碼,分別找對應(yīng)的信息復(fù)原,這樣就能起到換臉的效果了。
而Encoder獲取到共同的特征,比單獨學(xué)習(xí)A的特征,信息要損失得更為嚴(yán)重,故會產(chǎn)生模糊的效果,另一個照片模糊得原因是autoencoder使用得是均方誤差(mse)這一點已經(jīng)是不可置否的了,后文提及的使用GAN來優(yōu)化,可以一定程度上緩解模糊的問題。
在文處,我就強調(diào)了這個不是end2end的東西,接下來就著找介紹deepfake里的預(yù)處理和后處理。
我們都知道在CV里用深度學(xué)習(xí)解決問題前,需要用進行數(shù)據(jù)增強,然而涉及人臉的數(shù)據(jù)增強的算法和平時的有一點點不一樣。
在開源代碼中,作者分別使用了random_transform,random_warp 兩個函數(shù)來做數(shù)據(jù)增強。但這個兩個函數(shù)只是做一些有關(guān)比例之類的參數(shù)的封裝,真正做了轉(zhuǎn)換的是opencv的warpAffine、rmap兩個函數(shù)。下面分別解讀這兩個函數(shù)做了些什么。
首先解讀rmap其直譯過來就是重映射,其所做的就是將原圖的某一個像素以某種規(guī)則映射到新的圖中。利用該函數(shù),可以完成圖像的平移,反轉(zhuǎn)等功能。
在數(shù)據(jù)增強中,我們不希望改動數(shù)據(jù)會影響label的分布,在常見的有監(jiān)督任務(wù)中,數(shù)據(jù)的標(biāo)簽由人工打上,如類別,位置等,圖像的扭曲,反轉(zhuǎn)不會影響到label的分布,但在deepfake中,我們做的是生成任務(wù),作為無監(jiān)督任務(wù)中的一種,其反向轉(zhuǎn)播的誤差由圖像自己的提供,而要使得數(shù)據(jù)增強后(代碼中的warped_image)有對應(yīng)的樣本(代碼中的target_image),作者使用了rmap構(gòu)造除warped_image,而使用umeyama和warpAffine構(gòu)造出target_image。
Umeyama是一種點云匹配算法,簡單點來理解就是將源點云(source cloud)變換到目標(biāo)點云(target cloud)相同的坐標(biāo)系下,包含了常見的矩陣變換和SVD的分解過程,(礙于篇幅本文不作詳解)。調(diào)用umeyama后獲取變換所需的矩陣,最后將原圖和所求得矩陣放進warpAffine即可獲的增強后對應(yīng)的target_image。其中warpAffine的功能就是根據(jù)變換矩陣對源矩陣進行變換。
上圖是經(jīng)過變型處理的warped_image ,下圖是target_image。
說完了數(shù)據(jù)增強部分后,我們來分解后處理。
在deepfake(上述鏈接中)的命令行版本中,有一個-P參數(shù),選中后可以實時演示圖片的變化過程。在通過預(yù)覽這個演變過程中,不難發(fā)現(xiàn)進入神經(jīng)網(wǎng)絡(luò)的不是整張圖片,也不是使用extract出來的整個256x256的部分(頭像),而是僅僅只有臉部的小區(qū)域(64x64)。因此在預(yù)測階段,首先就是截取人臉,然后送進網(wǎng)絡(luò),再根據(jù)網(wǎng)絡(luò)的輸出覆蓋原圖部分。
至于將頭像部分傳進網(wǎng)絡(luò),也并非不行,臉部還是會可以進行轉(zhuǎn)換,但背景部分也會變得模糊,且很難修復(fù),因此我們只選擇臉部替換。
在臉部替換后,會出現(xiàn)如下問題:
膚色差異,即使是同種人,也會有細微的差異。
光照差異,每張照片的光照環(huán)境不同
假臉邊界明顯
前兩者的造成原因一是客觀差異,二是和數(shù)據(jù)集的大小相關(guān),作為想給普通的用戶用,數(shù)據(jù)集太大了,用戶承受不起,數(shù)據(jù)集太小,神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)不多。
至于最后一點則是前兩者造成的,但這一點可以通過降低分辨率緩解。這也是很多網(wǎng)上小視頻假臉邊界不明顯的原因,因為很少會有一張臉占屏幕80%的畫面。但如果你直接用在256x256的頭像圖上則邊界效果明顯,如下圖:
(原圖,下文所有圖片的原圖都是這個,由官方提供)
該圖使用的是官方提供的預(yù)訓(xùn)練權(quán)重和數(shù)據(jù)。接下來在試試低尺寸下的視覺效果:
相對來說,邊界效果沒那明顯了。
至于另外的兩個問題,官方給出了下面的幾種后處理方法緩減:
smooth_mask
這個方法解釋其實起來很簡單,你神經(jīng)網(wǎng)絡(luò)輸出的圖像不是很模糊嗎?要模糊變清晰很難,但清晰變糊還不簡單嗎?直接用高斯模糊將邊界進行處理,從而讓過渡看起來自然。
adjust_avg_color
這個方法背后的理論同樣很簡單,假設(shè)A圖要換成B圖,那么做法就是A圖加上自身和B圖的每一個像素的均值的差值,算是作為一種色彩的調(diào)和。
(左圖未經(jīng)處理,右圖經(jīng)過上述兩種方法處理)
以上兩種便是deepfake默認的處理方式。下面介紹另外一種圖像編輯常用的算法,這種算法作為deepfake的后備選項,由參數(shù)-S控制。
此外,deepfake給出了基于泊松融合算法的來進行后處理,泊松融合的大致思想提供一個一個mask矩陣,背景區(qū)域為0,ROI區(qū)域(region of insteresing 這里就是指臉部,下文同一簡稱ROI)的區(qū)域為255,算法通過該矩陣得知拿一步分是融合的部分,然后通過計算梯度,用梯度場作為指示,修改ROI的像素值,使得邊界與原圖更為貼切。
( 圖片源于網(wǎng)絡(luò))
Deepfake中的泊松融合可以選擇兩種模式。一種以人臉矩形框為邊界,另一種以人的特征點(即人臉邊界和眼睛邊界)為邊界。
(左圖未經(jīng)處理,右圖在整個替換區(qū)域進行泊松融合)
事實上,這里得補充一點,人臉檢測和定位如果不想自己實現(xiàn),一般有兩種實現(xiàn)方法(在本地實現(xiàn)),一種是使用dlib庫提供的api,另一種是使用opencv。dlib,face_recongize的模型比opencv的精度要高的,但要自己下載模型(模型比較大),且這個庫的編譯在windows上比較麻煩,但對于特征點檢測,opencv沒有現(xiàn)成的特征點檢測的接口。如果有同學(xué)不想依賴dlib,這里提供一種方法來代替在泊松融合時的特征點定位問題。(人臉檢測可以使用opencv即可)
顯然,我們選擇人臉的特征點的位置信息,目的時為了只替換人臉,這樣可以盡量將信息損失(模糊)局限于人臉部分,而其他部分則保留原圖的清晰度,而我們剛才說過了,deepfake并不將全圖放進神經(jīng)網(wǎng)絡(luò),而是將人臉部分(由人臉檢測算法確定),定位后的ROI是以人臉為主的矩形,這時唯一的膚色就只有人臉部分了,不用太過擔(dān)心其余噪音干擾。
如果再人臉定位這一步出錯,那么使用膚色檢測還是人臉特征點兩種方法,都不會有太大差別。因此,使用膚色檢測在這種場景上,在效果上一定程度能代替人臉特征點檢測這種方法。
下面解釋膚色檢測如何使用??偟膩碚f,膚色檢測一般常見RGB,HSV和YCrCb空間的檢測,所謂的YCrCb空間,Y代表的是亮度,Cr與Cb代表的都是色度,而HSV空間H代表色調(diào),S飽和度,V亮度,RGB則是常見的紅綠藍空間。
下面只介紹RGB空間下的膚色檢測,無需依賴其他庫,手寫即可,亦可以達到不錯的效果。
檢測規(guī)則如下:
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),則可認為該像素是膚色。
(左圖未經(jīng)處理,右圖經(jīng)過膚色模型構(gòu)造mask矩陣,再進行泊松融合)
最后說說deepfake可以優(yōu)化的空間。
Deepfake出現(xiàn)后也有很多工作對deepfake進行優(yōu)化,包括使用GAN的,這些優(yōu)化的針對生成圖像的質(zhì)量,但目前看質(zhì)量沒有太大的提升,同時幾乎沒有工作是針對模型的訓(xùn)練速度和圖像的后處理。
本文最后提出的膚色檢測代替原來人臉特征點檢測的,算是一種補充。
我也曾經(jīng)嘗試過一些模型壓縮的算法,雖然在原始數(shù)據(jù)下可以恢復(fù)精度,但遷移的能力差(因為參數(shù)少了)。而deepfake的目的是做成一款app,(已經(jīng)有了,叫fakeapp,在deepfake的基礎(chǔ)上添加了圖形界面),那么就不能不考慮軟件的體積,fakeapp共1.8G,以及沒有GPU的普通用戶在自己數(shù)據(jù)集上遷移的時間。
在Reddit上,作者是指出,在GPU上模型訓(xùn)練要幾小時,而CPU要近3天,這已經(jīng)超出很多人的忍受范圍了。
深度學(xué)習(xí)走入尋常百姓家,尤其是有自定制需求的深度學(xué)習(xí),仍然任重道遠。
雷峰網(wǎng)特約稿件,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。