欢迎光临散文网 会员登陆 & 注册

简述风格迁移Neural-Style细节

2020-05-23 11:13 作者:nyasyamorina  | 我要投稿

什么是风格迁移?

风格迁移是使用某些手段(合法的), 把图像从原风格转换到另外一个风格, 同时保证图像内容没有变化, 举个栗子, 下面的这类图片应该是很多人见过了

可以看到在把画风变成梵高的星夜后, 图片的内容也可以清晰可见(说实话我觉得不太行), 这种方法就叫做风格迁移了,  前几年兴起的"动漫滤镜"也是属于这种

背后的使用的方法就是被大家熟知的人工智障了, 下面详细讨论实现的细节

前置论文:

  • [1]A Neural Algorithm of Artistic Style  arxiv.org/pdf/1508.06576.pdf

  • [2]Perceptual Losses for Real-Time Style Transfer and Super-Resolution  网站找不到了 = =

一大段废话, 请跳过 -> 关于人工智能和神经网络的区别啊.....一般人见识来说呢, 人工智能就像是语音助手,图像识别什么的. 按照这种方法来说呢, 最初的图像识别(万恶的手写数字) 是简化版的人工智能, 但是从数学层面看比较像是一种自适应降维方法而已, 分类器总给人一种"和人工智能有搭上边"的感觉, 但是在此发展出来的对图像视频操作的神经网络, 反而没被一般人认可为人工智能呢........嘛, 每个人对人工智能和神经网络的定义不一样也是小问题了

高明的Loss设计

首先考虑单张内容图片Ic, Image_Content和单张风格图Is, Image_Style片迁移: 假设原本初始化的图片的噪声图I, 经过一段神秘操作后, 得到一张内容与Ic相近而风格与Is相近的图片, 也就是说, 其中的关键步骤是评估IIc,Is之间的差异. 也就是说需要设计一个Loss_Function

早在2012年就已经有研究表明"CNN确实有学到什么东西", Visualizing and Understanding Convolutional Networks, 并且不久后google开发了不那么著名但是令人震惊的Deep Dream, 所以我们可以使用CNN作为内容风格的评估, 并且就像Conv可视化一样, 使用CNN的conv输出作为评估, 而不使用dense层, 

图片来自[4]

可以看到loss大体分为两部分: ContentLoss(图片下方蓝色)StyleLoss(图片上方红色), 在确保被评估的输入I(对应图片里的y_het)大小与内容图片大小Ic(y_c)一致下, 在CNN里取同一层输出并取均方误差可以简单得到ContentLoss,简单地用公式表示:  记Φ为CNN, Φ_L(I)为I在CNN的第L层输出 

C,H,W是输出特征图的形状

而对于StyleLoss, 由于图片风格与位置无关, 所以需要把特征图转化成与HW无关的数据, 当然最简单的是直接取每张特征图的平均值得到长度为C的向量, 但是在[1]里使用了Gram矩阵, Gram矩阵不仅与HW无关, 它还计算了每张特征图之间的关系, 公式: F是C*H*W的一块特征图 

简单用程序表示, numpy支持ok

返回的Gram矩阵大小为C*C, 而StyleLoss就可以取I对应Gram矩阵和Is对应Gram矩阵的均方误差了: 

最后, 为了保证图像的多样性, Loss的输出可以不止1层, 如同[2]所示, 使用了4层VGG输出计算StyleLoss, 并且在计算总Loss可以乘上合适的权重W,  最后总Loss函数可以总结为.........

紧急情报, 如果初始化的图像I为噪声图, 在评估Loss并且最小化Loss时, 会出现梯度全部堆积都某几个像素上, 导致一些像素出现正负几千(正常图片范围在0~255)甚至发散的结果, 所以需要额外计算一个VariationLoss, 其实就是直接计算图片在HW方向的平方误差:

这个Loss在这里直接写array计算的方法吧

最后整理上面3种Loss: 得到总Loss的计算方法  虽然式子很长, 只不过是上面说过的拼到一起而已, 并不复杂 

有了求Loss的方法之后, 只需要选好各种超参数就可以开始风格迁移了

[2]中, Φ使用预训练的VGG16, 内容输出层Lc=[15], 风格输出层Ls=[3,8,15,22], 内容权重全为1.0, 风格权重全为5.0, 而VariationLoss的权重为1e-6这里的内容权重和风格权重只是相对而言的, 内容权重比风格权重的比值越小, 则最终图片越偏向风格, 保留的内容细节也越少, 反之亦然. 而w_V几乎是一个独立的值, 一般来说w_V在1e-6~1e-4比较好, 太大会导致图像过于圆滑损失细节, 太小会导致大部分梯度都集中到一小部分像素上

这里非常建议自己去试试做一个, 没什么用又不可以装逼的大技巧 +1

记得VGG输入的图像最好经过预处理, 也就是RGB每个通道减去ImageNet数据集的均值{R=123.680,G=116.779,B=103.939}, 并且输入BGR图像而不是RGB, 这个只是caffe预训练模型的预处理方法, torch模型与caffe模型有很大差别, 详情可以看官方torchvision文档, 或者百度 (google)

VGG16中, 层的编号

选取一张内容图片和风格图片, 使用白噪音初始化图像I, 然后使用L-BFGS更新图像I至最小Loss, 使用L-BFGS是因为计算一副图像的Loss就代表全局的Loss而不需要考虑batchsize, learning_rate什么的, 大约更新500次就收敛到局部最小值附近了 ***

红字提醒: 在原论文[1]中, 并没有使用VariationLoss, 也不是用白噪音初始化图像, 更不是使用VGG16, 他使用内容图像作为初始图像, 而使用VGG19和非常奇怪的输出层, Loss计算细节也不一样,    但是在我两天高强度测试中发现, [1]的Loss计算不使用于[2], 而[2]的计算适用于[1], 我觉得可能是[1]的Loss的计算只在内容图片附件的空间有良好的局部最小值, 而[2]则在大部分空间都具有相似且良好的局部最小值

如果有自己动手尝试上面的单内容单风格的风格迁移的话, 可能你会发现, 或者我现在告诉你: 非常慢, 写这篇文章时手上只有一块750是空闲的, 使用chainer也需要大约60s才可以得到不错的输出, 就算使用torch和ttx Pascal可能也需要~10s, 完全达不到"实时"的效果

这时候就提出了使用转换网络(?TransformNet)来学习图片风格的转换, TransformNet由3部分构成: 输入,下采样 - 转换 - 上采样,输出, 在[2]里给出的结构是

其中ResidualBlock为残差块, 直接扔出[2]里给出残差块的实现:  欲了解详情请搜索残差网络 

TransformNet的输入应该为内容图像Ic, 输出则等于上述Loss中需要更新的图像I, 因为上面已经知道求∂Loss/∂I可以优化I到局部最小值, 而这里 I = TransformNet(Ic), 可以继续利用反向传播求得TransformNet的梯度从而更新TransformNet至局部最优.

可以看到TransformNet只拥有一个图像输入, 也就是说一个TransformNet只能对应一种固定的风格, 训练时间虽长, 但是训练好TransformNet后只进行前向传播就可以完成风格迁移

训练细节: 训练集使用COCO(早安?), 图片大小全部resize到(256,256)风格图片re不re可以看自己心情, batchsize=4, 使用α=1e-3的Adam优化器, 一共更新40k步 *

* 更新40步的意思是: 如果恰好有一个4*40k个图片的数据集, 那么更新40k步就刚刚好用完数据集. 实际上当数据集足够大的时候, epoch是真的没什么用, 一整轮训练下来数据集都没跑完几次, 不如直接随机采样省力气.

上面说到的Loss计算问题, 因为TransformNet在初始化是随机的, 所以刚开始输出的图像I基本上是一个粉噪声图像, 试验过使用[1]中的Loss计算优化TransformNet, 测试了4次的半份训练(20k步), 每次都....完全不能说是"不理想了", 这简直是什么BS ↓

使用我又爱又恨的chainer和垃圾750完成一次训练需要大概20小时, 训练完成后, 计算一张512x512的图片大约需要1.28s, 并且视觉上的效果有时候比单图片单风格要好,  如果使用torch和1080ti写模型, 训练时间可以压缩至1小时左右, 而前向传播甚至达到了惊人207fps (?我是不太信的, 吹, 都可以吹)

风格迁移还有一个叫Meta Networks的快速多内容多风格的风格迁移, 不过介于chainer好虽好, 但是不太完善, 所以我先去摸摸torch再来MetaN了


对编程, 人工智障, 数学物理什么的感兴趣的都可以加群来耍啊, 在线24小时激情监工 : 274767696   (入群提问真的需要认真答好吧)

简述风格迁移Neural-Style细节的评论 (共 条)

分享到微博请遵守国家法律