08.md 37.8 KB
Newer Older
W
wizardforcel 已提交
1 2
# 8

W
wizardforcel 已提交
3
# 变分自编码器(VAE)
W
wizardforcel 已提交
4

W
wizardforcel 已提交
5
与我们在之前的章节中讨论过的**生成对抗网络****GAN**)类似,**变分自编码器****VAE**)[1] 属于生成模型家族。 VAE 的生成器能够在导航其连续潜在空间的同时产生有意义的输出。 通过潜矢量探索解码器输出的可能属性。
W
wizardforcel 已提交
6 7 8 9 10

在 GAN 中,重点在于如何得出近似输入分布的模型。 VAE 尝试对可解码的连续潜在空间中的输入分布进行建模。 这是 GAN 与 VAE 相比能够生成更真实信号的可能的潜在原因之一。 例如,在图像生成中,GAN 可以生成看起来更逼真的图像,而相比之下,VAE 生成的图像清晰度较差。

在 VAE 中,重点在于潜在代码的变分推理。 因此,VAE 为潜在变量的学习和有效贝叶斯推理提供了合适的框架。 例如,带有解缠结表示的 VAE 可以将潜在代码重用于传输学习。

W
wizardforcel 已提交
11
在结构上,VAE 与自编码器相似。 它也由编码器(也称为识别或推理模型)和解码器(也称为生成模型)组成。 VAE 和自编码器都试图在学习潜矢量的同时重建输入数据。
W
wizardforcel 已提交
12

W
wizardforcel 已提交
13
但是,与自编码器不同,VAE 的潜在空间是连续的,并且解码器本身被用作生成模型。
W
wizardforcel 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27

在前面各章中讨论的 GAN 讨论中,也可以对 VAE 的解码器进行调整。 例如,在 MNIST 数据集中,我们能够指定一个给定的单热向量产生的数字。 这种有条件的 VAE 类别称为 CVAE [2]。 也可以通过在损失函数中包含正则化超参数来解开 VAE 潜矢量。 这称为![](img/B14853_08_001.png) -VAE [5]。 例如,在 MNIST 中,我们能够隔离确定每个数字的粗细或倾斜角度的潜矢量。 本章的目的是介绍:

*   VAE 的原理
*   了解重新参数化技巧,有助于在 VAE 优化中使用随机梯度下降
*   有条件的 VAE(CVAE)和![](img/B14853_08_002.png) -VAE 的原理
*   了解如何使用`tf.keras`实施 VAE

我们将从谈论 VAE 的基本原理开始。

# 1\. VAE 原理

在生成模型中,我们经常对使用神经网络来逼近输入的真实分布感兴趣:

W
wizardforcel 已提交
28
![](img/B14853_08_003.png) (Equation 8.1.1)
W
wizardforcel 已提交
29 30 31 32 33 34 35

在前面的等式中,![](img/B14853_08_004.png)表示训练期间确定的参数。 例如,在名人面孔数据集的上下文中,这等效于找到可以绘制面孔的分布。 同样,在 MNIST 数据集中,此分布可以生成可识别的手写数字。

在机器学习中,为了执行特定级别的推理,我们有兴趣寻找![](img/B14853_08_005.png),这是输入![](img/B14853_08_006.png)和潜在变量![](img/B14853_08_007.png)之间的联合分布。 潜在变量不是数据集的一部分,而是对可从输入中观察到的某些属性进行编码。 在名人面孔的背景下,这些可能是面部表情,发型,头发颜色,性别等。 在 MNIST 数据集中,潜在变量可以表示数字和书写样式。

![](img/B14853_08_008.png)实际上是输入数据点及其属性的分布。 ![](img/B14853_08_009.png)可以从边际分布计算得出:

W
wizardforcel 已提交
36
![](img/B14853_08_010.png) (Equation 8.1.2)
W
wizardforcel 已提交
37 38 39

换句话说,考虑所有可能的属性,我们最终得到描述输入的分布。 在名人面孔中,如果考虑所有面部表情,发型,头发颜色和性别,将恢复描述名人面孔的分布。 在 MNIST 数据集中,如果考虑所有可能的数字,书写风格等,我们以手写数字的分布来结束。

W
wizardforcel 已提交
40
问题在于“公式 8.1.2”很难处理。 该方程式没有解析形式或有效的估计量。 它的参数无法区分。 因此,通过神经网络进行优化是不可行的。
W
wizardforcel 已提交
41

W
wizardforcel 已提交
42
使用贝叶斯定理,我们可以找到“公式 8.1.2”的替代表达式:
W
wizardforcel 已提交
43

W
wizardforcel 已提交
44
![](img/B14853_08_011.png) (Equation 8.1.3)
W
wizardforcel 已提交
45 46 47

![](img/B14853_08_012.png)是![](img/B14853_08_013.png)的先验分布。 它不以任何观察为条件。 如果![](img/B14853_08_014.png)是离散的,而![](img/B14853_08_015.png)是高斯分布,则![](img/B14853_08_016.png)是高斯的混合。 如果![](img/B14853_08_017.png)是连续的,则![](img/B14853_08_018.png)是高斯的无限混合。

W
wizardforcel 已提交
48
实际上,如果我们尝试在没有合适的损失函数的情况下建立一个近似![](img/B14853_08_019.png)的神经网络,它将忽略![](img/B14853_08_020.png)并得出一个简单的解![](img/B14853_08_021.png) = ![](img/B14853_08_022.png)。 因此,“公式 8.1.3”无法为我们提供![](img/B14853_08_023.png)的良好估算。 或者,“公式 8.1.2”也可以表示为:
W
wizardforcel 已提交
49

W
wizardforcel 已提交
50
![](img/B14853_08_024.png) (Equation 8.1.4)
W
wizardforcel 已提交
51 52 53

但是,![](img/B14853_08_025.png)也很棘手。 VAE 的目标是在给定输入![](img/B14853_08_028.png)的情况下,找到一种可预测的分布,该分布易于估计![](img/B14853_08_026.png),即潜在属性![](img/B14853_08_027.png)的条件分布的估计。

W
wizardforcel 已提交
54
## 变分推理
W
wizardforcel 已提交
55 56 57

为了使易于处理,VAE 引入了变化推理模型(编码器):

W
wizardforcel 已提交
58
![](img/B14853_08_030.png) (Equation 8.1.5)
W
wizardforcel 已提交
59 60 61

![](img/B14853_08_031.png)提供了![](img/B14853_08_032.png)的良好估计。 它既参数化又易于处理。 ![](img/B14853_08_033.png)可以通过优化参数![](img/B14853_08_034.png)由深度神经网络近似。 通常,![](img/B14853_08_035.png)被选择为多元高斯:

W
wizardforcel 已提交
62
![](img/B14853_08_036.png) (Equation 8.1.6)
W
wizardforcel 已提交
63 64 65 66 67 68 69

均值![](img/B14853_08_037.png)和标准偏差![](img/B14853_08_038.png)均由编码器神经网络使用输入数据点计算得出。 对角线矩阵表示![](img/B14853_08_039.png)的元素是独立的。

在下一节中,我们将求解 VAE 的核心方程。 核心方程式将引导我们找到一种优化算法,该算法将帮助我们确定推理模型的参数。

## 核心方程

W
wizardforcel 已提交
70
推理模型![](img/B14853_08_040.png)从输入![](img/B14853_08_042.png)生成潜矢量![](img/B14853_08_041.png)。 ![](img/B14853_08_043.png)类似于自编码器模型中的编码器。 另一方面,从潜在代码![](img/B14853_08_027.png)重构输入。 ![](img/B14853_08_046.png)的作用类似于自编码器模型中的解码器。 要估算![](img/B14853_08_047.png),我们必须确定其与![](img/B14853_08_048.png)和![](img/B14853_08_049.png)的关系。
W
wizardforcel 已提交
71

W
wizardforcel 已提交
72
如果![](img/B14853_08_050.png)是![](img/B14853_08_051.png)的估计值,则 **Kullback-Leibler****KL**)的差异决定了这两个条件密度之间的距离:
W
wizardforcel 已提交
73

W
wizardforcel 已提交
74
![](img/B14853_08_052.png) (Equation 8.1.7)
W
wizardforcel 已提交
75 76 77

使用贝叶斯定理:

W
wizardforcel 已提交
78
![](img/B14853_08_053.png) (Equation 8.1.8)
W
wizardforcel 已提交
79

W
wizardforcel 已提交
80
在“公式 8.1.7”中:
W
wizardforcel 已提交
81

W
wizardforcel 已提交
82
![](img/B14853_08_054.png) (Equation 8.1.9)
W
wizardforcel 已提交
83

W
wizardforcel 已提交
84
由于![](img/B14853_08_055.png)不依赖于![](img/B14853_08_056.png),因此可能会超出预期。 重新排列“公式 8.1.9”并认识到:
W
wizardforcel 已提交
85 86 87

![](img/B14853_08_057.png),其结果是:

W
wizardforcel 已提交
88
![](img/B14853_08_058.png) (Equation 8.1.10)
W
wizardforcel 已提交
89

W
wizardforcel 已提交
90
“公式 8.1.10”是 VAE 的核心。 左侧是术语![](img/B14853_08_059.png),由于![](img/B14853_08_060.png)与真实![](img/B14853_08_061.png)的距离,我们使误差最小化。 我们可以记得,的对数不会更改最大值(或最小值)的位置。 给定提供![](img/B14853_08_061.png)良好估计的推断模型,![](img/B14853_08_063.png)大约为零。
W
wizardforcel 已提交
91 92 93

右边的第一项![](img/B14853_08_064.png)类似于解码器,该解码器从推理模型中抽取样本以重建输入。

W
wizardforcel 已提交
94
第二个项是另一个距离。 这次是在![](img/B14853_08_050.png)和先前的![](img/B14853_08_066.png)之间。 “公式 8.1.10”的左侧也称为**变异下界****证据下界****ELBO**)。 由于 KL 始终为正,因此 ELBO 是![](img/B14853_08_067.png)的下限。 通过优化神经网络的参数![](img/B14853_08_068.png)和![](img/B14853_08_069.png)来最大化 ELBO 意味着:
W
wizardforcel 已提交
95 96

*   在将![](img/B14853_08_072.png)中的![](img/B14853_08_071.png)属性编码为时,![](img/B14853_08_070.png)或推理模型变得更好。
W
wizardforcel 已提交
97
*   右边的![](img/B14853_08_073.png)最大化了“公式 8.1.10”或解码器模型在从潜在矢量![](img/B14853_08_075.png)重构![](img/B14853_08_074.png)方面变得更好。
W
wizardforcel 已提交
98
*   在下一节中,我们将利用“公式 8.1.10”的结构来确定推理模型(编码器)和解码器的损失函数。
W
wizardforcel 已提交
99 100 101

## 优化

W
wizardforcel 已提交
102
“公式 8.1.10”的右侧具有有关 VAE 的`loss`功能的两个重要信息。 解码器术语![](img/B14853_08_076.png)表示生成器从推理模型的输出中提取![](img/B14853_08_077.png)个样本,以重建输入。 使最大化是指我们将**重构损失**和![](img/B14853_08_078.png)降到最低。 如果假设图像(数据)分布为高斯分布,则可以使用 MSE。
W
wizardforcel 已提交
103 104 105

如果每个像素(数据)都被认为是伯努利分布,那么损失函数就是二进制互熵。

W
wizardforcel 已提交
106
第二项![](img/B14853_08_079.png)易于评估。 根据“公式 8.1.6”,![](img/B14853_08_080.png)是高斯分布。 通常,![](img/B14853_08_081.png)也是平均值为零且标准偏差等于 1.0 的高斯。 在“公式 8.1.11”中,我们看到 KL 项简化为:
W
wizardforcel 已提交
107

W
wizardforcel 已提交
108
![](img/B14853_08_082.png) (Equation 8.1.11)
W
wizardforcel 已提交
109 110 111

其中![](img/B14853_08_083.png)是![](img/B14853_08_041.png)的维。 ![](img/B14853_08_085.png)和![](img/B14853_08_086.png)都是通过推理模型计算的![](img/B14853_08_087.png)的函数。 要最大化:![](img/B14853_08_088.png),![](img/B14853_08_089.png)和![](img/B14853_08_090.png)。 ![](img/B14853_08_091.png)的选择源于各向同性单位高斯的性质,在具有适当函数的情况下,它可以变形为任意分布[6]。

W
wizardforcel 已提交
112
根据“公式 8.1.11”,KL 损耗![](img/B14853_08_092.png)简称为![](img/B14853_08_093.png)
W
wizardforcel 已提交
113

W
wizardforcel 已提交
114
总之,在“公式 8.1.12”中将 VAE `loss`函数定义为:
W
wizardforcel 已提交
115

W
wizardforcel 已提交
116
![](img/B14853_08_094.png) (Equation 8.1.12)
W
wizardforcel 已提交
117 118 119 120 121

在给定编码器和解码器模型的情况下,在我们可以构建和训练 VAE(随机采样块,生成潜在属性)之前,还需要解决一个问题。 在下一节中,我们将讨论此问题以及如何使用重新参数化技巧解决它。

## 重新参数化技巧

W
wizardforcel 已提交
122
“图 8.1.1”的左侧显示了 VAE 网络。 编码器获取输入![](img/B14853_08_095.png),并估计潜矢量![](img/B14853_08_098.png)的多元高斯分布的平均值![](img/B14853_08_096.png)和标准差![](img/B14853_08_097.png)。 解码器从潜矢量![](img/B14853_08_099.png)中提取样本,以将输入重构为![](img/B14853_08_100.png)。 这似乎很简单,直到在反向传播期间发生梯度更新为止:
W
wizardforcel 已提交
123

W
wizardforcel 已提交
124
![](img/B14853_08_01.png)
W
wizardforcel 已提交
125 126 127 128 129

图 8.1.1:带有和不带有重新参数化技巧的 VAE 网络

反向传播梯度将不会通过随机**采样**块。 尽管具有用于神经网络的随机输入是可以的,但梯度不可能穿过随机层。

W
wizardforcel 已提交
130
解决此问题的方法是将**采样**处理作为输入,如“图 8.1.1”右侧所示。 然后,将样本计算为:
W
wizardforcel 已提交
131

W
wizardforcel 已提交
132
![](img/B14853_08_101.png) (Equation 8.1.13)
W
wizardforcel 已提交
133

W
wizardforcel 已提交
134
如果![](img/B14853_08_102.png)和![](img/B14853_08_103.png)以矢量格式表示,则![](img/B14853_08_104.png)是逐元素乘法。 使用“公式 8.1.13”,看起来好像采样直接来自潜在空间一样。 这项技术被称为*重新参数化技巧*
W
wizardforcel 已提交
135 136 137 138 139 140 141

现在,在输入端发生*采样*时,可以使用熟悉的优化算法(例如 SGD,Adam 或 RMSProp)来训练 VAE 网络。

在讨论如何在`tf.keras`中实现 VAE 之前,让我们首先展示如何测试经过训练的解码器。

## 解码器测试

W
wizardforcel 已提交
142
在训练了 VAE 网络之后,可以丢弃推理模型,包括加法和乘法运算符。 为了生成新的有意义的输出,请从用于生成![](img/B14853_08_105.png)的高斯分布中抽取样本。“图 8.1.2”向我们展示了解码器的测试设置:
W
wizardforcel 已提交
143

W
wizardforcel 已提交
144
![](img/B14853_08_02.png)
W
wizardforcel 已提交
145 146 147

图 8.1.2:解码器测试设置

W
wizardforcel 已提交
148
通过重新参数化技巧解决了 VAE 上的最后一个问题,我们现在可以在`tf.keras`中实施和训练变分自编码器。
W
wizardforcel 已提交
149 150 151

## ALAS 与 Keras

W
wizardforcel 已提交
152
VAE 的结构类似于典型的自编码器。 区别主要在于重新参数化技巧中的高斯随机变量的采样。“列表 8.1.1”显示了使用 MLP 实现的编码器,解码器和 VAE。
W
wizardforcel 已提交
153

W
wizardforcel 已提交
154
[此代码也已添加到官方 Keras GitHub 存储库中](https://github.com/keras-team/keras/blob/master/examples/variational_autoencoder.py)
W
wizardforcel 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167

为便于显示潜在代码,将![](img/B14853_08_106.png)的维设置为 2。编码器仅是两层 MLP,第二层生成均值和对数方差。 对数方差的使用是为了简化 KL 损耗和重新参数化技巧的计算。 编码器的第三个输出是使用重新参数化技巧进行的![](img/B14853_08_107.png)采样。 我们应该注意,在采样函数![](img/B14853_08_108.png)中,因为![](img/B14853_08_109.png)假定它是高斯分布的标准偏差。

解码器也是两层 MLP,它采用![](img/B14853_08_110.png)的样本来近似输入。 编码器和解码器均使用大小为 512 的中间尺寸。

VAE 网络只是将编码器和解码器连接在一起。 `loss`函数是*重建损失**KL 损失*的总和。 在默认的 Adam 优化器上,VAE 网络具有良好的效果。 VAE 网络中的参数总数为 807,700。

VAE MLP 的 Keras 代码具有预训练的权重。 要测试,我们需要运行:

```py
python3 vae-mlp-mnist-8.1.1.py --weights=vae_mlp_mnist.tf 
```

W
wizardforcel 已提交
168
[完整的代码可以在以下链接中找到](https://github.com/PacktPublishing/Advanced-Deep-Learning-with-Keras)
W
wizardforcel 已提交
169

W
wizardforcel 已提交
170
“列表 8.1.1”:`vae-mlp-mnist-8.1.1.py`
W
wizardforcel 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291

```py
# reparameterization trick
# instead of sampling from Q(z|X), sample eps = N(0,I)
# z = z_mean + sqrt(var)*eps
def sampling(args):
    """Reparameterization trick by sampling 
        fr an isotropic unit Gaussian. 
```

```py
 # Arguments:
        args (tensor): mean and log of variance of Q(z|X) 
```

```py
 # Returns:
        z (tensor): sampled latent vector
    """ 
```

```py
 z_mean, z_log_var = args
    # K is the keras backend
    batch = K.shape(z_mean)[0]
    dim = K.int_shape(z_mean)[1]
    # by default, random_normal has mean=0 and std=1.0
    epsilon = K.random_normal(shape=(batch, dim))
    return z_mean + K.exp(0.5 * z_log_var) * epsilon 
```

```py
# MNIST dataset
(x_train, y_train), (x_test, y_test) = mnist.load_data() 
```

```py
image_size = x_train.shape[1]
original_dim = image_size * image_size
x_train = np.reshape(x_train, [-1, original_dim])
x_test = np.reshape(x_test, [-1, original_dim])
x_train = x_train.astype('float32') / 255
x_test = x_test.astype('float32') / 255 
```

```py
# network parameters
input_shape = (original_dim, )
intermediate_dim = 512
batch_size = 128
latent_dim = 2
epochs = 50 
```

```py
# VAE model = encoder + decoder
# build encoder model
inputs = Input(shape=input_shape, name='encoder_input')
x = Dense(intermediate_dim, activation='relu')(inputs)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x) 
```

```py
# use reparameterization trick to push the sampling out as input
# note that "output_shape" isn't necessary 
# with the TensorFlow backend
z = Lambda(sampling,
           output_shape=(latent_dim,),
           name='z')([z_mean, z_log_var]) 
```

```py
# instantiate encoder model
encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder') 
```

```py
# build decoder model
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = Dense(intermediate_dim, activation='relu')(latent_inputs)
outputs = Dense(original_dim, activation='sigmoid')(x) 
```

```py
# instantiate decoder model
decoder = Model(latent_inputs, outputs, name='decoder')
# instantiate VAE model
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs, name='vae_mlp') 
```

```py
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    help_ = "Load tf model trained weights"
    parser.add_argument("-w", "--weights", help=help_)
    help_ = "Use binary cross entropy instead of mse (default)"
    parser.add_argument("--bce", help=help_, action='store_true')
    args = parser.parse_args()
    models = (encoder, decoder)
    data = (x_test, y_test) 
```

```py
 # VAE loss = mse_loss or xent_loss + kl_loss
    if args.bce:
        reconstruction_loss = binary_crossentropy(inputs,
                                                  outputs)
    else:
        reconstruction_loss = mse(inputs, outputs)

    reconstruction_loss *= original_dim
    kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
    kl_loss = K.sum(kl_loss, axis=-1)
    kl_loss *= -0.5
    vae_loss = K.mean(reconstruction_loss + kl_loss)
    vae.add_loss(vae_loss)
    vae.compile(optimizer='adam') 
```

W
wizardforcel 已提交
292
“图 8.1.3”显示了编码器模型,它是一个 MLP,具有两个输出,即潜矢量的均值和方差。 lambda 函数实现了重新参数化技巧,将随机潜在代码的采样推送到 VAE 网络之外:
W
wizardforcel 已提交
293

W
wizardforcel 已提交
294
![A screenshot of a cell phone  Description automatically generated](img/B14853_08_03.png)
W
wizardforcel 已提交
295 296 297

图 8.1.3:VAE MLP 的编码器模型

W
wizardforcel 已提交
298
“图 8.1.4”显示了解码器模型。 2 维输入来自 lambda 函数。 输出是重构的 MNIST 数字:
W
wizardforcel 已提交
299

W
wizardforcel 已提交
300
![A screenshot of a cell phone  Description automatically generated](img/B14853_08_04.png)
W
wizardforcel 已提交
301 302 303

图 8.1.4:VAE MLP 的解码器模型

W
wizardforcel 已提交
304
“图 8.1.5”显示了完整的 VAE 模型。 通过将编码器和解码器模型结合在一起制成:
W
wizardforcel 已提交
305

W
wizardforcel 已提交
306
![](img/B14853_08_05.png)
W
wizardforcel 已提交
307 308 309

图 8.1.5:使用 MLP 的 VAE 模型

W
wizardforcel 已提交
310
“图 8.1.6”显示了使用`plot_results()`在 50 个纪元后潜矢量的连续空间。 为简单起见,此功能未在此处显示,但可以在`vae-mlp-mnist-8.1.1.py`的其余代码中找到。 该函数绘制两个图像,即测试数据集标签(“图 8.1.6”)和样本生成的数字(“图 8.1.7”),这两个图像都是![](img/B14853_08_098.png)的函数。 这两个图都说明了潜在矢量如何确定所生成数字的属性:
W
wizardforcel 已提交
311

W
wizardforcel 已提交
312
![A close up of a plant  Description automatically generated](img/B14853_08_06.png)
W
wizardforcel 已提交
313 314 315

图 8.1.6:MNIST 数字标签作为测试数据集(VAE MLP)的潜在矢量平均值的函数。 原始图像可以在该书的 GitHub 存储库中找到,网址为 https://github.com/PacktPublishing/Advanced-Deep-Learning-with-Keras/tree/master/chapter8-vae

W
wizardforcel 已提交
316
浏览时,连续空格始终会产生与 MNIST 数字相似的输出。 例如,数字 9 的区域接近数字 7 的区域。从中心附近的 9 移动到左下角会将数字变形为 7。从中心向上移动会将生成的数字从 3 更改为 5,最后变为 0.数字的变形在“图 8.1.7”中更明显,这是解释“图 8.1.6”的另一种方式。
W
wizardforcel 已提交
317

W
wizardforcel 已提交
318
在“图 8.1.7”中,显示发电机输出。 显示了潜在空间中数字的分布。 可以观察到所有数字都被表示。 由于中心附近分布密集,因此变化在中间迅速,在平均值较高的区域则缓慢。 我们需要记住,“图 8.1.7”是“图 8.1.6”的反映。 例如,数字 0 在两个图的左上象限中,而数字 1 在右下象限中。
W
wizardforcel 已提交
319

W
wizardforcel 已提交
320
“图 8.1.7”中存在一些无法识别的数字,尤其是在右上象限中。 从“图 8.1.6”可以看出,该区域大部分是空的,并且远离中心:
W
wizardforcel 已提交
321

W
wizardforcel 已提交
322
![](img/B14853_08_07.png)
W
wizardforcel 已提交
323 324 325 326 327 328 329

图 8.1.7:根据潜在矢量平均值(VAE MLP)生成的数字。 为了便于解释,均值的范围类似于图 8.1.6

在本节中,我们演示了如何在 MLP 中实现 VAE。 我们还解释了导航潜在空间的结果。 在的下一部分中,我们将使用 CNN 实施相同的 VAE。

## 使用 CNN 进行 AE

W
wizardforcel 已提交
330
在原始论文《自编码变分贝叶斯》[1]中,使用 MLP 来实现 VAE 网络,这与我们在上一节中介绍的类似。 在本节中,我们将证明使用 CNN 将显着提高所产生数字的质量,并将参数数量显着减少至 134,165。
W
wizardforcel 已提交
331

W
wizardforcel 已提交
332
“列表 8.1.3”显示了编码器,解码器和 VAE 网络。 [该代码也被添加到了官方的 Keras GitHub 存储库中](https://github.com/keras-team/keras/blob/master/examples/variational_autoencoder_deconv.py)
W
wizardforcel 已提交
333 334 335 336 337 338 339 340 341

为简洁起见,不再显示与 MLP VAE 类似的某些代码行。 编码器由两层 CNN 和两层 MLP 组成,以生成潜在代码。 编码器的输出结构与上一节中看到的 MLP 实现类似。 解码器由一层`Dense`和三层转置的 CNN 组成。

VAE CNN 的 Keras 代码具有预训练的权重。 要测试,我们需要运行:

```py
python3 vae-cnn-mnist-8.1.2.py --weights=vae_cnn_mnist.tf 
```

W
wizardforcel 已提交
342
“列表 8.1.3”:`vae-cnn-mnist-8.1.2.py`
W
wizardforcel 已提交
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433

使用 CNN 层的`tf.keras`中的 VAE:

```py
# network parameters
input_shape = (image_size, image_size, 1)
batch_size = 128
kernel_size = 3
filters = 16
latent_dim = 2
epochs = 30 
```

```py
# VAE model = encoder + decoder
# build encoder model
inputs = Input(shape=input_shape, name='encoder_input')
x = inputs
for i in range(2):
    filters *= 2
    x = Conv2D(filters=filters,
               kernel_size=kernel_size,
               activation='relu',
               strides=2,
               padding='same')(x) 
```

```py
# shape info needed to build decoder model
shape = K.int_shape(x) 
```

```py
# generate latent vector Q(z|X)
x = Flatten()(x)
x = Dense(16, activation='relu')(x)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x) 
```

```py
# use reparameterization trick to push the sampling out as input
# note that "output_shape" isn't necessary 
# with the TensorFlow backend
z = Lambda(sampling,
           output_shape=(latent_dim,),
           name='z')([z_mean, z_log_var]) 
```

```py
# instantiate encoder model
encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder') 
```

```py
# build decoder model
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = Dense(shape[1] * shape[2] * shape[3],
          activation='relu')(latent_inputs)
x = Reshape((shape[1], shape[2], shape[3]))(x) 
```

```py
for i in range(2):
    x = Conv2DTranspose(filters=filters,
                        kernel_size=kernel_size,
                        activation='relu',
                        strides=2,
                        padding='same')(x)
    filters //= 2 
```

```py
outputs = Conv2DTranspose(filters=1,
                          kernel_size=kernel_size,
                          activation='sigmoid',
                          padding='same',
                          name='decoder_output')(x) 
```

```py
# instantiate decoder model
decoder = Model(latent_inputs, outputs, name='decoder') 
```

```py
# instantiate VAE model
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs, name='vae') 
```

W
wizardforcel 已提交
434
“图 8.1.8”显示了 CNN 编码器模型的两个输出,即潜矢量的均值和方差。 lambda 函数实现了重新参数化技巧,将随机潜码的采样推送到 VAE 网络之外:
W
wizardforcel 已提交
435

W
wizardforcel 已提交
436
![A screenshot of a cell phone  Description automatically generated](img/B14853_08_08.png)
W
wizardforcel 已提交
437 438 439

图 8.1.8:VAE CNN 的编码器

W
wizardforcel 已提交
440
“图 8.1.9”显示了 CNN 解码器模型。 2 维输入来自 lambda 函数。 输出是重构的 MNIST 数字:
W
wizardforcel 已提交
441

W
wizardforcel 已提交
442
![A screenshot of a cell phone  Description automatically generated](img/B14853_08_09.png)
W
wizardforcel 已提交
443 444 445

图 8.1.9:VAE CNN 的解码器

W
wizardforcel 已提交
446
“图 8.1.10”显示完整的 CNN VAE 模型。 通过将编码器和解码器模型结合在一起制成:
W
wizardforcel 已提交
447

W
wizardforcel 已提交
448
![](img/B14853_08_10.png)
W
wizardforcel 已提交
449 450 451

图 8.1.10:使用 CNN 的 VAE 模型

W
wizardforcel 已提交
452
对 VAE 进行了 30 个时期的训练。“图 8.1.11”显示了在导航 VAE 的连续潜在空间时数字的分布。 例如,从中间到右边从 2 变为 0:
W
wizardforcel 已提交
453

W
wizardforcel 已提交
454
![A picture containing tree  Description automatically generated](img/B14853_08_11.png)
W
wizardforcel 已提交
455 456 457

图 8.1.11:MNIST 数字标签作为测试数据集(VAE CNN)的潜在矢量平均值的函数。 原始图像可以在该书的 GitHub 存储库中找到,网址为 https://github.com/PacktPublishing/Advanced-Deep-Learning-with-Keras/tree/master/chapter8-vae。

W
wizardforcel 已提交
458
“图 8.1.12”向我们展示了生成模型的输出。 从质量上讲,与“图 8.1.7”(具有 MLP 实现)相比,模棱两可的位数更少:
W
wizardforcel 已提交
459

W
wizardforcel 已提交
460
![](img/B14853_08_12.png)
W
wizardforcel 已提交
461 462 463 464 465 466 467 468 469

图 8.1.12:根据潜在矢量平均值(VAE CNN)生成的数字。 为了便于解释,均值的范围类似于图 8.1.11

前的两节讨论了使用 MLP 或 CNN 的 VAE 的实现。 我们分析了两种实现方式的结果,结果表明 CNN 可以减少参数数量并提高感知质量。 在下一节中,我们将演示如何在 VAE 中实现条件,以便我们可以控制要生成的数字。

# 2.有条件的 VAE(CVAE)

有条件的 VAE [2]与 CGAN 相似。 在 MNIST 数据集的上下文中,如果随机采样潜在空间,则 VAE 无法控制将生成哪个数字。 CVAE 可以通过包含要产生的数字的条件(单标签)来解决此问题。 该条件同时施加在编码器和解码器输入上。

W
wizardforcel 已提交
470
正式地,将“公式 8.1.10”中 VAE 的核心公式修改为包括条件![](img/B14853_08_112.png)
W
wizardforcel 已提交
471

W
wizardforcel 已提交
472
![](img/B14853_08_113.png) (Equation 8.2.1)
W
wizardforcel 已提交
473

W
wizardforcel 已提交
474
与 VAE 相似,“公式 8.2.1”表示如果要最大化输出条件![](img/B14853_08_114.png)和![](img/B14853_08_115.png),则必须最小化两个损耗项:
W
wizardforcel 已提交
475 476 477 478 479 480

*   给定潜在矢量和条件,解码器的重建损失。
*   给定潜在矢量和条件的编码器之间的 KL 损耗以及给定条件的先验分布。 与 VAE 相似,我们通常选择![](img/B14853_08_116.png)

实施 CVAE 需要对 VAE 的代码进行一些修改。 对于 CVAE,使用 VAE CNN 实施是因为它可以形成一个较小的网络,并产生感知上更好的数字。

W
wizardforcel 已提交
481
“列表 8.2.1”突出显示了针对 MNIST 数字的 VAE 原始代码所做的更改。 编码器输入现在是原始输入图像及其单标签的串联。 解码器输入现在是潜在空间采样与其应生成的图像的一键热标签的组合。 参数总数为 174,437。 与![](img/B14853_08_117.png) -VAE 相关的代码将在本章下一节中讨论。
W
wizardforcel 已提交
482

W
wizardforcel 已提交
483
损失功能没有改变。 但是,在训练,测试和结果绘制过程中会提供单热标签。
W
wizardforcel 已提交
484

W
wizardforcel 已提交
485
“列表 8.2.1”:`cvae-cnn-mnist-8.2.1.py`
W
wizardforcel 已提交
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586

`tf.keras`中使用 CNN 层的 CVAE。 重点介绍了为支持 CVAE 而进行的更改:

```py
# compute the number of labels
num_labels = len(np.unique(y_train)) 
```

```py
# network parameters
input_shape = (image_size, image_size, 1)
label_shape = (num_labels, )
batch_size = 128
kernel_size = 3
filters = 16
latent_dim = 2
epochs = 30 
```

```py
# VAE model = encoder + decoder
# build encoder model
inputs = Input(shape=input_shape, name='encoder_input')
y_labels = Input(shape=label_shape, name='class_labels')
x = Dense(image_size * image_size)(y_labels)
x = Reshape((image_size, image_size, 1))(x)
x = keras.layers.concatenate([inputs, x])
for i in range(2):
    filters *= 2
    x = Conv2D(filters=filters,
               kernel_size=kernel_size,
               activation='relu',
               strides=2,
               padding='same')(x) 
```

```py
# shape info needed to build decoder model
shape = K.int_shape(x) 
```

```py
# generate latent vector Q(z|X)
x = Flatten()(x)
x = Dense(16, activation='relu')(x)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x) 
```

```py
# use reparameterization trick to push the sampling out as input
# note that "output_shape" isn't necessary 
# with the TensorFlow backend
z = Lambda(sampling,
           output_shape=(latent_dim,),
           name='z')([z_mean, z_log_var]) 
```

```py
# instantiate encoder model
encoder = Model([inputs, y_labels],
                [z_mean, z_log_var, z],
                name='encoder') 
```

```py
# build decoder model
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = concatenate([latent_inputs, y_labels])
x = Dense(shape[1]*shape[2]*shape[3], activation='relu')(x)
x = Reshape((shape[1], shape[2], shape[3]))(x) 
```

```py
for i in range(2):
    x = Conv2DTranspose(filters=filters,
                        kernel_size=kernel_size,
                        activation='relu',
                        strides=2,
                        padding='same')(x)
    filters //= 2 
```

```py
outputs = Conv2DTranspose(filters=1,
                          kernel_size=kernel_size,
                          activation='sigmoid',
                          padding='same',
                          name='decoder_output')(x) 
```

```py
# instantiate decoder model
decoder = Model([latent_inputs, y_labels],
                outputs,
                name='decoder')
# instantiate vae model
outputs = decoder([encoder([inputs, y_labels])[2], y_labels])
cvae = Model([inputs, y_labels], outputs, name='cvae') 
```

W
wizardforcel 已提交
587
“图 8.2.1”显示了 CVAE 模型的编码器。 附加输入,即单热矢量`class_labels`形式的条件标签表示:
W
wizardforcel 已提交
588

W
wizardforcel 已提交
589
![A screenshot of a cell phone  Description automatically generated](img/B14853_08_13.png)
W
wizardforcel 已提交
590 591 592

图 8.2.1:CVAE CNN 中的编码器。 输入现在包括 VAE 输入和条件标签的串联

W
wizardforcel 已提交
593
“图 8.2.2”显示了 CVAE 模型的解码器。 附加输入,即单热矢量`class_labels`形式的条件标签表示:
W
wizardforcel 已提交
594

W
wizardforcel 已提交
595
![A screenshot of a cell phone  Description automatically generated](img/B14853_08_14.png)
W
wizardforcel 已提交
596 597 598

图 8.2.2:CVAE CNN 中的解码器。 输入现在包括 z 采样和条件标签的串联

W
wizardforcel 已提交
599
“图 8.2.3”显示了完整的 CVAE 模型,该模型是编码器和解码器结合在一起的。 附加输入,即单热向量`class_labels`形式的条件标签:
W
wizardforcel 已提交
600

W
wizardforcel 已提交
601
![](img/B14853_08_15.png)
W
wizardforcel 已提交
602 603 604

图 8.2.3:使用 CNN 的 CVAE 模型 输入现在包含一个 VAE 输入和一个条件标签

W
wizardforcel 已提交
605
在“图 8.2.4”中,每个标记的平均值分布在 30 个纪元后显示。 与前面章节中的“图 8.1.6”和“图 8.1.11”不同,每个标签不是集中在一个区域上,而是分布在整个图上。 这是预期的,因为潜在空间中的每个采样都应生成一个特定的数字。 浏览潜在空间会更改该特定数字的属性。 例如,如果指定的数字为 0,则在潜伏空间中导航仍将产生 0,但是诸如倾斜角度,厚度和其他书写样式方面的属性将有所不同。
W
wizardforcel 已提交
606

W
wizardforcel 已提交
607
![](img/B14853_08_16.png)
W
wizardforcel 已提交
608 609 610

图 8.2.4:作为测试数据集(CVAE CNN)的潜在矢量平均值的函数的 MNIST 数字标签。 原始图像可以在该书的 GitHub 存储库中找到,网址为 https://github.com/PacktPublishing/Advanced-Deep-Learning-with-Keras/tree/master/chapter8-vae

W
wizardforcel 已提交
611
“图 8.2.4”在“图 8.2.5”中更清楚地显示,数字 0 到 5。每个帧都有相同的数字,并且属性在我们浏览时顺畅地变化。 潜在代码:
W
wizardforcel 已提交
612

W
wizardforcel 已提交
613
![](img/B14853_08_17.png)
W
wizardforcel 已提交
614 615 616

图 8.2.5:根据潜在矢量平均值和一个热点标签(CVAE CNN)生成的数字 0 至 5。 为了便于解释,均值的范围类似于图 8.2.4。

W
wizardforcel 已提交
617
“图 8.2.6”显示“图 8.2.4”,用于数字 6 至 9:
W
wizardforcel 已提交
618

W
wizardforcel 已提交
619
![](img/B14853_08_18.png)
W
wizardforcel 已提交
620 621 622

图 8.2.6:根据潜在矢量平均值和一个热点标签(CVAE CNN)生成的数字 6 至 9。 为了便于解释,均值的范围类似于图 8.2.4。

W
wizardforcel 已提交
623
为了便于比较,潜矢量的值范围与“图 8.2.4”中的相同。 使用预训练的权重,可以通过执行以下命令来生成数字(例如 0):
W
wizardforcel 已提交
624 625 626 627 628

```py
python3 cvae-cnn-mnist-8.2.1.py bce --weights=cvae_cnn_mnist.tf --digit=0 
```

W
wizardforcel 已提交
629
在“图 8.2.5”和“图 8.2.6”中,可以注意到,每个数字的宽度和圆度(如果适用)随`z`[0]的变化而变化。 ]从左到右追踪。 同时,当`z`[1]从上到下导航时,每个数字的倾斜角度和圆度(如果适用)也会发生变化。 随着我们离开分布中心,数字的图像开始退化。 这是可以预期的,因为潜在空间是一个圆形。
W
wizardforcel 已提交
630 631 632 633 634 635 636

属性中其他明显的变化可能是数字特定的。 例如,数字 1 的水平笔划(手臂)在左上象限中可见。 数字 7 的水平笔划(纵横线)只能在右象限中看到。

在下一节中,我们将发现 CVAE 实际上只是另一种称为![](img/B14853_08_002.png) -VAE 的 VAE 的特例。

# 3\. ![](img/B14853_08_119.png) -VAE –具有纠缠的潜在表示形式的 VAE

W
wizardforcel 已提交
637
在“第 6 章”,“非纠缠表示 GAN”中,讨论了潜码非纠缠表示的概念和重要性。 我们可以回想起,一个纠缠的表示是单个潜伏单元对单个生成因子的变化敏感,而相对于其他因子的变化相对不变[3]。 更改潜在代码会导致生成的输出的一个属性发生更改,而其余属性保持不变。
W
wizardforcel 已提交
638

W
wizardforcel 已提交
639
在同一章中,InfoGAN [4]向我们展示了对于 MNIST 数据集,可以控制生成哪个数字以及书写样式的倾斜度和粗细。 观察上一节中的结果,可以注意到,VAE 在本质上使潜矢量维解开了一定程度。 例如,查看“图 8.2.6”中的数字 8,从上到下导航`z`[1]会减小宽度和圆度,同时顺时针旋转数字。 从左至右增加`z`[0]也会在逆时针旋转数字时减小宽度和圆度。 换句话说,`z`[1]控制顺时针旋转,而`z`[0]影响逆时针旋转,并且两者都改变​​宽度和圆度。
W
wizardforcel 已提交
640 641 642

在本节中,我们将演示对 VAE 损失函数的简单修改会迫使潜在代码进一步解开纠缠。 修改为正恒重![](img/B14853_08_120.png) 1,用作 KL 损失的调节器:

W
wizardforcel 已提交
643
![](img/B14853_08_121.png) (Equation 8.3.1)
W
wizardforcel 已提交
644 645 646

VAE 的这种变化称为![](img/B14853_08_122.png) -VAE [5]。 ![](img/B14853_08_122.png)的隐含效果是更严格的标准偏差。 换句话说,![](img/B14853_08_124.png)强制后验分布中的潜码![](img/B14853_08_125.png)独立。

W
wizardforcel 已提交
647
实现![](img/B14853_08_126.png) -VAE 很简单。 例如,对于上一个示例中的 CVAE,所需的修改是`kl_loss`中的额外`beta`因子:
W
wizardforcel 已提交
648 649 650 651 652 653 654

```py
kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
kl_loss = K.sum(kl_loss, axis=-1)
kl_loss *= -0.5 * beta 
```

W
wizardforcel 已提交
655
CVAE 是![](img/B14853_08_127.png) -VAE 的特例,其中![](img/B14853_08_128.png) =`1`。 其他一切都一样。 但是,确定的值需要一些反复试验。 为了潜在的代码独立性,在重构错误和正则化之间必须有一个仔细的平衡。 解缠最大在![](img/B14853_08_129.png) =`9`附近。 当![](img/B14853_08_131.png)`9`的值时,![](img/B14853_08_132.png) -VAE 仅被迫学习一个解纠缠的表示,而忽略另一个潜在维度。
W
wizardforcel 已提交
656

W
wizardforcel 已提交
657
“图 8.3.1”和“图 8.3.2”显示![](img/B14853_08_133.png) -VAE 的潜矢量平均值,其中![](img/B14853_08_134.png) =`9`和![](img/B14853_08_132.png) =`10`
W
wizardforcel 已提交
658

W
wizardforcel 已提交
659
![](img/B14853_08_19.png)
W
wizardforcel 已提交
660 661 662

图 8.3.1:MNIST 数字标签与测试数据集的潜在矢量平均值的函数(![](img/B14853_08_136.png) -VAE,![](img/B14853_08_137.png) = 9)。 原始图像可以在该书的 GitHub 存储库中找到,网址为 https://github.com/PacktPublishing/Advanced- Deep-Learning-with-Keras / tree / master / chapter8-vae

W
wizardforcel 已提交
663
![](img/B14853_08_138.png) =`9`时,与 CVAE 相比,分布具有较小的标准偏差。 在![](img/B14853_08_134.png) =`10`的情况下,仅学习了潜在代码。 分布实际上缩小为一个维度,编码器和解码器忽略了第一潜码`z`[0]。
W
wizardforcel 已提交
664

W
wizardforcel 已提交
665
![](img/B14853_08_20.png)
W
wizardforcel 已提交
666 667 668

图 8.3.2:MNIST 数字标签与测试数据集的潜矢量平均值的函数(![](img/B14853_08_140.png) -VAE 和![](img/B14853_08_141.png) 10)

W
wizardforcel 已提交
669
[原始图像可以在该书的 GitHub 存储库中找到](https://github.com/PacktPublishing/Advanced-Deep-Learning-with-Keras/tree/master/chapter8-vae)
W
wizardforcel 已提交
670

W
wizardforcel 已提交
671
这些观察结果反映在“图 8.3.3”中。 具有`β = 9`的 β-VAE 具有两个实际上独立的潜在代码。 `z[0]`确定书写样式的倾斜度,而`z[1]`指定数字的宽度和圆度(如果适用)。 对于![](img/B14853_08_145.png) =`10`的 β-VAE,`z[0]`被静音。 `z[0]`的增加不会显着改变数字。`z[1]`确定书写样式的倾斜角度和宽度:
W
wizardforcel 已提交
672

W
wizardforcel 已提交
673
![A picture containing grass, window  Description automatically generated](img/B14853_08_21.png)
W
wizardforcel 已提交
674 675 676

图 8.3.3:根据潜在矢量平均值和单热点标签(![](img/B14853_08_146.png) -VAE ![](img/B14853_08_147.png) = 1、9 和 10)生成的数字 0 至 3。 为了便于解释,均值的范围类似于图 8.3.1。

W
wizardforcel 已提交
677
![](img/B14853_08_148.png) -VAE 的`tf.keras`代码具有预训练的权重。 要使用![](img/B14853_08_150.png) =`9`生成数字 0 来测试![](img/B14853_08_149.png) -VAE,我们需要运行以下命令:
W
wizardforcel 已提交
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

```py
python3 cvae-cnn-mnist-8.2.1.py --beta=9 --bce --weights=beta-cvae_cnn_mnist.tf --digit=0 
```

总而言之,我们已经证明与 GAN 相比,在![](img/B14853_08_151.png) -VAE 上更容易实现解缠表示学习。 我们所需要做的就是调整单个超参数。

# 4。结论

在本章中,我们介绍了 VAE 的原理。 正如我们从 VAE 原理中学到的那样,从两次尝试从潜在空间创建合成输出的角度来看,它们都与 GAN 相似。 但是,可以注意到,与 GAN 相比,VAE 网络更简单,更容易训练。 越来越清楚的是 CVAE 和![](img/B14853_08_128.png) -VAE 在概念上分别类似于条件 GAN 和解缠表示 GAN。

VAE 具有消除潜在向量纠缠的内在机制。 因此,构建![](img/B14853_08_002.png) -VAE 很简单。 但是,我们应该注意,可解释和解开的代码对于构建智能代理很重要。

在下一章中,我们将专注于强化学习。 在没有任何先验数据的情况下,代理通过与周围的世界进行交互来学习。 我们将讨论如何为代理人的正确行为提供奖励,并为错误的行为提供惩罚。

# 5.参考

W
wizardforcel 已提交
695 696 697 698 699 700 701
1.  `Diederik P. Kingma and Max Welling. Auto-encoding Variational Bayes. arXiv preprint arXiv:1312.6114, 2013 (https://arxiv.org/pdf/1312.6114.pdf).`
1.  `Kihyuk Sohn, Honglak Lee, and Xinchen Yan. Learning Structured Output Representation Using Deep Conditional Generative Models. Advances in Neural Information Processing Systems, 2015 (http://papers.nips.cc/paper/5775-learning-structured-output-representation-using-deep-conditional-generative-models.pdf).`
1.  `Yoshua Bengio, Aaron Courville, and Pascal Vincent. Representation Learning.`
1.  `A Review and New Perspectives. IEEE transactions on Pattern Analysis and Machine Intelligence 35.8, 2013: 1798-1828 (https://arxiv.org/pdf/1206.5538.pdf).`
1.  `Xi Chen et al.: Infogan: Interpretable Representation Learning by Information Maximizing Generative Adversarial Nets. Advances in Neural Information Processing Systems, 2016 (http://papers.nips.cc/paper/6399-infogan-interpretable-representation-learning-by-information-maximizing-generative-adversarial-nets.pdf).`
1.  `I. Higgins, L. Matthey, A. Pal, C. Burgess, X. Glorot, M. Botvinick, S. Mohamed, and A. Lerchner. -VAE: Learning Basic Visual Concepts with a Constrained Variational Framework. ICLR, 2017 (https://openreview.net/pdf?id=Sy2fzU9gl).`
1.  `Carl Doersch. Tutorial on variational autoencoders. arXiv preprint arXiv:1606.05908, 2016 (https://arxiv.org/pdf/1606.05908.pdf).`