把GAN用在无监督学习 上。到目前为止呢,我们介绍的几乎都是监督学习,即我们要训练一个网络,其输入是x,输 出为y,并且我们需要成对的数据才有办法训练网络。但是我们可能会遇到一个状况是,我们 有一系列的输入和输出,但是x和y之间并没有成对的关系,也就是说我们没有成对的数据。 举一个例子,比如图像风格转换的情况我们就没有成对的数据。我们有一系列真实的照片,然 后有一些动漫的头像,我们希望可以把真实的照片转换成动漫的头像。具体来讲,假设我们要训练一个深度学习的网络,它要做的事情是把x域的真人照片,转换为y域的动漫人物的头 像。在这个例子里面我们或许就没有任何的成对的数据,因为我们有一堆真人的照片,但是我 们没有这些真人的动漫头像。除非我们将动漫的头像先自己画出来,我们才有办法训练网络, 不过这个做法显然实在是太昂贵了。所以对于图像风格转换,我们可能一点成对的数据都没 有。那么在这种状况下,还有没有办法训练一个网络输入一个x产生一个y呢?这个时候就 可以用到GAN,在这种完全没有成对数据的情况下进行学习。

图1 从无成对数据中学习的GAN
如图1 所示,这个是我们之前在介绍无条件生成的时候所使用的生成器架构,输入是一个 高斯的分布,输出可能是一个复杂的分布。现在稍微转换一下我们的想法,输入不是高斯分 布,而是x域的图片的分布,y域是图片的分布。我们完全可以套用原来的GAN的想法,即 在原来的GAN中从高斯分布中采样一个向量输入到生成器里面,之前输入是x域的分布,我 们只要改成可以从x域中采样就可以了。其实都不一定要从高斯分布采样,只要是一个分布, 我们都可以从这个分布中采样一个向量丢到生成器里面,我们选择高斯分布只是因为它的公 式我们是知道的。这个采样过程可以理解为就从真实的人脸里面随便挑一张出来,然后把这 个照片丢到生成器里面,让它产生另外一张图片(分布)。这个时候我们的判别器就要改一下, 判别器不再是只输入y域的图片,而是同时输入x域的图片和y域的图片,然后输出一个数 值,这个数值代表这两张图片是不是一对的。
这整个过程与之前的GAN没有什么区别,但是仔细想想看只是套用原来的GAN训练, 好像是不够的。因为我们要做的事情是要让这个生成器输出一张y 域的图,但是它输出的y 域的图一定要跟输入有关系吗?此处我们没有做任何的限制,所以生成器也许就把这张图片 当作一个符合高斯分布的噪音,然后不管你输入什么它都无视它,只要判别器觉得它做得很 好就可以了。所以如果我们完全只套用一般GAN的做法,只训练一个生成器,这个生成器输 入的分布从高斯分布变成x域的图片,然后训练一个判别器,这样显然是不够的。因为训练 出来的生成器,它可以产生的人物头像跟输入的真实的照片没有什么特别的关系,这个也不 是我们要的。
那怎么解决这个问题呢?怎么强化输入与输出的关系呢?我们在介绍条件型GAN的时 候,提到说假设判别器只看y,那它可能会无视生成器的输入,所以产生出来的结果不是我们 要的。所以我们要让判别器看x和y,这样才可以让生成器学到x和y之间的关系。但是目 前如果我们要从没有样本对的数据中学习,我们也没有办法直接套用条件型GAN的想法,因 为在条件型GAN 里面我们是有成对的数据的,可以用这些成对的数据来训练的判别器。但 目前我们没有成对的数据来告诉判别器,怎么样的x和y的组合才是对的。为了解决这个问题,我们可以使用循环生成对抗网络(Cycle GAN)。
具体来说,在CycleGAN中,我们会训练两个生成器。第一个生成器是把x域的图变成 y 域的图,第二个生成器它的工作是看到一张y域的图,把它还原回x域的图。在训练的时 候,我们会增加一个额外的目标,就是我们希望输入一张图片,其从x域转成y域以后,要 从y 域转回原来一模一样的x域的图片。就这样经过两次转换以后,输入跟输出要越接近越 好,或者说两张图片对应的两个向量之间的距离越接近越好。因为这边有一个循环,从x到 y 再从y 回到x,所以它是一个循环,所以被称为CycleGAN。而因为输入经过两次转换以 后变成输出,并且需要保证输入跟输出越接近越好,所以这个过程也被称为CycleGAN的一 致性。所以在Cycle GAN中我们有三个网络,第一个生成器的工作是把x转成y,第二个生 成器的工作是要把y 还原回原来的x,另一个判别器的工作仍然是要看第一个生成器的输出 像不像是y域的图,如图2所示。

图2 Cycle GAN 的基本架构
那加入了第二个生成器以后,对于前面这个第一个的生成器来说,它就不能够随便产生 与输入没有关系的人脸了。因为如果它产生出来的人脸跟输入的人脸没有关系,那第二个生 成器就无法把它还原回原来的x域的图片。所以对第一个生成器来说,为了要让第二个生成 器能够成功还原原来的图片,它产生出来的图片就不能跟输入差太多,然后第二个生成器才 能够还原回原来的输入。
另外有一个问题,我们需要只保证第一个生成器的输出和输入有一定的关系,但是我们 怎么知道这个关系是所需要的呢?机器自己有没有可能学到很奇怪的转换并且满足cycle 的 一致性呢?比如一个很极端的例子,假设第一个生成器学到的是把图片左右翻转,那只要第二 个生成器学到把图片左右翻转就可以还原了啊。这样的话,第一个生成器学到的东西跟输入 的图片完全没有关系,但是第二个生成器还是可以还原回原来的图片。所以如果我们做Cycle GAN,用 cycle 的一致性的话似乎没有办法保证我们输入跟输出的人脸看起来很像,因为也 许机器会学到很奇怪的转换,反正只要第二个生成器可以转得回来就好了。面对这个问题目 前确实没有什么特别好的解法,但实际上使用CycleGAN的时候,这种状况没有那么容易出 现。输入和输出往往真的就会看起来非常像,甚至实际应用时就算没有第二个生成器,不用 cycle GAN,使用一般的 GAN 替代这种图片风格转换的任务,往往效果也很好。因为网络其 实非常"懒惰",输入一个图片它往往就想输出默认的与输入很像的东西,它不太想把输入的图 片做太复杂的转换。所以在实际应用中,CycleGAN的效果往往非常好,而且输入和输出往 往真的就会看起来非常像,或许只是改变了风格而已。
另一个角度,Cycle GAN 可以是双向的,如图3所示。我们刚才有一个生成器,输入 y 域的图片,输出x域的图片,是先把x域的图片转成y,在把y转回x。在训练cycleGAN 的时候,其实可以同时做另外一个方向的训练,也就是把橙色的生成器给它y域的图片,让 它产生x域的图片。然后在让蓝色的生成器把x域的图片还原回原来y域的图片。同时我们 依然希望输入跟输出越接近越好,所以一样要训练一个判别器,这个判别器是x域的判别器, 它是要看橙色生成器输出的图片像不像是真实人脸的图片。这个橙色的生成器它要去骗过这 个Dx 判别器。这个合起来就是CycleGAN。

图3 Cycle GAN 的双向架构
除了Cycle GAN以外,还有很多其他的可以做风格转换的GAN,比如DiscoGAN、Dual GAN 等等,如图8.33所示。这些GAN的架构都是类似的,一样的想法。此外还有另外一个 更进阶的可以做图像风格转换的版本,叫做StarGAN。CycleGAN只能在两种风格间做转换, 那StarGAN 厉害的地方是它可以在多种风格间做转换。这些文章就等待大家去自己研究。
同样的GAN的应用不仅限于图像风格的转换,你也可以做文字风格的转换。比如说,把 一句负面的句子转成正面的句子,这个也是可以用GAN来做的,只是输入变成文字,输出也 变成文字而已。也就等于是输入一个序列,输出一个序列,这里可能会使用Transformer架构 来做这个文字风格转换的问题。那具体怎么做文字的风格转换呢?其实和CycleGAN是一模一样的。首先要有训练数据,收集一些负面的句子和一些正面的句子,可以从网络上直接爬虫 得到。接下来就完全套用CycleGAN的方法,假设我们是要负面的句子转正面的句子,那么 判别器就要看现在生成器的输出像不像是真正的正面的句子。然后我们还要有另外一个生成 器要学会把正面的句子转回原来负面的句子,要用Cycle 的一致性。负面的句子转成正面的 以后还可以转回原来负面的句子。两个句子的相似度也可以编码为向量来计算。
其实像这种文字风格转换还有很多其他的应用,不是只有正面句子转负面句子。举例来 说,有很多长的文章想让机器学习文字风格的转换,让机器学会把长的文章变成简短的摘要。 让它学会怎么精简的写作,让它学会把长的文章变成短的句子。另外,同样的想法可以做无 监督的翻译,例如收集一堆英文的句子,同时收集一堆中文的句子,没有任何成对的数据,用 Cycle GAN 硬做,机器就可以学会把中文翻成英文了。另外还有,无监督式的语音识别,也 就是让机器听一些声音,然后学会把声音转成文字。这个也是可以用CycleGAN来做的,只 是输入变成声音,输出变成文字而已。当然还有很多很多的有趣的应用等待大家去探索。