Autoencoders

Basics

What is autoencoder?

  • autoencoder 是一种前馈神经网络,其功能是接收输入x并预测x

  • 存在 Trivial (short-cut) solutions:神经网络可以学会恒等映射 𝑥 = 𝑓(𝑥),即输入为x,经过中间的神经网络后,输出也为x

image.png

  • Bottleneck architecture:

image.png

  • 可以分为encoder(编码、降维、提取特征)和decoder(解码、复原重构x)

image.png

Why autoencoder?

  • 将高维数据映射至二维空间以实现可视化

  • 数据压缩(降低通信成本)

  • 无监督学习(预训练),通过加入扰动再去噪

  • 生成模型,生成image

The simplest autoencoder(线性autoencoder)

  • 最简结构的autoencoder包含单个具有linear activations的hidden layer

  • encoder通过线性投影到更小的空间,而decoder则通过线性投影还原到原来的维度,均为线性变化

image.png

  • 具体而言x通过线性变换由dx1变成kx1,变为隐层h实现encoder。h通过线性变换由kx1复原dx1变成输出output实现decoder

  • Note:

    1. 这个网络是线性的
    2. 通常设置k << d,如果k = d则可以使得VU = 1 从而为恒等变化而变得没有意义
    3. 当 𝑘 ≪ 𝑑 时,实际上是对数据 𝑥 进行降维
  • 优化目标:如何复原还原成output?output = VUx

  • 如何确定V和U?可以考察 output 和 x 的 p 范数

image.png

  • 这时,encoder就相当于主成分分析(PCA),可以通过最小二乘法求解

  • Note:

    1. 解不唯一:若 𝑈∗ 和 𝑉∗ 构成一组解,则 𝑈∗ × 2 与 𝑉∗/2 同样构成有效解
    2. 无需通过gradient descent求解该问题,存在closed-form 解,即通过有限次的标准运算和函数明确表达的解
  • autoencoder为什么要先encode降维再decode升维:先降维再升维的核心目的,是施加一种“信息瓶颈”(类似于主成分分析PCA),强迫网络只能选择性地通过最重要的信息,从而抛弃冗余和噪声,学习到数据的本质结构。如果不经过这个瓶颈,网络最简单的做法就是直接复制输入(恒等映射),这就完全失去了学习意义

More about autoencoder

  • Autoencoder 通常可表述为 𝑓(𝑔(𝑥)) = x 的数学形式:

    1. g函数是encoder
    2. f函数是decoder
    3. h = g(x)被称为 x 的 code / representation / latent variable
  • f 和 g 不应该过于复杂或者拟合能力过强:

    1. 避免学习copy(encoder) 和 paste(decoder)
    2. 避免过拟合
  • f 和 g 可以是浅层的神经网络:所有的参数可以通过梯度下降训练

  • Autoencoders 是可学习的以及 data-specific:

    1. 这与 mp3 或者 jpeg 等压缩方法不同
    2. autoencoder是数据相关的,在”cat images”上训练的autoencoder,在”dog images”上可能表现失效

Vanilla autoencoder is not a generative model

  • 标准Autoencoder:它不是一个合格的“生成模型”,由于其训练目标是让输出 $\hat{x}$ 无限接近输入 $x$,它的中间隐藏层(latent representation)确实学到了数据 $x$ 的本质特征,但是隐藏层中的分布是“混乱的”和“未知的”

  • x 虽然服从数据分布但是数据分布是未知的,且不好假设的

  • 而生成模型的定义为通过从 noise 中生成,得到去噪的结果,因此虽然AE可以压缩和解压缩,但是其没有涉及到随机分布、概率,且其分布不是可控、可建模的

image.png

  • 若训练完成后 ℎ 服从已知分布(如 standard Gaussian distribution),则将达到理想状态,可以用作生成模型

How to modify an autoencoder into a generative model?

  • 当encoder被替换为random noise时,decoder即转变为generative model

image.png

  • 若保证h是已知(e.g.高斯噪音)则可去掉 encoder ,只用 decoder 作为生成模型

  • 关键:如何使 h 在训练后变为已知分布?

Stochastic latent representation

  • 在随机隐层表示中,h 是有随机性的随机变量,服从 g(x) 分布,而不是一个确定的值

image.png

  • 给出 x 后,神经网络的一部分生成均值,另一部分生成方差,根据均值和方差构建高斯分布

  • 用神经网络构建的均值和方差都是可训练的参数

image.png

Examples

  • 在 mnist 的例子中,第一个 hidden layer 有256维,通过 encoder 后变为100维得到第二个 hidden layer

  • 在第二个 hidden layer中:

    1. 50维用来预测均值
    2. 另外50维用来预测方差
  • 从而得到可学习的均值和方差,然后再通过这个均值和方差构建高斯分布

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# encoder(incomplete)
class Encoder(torch.nn.Module):
def __init__(self, D_in, H, latent_size):
self.linear1 = torch.nn.Linear(D_in, H)
self.enc_mu = torch.nn.Linear(H, latent_size)
self.enc_log_sigma = torch.nn.Linear(H, latent_size)
# 使用 log_sigma 是将[0, +inf)变为(-inf, inf)

def forward(self, x):
x = F.relu(self.linear1(x))
mu = self.enc_mu(x)
log_sigma = self.enc_log_sigma(x)
sigma = torch.exp(log_sigma)
return torch.distributions.Normal(loc = mu, scale = sigma)

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# decoder(incomplete)
class Decoder(torch.nn.Module):
def __init__(self, D_in, H, D_out):
super(Decoder, self).__init__()
self.linear1 = torch.nn.Linear(D_in, H)
self.linear2 = torch.nn.Linear(H, D_out)

def forward(self, x):
x = F.relu(self.linear1(x))
mu = torch.tanh(self.linear2(x))
return mu

encoder = Encoder(input_dim, hidden_size. latent_size)
decoder = Decoder(latent_size, hidden_size, input_dim)
  • encoder与decoder不一定具有对称性

  • encoder与decoder不一定必须是MLP(多层感知机)

image.png

  • encoder的作用是得到可训练参数(均值、方差)的估计,decoder的作用是得到重构的image

  • 问题:如何train?如何得到可估计的均值、方差?


Variational Autoencoder

Training VAE

  • pipeline:
    1. 输入:x
    2. 通过encoder得到均值方差的估计,根据均值方差的估计得到分布函数
    3. 根据分布函数采样h
    4. 通过decoder得到重构后的output,并优化x和output的距离

image.png

  • decoder参数的更新可以通过梯度的反向传播完成(都可以通过链式法则求导得到):

image.png

  • encoder参数的更新无法通过梯度的反向传播完成,因为h~g(x)是采样过程,不可导,导致不可训练:

image.png

  • VAE 的解决方法:Reparameterization trick(重参数化)

Key tech: Reparameterization trick(重参数化)

  • 问题:采样过程是不可导的

  • 解决方法:Reparameterization trick,将先 rescale 后 sample 变成先 sample 后 rescale,这个变化过程是完全等价的

image.png

image.png

  • 此时导数不会传到 epsilon 之前,整个过程都是可导的,可以训练均值和方差

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# VAE:implementation
class Encoder(torch.nn.Module):
def __init__(self, D_in, H, latent_size):
super(Encoder, self).__init__()
self.linear1 = torch.nn.Linear(D_in, H)
self.enc_mu = torch.nn.Linear(H, latent_size)
self.enc_log_sigma = torch.nn.Linear(H, latent_size)

def forward(self, x):
x = F.relu(self.linear1(x))
mu = self.enc_mu(x)
log_sigma = self.enc_log_sigma(x)
sigma = torch.exp(log_sigma)
return torch.distributuins.Normal(loc = mu, scale = sigma)
  • 问题:如何在训练后使 h 服从已知分布?

  • 解决方法:设计regulation loss

    1. 防止过拟合
    2. 迫使编码器输出的潜在变量分布 q(z∣x) 逼近标准高斯分布 N(0,I)

image.png

  • summary:

image.png