Skip to main content

对抗隐性自动编码器

利用自动编码器的隐性能量,逐步解耦表征。
Created on October 14|Last edited on January 27
本报告是作者Ayush Thakur, Sairam Sundaresan所写的"Adversarial Latent Autoencoders"的翻译

引言

用Yann LeCun的话来说,生成对抗网络(GAN)是“过去十年机器学习领域最有趣的想法”。这并不奇怪,因为GAN几乎能够生成任何东西——从人们“逐渐变名人脸”的高分辨率图像、建筑布局和蓝图到表情包等等。它们优势在于其对复杂分布进行建模的惊人能力。尽管自动编码器试图像GAN一样多才多艺,但它们(至少到现在为止)还不具备GAN那样的生成能力,而且它们一直以来都使用了纠缠表示法(entangled representation)。该论文的作者从GAN的最新进展中汲取了灵感,提出了一种新的自动编码器,来解决这些根本性缺陷。在接下来的几节中,我们将更深入地探讨如何做到这一点.

                                                                                                                                Source

前言

自动编码器

自动编码器是编码器函数gϕ(x)和解码器函数fθ(z) 的组合,前者接收输入数据并将其转换为不同的表示形式,后者则将这些表示形式返回到原始域。其中z=gϕ(x)是输入的隐性表征。这意味着,编码器将高维输入空间(数据)压缩为低维隐性空间(表示形式)。解码器将给定的表征重新构造回原始域。因此,通过同时学习一个编码器-生成器(解码器)映射,它们可以结合生成属性和表征属性。

                                                                                                              基本编码器 来源

GAN(生成对抗网络)

一个GAN模型进行了两个对手之间的一场对战——即生成器Generator(G)和鉴别器Discriminator(D)之间的对战。顾名思义,生成器负责学习隐性空间(Z),这是已知的先验p(z)。这是为了生成新图像,表示合成分布q(x),而且这无需像我们使用自动编码器那样直接将图像编码到该隐性空间。另一方面,鉴别器负责将生成的图像与训练数据集中存在的图像区分开,训练集图像表示真实分布 pD(x)。 GAN旨在学习G,以使q(x)与pD(x)接近。这是通过使用鉴别器玩零和两人博弈来实现的。您可以从这里阅读有关自动编码器、GAN和隐性表征的更多信息。

基础的 GAN 来源

对抗隐性自动编码器

尽管自动编码器已经得到了广泛的研究,但一些问题尚未得到充分的讨论,它们是:

1.自动编码器能否具有与GAN相同的生成能力? 2.自动编码器可以学习解耦表征吗?

隐性空间中的点保存有关输入数据分布的相关信息。如果这些点之间的纠缠较少,那么我们将对生成的数据有更多的控制权,因为每个点都对数据域中的某个相关特征有所贡献。对抗隐性自动编码器 的作者设计了一种新的自动编码器,可以同时解决上述两个问题。接下来,让我们仔细研究一下它的架构。

原文章的repository链接

架构

ALAE

ALAE(对抗隐性自动编码器)的体系结构是对原始GAN的修改,通过将生成器(G)和鉴别器(D)的网络分解为两个网络: G =F∘G和D =E∘D.该架构如图3所示。假定两个分解的网络之间的隐性空间相同,并表示为W。让我们一个一个地看每个网络块。

image.png                                                                                                        ALAE的架构(来源)

1. 映射自隐性空间(F)

该网络负责将先验分布p(z)转换为中间隐性(ω)分布qF(ω)。本文 远离输入空间的中间隐性空间往往具有更好的解耦特性。 ALAE的作者已将F假定为在大多数情况下是一个确定性映射。

因此, F从已知先验p(z)提取样本,并输出qF(ω)。

model.pymodel1这个类中的网络定义:

## (F) Mapping from known prior p(z)->W 
self.mapping_fl = MAPPINGS["MappingFromLatent"](
            num_layers=2 * layer_count,
            latent_size=latent_size,
            dlatent_size=latent_size,
            mapping_fmaps=latent_size,
            mapping_layers=mapping_layers)

在同一类的generate方法中,self.mapping_f1是这样使用的

if z is None:
    z = torch.randn(count, self.latent_size)

## (F) maps p(z) to latent distribution, W
styles = self.mapping_fl(z)[:, 0]

2. 生成器(G)

这是我们的GAN老式生成器。但是它有两个不同之处:

1.对我们旧生成器的输入是直接从隐性空间中采样的,而现在,对于我们生成器的输入是中间隐性空间,您很快就会发现,这个中间隐性空间是从输入训练数据的空间中训练获得的。

  1. 2.旧生成器的输出被馈送到鉴别器,该鉴别器不过是一个二元分类器。在ALAE体系结构设计中,G的输出被馈送到编码器(E),如上图所示。

作者已经假设G可能有选择地依赖于一个独立的噪声输入η,该输入是从已知的固定分布pη(η)采样的。

因此,生成器(G)的输入为qF(ω)和可能的pη(η)。输出如下:

math-20200615.png

其中,qG(x∣ω,η)是在给定ω和η的情况下生成图像x的条件概率。

model.pymodel这个类中的网络定义::

## Generator (G) Takes in latent space and noise
self.decoder = GENERATORS[generator](
            startf=startf,
            layer_count=layer_count,
            maxf=maxf,
            latent_size=latent_size,
            channels=channels)

generator方法中self.decoder是这样使用的:

rec = self.decoder.forward(styles, lod, blend_factor, noise)

他们必须将其命名为解码器,因为GAN的生成器类似于自动编码器的解码器

3.编码器(E)

顾名思义,Encoder(E)将数据空间编码为隐性空间。G\textbf{G} = F∘G\textit{F} \circ \textit{G} and D\textbf{D} = E∘D\textit{E} \circ \textit{D} 同。也就是说,编码器应将数据空间编码为相同的中间隐性空间ω。

在训练期间,编码器的输入要么是来自真实数据分布pDq(x)q(x)的真实图像或是代表合成分布qpD(x)p_D(x) 的生成图像。如图3所示。

从合成分布中提取输入时,编码器的输出为:

math-20200615.png

其中,qE(ω)q_E(\omega) 是在给定数据空间 xxx的情况下,隐性空间ω\omega 的条件概率分布。

从真实数据分布pD(x)提取输入时,编码器的输出为:

math-20200615.png

由于ALAE采用对抗策略进行训练,因此q(x)q(x) 最终将朝着pD(x)p_D(x)移动。这也意味着qE,D(x)q_{E, D}(x)移动。

           

3.1匹配隐性空间

隐性空间的假设意味着,编码器 编码器(EE)的输出, 的输出分布(G\textbf{G}), qE(ω)q_E(\omega) 类似于生成器的输入分布 qF(ω)q_F(\omega).。

这是通过最小化两个分布之间的平方差来实现的。很简单,但很神奇。

在普通的自动编码器中,诸如 ll2\mathcal{l}_2范数的重建损失是在数据空间中计算的。然而,这并不能反映人类的视觉感知。自动编码器无法生成像GAN一样清晰图像的原因之一,就是 l2\mathcal{l}_2 范数在图像空间中的计算。这就是在隐性空间中加强互易性的作用所在。

Model.pyModel类的模型定义:

## Encoder (E): Encodes image to latent space W
self.encoder = ENCODERS[encoder](
            startf=startf,
            layer_count=layer_count,
            maxf=maxf,
            latent_size=latent_size,
            channels=channels)

在同一类的encoder方法中,self.encoder是如下使用的:

## Encode generated images into ~W 
Z = self.encoder(x, lod, blend_factor)

model类的forward方法是如下实施的:

## Known prior p(z) 
z = torch.randn(x.shape[0], self.latent_size)
## generate method returns input(s) and output(rec) to generator. 
s, rec = self.generate(lod, blend_factor, z=z, mixing=False, noise=True, return_styles=True)
## encode method returns encoder output(Z) 
Z, d_result_real = self.encode(rec, lod, blend_factor)
## Mean squared error in the latent space-l2 norm.
Lae = torch.mean(((Z - s.detach())**2))

4. 映射到隐形空间(D)

该网络获取由编码器馈入,并输出形状变量(batch_size,1),用作鉴别器进行二元分类的标签。

在训练期间,它被使用了两次:一次是在生成器生成D\textbf{D}的输入(也是编码器的输出)的时候,第二次是在使用真实数据作为输入生成编码器的输出的时候。

model.py中的Model类中的网络定义。

self.mapping_tl = MAPPINGS["MappingToLatent"](
            latent_size=latent_size,
            dlatent_size=latent_size,
            mapping_fmaps=latent_size,
            mapping_layers=3)

forward方法中self.mapping_t1是如下使用的:

## generator method returns the generated image.
 Xp = self.generate(lod, blend_factor, count=x.shape[0], noise=True)
## encode method takes in real data x and return real labels.
 _, d_result_real = self.encode(x, lod, blend_factor)
## encode method takes in generated data and return fake label.
 _, d_result_fake = self.encode(Xp.detach(), lod, blend_factor)

4. Mapping To Latent (D)

This network takes is fed by the encoder and outputs a variable of shape (batch_size, 1) to be used as labels for binary classification by the discriminator.

During training it is used twice: once when the output of the encoder which is input for D\textbf{D}, is produced by the generator, and second when the output of the encoder is generated by real data as input. Network definition in class Model in model.py.

self.mapping_tl = MAPPINGS["MappingToLatent"](
            latent_size=latent_size,
            dlatent_size=latent_size,
            mapping_fmaps=latent_size,
            mapping_layers=3)

In the forward method this is how self.mapping_tl is used.

## generator method returns the generated image.
 Xp = self.generate(lod, blend_factor, count=x.shape[0], noise=True)
## encode method takes in real data x and return real labels.
 _, d_result_real = self.encode(x, lod, blend_factor)
## encode method takes in generated data and return fake label.
 _, d_result_fake = self.encode(Xp.detach(), lod, blend_factor)

总而言之,ALEE的作者设计了一种自动编码器(AE)架构,其中:

1.通过输入数据学习隐性分布(ω)(ω)来解决纠缠(entanglement)。 2.通过对抗策略学习输出数据分布(q(x))(q(x)) 3.为了同时执行(1)和(2),在隐性空间中强加了自动编码器互易性。此属性与该体系结构从其代码重构数据样本(x)(x) 的能力有关,反之亦然

Style ALAE

现在我们已经了解了ALAE的构成要素。让我们快速浏览一下StyleALAE架构,该架构可以生成1024x1024的人脸图像,该图像可与StyleGAN相媲美,后者是最新的人脸生成技术。

StyleALAE有两个组件:

1.如图4右侧所示,将ALAE的生成器替换为StyleGAN的生成器。

2.图4的左侧是一个对称的编码器,因此可以提取样式信息,以驱动StyleGAN生成器。

通过在第i层中引入实例规范化Instance Normalization(IN)来提取样式信息。该层输出通道的平均值 (μ)(\mu)和标准偏差 (σ)(\sigma)。它们表示每一层中的样式内容。 IN层为每个层中的输入提供规范化。编码器每个此类层的样式内容都由对称生成器的Adaptive Instance Normalization(AdaIN)层用作输入,该层与隐性空间 ω\omega线性相关。因此,编码器的样式内容通过多线性映射映射到隐性空间。

作者在训练过程中使用了渐进式调整大小。就是说,训练从低分辨率图像(4 x 4像素)开始,然后通过将新的图块融合到编码器和生成器中而逐渐增加分辨率。

image.png

调整ALAE以得到StyleALAE(Source)



模型实施

ALAE训练

ALAE是对普通GAN架构的修改,并进行了一些新颖的调整。因此,对该体系结构的训练涉及学习关于生成器和鉴别器的minmax。普通GAN通过两步训练过程进行训练。通过改变生成器和鉴别器网络的训练,生成器变得更加善于欺骗鉴别器,而鉴别器变得更善于捕获由生成器人工创建的图像。这迫使生成器提出新的方法来欺骗鉴别器,并且该循环照此继续。

对于ALAE,在假设隐性空间的前提下,编码器Encoder(EE)的输出分布qE(ω)q_E(\omega)类似于生成器G\textbf{G}),qF(ω)q_F(\omega)的输入分布。这里涉及到第三训练步骤。这三个更新如下图所示。

  1. 第一步,更新鉴别器、网络块E和D

     encoder_optimizer.zero_grad()
     loss_d = model(x, lod2batch.lod, blend_factor, d_train=True, ae=False)
     tracker.update(dict(loss_d=loss_d))
     loss_d.backward()
     encoder_optimizer.step()
    
  2. 第二步,更新生成器、网络块F和G

    decoder_optimizer.zero_grad() 
    loss_g = model(x, lod2batch.lod, blend_factor, d_train=False, ae=False)
    tracker.update(dict(loss_g=loss_g))
    loss_g.backward()
    decoder_optimizer.step()
    
  3. 第三步,更新自动编码器的隐性空间、网络块G和E

    encoder_optimizer.zero_grad()
    decoder_optimizer.zero_grad()
    lae = model(x, lod2batch.lod, blend_factor, d_train=True, ae=True)
    tracker.update(dict(lae=lae))
    (lae).backward()
    encoder_optimizer.step()
    decoder_optimizer.step()
    

image.png                                                                                                        ALAE 训练ALAE算法( 来源 )



试验

在MNIST上训练ALAE

我们试着在MNIST数据集上训练ALAE模型结构,但是遇到了一些麻烦。作者使用自己的库Dareblopy 准备训练数据生成器。该库使用的是TFRecord格式。不幸的是,我们无法在colab上运行训练脚本train_alae.py

经过大量的调试和修复后,我们决定自己实施基于MLP的ALAE,并将其放在MNIST数据集上训练。您看到的结果来自于我们的非正式实施,并不是来自正式的存储库。您可以在以下链接中查看我们的实施:

在MNIST上训练一个简单的ALAE

注意:

•我们的实施无法检查其正确性,但它在理论上似乎是正确的。

•它的init很糟糕,因此如果您的损失不正常,则应尝试restart and run all。这个方法对我们是有效的。

我们使用作者推荐的超参数对网络进行了75个epoch(时期)的训练。如前所述,训练ALAE涉及三个阶段的优化。因此,我们有三个单独的损失指标来监控网络表现。您可以在下面查看记录的指标。

  • disc_loss: 这个损失指标与鉴别器从真实图像中预测假(生成)图像的能力有关。鉴别器的损失随着大量波动而减少,这在对抗训练中很常见。
  • gen_loss: 此损失指标与生成器欺骗鉴别器的能力有关。我们的gen_loss似乎上升了。但是生成的图像会随着时间的推移而改善。它不是完美的,但可以肯定的是,我们的非正式实施发挥了作用。
  • latent_loss: 此损失指标决定F网络和G网络之间以及E网络和D网络之间的隐性空间的相似性。因此,与仅从已知分布中采样隐性空间的GAN网络不同,该分布是在ALAE中学习的。随着时间的流逝,latent_loss减少。我们将很快看到这种效果。

在分别训练1,25,50,75个epoch之后的生成图像




Run set
1


StyleALAE试验

作者在FFHQ、LSUN和Celeb-A三个数据集上放了StyleALAE网络模型。他们在这些数据集上训练这个网络,让它生成、重构和混合样本。让我们看看训练的结果。

学习样式表征

作者在FFHQ数据集上训练了上述StyleALAE,该数据集由70k张人脸图像组成,图像均按照1024×10241024 \times 1024的分辨率对齐并裁剪。数据集被分为用于训练的6万张图像和用于测试的1万张图像。不出所料,在大量高分辨率图像上训练网络需要大量的计算资源。他们使用8个Titan RTX GPU训练了147个epoch,其中18个epoch使用了 1024×10241024 \times 1024分辨率的训练样本。他们采用了“渐进式调整大小”的方法,输入图像的分辨率首先为 4×44 \times 4,然后在训练过程中逐渐增加到最高分辨率。

有趣的Tidbit Klaxon !!!!!

有趣的是,StyleALAE能够像StyleGAN论文中所述一样在最高分辨率下产生可靠的结果,但是它在最高分辨率1024×1024时的图像训练时间仅为1M,而在相同分辨率下,StyleGAN的图像训练时间为15M

有趣的花絮Klaxon的结尾!!!!!

定量结果

FID或弗雷歇距离,是对图像视觉质量的一种度量,通常被认为是人类对图像质量的等效估计。StyleALAE的FID得分非常好,但按照该指标仍不如StyleGAN好。下表显示了FFHQ和LSUN数据集的结果。

image.png

然而,有趣的是,在通过“感知路径长度(PPL)” 指标来测量解耦表征的程度时,StyleALAE的表现优于StyleGAN,如下所示:

image.png

下一个要问的问题是“ StyleALAE与其他可比较的方法相比如何?”。该问题的答案也可以通过Celeb-A 数据集来获得:

image.png

定性结果

我们已经重新运行了作者在其存储库中共享的一些图像生成、重构和混合实验,结果如下。请注意,这些实验的预训练模型可在官方存储库中获得。如果您想继续学习,这里的colab笔记本可供您快速参考。

StyleALAE的运行参考和生成结果

生成图像

以下是使用StyleALAE生成的一些随机图像。这个训练是基于刚刚提到的3个数据库。




Run set
1


总结

这是一个自切片面包以来最令人印象深刻的自动编码器架构展示之一。复制其中的一些实验会非常有趣,也会帮助我们更好地理解这项工作。希望我们的报告对您有所帮助,或者至少让您对图像之间的插值产生兴趣。如有任何反馈,请随时在Twitter上给我们留言: @DSaience, @ayushthakur0. Fin .




Run set
1

Iterate on AI agents and models faster. Try Weights & Biases today.