NTU ML2023Spring Part2.7 GAN

License: CC BY-NC-SA 4.0

对于图像生成之类的任务,它要「生成」一些东西,而它的标准答案不是唯一的,这时怎么梯度下降呢?

只要在输入里加一个随机变量 \(Z\),服从一个较为简单的分布就行了。由于输入的 \(Z\) 不同,整个网络的输出也变成了一个(和 \(Z\) 的分布有关的)概率分布。那为什么不直接输入 softmax 前的结果呢?它带来的一个问题是损失函数不好算。考虑你的训练集,它只有(输入-输出)的一条条数据,你如果不统计就无法得知在同样的输入下输出的概率分布应该长什么样。对于规模较大的训练集,统计概率分布这种事本身就不大现实。

那在什么时候需要给神经网络的输入加一个随机变量呢?简单来说就是有创造力的任务,或者一个输入对应多种可能的输出,每种输出都是对的。

在 generative model 里比较知名的就是 GAN(generative adversarial network,生成对抗网络)

unconditional GAN

unconditional generation 就是输入只有随机变量的情况(不妨假设输入 \(Z\) 是一个维度比较低的向量,每一维服从正态分布)。这时我们的神经网络就是从一个简单的概率分布到另一个复杂的概率分布的函数。

但是问题又来了:既然没有标准答案,那如何评价我们的 generator 是好是坏呢?这里考虑的是 unconditional generator,没法对着输入比对输出。因此,在 GAN 里面,除了 generator 之外,我们还要训练一个东西叫 discriminator。它的输入是 generator 的输出,输出是一个标量。简单来说就是给 generator 的输出判分用的(毕竟 generator 的输出总不能让人来一个个打分)。有点协同进化的感觉。

discriminator 的任务就是分辨 generator 的输出和真正的输出的不同,generator 的任务就是骗过 discriminator。当它骗得足够好的时候,它大概率也可以骗过人眼,生成质量比较高的图片什么的。

训练的基本步骤:

  • 固定住一边,训练另一边
  • 交换

LHY 之前训练一个画二次元人脸的过程:上面的步骤循环 1e3 次出现了眼睛,5e3 次就有一点人脸的样子,1e4 次就有模糊的图像,5e4 次就稍微清晰一点了.

用机器产生图片有一个好处:图片关于随机变量的变化一般是连续的(激活函数是连续的)。于是如果你产生了两张图片,把这两张图片对应的输入向量 \(Z_1, Z_2\) 拿出来,输入 \(\lambda Z_1 + (1-\lambda) Z_2\),就可以做到两张图片之间连续的变化。

其他的神经网络都是最小化一个 loss 就结束了,GAN 为什么要让两个网络互动?为什么 generator 和 discriminator 的互动能让它们进化?我们到底想 minimize 什么东西?

要回答这些问题,首先回顾我们训练 GAN 的基本目标(这里还是先只讨论 unconditional,即只有随机输入的情况):你有一个简单的概率分布,神经网络是它到一个复杂的概率分布 \(P_G\) 的函数,你想让 \(P_G\) 尽可能接近真实的概率分布 \(P_{data}\)

于是我们想找出 \(G^* = \mathop{\arg \min} \limits_G dis(P_G, P_{data})\),其中 \(dis\) 是两个概率分布之间的某种距离,或者说差异(原视频里用的是 divergence,\(Div(P_G, P_{data})\))。但是 dis 怎么算?正是因为不好算,所以才有了 GAN,用另一个神经网络去算 dis. 它的思想是:只要你能从 \(P_G, P_{data}\) 里 sample 出东西,就有办法算它们的 dis.

于是我们想找出 \(D^* = \mathop{\arg \max} \limits_D V(D, G)\),其中 \(V(D, G) = E_{y \sim P_{data}}[\log D(y)] + E_{y \sim P_G} [\log (1-D(y))]\)\(E_{y \sim P_G}[f(y)]\) 就是说用从 \(G\) 里 sample 的方法暴力估算 \(E[f(y)]\). \(V(D,G)\) 的式子有没有觉得很像 cross-entropy?至少我是这么理解的。原论文一通推导推出来它与 JS divergence 有关。

于是我们就有了 \(dis(P_G, P_{data})\) ,把它代回去就是 \(G^* = \mathop{\arg \min} \limits_G \mathop{\max} \limits_D V(G, D)\)。式子里既有 min 又有 max,这也是为什么我们要让两个网络互动。有一种 alpha-beta 剪枝 的感觉,但这里应该用不了。

GAN 很不好训练:No pain, no GAN. 下面是训练 GAN 的小技巧:

(原视频这里字幕和音频不同步,需要手动将字幕提前 5000ms)

  • JS divengence 不好训练。

    • \(P_G, P_{data}\) 都是高维空间里低维的 manifold(高维空间里多数点都不对应有效的生成结果),因此它们几乎不重合。即使重合了也不太可能刚好 sample 到同样的点。

    • 如果两个分布没有重叠,JS divergence 总是为 \(\log 2\),于是 discriminator 就训不起来。

    • 换句话说就是 discriminator 使用 binary classifier 时几乎总是能完美分辨,只有在 generator 表现非常好的时候准确率会突然下降。(这不就是 loss 没设计好吗?)

  • 可以换成 Wasserstein distance.

    • 直观理解:假设有两个分布 \(P, Q\),把它们的概率密度函数用一台「推土机」推成相同所需的移动距离最小值。

    • 式子:\(\max \limits_{D \in 1-Lipschitz(即 D 足够平滑)}\{E_{y \sim P_{data}}[D(y)] - E_{y \sim P_G}[ D(y)]\}\)

    • 用它作 loss 的好处是比较好优化。对应是神经网络就是 WGAN. 要求 D 足够平滑就可以避免它在 real data 和 generated data 分布接近时产生过拟合。

      (原视频这里字幕和声音又不同步了,放弃治疗关字幕看吧)

  • 除了原始的 WGAN 之外,还有基于此的其他改进方法.

    • 使用 spectral normalization(SNGAN)

在序列生成上的 GAN 更加难训练,原因在于它的 loss 是不可微的,没法用 gradient descent 优化。在产生序列中每个 token 的时候会在概率分布里找一个最大的,但如果参数的改变量很小就不会影响输出,相当于这里的 gradient 为零,当然就没法 gradient descent 了。解决方法是 reinforcement learning. 然而这也是一个大坑,两个难以训练的东西加在一起基本就是白给。

回到之前输入一个随机向量,输出一张图片的情况。有一种思路如下:对每一张图片随机分配一个向量,然后就有了输入-输出关系,直接做 supervised learning 就行了。但是实测下来效果比较差,或者说你不能给数据集里每张图片随机一个向量,要用一些特殊的方法安排这些向量。

如何评价 generator 输出图片的好坏?直接用人眼看是可以的,但最大的问题就是成本高(以及比较主观)。那有没有什么自动化的方法呢?可以找一个现成的影像分类系统,把图片输入进去,如果它的输出(概率分布)比较集中,那么就可以认为 generator 生成的图片质量比较好。但是光用这种方法是不够的,会有一种 mode collapse 的问题。考虑一个模型,不管输入什么,都产生同样的一张(训练集里的)图片。所以有一个暴力的解决方法:在训练过程中定期存档,如果发生了 mode collapse 就直接回档。

还有一种问题就是 mode dropping,这种问题更难发现。它其实和 mode collapse 差不多,但是它输出的是训练集里数据分布的一部分。例如训练集里有二次元和三次元的图片,但是 model 只会产生二次元的图片。这种问题也可以借助 image classify 解决。先随机抽样一大堆图片,再把这些图片都丢进 image classifier 里,把所有产生的 distribution 取平均。如果最后平均的 distribution 不怎么平均(这句话有点绕,「平均」是对图片来说,「不平均」是对分类结果来说,或者应该叫「不集中」?),那么生成的图片就比较好。

把 quality(单张图片的集中性)和 diversity(多张图片的多样性)结合起来看就是 inception score(IS). 但是在作业中产生的是二次元人物,可能 diversity 都比较小,因此会使用 fréchet inception distance(FID). 做法就是取 image classifier 的 softmax 前一层的向量,每张图片的向量拿出来,对真实图片和生成的图片算这两个分布的 fréchet distance.

conditional GAN

但你现在已经不满足于只是生成一张随机图片,而是想着文生图了。如何把一段文字输入你的 generator?方法是很多样的,可以给 transformer 的 encder 输入之后转成向量,也可以用别的类似的方法把文字转成向量。但是直接输入文字应该效果不会很好。训练 generator 和 discriminator 时都要额外输入文字(对应的向量)。在训练 discriminator 的时候要刻意将一部分图片标上错误的文字,让机器学习到文字和图片的对应关系。这就是 conditional GAN.

我们之前都是输入输出成对的资料,但如果给你一堆输入和输出,它们之间没有对应关系呢?这就需要 semi-supervised training 或 unsupervised learning. 对于这种任务,我们也可以上 GAN。假设我们要将三次元的图片(设为 domain X)转换成二次元版本(设为 domain Y),但你找到的资料里没什么同样的人物(unpaired)。

  • 一个显然的想法:把 domain X 里的照片输入进 generator(代替原来的随机向量),然后将输出照片与 domain Y 里的照片给 discriminator 分辨。

    但是这样做之后输入和输出可能毫无关系。

  • 这种困境好像在 conditional GAN 里见过?能不能套用它的解决方法?

    当时是有成对资料的,现在没有了。

  • Cycle GAN,启动!

    我们会 train 两个 generator,一个负责把 X domain 的图片转换成 Y domain 的图,另一个与之相反。我们的目标是一张图经过两次转换可以回到自身(cycle consistency)。还有一个 discriminator 要看中间产物与 Y domain 的差距(否则直接不做任何事也能让一张图转换两次不变)

    • 这样不会让机器学到其他奇怪的转换吗?也没法保证人眼看起来效果好吧?

      你说的对,但 train 就完了。实际上我们的模型还是倾向于输出和输入很像的东西。

    当然,你还可以再 train 一个 discriminator,分辨 X domain 里的图片,然后把上面两个 generator 拿来调换一下顺序然后和上面类似地训练。

    合起来这就是 cycle GAN.

同样的技术也可以拿来用在文字上,把负面的文字转成正面的文字之类的。但是涉及到了 seq2seq,所以可以上 transformer.

它用在翻译上就是 unsupervised translation。是不是可以用来破译密码/未知语言……?

posted @   383494  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示