CycleGAN

CycleGAN

好久没有更新文章了,都快一个月了。其实我自己一直数着日期的,好惭愧,今天终于抽空写一篇文章了。

今天来聊聊CycleGAN,知乎上面已经有一篇文章介绍了三兄弟。哪三兄弟?CycleGAN,DualGAN,DiscoGAN。它们在原理上是一样的,借助GAN实现两个domain的数据迁移。

今天的文章会比较短,因为CycleGAN的原理比较简单。不过,简单却很有效。

General的GAN面向一个domain的数据,G尝试生成尽可能接近真实的数据,而D则尽可能地分辨来自domain的真实数据和生成数据。两者是一直在博弈的,博弈中G逐渐占据上风,最终生成的数据跟domain的数据没什么两样。

怎么实现两个domain的数据迁移呢?下面以图像为例来阐述吧。

实现图像间的翻译,借助GAN,应该有两个domain的discriminator,每个discriminator单独判断各自domain的数据是否是真实数据。至于generator,图像的翻译需要将domain A的图像翻成domain B的图像,所以generator有点像autoencoder结构,只是decoder的输出不是domain A的图像,而是domain B的图像。为了充分利用两个discriminator,还应该有一个翻译回去的过程,也就是说,还有一个generator,它将domain B的数据翻译到domain A。如果你看过对偶学习(dual learning)那篇文章,你应该对此很熟悉。感觉有点绕?还是看图吧。

图中的虚线箭头表示『将箭头起始的图像当做箭头结束的图像,按照流程图继续走 』,什么意思呢?对于Real A,它的完整流程是这样的:A_{real} \rightarrow B_{fake} \rightarrow A_{fake},对于Real B,它的流程是这样的:B_{real} \rightarrow A_{fake} \rightarrow B_{fake}。可以看到,无论是domain A还是domain B的图像,整个流程就是一个cycle啊!所以叫CycleGAN。整个cycle可以看成是一个autoencoder,两个generator看成是encoder和decoder。而两个discriminator则是准则。

一般来说,两个generator的设计是这样的:

z在G中控制一些属性,使得生成的结果不是唯一的,可以是多种多样的。

明确了CycleGAN的流程,我们就能写出它的目标函数了:

对于discriminator A: \mathcal{L}_{D_A} = \mathbb{E}_{x \in \mathbb{P}_A} \log D_A(x) + \mathbb{E}_{x \in \mathbb{P}_{B2A}} \log(1-D_A(x))

对于discriminator B: \mathcal{L}_{D_B} = \mathbb{E}_{x \in \mathbb{P}_B} \log D_B(x) + \mathbb{E}_{x \in \mathbb{P}_{A2B}} \log(1-D_B(x))


对于generator BA: \mathcal{L}_{G_{BA}} = \mathbb{E}_{x \in \mathbb{P}_{B2A}} \log D_A(x) + \lambda \mathbb{E}_{x \in \mathbb{P}_A} \|x - G_{BA}(G_{AB}(x))\|_1

对于generator AB: \mathcal{L}_{G_{AB}} = \mathbb{E}_{x \in \mathbb{P}_{A2B}} \log D_B(x) + \lambda \mathbb{E}_{x \in \mathbb{P}_B} \|x - G_{AB}(G_{BA}(x))\|_1

(对于discriminator,需要最大化目标函数;对于generator,需要最小化目标函数)

对于generator添加重构误差项,跟对偶学习一样,能够引导两个generator更好地完成encode和decode的任务。而两个D则起到纠正编码结果符合某个domain的风格的作用。结构很简答,但是很有效。并且,你并不需要pair的数据。以下是我跑的一个实验结果,CelebA数据集上的卡通化和反卡通化(可以用opencv获得cartoonize的数据,可以参考这个代码)。


(CelebA -> cartoonize CelebA, samples from epoch 11)

(Cartoonize CelebA -> CelebA, samples from epoch 11)

作者做了很多有意思的实验,包括horse2zebra,apple2orangle,以及风格迁移,如:对风景画加上梵高的风格。

讨论


1. 去掉重构误差?模型是否还有效?

模型仍然有效,只是收敛比较慢,毕竟缺少了重构误差这样的强引导信息。以及,虽然实现了风格迁移,但是人物的一些属性改变了,比如可能出现『变性』、『变脸』,而姿态在转换的时候一般不出现错误。这表明,对偶重构误差能够引导模型在迁移的时候保留图像固有的属性;而对抗loss则负责确定模型该学什么,该怎么迁移

下图是跑了20个epoch的结果。

(CelebA -> cartoonize CelebA, sample from epoch 20)

(cartoonize CelebA -> CelebA , sample from epoch 20)


2. 能不能不要完整的cycle,只做一半?例如:


结论是不行,缺少了对偶的部分,就少了重构误差,仅仅依靠D_B来纠正G_{AB}是不够的。从讨论1来看,对偶的作用还是很大的,即使缺少了重构误差。以上面CelebA的cartoonize为例,迁移的图像全是随机噪声。这里就不放结果了。

代码


参考文献

1. Zhu J Y, Park T, Isola P, et al. Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks[J]. arXiv preprint arXiv:1703.10593, 2017.


最后的最后,多说几句。三兄弟的想法如此相似,怎么避免这种重复工作呢?在做一个东西以前,需要先调研是否别人已经做过了。然而这是一个NP hard的问题,在朋友圈看到一个绝妙的解决方案(来自reddit),仅供参考,手动微笑。

编辑于 2017-05-19

文章被以下专栏收录