前言
大家好,笔者将在本文介绍一种基于UGATIT的图像翻译网络,并且DIY,加入两项额外的trick,使UATIT能支持渐进式的域迁移,即能实现A域的图像样本是如何逐渐向B域迁移的。我们叫该DIY模型为Morph-UGATIT。笔者在该项目的主要工作有:
- 首先基于UGATIT官方tensorflow源代码,用PyTorch 1:1完美还原,包括网络模型,训练代码,超参数。
- 在生成器(G)的loss中引入额外的一项:identity preserving loss。
- 在生成器(G)中,增加MLP,沿用StyleGAN利用w 空间的方式,代替UGATIT生成beta和gamma的方式。
- 将UGATIT的两个生成器,整合为一个生成器。判别器依然使用两个,分别判别A域和B域的真假。
Note:写在前面,笔者的改进思路,并非完全原创,其借鉴了Eccv2020的一篇论文。文中也会提及。全部代码已经开源,地址在:
代码语言:javascript复制https://github.com/shoutOutYangJie/Morph-UGATIT
预备知识
我们先简单回顾一下UGATIT,作为一个Cycle-base图像翻译方法,它和cycleGAN的主要区别在于:
- 提出CAM loss,CAM loss在G和D中起到的作用也不一样。
- 提出AdaLIN,自适应改变LN和IN的比例。
https://github.com/taki0112/UGATIT
由于以上两个区别不会导致和CycleGAN framework的巨大差异,为了方便我以下的描述,笔者直接沿用cycleGAN的framework进行描述。CycleGAN的framework大致如下,仅画了从A域向B域迁移的过程,黄色虚线是计算loss,省略了identity loss:
cycle-base GAN (方向:AtoB)
A域的真实样本经过G_A得到假的B域样本fakeB,fakeB经过G_B又从B域向A域迁移,为了是建立cycle consistency loss。优化cycle consistency loss,使得A和B域之间的各个属性mapping能一一对齐,这样就解决了unpair的图像翻译。
同时,A域的样本经过B,直接得到了B域的样本,各位炼丹师们是无法得知,样本是如何从A域变换到B域的。
接下来简单介绍笔者借鉴的另一篇论文。
代码语言:javascript复制https://github.com/royorel/Lifespan_Age_Transformation_Synthesis
lifespan age synthesis
该论文是一个unpair multi-domain transfer的图像翻译方法。作者将年龄分成6个段,作为单独的6个域,能实现一个样本在这6个域的连续渐变迁移。巧妙的地方在于,不同于其他face aging(人脸年龄编辑)的cgan方式,作者使用了一个mlp编码年龄向量z,进入到一个隐空间。
不同年龄段的latent code进行插值,用插值之后的latent code生成图像,则图像的效果就介于两个域之间。比如说,该论文选择face aging这个方向实验。数据集中各个年龄被化分为几个段:{0:6},{16:30},...。如果我们想得到{7:15}岁的人脸,则将{0:6}和{16:30}这两个区间对应的latent code进行按比例插值即可。
大家要注意,如果没有这个mlp,现存的方式的做法是,z将会被视作condition,直接送入G中。但是,如果直接在z空间插值,得到z',z'是无法直接起到作用的。因为在训练阶段,G就没有见过z'这种数据分布。在隐空间插值,绕过了这个问题。
这样的话,笔者已经介绍完毕所需要的预备知识。
方法
Morph-UGATIT
overview:Morph-UGATIT直接使用一个生成器完成2个域的迁移。X是生成器的输入,接收来自两个域的样本。Z空间也是两个域分别对应一个随机z向量。如果Z空间输入的是z1,则代表,生成器要生成B域图像;
反之亦然。有两个判别器,分别对生成的A域真or假样本以及B域真or假样本进行判别。同时生成的样本X`,也会在经过一个E,和原始输入X对应的E(X),计算L1 loss,作为identity presevering loss,即希望生成的样本和原始样本的细节接近一致。
Z空间的初始化是依赖于生成器想生成哪个域的样本,如果想生成B域样本,则输入z1;反之亦然。z1和z2的初始化方式也不一样。Z向量是一个64维向量,其初始化方式为:
z1和z2的初始化方式,仅仅在于加1的位置不同,z1在前zdim个位置都加上1,z2则在后zdim个位置上加1。z_dim的值是Z长度的一半,即32(在笔者的实验中)。
看到这里大家也许就明白为何不能在Z空间插值了。因为插值出来的新z‘,不属于两种分布之一,G没有在训练中接收到这种分布,自然没法在测试阶段起到作用。
将两个域用一个生成器实现,以及MLP的应用,都是遵从论文“Lifespan Age Transformation Synthesis”的做法。
笔者认为,原作者首先将Z单独使用,由Z决定生成器要往哪个域上迁移,有助于Encoder(E)学习到A域和B域共同属性的特征,再加上identity preserving loss的作用,进一步约束两个域的相似。
下面以从A域向B域迁移为例子:
- 初始化一个向量z1,用属于方向"AtoB"的方式新建一个z1。(两个方向,初始化z的方式不一样),送入生成器中。
- x经过Generator,得到E(x), x', cam_ab;cam_ab是为了计算cam loss,属于ugatiti论文的做法,不再多说明
- 重新初始化一个向量z2,把x'和z2都送进生成器,得到x''。
- 计算对抗loss,恒等映射loss(identity loss),cam loss,cycle consistency loss,以及identity preserving loss。G和D交替优化。
更相似的过程可以参考笔者开源的代码:
代码语言:javascript复制https://github.com/shoutOutYangJie/Morph-UGATIT
实验
笔者设置了3组模型。分别在{成人脸,娃娃脸}和{真实人脸,动漫人脸}两种数据集探究Morph-UGATIT的能力。
- config-A: 使用笔者自己用pytorch复现的UGATIT训练
- config-B:在config-A的基础上,增加identity preserving loss
- config-C: 在config-B的基础上,增加MLP学习隐空间
数据集来源:
- {成人脸,娃娃脸}:来自G-lab开放下载的,由StyleGAN2生成的萌娃数据集,以及StyleGAN生成的成人数据集。(没错,用的生成的假数据训练的。实在没有好的数据来源。)所幸这批数据大部分样本还是很逼真,有些样本的背景包括发尾,颈部以下会失真。
http://www.seeprettyface.com/mydataset.html#adult
- {真实人脸, 动漫人脸}:来自UGATIT开源的代码中提供的数据集,大家可以自行寻找。目前这个实验正在做,还没有做完。
首先看一下在成人脸向娃娃脸(AtoB)转化,在训练集上的表现。
以下图像按照原图(第一列),config-A(第二列,UGATIT),config-C(第三列,Morph-UGATIT)。因为config-B的视觉效果和config-A差不多,故此省略。
第3列的样本,morph-ugatit生成的脸更像输入人脸
config-A和config-C总体上差不多,也说明UGATIT自身的强大。
受样本分布影响,黑人基本上都转成了白人娃娃
总体来看,在训练集上,config-{A,B,C}差不多,且都存在bad case。config-C在细节的保留上略微好了一丢丢。这里面有两个点需要探讨:
- 如果不在训练集上测试,config-{A,B,C}的差距会不会拉大。毕竟训练集是做了针对性优化的
- config-C的CAM如果去除,会不会提升其视觉效果,进一步拉开与config-{A,B}的差距。(笔者木有时间做了)
笔者在网络上搜集了一些名人明星的照片,作为测试集。因为时间及精力有限,仅搜集了几张。这些照片均使用FFHQ规则进行align。
四列按照 原图,config-A, config-B,config-C的排列。
接下来看看在{真实人脸,动漫人脸}数据集上的效果。笔者在UGATIT论文提供的数据集“selfie2anime”上的训练集训练,在测试集测试。由于时间关系,笔者仅仅做了config-A的实验(即笔者自己用pytorch实现的UGATIT)。
消融讨论(ablation discussion)
1.Morph-UGATIT的Encoder是否可以学习到公共的属性,能如笔者所想?
在笔者的实验过程中,意外的发现,cam loss的曲线异常,这算是一个实验的惊喜。笔者搭建的morph-ugatit,是在笔者自己复现的ugatit的基础上完成的,自然保留了CAM这个模块以及对应的loss。
起初笔者并没有思考,在自己DIY的基础上,还需不需要CAM,而是选择直接保留。于是就看到了这样的CAM loss 曲线。
config-C(第一行)和config-B(第二行)的CAM loss曲线。
这里简单回顾一下生成器的CAM loss:
在UGATIT原文中,G中的CAM负责找出最不像目标域的区域,并使用cam的方式强调该区域。CAM loss则优化从源域到目标域得到的置信概率,以及目标域到目标域(恒等映射)得到的置信概率的距离。
CAM loss可以简单理解为:让两个不同域的样本进入相同的Encoder,特征分布要有所区分。我们从上面的曲线图可以看出,config-B的CAM loss都优化都到了接近0的位置。而config-C的CAM loss优化到1300多,就已经要收敛了!!!
这提供了一个事实依据:Morph-UGATIT能够解耦出AB域共同的特征属性。因为config-C的cam loss很早就陷入了拉锯战:一个相同的分布,如何让它被分到两个类别上去?自然无法做到,因此cam loss一直很高,无法下降。
2. 在AB域插值,查看其渐变迁移效果如何。
很遗憾,在{成人脸,娃娃脸}数据集上,AB域的转换非常不平滑。没有论文“lift age transformation synthesis”中的那么好。这里面存在的可能原因将在Extension.3中提及。
A域向B域渐进迁移(从右向左)
在A域逐渐向B域迁移的过程中,可以看出,迁移效果并不稳定。一些中间结果出现了artifacts。迁移的变化,主要体现在面部脸盘变大,发型开始变化,面部细节的变换很生硬,基本是直接跳过去的。
笔者认为,如果A域B域的关键因素(比如年龄)的间隔如果小一些,可能迁移会更加平滑,正如论文“lift age transformation synthesis”展示的效果那样。
另外如果在训练过程中,设置一个新的判别器,用来判别用mix W空间隐向量生成的样本的真伪,在辅助identity preserving loss,以及content loss,push生成结果更加真实,也许能在该数据集上,做到比较真实且平滑的大人脸到娃娃脸之间的迁移。
Extension
1. 在希望编码公共属性的同时,也许我们留出某些通道,去挖掘AB域的不同点,剩下的通道学习AB域的公共属性,让CAM loss只去优化挖掘不同点对应的权重,也许会有更好的视觉效果。
2. 笔者虽然引入了Z空间,但Z空间的作用只为了满足两个域的转换所需要的分布。这导致z的不同并不能生成基于原始A域样本人物的多样性B域样本。如何能让z的变化,带来domain transfer上的变化,也是一个不错的探索方向。
3. AB域的渐进变化,并不平滑。这里可能是因为{成人脸,娃娃脸}年龄相差太大导致。也可能是因为decoder没有完全采用论文“Lifespan_Age_Transformation_Synthesis”中的style-based decoder。
4. 由于用的是L1 loss进行恒定映射,所以导致A域到A域的映射会输出一张模糊的照片,这是L1,L2loss自身的局限性。但因为cycle-base训练方式需要恒定映射,而L1 loss也是最简单的做法。
如果想生成更真的恒定映射结果,或许可以用content loss(vgg loss)以及将恒等映射的结果也送到判别器,参与训练,说不定可以解决该问题。同理,cycle loss需要的recA,recB也是可以用同样的做法。
5. 在训练过程中,设置一个新的判别器,用来判别用mix W空间隐向量生成的样本的真伪,在辅以identity preserving loss,以及content loss,以此来push生成结果更加真实,也许能在{大人脸,娃娃脸}上,做到比较真实且平滑的大人脸到娃娃脸之间的迁移。
总结
- cycle-based的domain transfer,还是尽量对齐数据集的分布,就拿人脸数据集来说,男性女性分开,前景背景分离,以及侧脸正脸区分,都是有助于模型的收敛。我在实验的时候发现,对于侧脸的情况以及带眼睛(墨镜)的情况,生成器倾向于生成正脸,但脸部的边缘又有侧脸情况的重影(导致视觉效果假),墨镜则被完全移除。
- identity preserving loss的一个副作用,就是让生成器过度关注人脸面部,而忽略的其他细节的合理性:比如假样本娃娃域的耳朵实在是太大了(哈哈)
- identity preserving loss并不是让Encoder学习公共属性的关键,而是引入MLP,将域的转换依赖于Z空间分布,并且让Encoder接收来自不同域的样本,迫使encoder学习公共属性。因为config-B也使用了identity preserving loss,但是CAM loss 一样优化到了很低.
- Morph-UGATIT中,生成器的CAM loss虽然经过实验得知,没有必要保留,但笔者开源的代码中还是留存了;笔者也不会再去花费时间验证去除G中CAM loss的效果。但如果去除掉CAM,会不会有视觉效果的提升呢?
- 男性转化的难度比女性大。