0%

用18支画笔作画的AI ~ StyleGAN特点浅析

GAN(生成对抗网络)是一种能够自动生成内容的神经网络模型。近年来,许多图像生成的研究都基于GAN。

以人脸生成任务为例,一类常见图像GAN的原理如下:模型先要学会辨别一张图像是不是人脸。之后,模型会把一个个高维实数向量表示的“身份证号”映射成一幅幅图像,并根据辨别人脸的知识学习如何让图像长得更像人脸。最终,学习结束后,每一个“身份证号”都会映射到一张逼真的人脸上。只需要给模型一个随机的高维向量,模型就会生成一张人脸。

但是,使用这类图像GAN时,我们不能对图像生成的过程加以干预。也就是说,我们不知道神经网络是怎么把一个个向量映射成一张张栩栩如生的人脸的,而只能将其视作一个黑盒。因此,这些GAN只能用来随机地画出几张漂亮的画,搞搞大新闻,难以产生更加实际的应用。

对此,英伟达提出了可控的图像生成网络StyleGAN,引发了无数研究者的关注。在这个模型生成完一幅图像后,我们可以对图片进行由粗至精共18种微调:同样以人脸生成为例,我们既可以调整性别、年龄这种更宏观的属性,也能调整肤色、发色这种更具体的属性。下图是论文中展示的结果:

最左侧一列是生成的图集A,最上方一行是生成的图集B。前三行、中间两行、最后一行分别是把图集B图像的高级、中级、低级属性混合进图集A图像得到的结果。

可以看出,混入高级属性,人脸的肤色得以保留,而五官、性别等特征被修改了;混入中级属性,人脸的性别、年龄得以保留,而脸部的轮廓被修改了;混入低级属性,人脸的样子几乎不变,而发色、肤色被修改了。StyleGAN确实能神奇地修改生成图像的各类属性。

那么,StyleGAN是如何用这18支“画笔”作画的呢?StyleGAN还有哪些出色的特性呢?我们能用StyleGAN开发出怎样的应用呢?在这篇文章里,让我们来认识一下StyleGAN的主要特点,并快速地用开源项目运行一下StyleGAN。

本文不会对StyleGAN的原理进行详细的解读。在后续文章中,我会系统地讲解StyleGAN的论文及开源实现的使用方法。

原理讲解

控制图像的风格

StyleGAN的名字里有一个”style”,该单词是“风格”的意思。这个单词在图像领域有一个特别的含义:一项神经网络风格迁移(Neural Style Transfer)的研究曾指出,图像可以看成是内容与风格的结合。即使是同一幅风景,不同艺术家也会画出不同风格的作品:

如果对神经网络风格迁移的经典论文感兴趣,欢迎阅读我之前写的解读文章

在那项研究中,人们发现,在由很多卷积层堆成的卷积神经网络中,越浅的层能表示越实际的风格,越深的层能表示越抽象的风格。受此启发,StyleGAN也使用了卷积神经网络来生成图像,并把“控制信号”放在了每个卷积层后。这样,只要调整“控制信号”,就能改变图像的风格了。StyleGAN的生成网络的部分结构如下:

在这个网络中,”Const 4x4x512”表示一个恒定的数据块,该数据块的分辨率是4x4。网络会通过一系列操作,把这个数据块逐渐放大成一幅1024x1024的图像。”AdaIN”是一种运算,该运算受到表示风格的“控制信号”A的影响。”Conv 3x3”是普通的3x3卷积层。”Upsample”表示图像上采样2倍。

把图像从4x4翻倍放大至1024x1024,要翻倍8次,一共涉及9个模块的运算(一个模块就是图中的一个灰框)。而每个模块里又有2个AdaIN,所以,一共有18个调整图像风格的“控制信号”。这就是为什么我们可以说AI在用18支画笔作画。

那么,如何像开头所展示得一样,混合不同人脸的风格呢?这就要详细介绍一下“控制信号”的由来了。前面也提过,通常图像GAN需要输入一个高维实数向量,模型会根据这个向量来生成图像。在StyleGAN中,“控制信号”就来自于这个高维向量。默认情况下,所有“控制信号”都来自同一个高维向量。而如果令某些层的“控制信号”来自于另一个高维向量,就能产生风格混合的效果。前面提到把图像B的低级、高级特征混入图像A,其实就是用图像B代替图像A在网络的浅层、深层的“控制信号”。

为什么调整不同层的风格能够对图像产生不同程度的改变呢?可以这样想象:浅层的数据分辨率较低,只能记录图像的年龄、姿态这种更宏观的信息;而随着数据的分辨率不断放大,深层的数据已经逐渐记录下了人脸的形状,只剩下肤色、发色这种更具体的信息可供更改了。

实际上,从开头展示出来的图片中能够看出,风格混合并不是真的混合了图像的绘画风格,而是混合了图像的各种属性。出于对之前「神经风格迁移」论文中“风格”一词的统一描述,StyleGAN的论文沿用了“风格”一词。

除此之外,StyleGAN还有哪些特性呢?让我们看下去。

随机调整图像细节

在让计算机生成图像时,除了要求图像足够像某种事物外,最好还要能够随机改变图像的细节。比如对于一幅人脸照片来说,如果几束头发的位置发生了偏移,我们还是会认为这是原来那张照片。因此,我们希望生成出来的人脸在头发上的细节可以随机一点。

在传统的图像生成方法中,研究者总是得构造出一些巧妙的参数,通过随机改变这些参数让图像在内容大致不变的前提下调整细节。构造这些参数的过程是非常困难的。而对于StyleGAN来说,它的结构特别适合插入能够修改图像细节的噪声,让我们看一看StyleGAN生成网络完整的结构图:

其实,在输入层或者卷积层后,还有一个与噪声B的加法操作。其中,B通常是从标准正态分布中随机生成的。对于同一个高维向量生成出的图像,改变噪声B会修改图像的细节:

如图所示,改变噪声会改变头发的细节。实际上,噪声几乎不会影响整幅图片的观感,而只会改变头发、胡须、衣领等小细节。

通过改变噪声,我们能够从一幅照片的多个版本中找出一个细节最好的。此外,通过连续改变噪声,我们能够让图像发生连续的变化。这一特性很适合制作简单的2D动画。

靠近平均图像

StyleGAN还有一个很好玩的应用:让生成的某张脸更加靠近大众脸。这一功能是怎么实现的呢?

对数字求平均值,得到的是所有数字的平均水平;对坐标求平均值,得到是一个平均位置。可是,该怎么对照片求平均值呢?如果只是把所有照片的像素值加到一起,再求平均值,肯定只会得到一幅乱糟糟的图像。而StyleGAN则提供了一种求平均图像的方法。

前面提过,GAN是靠一个高维向量表示的“身份证号”来生成图像的。StyleGAN通过一些映射操作,让高维向量的距离与生成出来的图片的相似度相关。也就是说,越近的向量,生成出来的图片就越像。因此,我们可以求出一堆向量的平均值,从而得到一幅平均图像。

有了平均图像,接下来就是如何让另一幅图像更靠近平均图像了。和前面一样的道理,相似的向量能生成相似的图像,那么两个向量的平均值,就能几乎均等地表示两幅图的特性。理想情况下,如果一个向量表示“白发萝莉”,另一个向量表示“黑发熟女”,那么它们的平均向量应该表示“银发少女”。当然,如果不使用平均值,而是使用其他和为1的加权方式,就能让中间的图像更靠近另外某幅图像了。这一操作叫做图像插值。

有了平均图像,有了图像插值方法,就可以一幅图像更靠近平均图像了。下面是几个插值示例图,其中$\psi$表示原图像的加权权重:

$\psi=1$表示随机生成的原图像,$\psi=0$就是平均图像,$\psi<0$表示图像往平均图像“相反”的方向移动得到的图像。

可以看出,随着人像不断靠近平均,甚至往反的方向移动,人像的整体内容都在平滑地改变。比较有趣的是,当人像反向后,人物的性别都反过来了。

从这个例子能看出,StyleGAN使用的输入向量隐含了语义上的信息。通过对输入向量进行简单的数学操作,就能让生成出来的图像朝有意义的方向改变。

总结与展望

通过认识StyleGAN的网络结构,我们了解了StyleGAN的两大输入:表示风格的高维向量与随机扰动图像的噪声。通过修改这些输入,图像会发生不同程度的改变。

基于这些基本操作,我们可以开发出许多图像编辑应用,比如风格混合、简单动画、图像插值、语义反向等。正是因为这些五花八门的图像编辑效果,许多研究者都尝试对StyleGAN的功能进行改进与拓展,发表了很多有趣的科研工作。

令一方面,由于GAN的生成内容取决于训练数据。如果我们用人脸以外的图片作为训练集,就可以让AI画出其他物体来,比如动漫头像、小猫、汽车、酒店房间。这样,就可以开发出人脸编辑之外的应用了。

如果你想直观地体会StyleGAN的效果,可以查看StyleGAN作者发布的视频(在外网)。

如果你想立刻跑一跑StyleGAN,别走开。在附录中,我会介绍如何利用开源项目快速运行StyleGAN。

这篇文章只是对StyleGAN非常粗浅的一个介绍。如果你想认真研究StyleGAN,欢迎阅读我之后发布的StyleGAN论文精读。

快速运行StyleGAN

OpenMMLabMMGeneration用PyTorch实现了StyleGAN并提供了模型权重文件。让我们看看该怎样快速运行StyleGAN。

我使用的MMGen版本是0.7.1

安装

访问官方文档,按照教程装好mmgen。

安装大致分以下几步:

  1. 装PyTorch。
  2. 装mmcv。
  3. 装mmgen。

下模型权重文件

这个网站里找到模型的下载链接。

模型名称中最后的数字表示生成图像的分辨率。按照需要,点击某个模型后面的”model”,下载权重文件。

权重文件下载好了后,推荐放到代码仓库的checkpoints目录下。

运行模型

在某目录下(比如代码仓库的work_dirs目录下)新建并编写Python文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from mmgen.apis import init_model, sample_unconditional_model
import mmcv
from torchvision import utils

config_file = "configs/styleganv1/styleganv1_ffhq_1024_g8_25Mimg.py"
checkpoint_file = "checkpoints/styleganv1_ffhq_1024_g8_25Mimg_20210407_161627-850a7234.pth"
device = "cuda:0"

model = init_model(config_file, checkpoint_file, device)
results = sample_unconditional_model(model, 16)
results = (results[:, [2, 1, 0]] + 1.) / 2.

# save images
mmcv.mkdir_or_exist('work_dirs/styleganv1')
utils.save_image(results, 'work_dirs/styleganv1/output.png', nrow=4)

稍微解释一下这段代码。init_model用于新建一个模型,该函数有三个参数:配置文件config_file、权重文件checkpoint_file、运行设备device。配置文件放在仓库的configs/styleganv1目录下,根据刚刚下载的权重文件,选择配套的配置文件,修改config_file即可。checkpoint_file要填写刚刚下载好的权重文件的路径。device是运行的设备,有GPU的话写cuda:0即可。

sample_unconditional_model用于随机生成一些向量,并用这些向量来生成图片。该函数第一个参数是模型,第二个参数是生成图像的数量。

图像生成完毕后,数据范围是(-1, 1),我们要把它转换成数据范围是(0, 1)的图像。同时,为了兼容输出图像的API,我们还要把颜色通道反向。

最后,调用创建文件夹和保存图片的API,把所有输出图片以网格形式保存到某个文件中。

执行这个Python脚本后,我们就能得到分布在4x4网格中的16幅人脸图像了。我得到的一个结果是:

注意!虽然大部分情况下生成器的表现都挺不错,但它偶尔会生成一些很吓人的图像(比如右上角那张史莱姆人)。大家看输出结果前一定要做好心理准备!


这段代码仅仅展示了StyleGAN生成图像的基本功能。在后续的论文解读文章中,我还会继续介绍如何利用mmgen实现StyleGAN的各种花式应用。