当前位置:   article > 正文

StyleGAN2 解释

stylegan2

本文是[1]的译文, 按照作者Connor Shorten
的说法, 此博客讨论的是StyleGAN2的诸如weight demodulation, path length regularization和去掉progressive growing等信息。虽然我去年底自己复现过StyleGAN2的pytorch版, 但对这些内容也有些忘记了,借此机会复习下。
对于StyleGAN不了解的小伙伴,建议先看下别人写的关于StyleGAN的基本介绍,然后再来看本文,相信会收获更多~

0. 前言

来自Nvidia 赫尔辛基实验室的Karras等人提出的StyleGAN1的架构在Flicker-Faces-HQ (FFHQ)等数据集上表现非常惊人,相比之前的DCGAN和Conditional GAN等结构。

以FFHQ数据集为例,StyleGAN不但可以生成逼真的人脸(几乎无懈可击),而且能够对人脸进行解耦, 以便对人脸进行编辑(19年的论文,截至2020年10月中旬,引用已破千(截至2020年10月20日,是1232.),在twitter上也经常有用StyleGAN的latent space做文章的工作,比较典型的厉害人物有CUHK的沈宇军和周博磊)。

在这里插入图片描述

StyleGAN生成的人脸图像

在StyleGAN中, Frechet Inception Distance (FID) 是最常用的衡量图片真实性的指标(由法国科学家提出,也称遛狗绳距离)。
在这里插入图片描述

第一代StyleGAN[2]的实验表,可见,StyleGAN1在FFHQ最好的FID为4.40,FID越低越好。

在这里插入图片描述

第二代StyleGAN[3]的实验表,可见,StyleGAN2在FFHQ上的表现比第一代更好,其中,FID值由4.40提升到2.84. 算的上是巨大的提升了。

本文主要讨论StyleGAN2相比StyleGAN1在架构上的改变,正是这些改变使得FID指标有了显著提升~,定性观察上面,StyleGAN2的artifacts出现频率也显著比StyleGAN1低。

并基于很多人对latent space进行魔改的需求,对latent space进行平滑操作。

原作者搞了个17分钟的解释StyleGAN2的视频在下面,如果感兴趣的小伙伴,可以饭墙去看看[4]

在这里插入图片描述

1. 重大改进

1.1 Weight Demodulation

karras和ming-yu liu等大佬非常擅长用改造的normalization层进行image synthesis任务(如GauGAN和StyleGAN)。如GauGAN中的SPADE和StyleGAN的AdaIN

对StyleGAN,karras等人使用AdaIN (adaptive instance normalization)来控制source vector w w w对生成人脸的影响程度。

对StyleGAN2来讲,作者们调整了AdaIN的使用,从而有效的避免了水印artifacts(water droplet artifacts)

AdaIN是被用于快速Neural Style Transfer的normalization层。在Neural Style Transfer任务中,研究者们发现:AdaIN可以显著的解耦(remarkable disentanglement) low-level的"style"特征high-level的"content"特征

在这里插入图片描述

图像来自<Arbitrary Style Transfer in real-time with Adaptive Instance Normalization> authored by Xun Huang and Serge Belongie.

不同于一般的风格迁移(Style Transfer)任务,AdaIN的出现使得风格迁移任务从受限于一种风格或者需要lengthy optimization process的情况中摆脱了出来。

AdaIN表明,仅通过归一化统计就可以将风格(style)和内容(content)结合起来。

Karras等人在StyleGAN2中解释了AdaIN这种归一化方法会"discard information in feature maps encoded in the relative magnitudes of activations"。

生成器(Generator)通过将信息sneaking在这些层中来克服信息丢失的问题,但是这却带来了水印问题(water-droplet artifacts)

对于为什么鉴别器(Discriminator)不能识别水印,作者与读者有同样的困惑。

在StyleGAN2中,AdaIN被重构为Weight Demodulation, 如下所示:

  • AdaIN 层的含义: 同BN层类似,其目的是对网络中间层的输出结果进行scale和shift,以增加网络的学习效果,避免梯度消失。相对于BN是学习当前batch数据的mean和variance,Instance Norm则是采用了单张图片。AdaIN则是使用learnable的scale和shift参数去对齐特征图中的不同位置。
    在这里插入图片描述

a,b为StyleGAN的细节图,c和d为StyleGAN2的细节图。可以看出[5]normalization中不再需要mean,只计算std即可。并将noise模块移除style box中,如下所示[5]

在这里插入图片描述

Weight demodulation的处理流程如下

  • ① 如上图里面的©所示,Conv 3x3后面的Mod std被用于对卷积层的权重进行scaling(缩放)
    w i j k ′ = s i × w i j k w_{ijk}^{'} = s_{i} \times w_{ijk} wijk=si×wijk, 这里的 i i i表示第 i i i个特征图。

  • ② 接着对卷积层的权重进行demod
    σ j = ( ∑ i , k ( w i j k ′ ) 2 ) \sigma_j = \sqrt (\sum_{i,k} (w_{ijk}^{'})^2) σj=( i,k(wijk)2)
    那么,得到新的卷积层权重为
    在这里插入图片描述
    加一个小的 ϵ \epsilon ϵ是为了避免分母为0,保证数值稳定性。尽管这种方式与Instance Norm并非在数学上完全等价,但是weight demodulation同其它normalization 方法一样,使得输出特征图有着standard的unit和deviation。

    此外,将scaling参数挪为卷积层的权重使得计算路径可以更好的并行化。这种方式使得训练加速了约40%(从每秒处理37张图片到每秒处理61张图片—不知道作者用的是什么机器)。

1.2 Progressive growth

StyleGAN图像对鼻子和眼睛等面部特征有很强的位置偏好。作者Karras等人将此归因于progressive growing training (同Karras作品PGGAN[6],18年的论文,引用已经有2200左右了,Karras太强了。。。)

Progressive growing指的是:先训一个小分辨率的图像,训好了之后再逐步过渡到更高分辨率的图像。然后稳定训练当前分辨率,再逐步过渡到下一个更高的分辨率。

尽管对研究者来说,复现progressive growing非常令人头大(因为Karras他们全都是用tensorflow 1.x写的这些网络)。这需要复杂的循环和策略设计。但是总的来说,progressive growing还是属于一种比较直观的对高分辨率图像合成coarse-to-fine的方式。这是因为一般的GAN在训练超高分辨率( 102 4 2 1024^2 10242)的图像生成上面相当不稳定,按照作者的话说:

The discriminator will easily distinguish real and fake images, resulting in the generator unable to learn anything during training.

不同于StyleGAN第一代使用progressive growing的策略,StyleGAN2开始寻求其它的设计以便于让网络更深,并有着更好的训练稳定性。
对Resnet结构而言,网络加深是通过skip connection实现的。所以StyleGAN2采用了类似ResNet的残差连接结构(residual block)。对于这些设计,我们使用双线性滤波对前一层进行上/下采样,并尝试学习下一层的残差值(residual value)

如下图所示,Karras等人使用来自TomTom公司和Adobe研究院的作者提出的“Multi-Scale Gradients for Generative Adversarial Networks” MSG-GAN[7]来revisit之前的progressive growing的方式,从而更好的利用不同尺度的信息。

正是受MSG-GAN的启发,StyleGAN2设计了一个新的架构来利用图像生成的多个尺度信息(不需要像progressive growing那样麻烦了),他们通过一个resnet风格的跳跃连接在低分辨率的特征映射到最终生成的图像(下图的绿色block)

在这里插入图片描述

在这里插入图片描述

StyleGAN2的网络结构(受MSG-GAN启发)。

在这里插入图片描述

Here is the performance improvement using different approaches. FID越低越好,可以看出对G output加skip和对D 增加residual的组合效果最好。

作者表明MSG-GAN的方式同progressive growing类似,训练的早期更多地依赖低频/分辨率来对最终的输出产生影响。下图显示了特征图对最后输出的贡献情况。对这一点的研究促使Karras等人扩大网络规模,使1024x1024的分辨率对最终输出贡献更大。

在这里插入图片描述

1.3 Lazy Regularization

StyleGAN1对FFHQ数据集使用了R1正则化。实验结果表明,在评估计算代价的时候,regularization是可以忽略的。实际上,即使每隔16个mini-batch使用regularization的方式,模型效果依旧很不错,因此,在StyleGAN2中,我们可以使用lazy regularization的策略,即对数据分布开始跑偏的时候才使用R1 regularization,其它时候不使用。

1.4 Path Length Regularization

Path Length Regularization的意义是使得latent space的插值变得更加smooth和线性。简单来说,当在latent space中对latent vector进行插值操作时,我们希望对latent vector的等比例的变化直接反映到图像中去。即:“在latent space和image space应该有同样的变化幅度(线性的latent space)”(比如说,当你对某一组latent vector进行了5个degree的偏移,那么反映在最后的生成图像中,应该是同样的效果, 如下图所示)。
在这里插入图片描述
Karras等人通过对生成器(Generator) 增加了一个loss项来达到这个目标。
在这里插入图片描述
代码如下,简单来说就是计算生成器生成的图像对其latent vector的梯度(Jacobian矩阵), ∣ ∣ J w T y ∣ ∣ 2 ||J_w^Ty||_2 JwTy2就是代码中的pl_lengths, a a apl_mean_var的移动平均: pl_mean_var= pl_mean_var + 0.01 * ( m e a n mean mean(pl_lengths) - pl_mean_var)。

这种方法"dramatically facilitates projecting images back into the latent space"(让图像得到更加线性的对应latent vector)。

#----------------------------------------------------------------------------
# Non-saturating logistic loss with path length regularizer from the paper
# "Analyzing and Improving the Image Quality of StyleGAN", Karras et al. 2019

def G_logistic_ns_pathreg(G, D, opt, training_set, minibatch_size, pl_minibatch_shrink=2, pl_decay=0.01, pl_weight=2.0):
    _ = opt
    latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:])
    labels = training_set.get_random_labels_tf(minibatch_size)
    fake_images_out, fake_dlatents_out = G.get_output_for(latents, labels, is_training=True, return_dlatents=True)
    fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True)
    loss = tf.nn.softplus(-fake_scores_out) # -log(sigmoid(fake_scores_out))

    # Path length regularization.
    with tf.name_scope('PathReg'):

        # Evaluate the regularization term using a smaller minibatch to conserve memory.
        if pl_minibatch_shrink > 1:
            pl_minibatch = minibatch_size // pl_minibatch_shrink
            pl_latents = tf.random_normal([pl_minibatch] + G.input_shapes[0][1:])
            pl_labels = training_set.get_random_labels_tf(pl_minibatch)
            fake_images_out, fake_dlatents_out = G.get_output_for(pl_latents, pl_labels, is_training=True, return_dlatents=True)

        # Compute |J*y|.
        pl_noise = tf.random_normal(tf.shape(fake_images_out)) / np.sqrt(np.prod(G.output_shape[2:]))
        pl_grads = tf.gradients(tf.reduce_sum(fake_images_out * pl_noise), [fake_dlatents_out])[0]
        pl_lengths = tf.sqrt(tf.reduce_mean(tf.reduce_sum(tf.square(pl_grads), axis=2), axis=1))
        pl_lengths = autosummary('Loss/pl_lengths', pl_lengths)

        # Track exponential moving average of |J*y|.
        with tf.control_dependencies(None):
            pl_mean_var = tf.Variable(name='pl_mean', trainable=False, initial_value=0.0, dtype=tf.float32)
        pl_mean = pl_mean_var + pl_decay * (tf.reduce_mean(pl_lengths) - pl_mean_var)
        pl_update = tf.assign(pl_mean_var, pl_mean)

        # Calculate (|J*y|-a)^2.
        with tf.control_dependencies([pl_update]):
            pl_penalty = tf.square(pl_lengths - pl_mean)
            pl_penalty = autosummary('Loss/pl_penalty', pl_penalty)

        # Apply weight.
        #
        # Note: The division in pl_noise decreases the weight by num_pixels, and the reduce_mean
        # in pl_lengths decreases it by num_affine_layers. The effective weight then becomes:
        #
        # gamma_pl = pl_weight / num_pixels / num_affine_layers
        # = 2 / (r^2) / (log2(r) * 2 - 2)
        # = 1 / (r^2 * (log2(r) - 1))
        # = ln(2) / (r^2 * (ln(r) - ln(2))
        #
        reg = pl_penalty * pl_weight

    return loss, reg

#----------------------------------------------------------------------------
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

2. 感谢阅读

感谢阅读StyleGAN2的重要特性分析,谢谢~

参考文献

[1] StyleGAN2–medium
[2] StyleGAN: A Style-Based Generator Architecture for Generative Adversarial Networks
[3] StyleGAN2: Analyzing and Improving the Image Quality of StyleGAN
[4] StyleGANv2 Explained!
[5] GAN — StyleGAN & StyleGAN2 – Jonathan Hui
[6] PGGAN
[7] MSG-GAN
[8] StyleGAN2-pytorch

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/454458
推荐阅读
相关标签
  

闽ICP备14008679号