教人工智能生成新的口袋妖怪
宝可梦最初诞生于1996年。二十年来,它已成为全球最知名的游戏系列之一。截至2020年3月:
- 神奇宝贝电子游戏在全球的销量已超过3.8 亿份。
- Pokémon Go 是下载次数最多的手机游戏,下载量超过10 亿次。
- 神奇宝贝集换式卡牌已售出超过341 亿张。
- 整个媒体系列是有史以来票房最高的娱乐媒体系列,总收入估计达900 亿美元
然而,即便如此,独特的神奇宝贝总数仍然只有 893 只。
有了人工智能,我们就能改变这种状况。
我们将在这项工作中使用的基础技术是生成对抗网络。具体来说,是Style GAN 的变体。
对 GAN、渐进式 GAN 和风格 GAN 的直观理解
GAN 于 2014 年首次亮相,并因其生成的图像相当逼真、易于训练和采样、且理论上令人满意而备受瞩目。我另有一篇文章更深入地讨论了 GAN 的构成。
从那时起,对基本 GAN 进行了一系列更改,以生成一些看起来非常逼真的图像。
最初的 GAN 架构采用生成器和鉴别器设计,与对图像进行放大或缩小的标准卷积神经网络非常相似。
渐进式 GAN
渐进式 GAN试图解决传统 GAN 的一个根本问题:生成器比鉴别器的工作难度大得多,尤其是在处理高分辨率图像时。(就像你把一张图片分类为猫或狗比画出一张猫或狗的图像要容易得多一样。)
渐进式 GAN 改变了传统 GAN 的训练阶段,它首先针对 4x4 图像训练一个单层 GAN,然后针对 8x8 图像训练一个双层 GAN,并重复使用已经训练好的 4x4 层。这使得生成器在训练的早期阶段更容易处理问题,并能够扩展生成高分辨率图像。
风格GAN
然而,传统 GAN 和渐进式 GAN 都无法控制生成器生成的图像,例如,无法生成深色头发和浅色头发的人,也无法生成女性和男性的人。风格 GAN 扩展了传统 GAN 的架构,从而可以更好地控制生成器生成的图像。
它通过添加“风格向量”来改变生成器的架构,风格向量是图像生成过程中主要的随机性来源。风格向量被注入到生成器网络的每一层,以在不同分辨率下添加风格变化。
然后,可以通过注入相同的风格向量,将所使用的风格向量从一个生成的图像重复使用到下一个生成的图像,从而将风格(头发颜色、年龄、性别等)从一张图像“转移”到另一张图像。
我该如何构建一个?
Style GAN 的代码有点太多,无法全部查看,但我们可以通过一些代码示例来查看每个重要部分。
- 构建渐进式 GAN
- 添加映射网络
- 自适应实例规范化
- 移除生成器的潜在向量输入
- 为每个块添加噪声
Style GAN 架构
Style GAN 以 Progressive GAN 为基础,并添加了一系列改进。
测绘网络
这是 StyleGAN 的架构。请注意,潜在变量 z 并非直接传入生成器。而是通过一个 8 层 MLP(称为映射网络)来生成“风格向量”。
然后,该风格向量被注入到生成网络(本文中称为合成网络)的每一层。作为自适应实例归一化的一部分,风格向量用于为图像中的每个通道生成尺度和偏差向量。
flatten = lambda t: [item for sublist in t for item in sublist]
class MappingNetwork(nn.Module):
def __init__(self):
super().__init__()
blocks = [[nn.Linear(512, 512), nn.LeakyReLU(0.2)] for _ in range(8)]
self.net = nn.Sequential(*flatten(blocks))
def forward(self, latent_vector):
style_vector = self.net(latent_vector)
return style_vector
自适应实例规范化(AdaIN)
为了理解自适应实例规范化的工作原理,让我们首先回顾一下批量规范化的工作原理。
AdaIN 的公式与批量标准化的公式非常相似:
class AdaIN(nn.Module):
def __init__(self):
super().__init__()
def mu(self, x):
""" Takes a (n,c,h,w) tensor as input and returns the average across
it's spatial dimensions as (h,w) tensor [See eq. 5 of paper]"""
n = torch.sum(x,(2,3))
d = x.shape[2]*x.shape[3]
return n / d
def sigma(self, x):
""" Takes a (n,c,h,w) tensor as input and returns the standard deviation
across it's spatial dimensions as (h,w) tensor [See eq. 6 of paper] Note
the permutations are required for broadcasting"""
n = torch.sum((x.permute([2,3,0,1])-self.mu(x)).permute([2,3,0,1])**2,(2,3))
d = x.shape[2]*x.shape[3]
return torch.sqrt(n / d)
def forward(self, x, y):
""" Takes a content embeding x and a style embeding y and changes
transforms the mean and standard deviation of the content embedding to
that of the style. [See eq. 8 of paper] Note the permutations are
required for broadcasting"""
return (self.sigma(y)*((x.permute([2,3,0,1])-self.mu(x))/self.sigma(x)) + self.mu(y)).permute([2,3,0,1])
添加高斯噪声
在每个 AdaIN 操作之前,都会将高斯噪声添加到激活图中,用于在生成器的每个级别生成风格变化。
引入这种噪声的原因是为了强制模型学习局部风格水平的变化。
移除生成器的潜在向量输入
传统 GAN 会生成一个潜在向量,并将其输入生成器,从而生成样本。而风格 GAN 实际上只使用一个 4x4x512 的恒定向量,该向量在训练和推理过程中保持不变。这是因为变体来自通过 AdaIN 操作在每一层添加的风格向量和高斯噪声,而不是初始潜在向量。
请记住,Style GAN 的最终目的是发现可以从一张图片应用到另一张图片的风格向量。这只有当两张图片都基于同一个“画布”时才有效,而这个 4x4x512 的常数就充当了画布的角色。如果画布发生变化,那么学习到的风格向量就无法迁移。
在 Pokemon 数据集上进行训练
让我们看看将这个模型用于约 35,000 张 Pokemon 图片的数据集时会发生什么。 训练模型大约需要一周时间,才能在 Nvidia GeForce 3070 GPU 上产生看起来不错的结果。我不确定再训练几周后图像效果会有多好,但我会让它继续运行一段时间。
关于新宝可梦的一些建议
想要了解更多 AI 知识?准备好构建自己的机器学习模型了吗?立即免费使用 Mage!