還記得在2018月3月份火爆reddit的deepfake嗎?將視頻中的頭換成另外一我的的頭像,雖然可能有些粗糙和模糊,可是在分辨率不要求很高的狀況下能夠達到以假亂真的效果。git
舉個栗子,以下圖中將希拉里換成特朗普的一段演講視頻。程序員
另外還有實現川普和尼古拉臉相換:github
固然這只是DeepFake的冰山一角,Deepfake當初火起來的緣由能夠說是廣大擁有宅男心態的程序員們一塊兒奮鬥的結果。那就是,呃,能夠將你想要的某張臉換到AV中去。固然這裏就不進行演示了,而且相關的reddit論壇已經被禁止。因此這裏就很少進行討論啦。算法
本文爲 github.com/Oldpan/Face… 代碼的搭配教程(填一下以前埋得坑),這裏簡單對此進行講解下,填補一下以前的空缺。bash
其實有關深度學習的換臉相關的研究已經很普及了,有基於GAN
的也有基於Glow
的,但本質上都是生成模型,只是換了一種實現方式,而這個DeepFake呢,使用的是機器學習中的自編碼器,擁有與神經網絡相似的結構,魯棒性較好,咱們能夠經過學習它來對生成網絡有一個大概的瞭解,這樣以後碰到類似的網絡或者構造就好上手了。網絡
人臉互換是計算機視覺領域中一個比較熱門的應用,人臉互換通常能夠用於視頻合成、提供隱私服務、肖像更換或者其餘有創新性的應用。最先以前,實現人臉互換是經過分別分析二者人臉的類似信息來實現換臉,也就是經過特徵點匹配來提取一張臉中例如眉毛、眼睛等特徵信息而後匹配到另外一張人臉上。這種實現不須要進行訓練,不須要的數據集,可是實現的比較差,沒法本身修改人臉中的表情。機器學習
而在最近發展的深度學習技術中,咱們能夠經過深度神經網絡提取輸入圖像的深層信息,從而讀取出其中隱含的深層特徵來實現一些新奇的任務,好比風格遷移(style transfer)就是經過讀取訓練好的模型提取圖像中的深層信息來實現風格互換。函數
也有使用神經網絡進行人臉互換(face-swap),其中使用VGG網絡來進行特徵提取並實現人臉互換。這裏咱們經過特殊的自編碼器結構來實現人臉互換,而且達到不錯的效果。學習
自編碼器相似於神經網絡,能夠說是神經網絡的一種,通過訓練後可以嘗試將輸入複製到輸出。自編碼器和神經網絡同樣,有着隱含層測試
(自編碼器的結構,x爲輸入,f爲編碼函數,將x編碼爲隱含特徵變量h,而g爲解碼網絡,經過將隱變量h進行重構獲得輸出結果r,咱們也能夠看到數字2被放入編碼器以後獲得其隱含層的編碼也就是Compressed representation,以後經過解碼器從新生成出來)
現代的自編碼器從宏觀上也能夠理解爲隨機映射
關於更多自編碼器的知識:理解深度學習:與神經網絡類似的網絡-自編碼器(上)
那麼應該如何經過自編碼器實現咱們的換臉技術呢?
在以前咱們已經知道了自編碼器能夠學習輸入圖像的信息從而對輸入圖像信息進行編碼並將編碼信息存到隱含層中,而解碼器則利用學習到的隱含層的信息從新生成以前輸入的圖像,可是若是咱們直接將兩個不一樣個體圖像集的圖像輸入到自編碼器當中會發生什麼呢?
如上圖,假如咱們僅僅是簡單地將兩張不一樣的臉的集合扔到自編碼網絡中,而後挑選一個損失函數去訓練,但這樣去訓練咱們是什麼也得不到的,所以咱們須要從新設計一下咱們的網絡。
怎麼設計呢?
既然咱們想要將兩張臉互換,那麼咱們能夠設計兩個不一樣的解碼網絡,也就是使用一個編碼網絡去學習兩張不一樣人臉的共同特徵,而使用兩個解碼器去分別生成他們。
如上圖,也就是咱們設計一個輸入端或者說一個編碼器(分別輸入兩個不一樣的臉),而後兩個輸出端或者說兩個解碼器,這樣咱們就能夠經過隱含層來分別生成兩張不一樣的人臉了。
這樣如此的話,咱們的具體構架以下:
如上圖,能夠看到這個自編碼器有一個input端而有兩個output端,在input端分別輸入兩個不一樣的人臉集(尼古拉和川普),而後在輸出端再從新生成以前的人臉,注意,這裏的每一個解碼器分別負責生成不一樣個體的臉。而在隱含層則學習到了兩個不一樣個體的共同信息,從而兩個不一樣的解碼器能夠根據學習到的共同信息去還原以前輸入的圖像。
再具體點就是這樣:
如上圖,咱們將兩個不一樣個體的圖像集分別進行進行輸入,此時的Encoder是同一個編碼器,隨後將使用同一個Encoder生成的共同的隱含信息。再利用兩個不一樣個體圖像的解碼器A、B從新生成各自的圖像進行損失標準(criterion)進行比較(這裏損失採用L1損失函數),經過Adam優化算法進行梯度降低。
以後咱們利用解碼器A、B分別去從新生成由輸入圖像B、A後隱含層學習到的信息,以下公式:
下面則是以前提到的結構的具體的網絡設計,咱們能夠看到網絡結構有一個輸入端和兩個輸出端,輸入端由卷積層和全鏈接層構成,而輸出端則一樣由卷積層構成,可是須要注意這裏的輸入端是下采樣卷積,而輸出端則是上採樣卷積,也就是圖像的分辨率是先變低再慢慢升高。
能夠看下Pytorch中網絡設計的代碼:
class Autoencoder(nn.Module):
def __init__(self):
super(Autoencoder, self).__init__()
self.encoder = nn.Sequential( # 編碼網絡
_ConvLayer(3, 128), # 3 64 64
_ConvLayer(128, 256), # 32/2=16
_ConvLayer(256, 512), # 16/2=8
_ConvLayer(512, 1024), # 8/2=4
Flatten(),
nn.Linear(1024 * 4 * 4, 1024),
nn.Linear(1024, 1024 * 4 * 4),
Reshape(),
_UpScale(1024, 512),
)
self.decoder_A = nn.Sequential( # 解碼網絡
_UpScale(512, 256),
_UpScale(256, 128),
_UpScale(128, 64),
Conv2d(64, 3, kernel_size=5, padding=1),
nn.Sigmoid(),
)
self.decoder_B = nn.Sequential(
_UpScale(512, 256),
_UpScale(256, 128),
_UpScale(128, 64),
Conv2d(64, 3, kernel_size=5, padding=1),
nn.Sigmoid(),
)
def forward(self, x, select='A'):
if select == 'A':
out = self.encoder(x)
out = self.decoder_A(out)
else:
out = self.encoder(x)
out = self.decoder_B(out)
return out
複製代碼
上述代碼網絡能夠由下圖的圖例所表示:
可是這些結構都是能夠變化的,其中卷積核的大小能夠按照需求調整,而全鏈接這種能夠打亂空間結構的網絡咱們也能夠尋找相似的結構去代替。另外,在解碼器階段的最後一層還採用了Sub-pixel的上採樣卷積技術(在本博客的 一邊Upsample一邊Convolve:Efficient Sub-pixel-convolutional-layers詳解 一文中有對此技術的詳細講解)能夠快速而且較好地生成圖像的細節。
總之,咱們想實現換臉的操做,在總體結構不變的基礎上,須要知足如下幾點:
如上圖,也就是相似於VGG的編碼網絡、還要能夠打亂空間結構結構的全鏈接網絡、以及能夠快速且較好地上採樣圖像的Sub-Pixel網絡。咱們進行了額外的測試,發現做爲編碼網絡的話,傳統的VGG形式的網絡結構的效果最好,可使損失函數降到最低。可是若是採用其餘較爲先進的網絡,其效果並無傳統的VGG構架好,這也是爲何風格遷移和圖像生成使用VGG網絡格式更多一些。
一樣,若是咱們將全鏈接網絡從編碼器中去掉或者使用卷積網絡代替,那麼圖像是沒法正常生成的,也就是編碼器學習不到任何有用的知識,可是咱們可使用1x1的卷積網絡去代替全鏈接網絡,1x1網絡如:
nn.Conv2d(1024, 128, 1, 1, 0, bias=False),
nn.Conv2d(128, 1024, 1, 1, 0, bias=False),
複製代碼
一樣也擁有打亂空間結構的特性,優勢是比全鏈接網絡運行更快,可是效果並無全鏈接網絡好。
至此,咱們簡單說明了基本構架以及網絡層的選擇。
固然訓練的時候是有不少小技巧的,由於咱們須要隱含層學習到兩個不一樣個體的共同特徵,咱們能夠採起一些小Tricks來讓咱們的訓練過程更快更平滑,相似於以前談到的 淺談深度學習訓練中數據規範化(Normalization)的重要性 ,咱們要作的就是使訓練的圖像的分佈信息儘量相近:
如上圖,咱們能夠將圖像A(川普)集加上二者圖像集的平均差值(RGB三通道差值)來使兩個輸入圖像圖像的分佈盡能夠相近,這樣咱們的損失函數曲線降低會更快些。
拿代碼表示則爲:
images_A += images_B.mean(axis=(0, 1, 2)) - images_A.mean(axis=(0, 1, 2))
複製代碼
固然還有圖像加強技術,這個技術就沒必要多說了,基本是萬能的神器了。咱們能夠旋轉、縮放、翻轉訓練圖像從而使圖像的數量翻倍進而增長訓練的效果。
如上圖,對於人臉來講,使用扭曲的加強技術能夠有效地下降訓練過程當中的損失值,固然加強也是有限度的,不要太過,物極必反。哦對了,還忘了說,咱們訓練的時候使用的臉部圖像只從原圖截取了包含臉部的部分,好比上圖右上角的aligned image
,咱們使用OpenCV庫截圖臉部圖像做爲訓練素材。
至於圖像後處理,固然是將咱們生成的臉部圖像從新拼回去了:
這裏使用了泊松融合以及Mask邊緣融合的方法,咱們能夠很容易地看出融合的效果。
總得來講,這個換臉技術是一個結構簡單可是知識點豐富的一個小項目,其結構簡單易於使用以及修改,而且能夠生成不錯的效果,可是由於其擁有較多的參數,其運行速度並非很快(固然咱們能夠經過改變編碼層和解碼層結構加快訓練生成的速度),而且對於臉部有異物的圖像可能會生成不真實的效果。
這是由於自編碼器網絡並無針對圖像中須要學習的部位進行學習而是所有進行了學習,固然會有不少雜質,這能夠經過注意力的機制適當改善。
就說這些吧~
文章來源於OLDPAN博客,歡迎來訪:Oldpan博客
歡迎關注Oldpan博客公衆號,持續醞釀深度學習質量文: