1、前言

上一篇,我们讲了PGGAN的模型原理,本章我们就来讲解一下StyleGAN,这个模型能够自由控制图像的风格,细节变化等等,生成用户想要的图像,甚至从某种程度上说,其可以实现AI换脸。

PS:这篇文章其实我做了很多功课,本来不想写的。因为对于我这种水平的人来说,论文太难理解,不仅翻译过来语句不顺(本人英语不好,只能看机翻的版本),里面的原理部分也感觉相当抽象。本来想在网上搜一些文章来看一下,结果很多文章都是跟机器翻译直接复制过来的一样,完全不作解释,晦涩难懂。当燃了,也许是我资质驽钝,无法理解里面的那些浅显的概念。为了防止有人和我一样,看论文看的云里雾里,难以理解其中的意思,我还是下决心以通俗的语言去讲解其中的一些概念,不敢说一定正确理解了论文所讲,只希望能帮助到屏幕前对StyleGAN懵逼的你。

视频:图像风格混合——StyleGAN原理解析-哔哩哔哩

效果图:

在这里插入图片描述

2、引入

首先,为什么要有StyleGAN。在上一篇的PGGAN中,我们已经能够生成高清大图了,并且质量相当不错。可是,我们仍有一个问题——当我们生成图像的时候,我们对这个图像的一些细节不满意,那能不能对这个图像进行一些修改,比如头型,头发等等进行一些变化。在传统的GAN模型系列中,几乎是做不到的。

为什么呢?因为你不知道那些数据代表头发,哪些数据代表头型。此时的你可能会想,那我们一点点的修改其中的量,看图像的变化,不就能试出来哪些变量代表什么了吗?

想法是美好的,但是现实是骨感的。你就是做不到,因为图像的特征之间存在极大的耦合(相关性),一个变量的修改会影响其他变量的更改。比如你修改了其中一个值,很有可能会让整张图像直接毁掉,因为在本来的框架中,那个值的变动要引起其他值的变动(相关性),才能形成图像。而你只修改了其中一个,很大可能会造成图像崩溃。

于是,人们就想,能不能充分的分离出这些特征,减小特征之间的耦合,让特征之间相互独立,互不影响。这样就可以单独修改图像的某一部分了。而StyleGAN正是解决了这个问题。

2、StyleGAN结构图

StyleGAN模型主要是通过修改生成网络,达到上面的目的

2.1、流程

生成网络的结构图是这篇论文最简单的部分了,我们来看这张图

在这里插入图片描述

其分为a,b两部分,左边是我们传统模型GAN的生成网络,而右边则是修改后的,StyleGAN的生成网络结构。

StyleGAN由两部分构成——Mapping network and Synthesis network ,其中Mapping network就是用来控制图像的风格信息的。Synthesis network用来生成图像。流程如下

首先,由Mapping network从标准正态分布中(也可以是其他简单概率分布)采样出一个z latent Code(512维的向量),然后归一化,依次经过8个全连接层映射,得到的值记作w latent Code(512维的向量)。我们把z latent Code的概率分布空间记作Z latent Space,w latent Code的概率分布空间记作W latent Space。如图

在这里插入图片描述

接着,我们初始化一个可学习的常数(Const),记为x,然后,x加上一个B(B是一个随机噪声经过了仿射变化后的值,也就是 B = w × n o i s e B=w\times noise B=w×noise,其中 w w w是一个可学习的参数,为了对噪声进行一些变化),再经过一个AdaIN(Adaptive Instance Normalization),这里的AdaIN实际上就是上一层的输出进行实例归一化,然后再加上缩放和偏置项,输出公式如下
o u t p u t = y s , i x i − μ ( x i ) σ ( x i ) + y b , i output = y_{s,i}\frac{x_i-\mu{(x_i)}}{\sigma(x_i)}+y_{b,i} output=ys,iσ(xi)xiμ(xi)+yb,i
x i − μ ( x i ) σ ( x i ) \frac{x_i-\mu{(x_i)}}{\sigma(x_i)} σ(xi)xiμ(xi)就是实例归一化了,然后通过 y s , i , y b , i y_{s,i},y_{b,i} ys,i,yb,i就是对其进行缩放和偏置项。这两个y哪来的呢,实际上就是左边的w latent Code 经过一个仿射变化(全连接层)转化为512x2的向量,记为A,然后A拆分为两个512向量,分别对应 y s , i , y b , i y_{s,i},y_{b,i} ys,i,yb,i

经过AdaIN后再经过一个卷积层Conv 3x3,然后再重复一个过程,接着上采样分辨率,又重复这个过程。

所以这就是StyleGAN的生成网络结构图了。

看起来没啥特殊的是不是?从哪里分离特征了?我们知道,synthesis network在生成图像的时候,在每个分辨率都是会将左边的w latent Code注入进去。作者经过实验,**发现在低分辨率注入w latent Code,能够控制图像的姿势、发型、脸型等,中分辨率注入w latent Code,则控制面部特征等,当高分辨率注入w latent Code,会带来颜色和微观结构的调整,比如说肤色。 **作者怎么做实验呢?当模型训练好了之后,作者生成两张图像A,B,他们对应的w latent Code为w0,w1,在低分辨率的时候,我们注入w0,在高分辨率的时候,我们注入w1,就可以观察到变化。如图所示

在这里插入图片描述

​ 这个实验的成功,已经充分说明了图片的特征之间已经充分解耦(线性无关)。

​ 除此之外,我们在结构图中,还看到了在不同分辨率中,都有随机噪声的注入。通过实验,作者发现这些噪声能够用来增加图像某些细节的随机性,比如头发、胡茬、雀斑或皮肤毛孔的准确位置。这个随机噪声的注入,在不同分辨率的影响也不同,具体我们来看这张图

在这里插入图片描述

(a)代表全局输入噪声的生成图。(b)代表无噪声的生成图。(c)代表在高分辨率使用噪声的生成图。

(d)代表在低分辨率使用噪声的生成图。

不难看到,当没有噪声的时候,图片几乎没啥细节、特色,其外观平平;而当加入噪声时,整张图像变得更加细腻。在高分辨率使用噪声时,生成图像的皮肤、头发卷曲、背景,都变得更加细致;在低分辨率使用噪声时,会让头发等变得卷曲或出现背景特征。

2.2、问题①:z latent Code 到 w latent Code

讲到这里,我不知道你是否会有疑惑,但是论文里面雀食讲到了,那就是为什么要多此一举把z latent Code 映射到w latent Code 才注入到synthesis network中,而不是直接把z注入到synthesis network中?

前面我们提到,在不同位置把w latent Code注入,会影响图像的风格(姿态、发型等等),说明w latent Code 是风格信息的代表。而如果我们直接用z latent Code去注入,那么z latent Code就是风格信息的代表。

可是,你想过没,z latent Code是从标准正态分布里面采样出来的,里面的值在一开始都是随机的,从某种意义上来说,这些数值还没有实质意义。什么意思呢?举个不太恰当的例子,假如你把从标准正太采样出来的值赋予意义,第一个值代表性别,第二个值代表头发长度,第三个值代表…,这些赋予的实际意义的值合理吗?

不合理!非常不合理!如果我们的数据集不存在男性且长发的数据,可这两个值是完全随机从标准正太分布中采样的,那么采样出男性且长发的概率就相当大。把这些信息注入到synthesis network中,如果这些信息仍然代表风格信息,那么判别网络肯定会判别为假图像,因为真图像根本没有这种图像。

而对于生成网络而言,既然它避免不了随机采样出代表男性且长发的值,那唯一的办法就是,在后面的数值传播中,将这个组合信息抹去。这种操作会造成什么呢?论文里面的意思会造成特征的扭曲(可简单理解为特征耦合)。

以下为个人看法

换句话说,此时的z latent Code代表的不再是真正意义上的风格信息,因为真正的风格信息不会有男性且长发的组合。如果我们把此时的z latent Code仍然当作是风格信息,那么在后续的前向传播中削去这个组合之后,图像的性别和头发信息又该从哪来?这些都不得而知

在后面的数值传播中,比如在模型图中,经过一个Conv 3x3 的卷积层的变化后,或许就消去了那个组合。那么此时我是否可以认为,此时得到的值,才是真正代表风格信息的呢?但是,你如何确保在经过一个3x3之后就会消除这个组合呢?万一它到了后面输出图像的前一刻才消除呢?那个时刻的信息才真正代表风格信息呢?那个时候的信息已经充分耦合了,你怎么办?这些你是没办法控制的**(也许此时你会疑惑为什么w latent Code就一定能充分解耦,后面会讲到,别急)**

以上为个人看法

而如果先把z latent Code映射到w latent Code,就可以在映射的过程中,直接消去男性且长发的组合。并且,由于经过的是非线性变化,此时的概率分布,理论上可以接近风格信息所对应的概率分布。(当燃了,前提假设是生成网络对于充分解耦的特征能够生成更好的图像,而耦合的则更难)

论文里面用了一张非常形象的图来表示

在这里插入图片描述

(a)是数据集特征空间,左上角缺失的那一部分代表男性且长发的数据。

(b)代表从Z latent Space映射到图像的特征空间,可以看到空间扭曲。这张图的意思更像是Z latent Space本身包含了数据男性且长发的组合,所以其形状是一个圆,如果不扭曲空间,就会包含有那个组合,后续的数值传播中,神经网络不得不扭曲空间,而从达到消去该组合的目的。

(c)代表从W latent Space映射到图像的特征空间,其和数据集的特征空间形状很接近,可以看到特征之间相当平整,有序,更加线性。

作者还进行了消融实验,发现w雀食能够充分解耦,而z却不行。

2.3、 Style mixing(风格混合)

之所以在w latent Code这个位置注入到synthesis network 能够充分解耦,我个人认为很大原因就是因为Style mixing。

风格混合其实就是在训练的时候,我们随机采样出两个z latent Code——z0,z1,然后经过全连接层变成w0,w1。接着,就到了风格的混合。选定一个分辨率位置,低于这个分辨率的层把w0注入进去,高于这个分辨率的层,把w1注入进去。从而达到风格混合。

想法也很简单,如果w代表的是风格信息且没有充分解耦,那么我们随意的对两个w latent Code进行混合,必然会造成文章前面所说到的图像崩溃,从而判别器会一眼判断出真假。而生成网络为了避免这种情况,会让w所代表的风格信息充分解耦起来。

2.4、问题②:W latent Space or Noise ?

前面实验的结果已经很明显了,w latent Code 代表风格信息,控制着图像的全局信息。而噪声则代表一些局部的随机变化。

你是否会有一个疑问,为什么风格是由w latent Code来控制的?就是因为它在不同分辨率注入进去了?噪声也在不同分辨率都注入进去了呀。 凭什么就是你w latent Code代表全局?噪声代表局部?

论文里面提到的如果噪声尝试控制全局信息,会导致空间不一致的情况,从而被判别网络惩罚。

空间不一致?什么意思呢?假如,我们要生成的是一张复古风格的图像,那么在低分辨率的姿态,面部等会带有一些复古的元素;在高分辨率的时候,人面部的肤色以及背景,肯定也是服从复古风格。而这些风格的来源,皆来自同一个w latent Code。

可如果是要噪声来控制,每次都会随机采样一个噪声注入进去,也许在低分辨率的时候,采样出来的风格是复古风格,但是在高分辨率,由于随机性,可能会生成一张清新风格的背景和肤色。这会造成在不同分斌率的风格不一样,这就是空间不一致性。这种不一致性大大提高了判别器判别假图片的成功率。所以,生成网络必然会学习使用w latent Code来代表风格信息,噪声代表局部随机变化。

2.5、 Truncation trick in W(截断技巧)

这个小技巧并不是这篇论文提出来的,其方法是对W latent Code 进行一些约束。首先,计算w latent Code的数学期望
w ˉ = E z ∼ P ( z ) [ f ( z ) ] \bar w = \mathbb{E}_{z \sim P(z)}[f(z)] wˉ=EzP(z)[f(z)]
然后新的w latent Code就等于
w ′ = w ˉ + ϕ ( w − w ˉ ) w^{'}=\bar w + \phi(w-\bar w) w=wˉ+ϕ(wwˉ)
w ′ w^{'} w代表输出的新的w latent Code , ϕ \phi ϕ是我们设定的超参数,其中 ϕ < 1 \phi<1 ϕ<1

这个公式怎么理解呢?在我们进行训练的时候,或许我们存在某种类型的数据较为稀少(低密度区域),那么这种数据肯定没有得到很好的学习。为了提高后面图像的生成质量,采用截断技巧收缩风格空间,减少生成低密度区域图像的可能。

所以我们先对风格信息求出数学期望,得到平均风格,然后用 d = w − w ˉ d =w-\bar w d=wwˉ代表每张图片的风格信息与平均风格的距离。再乘以一个 ϕ \phi ϕ,就代表对这个距离进行缩放。比如 ϕ = 0.5 , d = 0.1 \phi = 0.5,d=0.1 ϕ=0.5d=0.1,那么最终得到0.05,可如果 d = 100 d = 100 d=100,那么最终得到50。不难看到,当这个距离很小的时候,对其进行缩放的程度就越小。而当距离很大时(低密度区域),其缩放程度就越大。

3、Perceptual path length(感知路径长度)

前面我们只是感性地认识了W latent Space可以充分解耦,那么我们如何去衡量解耦的程度呢?

那就通过感知路径长度,首先,我们随机从标准正态中采用出 z 1 , z 2 z_1,z_2 z1,z2,然后利用生成网络,生成左上角和右下角的图像。当特征充分解耦,那么从 z 1 z_1 z1图像的狗变到 z 2 z_2 z2图像的狗的过程中,理应就是改变一些肤色等等。比如我们在点t的位置,仍然是只狗,然后再往前走一步 t + ϵ 1 t+\epsilon_1 t+ϵ1改变一些值,如果充分解耦,那么理应得到的也是一只狗。但是,当特征耦合程度很高的时候,你随意改变其中一个值而其他值没有得到修改,会让图像崩掉,也许就变成了左下角那张床的图像。对于这种情况,你所要修改的值会更多,路径也会更加长(对应图中绿色的线)

图像来自参考【1】

Ps:图像来自参考【1】

所以,当把z latent Code直接注入到synthesis network,我们使用下面的公式求出他的感知路径长度
L Z = E [ 1 ϵ 2 d ( G ( s l e r p ( z 1 , z 2 ; t ) ) , G ( s l e r p ( z 1 , z 2 : t + ϵ ) ) ) ] \mathbb{L}_Z = \mathbb{E}\left[\frac{1}{\epsilon^2}d\left(G(slerp(z_1,z_2;t)),G(slerp(z_1,z_2:t+\epsilon))\right)\right] LZ=E[ϵ21d(G(slerp(z1,z2;t)),G(slerp(z1,z2:t+ϵ)))]
其中 z 1 , z 2 ∼ P ( z ) z_1,z_2 \sim P(z) z1,z2P(z) t ∼ U ( 0 , 1 ) t ∼ U(0,1) tU(0,1), G是生成器,d代表的是感知距离, ϵ = 10 −4,slerp表示球面插值,插值其实就是求出两点之间某个点的所对应的值,比如图中, z 1 , z 2 z_1,z_2 z1,z2之中t所对应的值,不懂的话参考线性插值

而对于将z latent Code映射为w latent Code再注入,其感知距离为
L W = E [ 1 ϵ 2 d ( G ( l e r p ( f ( z 1 ) , f ( z 2 ) ; t ) ) , G ( l e r p ( f ( z 1 ) , f ( z 2 ) : t + ϵ ) ) ) ] \mathbb{L}_W = \mathbb{E}\left[\frac{1}{\epsilon^2}d\left(G(lerp(f(z_1),f(z_2);t)),G(lerp(f(z_1),f(z_2):t+\epsilon))\right)\right] LW=E[ϵ21d(G(lerp(f(z1),f(z2);t)),G(lerp(f(z1),f(z2):t+ϵ)))]
其中lerp表示线性插值

下面我们来看一下流程w latent Code计算感知路径长度的流程

①随机从标准正太采样出 z 1 , z 2 z_1,z_2 z1,z2,映射成 w 1 , w 2 w_1,w_2 w1,w2

②从0~1分布中随机采样一个t,计算 w 1 , w 2 w_1,w_2 w1,w2在t这个位置的线性插值,得到的值记作wt0。再计算t+ ϵ \epsilon ϵ时刻的线性插值,得到的值记作wt1。然后把wt0,wt1注入给synthesis network生成图像 i m g 1 , i m g 2 img_1,img_2 img1img2,对这两张图片进行剪裁,只留下人脸的部分(消去背景)。

③用原始训练数据训练好一个VGG16模型。

④将 i m g 1 , i m g 2 img_1,img_2 img1img2喂给VGG16,VGG16输出他们的特征向量分别记为feature1,feature2

⑤求平方,然后在通道维度求和 d = ∑ c h a n n e l ( f e a t u r e 1 − f e a t u r e 2 ) 2 d = \sum\limits_{channel}(feature1-feature2)^2 d=channel(feature1feature2)2

L w = 1 ϵ 2 d \mathbb{L}_w=\frac{1}{\epsilon^2}d Lw=ϵ21d

最后实验发现,z latent Code的路径长度远远高于w latent Code,这说明w latent Code的解耦程度比z高很多。

4、结束

以上,就是StyleGAN的全部内容了,其中还有一些细节,比如线性可分性我没讲到,因为我觉得无关紧要。如有问题,还望指出,阿里嘎多

在这里插入图片描述

5、参考

【1】图像生成典中典:StyleGAN & StyleGAN2 论文&代码精读 - 知乎 (zhihu.com)

【2】StyleGAN 架构解读(重读StyleGAN)精【1】-CSDN博客

【3】Python PyTorch lerp用法及代码示例 - 纯净天空 (vimsky.com)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐