天天看點

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

提起前段時間紅遍朋友圈的 prisma,可能許多朋友都還記憶猶新:輸入一張自己的照片,再選一個 prisma 内置的名畫濾鏡,幾秒之後就能得到一張名畫風的新照片。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

絕大部分使用者可能隻是通過 prisma 過了一把當畫家的瘾,但對于程式猿們來說,僅僅得到一張風格迥異的新照片似乎還遠遠不夠。

問題1:什麼是風格轉換器(style transfer)?

所謂照片風格轉換器,就是類似 prisma 的,轉換照片風格的軟體 app。他們抽取 a 照片的風格特征(一般都是一張名畫),然後将這種特征應用到 b 照片的内容上,進而生成了全新的照片 c。

問題2:怎樣分隔一張照片的風格和内容?

使用卷積神經網絡(cnn)。由于 alexnet 已經成功地将 cnn 應用于目辨別别(即确定圖像中的主體内容),并且在 2012 年主導了最流行的計算機視覺競賽,是以 cnn 是目前用于圖像目辨別别的最流行和有效的方法。

簡單說,cnn 是通過學習建構在先前圖層上的各個過濾器層來識别對象的。例如,第一層通常用來學習識别簡單的圖案,例如物體的邊緣和棱角。中間層可能用來識别更複雜的圖案,例如人物的眼鏡、汽車的輪胎等。jason yosinski 大神曾在下面這個視訊中詳細介紹了 cnn 的相關内容。

事實證明,cnn 第一層中的過濾器對應于一張照片的風格,包括畫筆描邊、紋理等。靠後的圖層中的過濾器對應于識别圖像中的主體,例如狗,建築物或一座山等。

例如,将一幅畢加索的畫作輸入 cnn,并分析第一層(樣式層)有多少過濾器被激活,就可以得到該畫作的樣式表示。同樣,通過最後一層(内容層)的分析,我們也可以得到畫作内容的表示。

問題3:怎樣将風格和内容融合在一起?

這一步很有意思。由于兩張照片的風格大不相同,是以它們的樣式層中激活的過濾器也就不同,通過分析兩個樣式層中的過濾器,就能獲得兩張照片的樣式之間的差别。同樣,對内容層中過濾器的分析,也能得到兩張照片内容的差别。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

例如,如圖所示,我們想把一張自拍照和畢加索的畫作融合。融合後的圖像首先以圖示中的噪聲圖像為起點,然後将這張圖像輸入 cnn ,它會激活樣式層和内容層中的一些特定的過濾器。按照上述的方法,通過對比融合照片和畢加索畫作的風格層,就可以得到風格損失(style loss);通過對比融合照片和自拍照的内容層,就可以得到内容損失(content loss),将兩種損失相加,就得到了總損失。

下面的任務就很清楚了:通過優化算法的介入,我們想辦法将這個總損失最小化,最終就得到了一張畢加索風格的自拍照了。

問題4:有哪些常見的優化算法?

到目前為止,我遇到了兩種類型的優化算法:一階的和二階的。

一階方法通過梯度(gradient)将目标函數最小化(或者最大化)。應用最廣泛的就是梯度下降法(gradient descent)及其各種變體,詳情見如下連結:

二階方法是通過二階導數将目标函數最小化(或者最大化)。由于二階導數的計算成本很高,是以這裡所讨論的二階算法 l-bfgs(limited-memory broyden–fletcher–goldfarb–shanno) 使用了 hessian 矩陣近似。

由于我們在以下試驗中處理的照片顔色灰階都介于 0-255 之間,是以将各算法的學習率(learning rate)都設定為 10,這看起來可能有點大,但效果還可以接受。算法的其他超參數(hyperparameters)都保持預設。測試的硬體環境是:amazon p2 執行個體上的單片 k80 gpu。

實驗1:100 次循環,300 x 300 像素

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

如圖所示,我們輸入了兩張 300 x 300 像素的照片,并運作整個優化循環 100 次。雖然 100 次并不足以生成一個效果很好的融合照片,但對我們分析各個優化算法的性能已經足夠了。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?
用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

如圖所示,由于學習率設定的略大,是以梯度下降(gradient descent)、adadelta 和 rmsprop 在整個循環中都處于不斷的震蕩狀态,并沒有顯示出明顯的收斂趨勢。反觀 adam 和 l-bfgs 算法則能夠快速收斂,并且誤差也基本相同。

實驗2:100 次循環,600 x 600 像素

當參數增多時,l-bfgs 算法應該表現的更好。為此,我們在試驗2中增大了圖像,并切換了素材。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?
用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

如圖所示,雖然學習率的設定還是略大,但梯度下降和 adadelta 算法在面對大資料量時顯得更穩定,rmsprop 還是始終處于震蕩狀态。

另外,adam 算法一開始收斂很快,但後期被 l-bfgs 反超。不知道是不是和循環次數有關,下面我們試着增加循環次數。

實驗3:1000 次循環,300 x 300 像素

在實驗3中,我們增加了循環次數,依然使用實驗2中的照片素材,但像素變為 300 x 300。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?
用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

如圖所示,在略大的學習率設定下,梯度下降、adadelta 和 rmsprop 始終處于震蕩狀态無法收斂。但 adam、adagrad 和 l-bfgs 三種算法的收斂情況則相對較好,其中效果最好的 l-bfgs 大約比 adam 的優化效果好 50% ,并且速度也更快。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

從最終生成的融合照片的成像效果也能看出來,l-bfgs、adam 和 adagrad 的效果要好一些。

實驗4:不同的學習率,100 次循環,300 x 300 像素

有說法稱過大的學習率可能會導緻梯度下降、adadelta 和 rmsprop 三種算法不收斂,是以在實驗 4 中我們減小這三種算法的學習率。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

可以看到,所有算法最終都收斂了。可能是得益于較低的學習速率,梯度下降的最終表現要優于 adadelta 算法。另外,較高的學習率雖然在一開始時幫助 adam lr 10 取得了較快的收斂速度,但最終效果并不好。而 adam lr 1 雖然收斂緩慢,但表現很穩定。那麼問題來了,如果增加循環次數,adam lr 1 的表現是否會超過 adam lr 10 呢?

實驗5:不同的學習率,500 次循環,300 x 300 像素

增加循環次數之後,即便在學習速率較小的情況下,梯度下降、adadelta 和 rmsprop 三種算法也還是出現了震蕩。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

有趣的是,adam lr 1 最終果然反超了 adam lr 10,甚至有超過 l-bfgs 的趨勢。

實驗6:1000 次循環,300 x 300 像素

這一次我們僅僅對 adam lr 1 和 l-bfgs 進行了對比,通過進一步增加循環次數,可以看到,adam lr 1 最終的表現并沒有超過 l-bfgs。

用資料說話:把自拍照變成畢加索名畫 哪種算法最高效?

從上述試驗可以發現:在較大的學習率設定下,梯度下降、adadelta 和 rmsprop 三種算法不容易收斂,但增大資料量,前兩種會有所好轉。總體上,l-bfgs 算法的收斂效果最好,速度也最快。

改變學習率。adam 在學習率較小時,收斂情況提升明顯,随着循環次數的增大,收斂效果幾乎與 l-bfgs 算法相當,但收斂情況最好的依然是 l-bfgs 算法。

最後作者表示,以上實驗隻是從參數設定、資料量和疊代次數等方面入手簡單探索了幾種常見算法的特性,目的隻是幫助大家在開發中更好地使用它們。雖然試驗結果顯示 l-bfgs 算法的收斂速度最快,效果最好,但按照個人習慣,他用 adam 算法的情況反而更多。另外,究竟哪種算法效果最好,也不能一概而論,還是要根據資料類型和項目要求靈活選擇。

本文作者:恒亮

繼續閱讀