如何用Keras实现VAE处理?
摘要:变分自编码器(variational autoencoder, VAE)是一种生成模型,训练模型分为编码器和解码器两部分。 编码器将输入样本映射为某个低维分布,这个低维分布通常是不同维度之间相互独立的多元高斯分布,因此编码器的输出为这个高斯
变分自编码器(variational autoencoder, VAE)是一种生成模型,训练模型分为编码器和解码器两部分。
编码器将输入样本映射为某个低维分布,这个低维分布通常是不同维度之间相互独立的多元高斯分布,因此编码器的输出为这个高斯分布的均值与对数方差(因为方差总是大于0,为了将它映射到$(-\infty,\infty)$,所以加了对数)。在编码器的分布中抽样后,解码器做的事是将从这个低维抽样重新解码,生成与输入样本相似的数据。数据可以是图像、文字、音频等。
VAE模型的结构不难理解,关键在于它的损失函数的定义。我们要让解码器的输出与编码器的输入尽量相似,这个损失可以由这二者之间的二元交叉熵(binary crossentropy)来定义。但是仅由这个作为最终的目标函数是不够的。在这样的目标函数下,不断的梯度下降,会使编码器在不同输入下的输出均值之间的差别越来越大,输出方差则会不断地趋向于0,也就是对数方差趋向于负无穷。因为只有这样才会使从生成分布获取的抽样更加明确,从而让解码器能生成与输入数据更接近的数据,以使损失变得更小。但是这就与生成器的初衷有悖了,生成器的初衷实际上是为了生成更多“全新”的数据,而不是为了生成与输入数据“更像”的数据。所以,我们还要再给目标函数加上编码器生成分布的“正则化损失”:生成分布与标准正态分布之间的KL散度(相对熵)。让生成分布不至于“太极端、太确定”,从而让不同输入数据的生成分布之间有交叉 。于是解码器通过这些交叉的“缓冲带”上的抽样,能够生成“中间数据”,产生意想不到的效果。
详细的分析请看:变分自编码器VAE:原来是这么一回事 - 知乎
以下使用Keras实现VAE生成图像,数据集是MNIST。
代码实现
编码器
编码器将MNIST的数字图像转换为2维的正态分布均值与对数方差。简单堆叠卷积层与全连接层即可,代码如下:
#%%编码器
import numpy as np
import keras
from keras import layers,Model,models,utils
from keras import backend as K
from keras.datasets import mnist
img_shape = (28,28,1)
latent_dim = 2
input_img = layers.Input(shape=img_shape)
x = layers.Conv2D(32,3,padding='same',activation='relu')(input_img)
x = layers.Conv2D(64,3,padding='same',activation='relu',strides=2)(x)
x = layers.Conv2D(64,3,padding='same',activation='relu')(x)
x = layers.Conv2D(64,3,padding='same',activation='relu')(x)
inter_shape = K.int_shape(x)
x = layers.Flatten()(x)
x = layers.Dense(32,activation='relu')(x)
encode_mean = layers.Dense(2,name = 'encode_mean')(x) #分布均值
encode_log_var = layers.Dense(2,name = 'encode_logvar')(x) #分布对数方差
encoder = Model(input_img,[encode_mean,encode_log_var],name = 'encoder')
解码器
解码器接受2维向量,将这个向量“解码”为图像。
