用MXnet实战深度学习之二:Neural art
用MXnet實戰深度學習之二:Neural art - 推酷
題注:本來這是第三集的內容,但是?Eric Xie?勤勞又機智的修復了mxnet和cuDNN的協作問題,我就把這篇當作一個卷積網絡ConvNet(CNN)神奇而有趣的例子,寓教于樂給大家提起學習興趣,原計劃的CNN教學順延到下一集。
Neural art:用機器模仿梵高
Neural art是個讓機器模仿已有畫作的繪畫風格來把一張照片重新繪畫的算法,比如給一張貓的照片和一張梵高的自畫像,我們就可以得到用梵高風格畫出來的貓,比如這個樣子(圖二為梵高在1889年的自畫像,引用自?wikipedia?):
Neural art算法來自于這篇論文 “A Neural Algorithm of Artistic Style” by Leon A. Gatys, Alexander S. Ecker, and Matthias Bethge,鏈接在?http://arxiv.org/abs/1508.06576?有興趣的觀眾朋友們可以閱讀。它的基本想法是,利用一個多層的卷積網絡(CNN)抽象出給定繪畫作品里一些高級的隱藏特征用來模仿繪畫風格,并把這個繪畫風格應用到一個新的圖片上。這類的圖像生成模型是深度學習的一個方向,比如谷歌的?Inception?把一個羊的圖片和一個云的圖片生成羊形狀的云之類的“迷幻類”圖像也是類似模型的一種。Facebook也有類似的生成模型,他們基于這篇?http://arxiv.org/abs/1406.2661?由DMLC作者@antinucleon等人合作的文章。
Neural art算法模型有多種實現方式,比如?這里?和?這里?是兩個Lua/Torch版的實現,這片論文的gitxiv?下面也包含了五花八門的各種實現,他們都是實現論文中的VGG模型并用caffe描述,MXnet在?大家的提議?下當然也要實現一下了。按照慣例,mxnet這么有意思的深度學習工具,我們去幫它的github加個星,大家說好不好啊?傳送門:?https://github.com/dmlc/mxnet
MXnet的Neural art樣例
tar -zxf cudnn-7.0-linux-x64-v3.0-prod.tgz cd cuda sudo cp lib64/* /usr/local/cuda/lib64/ sudo cp include/cudnn.h /usr/local/cuda/include/如果之前沒有編譯安裝cuDNN版的mxnet,請在?make/config.mk?里把?USE_CUDNN = 0?修改為1重新編譯,并更新安裝對應的python包。
如果你沒有安裝mxnet GPU版本的條件,也可以訪問以下這些網站或app玩一下Neural art。這個算法需要大量的GPU計算,以下這些免費或收費的實現都需要排隊。
觀眾朋友們如果正好有一個裝了GPU版mxnet的機器的話,那我們就開始用mxnet自己動手豐衣足食,還可以幫朋友們生成有藝術感的微博頭像喲。以下例子中我用我妹 @dudulee的浪里格朗 家的美貓“破狗”的照片為例講解具體生成藝術圖的步驟。如果觀眾朋友們想看更多破狗和她妹妹“泥巴”的日常,可以關注嘟嘟家兩只貓“破狗”和“泥巴”的微博@POGOGO-NIBABA,內有大量圖片可供深度學習實驗。
簡要步驟和參數調整
mxnet使用的是論文中描述的VGG模型,在第一次使用的時候需要執行?download.sh?下載該模型,mxnet的模型版本占約幾十MB的空間。下載模型完畢之后,可以把需要繪畫的原始圖片和模仿的圖片放到?input?目錄里,比如說破狗的照片和梵高的圖像,然后執行:
python run.py耐心等待1-2分鐘,就可以看到結果保存在?output?目錄里,比如是這樣的:
如果給另外一張現代藝術油畫 'Blue Horse' Modern Equine Art Contemporary Horse Daily Oil Painting by Texas Artist Laurie Pace (鏈接?https://www.pinterest.com/pin/407223991276827181/) 替代梵高的畫作讓機器學習風格,破狗可以畫成這樣的:
python run.py
run.py?里有一些可以調整的參數,如果想調試輸出效果可以按照如下解釋調整:
- --model?指定模型。例子里暫時只有vgg這一個模型,以后可能添加前面提到的inception等其他模型。暫時先不用改。
- --content-image?內容圖片,比如上面的“破狗”的照片
- --style-image?輸入的繪畫原作的路徑,比如上面的的“梵高自畫像”。
- --stop-eps?模型里用?eps?值代表兩幅圖的風格相似度,在訓練的過程里會看到這個值逐漸收斂,值越小相似度越高。?stop-eps?參數指定的是收斂的終止值,一般越小就代表畫的越像,但如果太小了會需要很多的計算時間來收斂,默認0.005已經可以得到不錯的效果,可適當減小到0.004等。
- --content-weight?--style-weight?內容圖片和繪畫原作的相對權值,默認是10:1,如果發現繪畫風格過于強烈涂抹一片,可適當修改為20:1或者30:1,反之改小。
- --max-num-epochs?最大收斂步數,默認是1000步。不過一般畫作在200步左右就能找到差不多合適的?eps?風格相似值,這個最大收斂步數不需要修改。
- --max-long-edge?長邊最大邊長。程序會自動把輸入圖片按照這個值等比例縮放,比如上面的圖就是縮放到高度為512像素。程序運行時間及內存消耗約和圖片面積成正比,因為卷積網絡的計算量每個像素相關,700像素的圖片差不多比500像素的圖片多一倍內存和運行時間。在接下來的對比測試里面可以看到,512像素的圖差不多需要1.4GB顯存,適合2G顯存的顯卡比如nvidia顯卡的macbook pro等娛樂一下就足夠了,4GB的顯卡差不多最高可以處理到850-900像素的圖片,要想上1080p就得有Titan X的12GB了。同樣的,計算時間也會相應拉長,它也和顯卡的CUDA核心數約成反比。現在你基本上明白了為什么上面提到的免費版都需要排隊幾個小時到幾周不等了。
- --lr?logistic regression的梯度下降(SGD)學習率,用來尋找既在內容上滿足“像破狗”又在風格上“像梵高”的生成圖像。較大的?eta?收斂較快,節省計算時間但會在最小值附近跳躍。默認值0.1,可以調整到0.2和0.3都可以。
- --gpu?使用第幾個GPU,默認是0號GPU,適合只有一塊顯卡的用戶(比如我家里的機器)。如果土豪你有4塊顯卡可以并行使用,只需要指定為?--gpu 0,1,2,3?就可以了,8塊顯卡以此類推,mxnet支持多塊顯卡并行而且顯存分配效率很高。如果沒有GPU并能忍耐40分鐘左右算一張圖,?--gpu -1?也可以指定為純CPU計算。
- --output?輸出文件名。
- --save-epochs?是否保存中間結果,默認每50步保存一下結果。
- -remove-noise?降噪參數,默認0.2,可以降低一些為0.15,這就是高斯降噪的半徑。程序在學習模仿畫作的過程里會使用兩個白噪聲圖片逼近風格圖和內容圖,在最終生成的圖片里面可能殘留一些不必要的噪聲點,程序里面可以降噪處理。
可能遇到的問題
內存不足
運行時消耗的顯存和圖像的面積成正比,如果圖像的縮放目標邊長太大,很可能會顯存不足,mxnet的提示錯誤信息如下:
terminate called after throwing an instance of 'dmlc::Error' what(): [18:23:33] src/engine/./threaded_engine.h:295: [18:23:33] src/storage/./gpu_device_storage.h:39: Check failed: e == cudaSuccess || e == cudaErrorCudartUnloading CUDA: out of memory對于512邊長的圖片,mxnet需要1.4G顯存,一般的nVidia版的macbook pro或者其他有2G顯存的機器可以跑起來;對于850邊長的圖片,mxnet需要3.7GB顯存,一般4G顯存的機器可以跑起來。這里有兩點提醒注意:
工作空間不足
如果圖片邊長大于600到700,原始例子里默認的workspace可能不夠,會出現如下的錯誤信息:
terminate called after throwing an instance of 'dmlc::Error' what(): [18:22:39] src/engine/./threaded_engine.h:295: [18:22:39] src/operator/./convolution-inl.h:256: Check failed: (param_.workspace) >= (required_size) Minimum workspace size: 1386112000 Bytes Given: 1073741824 BytesMxnet需要工作緩沖空間,這個變量可以在模型的定義里面設置。找到?model_vgg19.py?文件,把里面的所有?workspace=1024?改成?workspace=2048?就可以了。
速度測試
為了體現MXnet在速度和高效的內存使用上的優勢,在這里我們選擇這這個Lua (Torch 7)的實現https://github.com/jcjohnson/neural-style?,用同一組圖“破狗”+“梵高”對比測試mxnet和它的性能。實驗條件,單塊GTX 960 4GB,4核AMD CPU,16GB內存。值得提醒的是,Lua版使用的原版的VGG模型在第一次運行的時候也需要下載,占用大約1GB多的空間。
512像素邊長的圖片
內存消耗 運行時間?
MXnet 1440MB 117s?
Lua Torch 7 2809MB 225s?
850像素邊長的圖片
Lua/Torch 7版對于850px邊長無法測試,等我的Titan X到貨再來一戰。
內存消耗 運行時間?
MXnet 3670MB 350s?
Lua Torch 7 顯存不足 顯存不足?
簡單來說,MXnet節省一倍的顯存,速度也接近翻倍。該Lua版本的官方樣例使用Titan X(12GB)生成邊長512像素的圖,需要約一到兩分鐘,而mxnet只需要一塊 GTX 960約兩分鐘,對比Titan X(1000$)和GTX 960 (200$) 的價格差距,mxnet差不多省了4-5倍的錢。關于運行速度對比值得提醒的是,Lua版本的速度稍慢主要因為它是用?L-BFGS?來收斂,收斂效果好但是速度較低,而mxnet使用更快的?SGD?,它有速度優勢但是對不同的輸入參數可能需要手工微調,在這一點上不能簡單的說MXnet一定總是快兩倍。
MXnet能達到這樣的速度和高效內存使用,得益于他所在的DMLC組件的高效設計和實現。關于DMLC和MXnet的高效內存設計方法,有興趣的觀眾朋友們可以前往?這里?作深入閱讀了解DMLC的黑科技。
到這里,觀眾朋友們應該可以愉快的玩耍起來Neural Art給自己和朋友們生成藝術圖片了。接下來的部分討論一下機器為什么能學習模仿到繪畫風格。
機器怎么模仿繪畫風格
這個問題的答案在原論文里也語焉不詳,作者也沒有想解釋清楚。以下的討論均按我個人根據原文以及reddit和知乎上的相關討論在這里概述一下,更多討論詳情請參閱:?reddit?知乎?這里一并感謝上述鏈接里的作者和評論者。
量化表示“繪畫風格”
“繪畫風格”是一個抽象定型的詞語,它可能和圖像的某種高階統計量相關,但不同的繪畫風格有不同的表示,對于一個沒有具體定義風格的一般性問題,它很難用人工設計算法去完成。幸運的是,我們知道卷積網絡CNN可以通過?多層卷積提取物體的抽象特征?完成物體識別(請參考?Yann Lecun的深度學習教程?),這一點“提取抽象特性”的能力被作者借用來描述“風格”。也就是說,經過多層CNN抽象之后的圖片丟棄了像素級的特征,而保留了高級的繪畫風格。下圖引用自原論文圖1。在文章里,作者定義了一個5層的CNN網絡,梵高的星空在通過第一二三層的時候保留了一些原圖的細節,但是在第四第五層的時候,就變成了“看起來是梵高星空的樣子”這樣的抽象特征:
這時候作者機智的想到了,如果把一張梵高一張其他照片同時都放到這個CNN網絡里,經過合適的調整讓第二張照片在第四五層接近梵高,而第一二三層保持和原來差不多,那就可以模仿梵高了!細節上,作者為了沿用了CNN的特征抽象能力使用了CNN作物體識別的VGG模型。關于mxnet實現CNN作物體類別識別的相關例子,我在下一集會講到。
學習風格并生成圖像
于是讓機器模仿繪畫風格并生成圖片成了一個優化問題:生成的圖像要像原內容圖,比如我給一張貓的圖片最終還是要像貓;生成的圖像要像是由風格圖畫的,比如我給了個梵高的圖,我生成的貓的圖片要看起來有梵高的風格。也就是說要找到這樣一個中間結果,它的內容表示(第一二三層CNN)接近于破狗,它的風格的表示(第四第五層CNN)接近于梵高。在文章里,作者用一個白噪聲圖片通過梯度下降生成一個接近內容圖的圖片,以及另一個白噪聲圖片生成一個接近繪畫圖風格的圖片,并定義了神奇的描述紋理的?gram matrix?定義了這兩個圖的損失函數并加權平均當作優化目標函數,在mxnet的實現里通過梯度下降(SGD)完成收斂找到這樣一個內容和風格都搭配中間結果。舉例來說,“破狗”和“梵高自畫像”的生成過程的200多步的循環里,圖像的變化依次如下圖所示:
我們可以看到,在剛開始的幾十步里,圖片更像是原圖和繪畫的簡單紋理的疊加,而隨著循環步數增加,程序慢慢學習到了配色和筆觸的風格,在150步左右基本成型,最終把破狗的照片繪畫成梵高的風格。
模仿風格是不是只有這一個辦法?
事實上不是的,很多計算圖形學的論文已經針對各種方向做出了一些成果,只是這篇文章利用了深度學習和CNN的方法,其他類似學習風格的論文可以參考相關閱讀:
- "A Parametric Texture Model Based on Joint Statistics of Complex Wavelet Coefficient"?http://www.cns.nyu.edu/pub/lcv/portilla99-reprint.pdf?這片文章用小波變換的方式提取了圖片紋理“風格”所對應的二階統計量,和本文提到的論文想法是一致的。
- “Style Transfer for Headshot Portraits”?https://people.csail.mit.edu/yichangshih/portrait_web/?這篇文章針對頭像照片的風格做到了很快的風格學習,并且可以實時轉換視頻,對于這個有嚴格限制的問題,它的速度比Neural art高到不知道哪里去了。
結語
作為深度學習和CNN的例子,Neural art確實很好玩,觀眾朋友們可以自己用MXnet給自己和朋友們生成有意思的藝術圖片,記得發到微博上加#mxnet#話題分享。值得提醒的是,如果原圖是半身人像類,建議也使用一些人像的畫作來學習風格,比如“破狗”+“梵高”的組合;相對應的,風景圖片最好用風景畫作風格學習。因為風景的表現重點和人像不同,強行把風格畫到人像的照片上并不適合,它會看起來像是兩幅圖簡單疊加,這個即使是人類畫家也不好畫在一起。大家好好玩,下一集會詳細講解卷積網絡CNN作物體分類識別,也就是教機器如何識別貓和狗。
from:?http://www.tuicool.com/articles/N3MRvqq
總結
以上是生活随笔為你收集整理的用MXnet实战深度学习之二:Neural art的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用MXnet实战深度学习之一:安装GPU
- 下一篇: 最牛B的编码套路