Neural art:用机器模仿梵高

http://phunter.farbox.com/post/mxnet-tutorial2 html

题注:原本这是第三集的内容,可是Eric Xie 勤劳又机智的修复了mxnet和cuDNN的协做问题,我就把这篇看成一个卷积网络ConvNet(CNN)神奇而有趣的例子,寓教于乐给你们提起学习兴趣,原计划的CNN教学顺延到下一集。 node

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 python

MXnet的Neural art样例

MXnet的neural art范例在mxnet/example/neural-style/目录下。由于这个例子须要大量的计算,推荐安装GPU版的mxnet。安装mxnet GPU版的教程参见前一集http://phunter.farbox.com/post/mxnet-tutorial1 这里就再也不重复。固然了,mxnet的CPU和GPU无缝链接,若是没有GPU可使用CPU版本,只是须要每张图耐心等待约40-50分钟。
选择安装:mxnet可选使用cuDNN加速。对Neural art的例子,cuDNN v3和v4都可运行,v4在个人GTX 960上比v3稍微快约2-3秒。你们能够到这里https://developer.nvidia.com/cudnn 申请开发者项目,若是批准经过能够下载安装cuDNN工具包,具体请参照nVidia官方教程或者简单的执行这几步(参考来源Install Caffe on EC2 from scratch (Ubuntu, CUDA 7, cuDNN))):linux

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计算,如下这些免费或收费的实现都须要排队。 git

  1. Deepart:网址 https://deepart.io/ 用户能够免费提交,平均等待时间为1周左右,若是想插队到24小时以内,能够捐款给网站。
  2. Pikazo App:网址 http://www.pikazoapp.com/ 它至关于把deepart这个网站作成app,须要收费$2.99,也须要排队。
  3. AI Painter: 网址 https://www.instapainting.com/ai-painter 这是instapainting的一个业务,免费,也是须要排队。

观众朋友们若是正好有一个装了GPU版mxnet的机器的话,那咱们就开始用mxnet本身动手丰衣足食,还能够帮朋友们生成有艺术感的微博头像哟。如下例子中我用我妹 @dudulee的浪里格朗 家的美猫“破狗”的照片为例讲解具体生成艺术图的步骤。若是观众朋友们想看更多破狗和她妹妹“泥巴”的平常,能够关注嘟嘟家两只猫“破狗”和“泥巴”的微博@POGOGO-NIBABA,内有大量图片可供深度学习实验。 github

简要步骤和参数调整

mxnet使用的是论文中描述的VGG模型,在第一次使用的时候须要执行download.sh下载该模型,mxnet的模型版本占约几十MB的空间。下载模型完毕以后,能够把须要绘画的原始图片和模仿的图片放到input目录里,好比说破狗的照片和梵高的图像,而后执行:web

python run.py --content-image input/pogo.jpg --style-image input/vangogh.jpg

耐心等待1-2分钟,就能够看到结果保存在output目录里,好比是这样的:
算法

若是给另一张现代艺术油画 'Blue Horse' Modern Equine Art Contemporary Horse Daily Oil Painting by Texas Artist Laurie Pace (连接https://www.pinterest.com/pin/407223991276827181/) 替代梵高的画做让机器学习风格,破狗能够画成这样的:ubuntu

python run.py --content-image input/pogo.jpg --style-image input/blue_horse.jpg

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显存的机器能够跑起来。这里有两点提醒注意:

  1. 若是你使用的是GTX 970 4G版,它的有效显存使用最高只到3.5GB,超过这个就会有莫名的错误。具体参考这里
  2. 若是显存正好差一点能够关掉系统占用的显存,好比在ubuntu下面能够Alt-Ctrl-F1关掉系统图形界面,节省几十MB的显存。
工做空间不足

若是图片边长大于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 Bytes

Mxnet须要工做缓冲空间,这个变量能够在模型的定义里面设置。找到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(不使用cuDNN)
1440MB
117s

MXnet(使用cuDNN)
1209MB
89s

Lua Torch 7
2809MB
225s

850像素边长的图片

Lua/Torch 7版对于850px边长没法测试,等个人Titan X到货再来一战。

内存消耗
运行时间

MXnet(不使用cuDNN)
3670MB
350s

MXnet(使用cuDNN)
2986MB
320s

Lua Torch 7
显存不足
显存不足

MXnet黑科技(12.21.2015更新)

在reddit上和网友们讨论这篇blog后,Lua版的做者回帖表示不服并成功的把内存消耗下降到1.5GB,具体讨论请参考这一条reddit的讨论。我和Mxnet的各位做者讨论以后,拿出MXnet最新压缩内存使用的黑科技MXNET_BACKWARD_DO_MIRROR迎战,相关技术细节请参看这条github issue。想使用黑科技版MXnet请更新M到github的最新版本并从新编译。在执行代码前加入MXNET_BACKWARD_DO_MIRROR=1便可调用黑科技,好比:

MXNET_BACKWARD_DO_MIRROR=1 python run.py --content-image input/pogo.jpg --style-image input/vangogh.jpg

512像素对比测试

内存消耗
运行时间

MXnet(不使用cuDNN)
1440MB
117s

MXnet(使用cuDNN)
1209MB
89s

MXnet(使用cuDNN和内存压缩)
1116MB
92s

850像素对比测试

内存消耗
运行时间

MXnet(不使用cuDNN)
3670MB
350s

MXnet(使用cuDNN)
2986MB
320s

MXnet(使用cuDNN和内存压缩)
2727MB
332s

咱们能够对比看到使用了压缩内存选项以后,MXnet损失了一点运行时间,可是内存获得10%的压缩,如今4GB内存最高能够支持1024px的图片,消耗内存为3855MB。值得指出的是,Mxnet里gram matrix的实现暂时没有用到符号计算的功能(做者告诉我他太忙了以致于偷懒了),等更新了符号计算版本以后会再下降一些内存使用。
简单来讲,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做物体分类识别,也就是教机器如何识别猫和狗。

相关文章
相关标签/搜索