:【迁移】用神经风格迁移生产美图,你也是梵高


:【迁移】用神经风格迁移生产美图,你也是梵高
本文插图
神经风格迁移大法好 , 人人都能变梵高 , 但实际上这可是个技术活 。 虽然神经风格迁移NST从概念上很容易理解 , 但想生成高质量的图片却实属不易 。 为了获得良好结果 , 必须正确实施其中许多复杂的细节和隐藏的技巧 。
本文就将深入研究神经风格迁移原理 , 并详细讨论这些技巧 。
关于NST的介绍这里就不再赘述了 , 你可以通过官方PyTorch教程了解NST 。 不过如同其它介绍性文章一样 , 它们的执行结果都较为普通(如下图) 。 笔者将展示能提高迁移质量的编码教程 , 但是先说一些题外话 。
:【迁移】用神经风格迁移生产美图,你也是梵高
本文插图
(上图是两种不同方法实现的神经风格迁移质量比较 。 左上图是要匹配其内容的图像 。 左下图是要匹配其风格的图像 。 中间图是由PyTorch教程实现的迁移结果 , 右图是由本文所述步骤实现的迁移结果 。 很明显 , 右图视觉质量更高 , 且更忠实于左上方图像的风格 。 )
问:为什么Gram矩阵能度量风格?
Gatys等人的文章(介绍神经风格迁移)大都简单易懂 。 然而他们却没有回答这个问题:为什么选用Gram矩阵来表示风格(即纹理)?
在较高层上 , Gram矩阵能测量同一层中不同特征图之间的相关性 。 特征图即卷积层激活后的输出 。 例如 , 如果一个卷积层有64个滤波器 , 将生成64个特征图 。 Gram矩阵能测量层中不同特征图之间的相关性(相似性) , 而无需关心像素的确切位置 。
为了阐明Gram矩阵为什么能度量纹理 , 假设有两个滤波器 , 一个用于检测蓝色事物 , 一个用于检测螺旋 。 将这两个滤波器应用于输入图片以产生两个滤波图 , 并测量其相关性 。 如果两个滤波图高度相关 , 那么基本可以确定图片中所有螺旋都是蓝色的 。 这意味着图片纹理是由蓝色螺旋组成 , 而非红色、绿色或是黄色螺旋 。
:【迁移】用神经风格迁移生产美图,你也是梵高
本文插图
尽管这项解释仍令笔者有些不解 , 但Gram矩阵能度量风格似乎是纹理合成社区公认的事实 。 此外 , 不能否认由Gram得到的结果确实令人印象深刻的 。
修复PyTorch执行
提高迁移质量的第一步是修复PyTorch教程执行 。 该教程内容试图忠于Gatys等人的文章 , 却遗漏了一些细节 。 一方面 , 文章作者将 MaxPool2d替换为AvgPool2d , 因为他们发现AvgPool2d能生成更高质量的结果 。
另一细节是 , 该教程计算的是卷积输出而非ReLu激活函数的ContentLoss(内容损失)和StyleLoss(风格损失) 。 这有点吹毛求疵 , 因为笔者在实验中并没有观察出使用卷积和ReLu之间有什么大区别 。
:【迁移】用神经风格迁移生产美图,你也是梵高
本文插图
VGG19网络及其各层
该教程与文章之间最大的差别是它对于ContentLoss 和StyleLoss分别使用了“错误”的层 。 笔者之所以在错误一词上打了引号 , 是因为层的选择是比较主观的一件事 , 很大程度上取决于最令人喜欢的风格 。
也就是说 , 可以使用一些经验法则来指导决策的制定 。 在度量内容相似性时 , 若content_img与input_img之间存在完美的像素匹配 , 较低层往往激活程度最高 。 越深入网络 , 层越不关心匹配是否精确 , 相反 , 当特征处于正确位置时 , 层会被高度激活 。
为了将每层的内容都进行可视化展示 , 可以设置style_weight=0 , 并使用不同的层作为content_layer , 基于随机的input_img运行训练过程 。
:【迁移】用神经风格迁移生产美图,你也是梵高


推荐阅读