1. 程式人生 > >利用神經網路為大頭照生成卡通表情包(Memoji)

利用神經網路為大頭照生成卡通表情包(Memoji)

在今年釋出的 iOS 12 系統中,蘋果推出了一個有趣的新功能——Memoji,這是一種新型的 Animoji,可以用手機的前置攝像頭製作自己的專屬動畫頭像。這個功能剛推出的時候,網上就掀起一波晒 Memoji 的熱潮。


在玩 Memoji 的時候,有沒有想過僅從一張照片上就能生成一個 Memoji?本文就分享一下機器學習專家 Pat Niemeyer 的成果,使用神經網路為真實的人物照片生成相應的 Memoji。具體來說,他測試了 VGG16Face 模型,這是一個訓練用於人臉識別的網路,看看將真實照片和“看起來”像多種物件的 Memoji 比較時,它的效果怎樣。然後用它來指導選擇特徵,為新物件建立 Memoji。


程式碼地址見文末。

圖:為特朗普大頭照生成的Memoji(娘化了? 圖:為奧巴馬大頭照生成的Memoji


劇透

上面這兩張圖展示的就是神經網路的生成結果。雖然還有很多不足之處,但我(作者 Pat Niemeyer——譯者注)覺得還是很有意思的,而且這種方法不僅簡單,還很有效。我個人覺得神經網路可能並沒有把這些 Memoji 當成人臉,而且還有多個不利因素,容我一一道來:


  • 卡通影象

首先,第一個問題就是人們以卡通形式表現出來時,“看著”會是什麼樣子?卡通影象會誇大人物的最明顯特徵,但有些特徵比如髮型並不是固有不變的,在不同的照片裡都變化很大,甚至每天都不是一個樣。由於這個原因,似乎訓練能夠識別個體的神經網路,才能以考慮到這種變異情況的抽象方式捕捉髮型資訊。相反地,這意味著它可能不適合從隨機影象中生成髮型。


  • 膚色和頭髮顏色

在隨機光照條件下拍攝的照片中很難推斷膚色,我做了一個簡單測試,效果非常糟糕,很好地印證了這一點。在測試中,神經網路通常會選擇較亮的膚色,而且總是不能很好地區分現實和不現實選項(未展示)。另外,雖然測試在區分淺色頭髮和深色頭髮方面表現良好,但是在呈現色彩鮮豔的頭髮時多多少少都存在失誤。



  • 沒有 API

我在做生成 Memoji 這個實驗時,面臨的一個限制就是目前沒有能批量化生成它們的 API(沒有直接的方式能在 iOS 上自動化生成它們)。這就限制了我們很難高效地找到可能的 Memoji域作為生成過程的一部分。理想情況下,我們希望使用遺傳演算法大幅優化特徵組合,而非依靠它們的可分離性,但在這個案例中並不可行。


  • 照片選擇

選擇哪張照片作為生成 Memoji 的素材對最終結果也有很大影響。有些照片生成的結果就比其它的好很多,我也不清楚原因在哪。總的來說,我儘量找那些由代表性的、剪裁得當以及正臉朝前的照片。


神經網路&設定

這項實驗的實際程式碼其實很少,我挨個說一說,原始碼連結放在文末。


  • VGG

VGG 是一個非常流行的用於影象識別的神經網路架構。VGG Face 則是實現了專門用於人臉識別的模型,而且整個訓練後的網路(包括網路層資訊和學習權重)都可以公開下載和使用。所以使用這種預訓練模型是最好的選擇之一,從頭開始訓練一個這樣的模型需要花費大量的時間。


圖:VGG Face影象模型架構


  • Torch

我使用的是 Torch 科學計算框架,它提供了執行 VGG 模型所需的環境,內有基於 Lua 的程式設計環境、供使用張量進行數學計算所需的程式庫,以及搭建神經網路所需的構建模組。我選擇 Torch 是因為我之前經常用它。


Torch 可以為我們載入提供好的 VGG Face 模型,只需幾行程式碼就能在上面執行一張影象。基本流程為:


-- 載入神經網路
net = torch.load('./torch_model/VGG_FACE.t7')
net:evaluate()

-- 應用影象
img = load_image(my_file)
output = net:forward(img)
複製程式碼


還有幾步涉及到載入影象和影象標準化,在原始碼裡可以找到。


  • 使用網路層

如上圖所示,VGG 包含不同型別的網路層。首先是包含了 RGB 影象資料的張量,它應用了一系列的卷積、池化、加權以及其它型別的轉換。資料的“形狀”和維度發生了變化,因為每個網路層會不斷學習更多的抽象特徵。最終,神經網路的最終層生成一個一維的 2622 個元素的預測向量。該向量表示和訓練網路所用的特定人物的匹配概率。


在我們的案例中,我們並不關心這些預測結果,而是想用神經網路比較我們自己的任意人臉資料集。要想實現這一點,我們可以利用預測層下面一層的輸出。這一層提供了一個有 4096 個元素的向量,描述了人臉的特徵。

output = net.modules[selectedLayer].output:clone()
複製程式碼


VGG16 有 16 個網路層,用 Torch 的實際實現結果生成了一個 40 層的“模型”設定,其中第 38 層生成了我們所需的結果。


  • 相似性

我們要做的事情基本上就是在神經網路中執行成對的影象,並用相似度指標比較各自的輸出結果。比較兩個超大型數字向量的一個方法就是使用點積:

torch.dot(output1, output2)
複製程式碼


這會生成一個標量值,可以把它當成表示向量和高維空間“一致”的比率。


在這個測試中,我們想將預期 Memoji 和多個引用影象進行比較,併合並它們。所以我需要將每對值標準化,進行平均取值以得到一個“分數”。


sum = 0
for i = 1, #refs do
  local ref  = refs[i]
  local dotself = torch.dot(ref , ref) 
  sum = sum + torch.dot(ref, target) / dotself
end
...
return sum / #refs
複製程式碼


標準化意味著將影象和它自己比較的得分會是 1.0,所以後面越高的“分數”值以為著更高的相似度。


我們還需要用到很多其它型別的指標,兩個最明顯的指標就是輸出結果之間的歐幾里得距離和均方誤差。我簡單用這兩個試了一下,但是似乎點積能產生更好的結果,這裡我有點摸不著頭腦。


第一個測試:一組頭像

我首先想驗證的是這個人臉網路能不能處理卡通風格的 Memoji。我首先抓取了由 63 個、從谷歌搜尋來的人臉 Memoji(大部分來自蘋果的 demo)。



然後我選擇了一個,讓神經網路對所有 Memoji 排序,為我展示基於單張引用影象的前三個匹配結果。


結果很不錯。神經網路不僅找出了同一 Memoji(排序第一,分數為 1.0),但第二個和第三個結果可信度不高。


真實影象

現在到了“真實”影象的測試:當和這些 Memoji 比較時,神經網路對真實生活中的影象會做出怎樣的結果?我抓取了一些名人的照片,結果如下:

結果還是很有意思的。注意,神經網路只能在數量有限的 Memoji 中選擇,而且它在這些影象中看到的主要特徵可能並不符合我們的預期。此外,注意這些比較中的分數(置信度)大幅低於和其它 Memoji 相比時的分數。


生成過程

接著,我想把這個過程反過來,使用神經網路選擇特徵來建立一個 Memoji。這就有點棘手了。我前面提過,並沒有明顯的方法可以在 iOS 上自動建立 Memoji。雖然在越獄裝置上或者黑進某些藝術網路或許能做到,但我還是想試試神經網路這種簡單的方法。

在測試時,我用 QuickTime Player 的視訊錄製功能將我的手機和筆記本相連,然後將其放在角落,剛好讓指令碼能抓取錄屏用於處理。每種特徵我都嘗試了各種可能性,選擇每一種選項,按回車鍵來抓取和排列輸出。



很明顯這並不理想,有幾個原因:首先,過程很痛苦(有 93 對選擇,試著運行了十幾次)。更重要的是,它只能讓我們每次評估一個特徵差異。理論上,我們可以對其迭代,重複嘗試直到神經網路不再建議我們改動,但這也並不完美,因此可能存在“區域性最小值”(如果一個特徵會影響另一個特徵的感知,那麼評估的順序就很重要)。


另外,還有個惱人的事情就是攝像頭一直跟著我,很小的動作也會影響得分。


結果

開頭的時候我劇透了幾張結果,但是還可以再精心打磨一番。

不過神經網路在選擇臉部特徵時似乎很不穩定,也就是在某些情況下,模型選擇的前 3 張影象非常相近,但有時又不這樣。例如,下面是神經網路為特朗普的髮型選擇的前三種 Memoji:

有些特徵倒也符合我的預期,比如奧巴馬據說長有一對“招風耳”,然後神經網路確實按照匹配度從大到小列出了三個結果:

圖:為奧巴馬Memoji選擇的耳朵

但眼睛的變化就比較大了:


圖:為奧巴馬Memoji選擇的眼睛

相反,為特朗普選擇的眼睛就變化不大:

圖:為特朗普Memoji選擇的眼睛


剛開始的時候,奧巴馬的下巴我看著實在是太方了,但是過了一會兒我又覺得看著正好(所以說,在這方面如果主觀性太強是不太妙的)。


頭髮顏色

我前面說過,膚色很難區分,選擇頭髮顏色同樣是個問題。特朗普和奧巴馬兩人的頭髮顏色看起來還說得過去,但是後面我用亮紅色頭髮測試時,神經網路卻老是想選灰色:



雖說排名前三的生成結果中有紅色頭髮,但結果並不理想。我嘗試了很多照片,想看看有哪些影響因素,比如調整影象的預處理方式。然而,即便我大幅修改了輸入影象,神經網路依然鍥而不捨的生成灰色頭髮的 Memoji。


在另一項實驗中,我查看了其它網路層的生成結果。回想一下,我們之前選的是第 38 個網路層,因為它是表示臉部特徵的最高層。然而我們可以和更低的網路層做個比較,看看有何區別。在使用第 32 個網路層時,結果確實有所不同,頭髮的顏色得到了更多關注。這一層對應的是 VGG16 模型中最後一個“池化”層,就在第一個“全連線層”之前,所以可能因此它保留了更多的空間和顏色資訊。這一層和其它更低的網路層在為亮紅色頭髮生成 Memoji 時,生成的結果更好。


此外,我還嘗試了多種方法將顏色頭髮平均化(按照前三個選擇和新網路層)。雖然這樣生成了更為合理的結果,但最終也沒有得到理想的亮紅色頭髮。


本專案的 Torch 指令碼程式碼見我的 GitHub 專案:

github.com/patniemeyer…


參考資料:
https://patniemeyer.github.io/2018/10/29/generating-memoji-from-photos.html