變分自編碼器VAE

基於變分的自編碼器(variational Autoencoder)是2014由Kingma等人提出的一種基於變分貝葉斯推斷的生成網絡。與傳統的生成網絡相比它具有兩點優勢:
1。避免了複雜的邊界似然概率(太難了,誰會算啊)
2。避免了馬爾科夫鏈的採樣過程(好像最近很火生成對抗網絡也避免了這個)

1. 生成器網絡

對於一堆我們收集到的樣本,這些樣本在默認情況下來自一個獨立的同分布,也就是我們常說的iid。我們不妨把這個概率分佈記作p(x) ,然而想搞清楚這個概率分佈是很難的,因爲我們要對這個概率的邊緣分佈進行積分。於是乎,就有高人想到了能不能用一個簡單的概率分佈去近似我們未知的複雜概率,於是乎就有人將這個概率命名爲q(x) 。有了這兩個概率以後,需要建立一種度量方式來比較兩個概率分佈的相似程度,因此給出出這兩個概率分佈的潛變量的產生概率的KL散度
KL(p||q)=plogpq

2. 邊分邊界

當我有了兩個概率分佈的評價模型以後,需要做的就是優化。首先將KL散度進行拆分:
p(z|x)logp(z|x)q(z|x)=p(z|x)logp(z|x)p(z|x)logq(z|x)
根據貝葉斯公式,p(z|x)=px|z)p(z)p(x)
KL=p(z|x)[logq(z|x)logp(x,z)]+logp(x)
其中,中間含有 的一項可以看做是相關分佈在概率分佈p(z|x) 下的期望。我們可以將這一項記爲L 重寫一下式子,通過變形可以得到:
logp(x)=KL+L 其中L 就是這個Kl分佈
假設我們的概率優化的夠好,讓我們的變分下界儘可能的大,那麼我們的KL散度就會越來越小,兩個概率分佈的相似性就會越來越好。
logp(x)L=Eq(z|x)[logq(z|x)+logp(x,z)] 通過一系列變換,結合貝葉斯,可以得到L=KL(q(z|x)||p(z))+Eq(z|x)[logp(x|z)]

3. 變分自編碼器

上面的式子可以簡寫成Eq(z|x)[f(z)] ,也就是將原分佈看做一個關於z的函數,記爲z=g(ϵ,x) ,在x是已知的情況下,我們的整個z的產生將由ϵ 決定。
針對自編碼器的結構,我們採用多維標準高斯進行逼急z的後驗分佈q(z|x)
結合keras中的vae代碼進行分析:

@author: sky
"""

'''This script demonstrates how to build a variational autoencoder with Keras.
Reference: "Auto-Encoding Variational Bayes" https://arxiv.org/abs/1312.6114
'''
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

from keras.layers import Input, Dense, Lambda
from keras.models import Model
from keras import backend as K
from keras import objectives
from keras.datasets import mnist

batch_size = 100
original_dim = 784
latent_dim = 2
intermediate_dim = 256
nb_epoch = 50
epsilon_std = 1.0
#定義模型初始化
x = Input(batch_shape=(batch_size, original_dim))
h = Dense(intermediate_dim, activation='relu')(x)
z_mean = Dense(latent_dim)(h)
z_log_var = Dense(latent_dim)(h)
#建立一個連接模型,這裏的z_mean代表了高斯分佈的均值,z_log_var代表了高斯分佈方差的對數表達。

def sampling(args):
    z_mean, z_log_var = args
    epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0.,
                              std=epsilon_std)
    return z_mean + K.exp(z_log_var / 2) * epsilon
#建立一個採樣方程,最終返回一個生成的z
# note that "output_shape" isn't necessary with the TensorFlow backend
z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_var])


decoder_h = Dense(intermediate_dim, activation='relu')
decoder_mean = Dense(original_dim, activation='sigmoid')
h_decoded = decoder_h(z)
#將採樣後的z映射到隱含層中(可以參考AE)
x_decoded_mean = decoder_mean(h_decoded)
#對隱含層的h進行解碼得到重構樣本x

def vae_loss(x, x_decoded_mean):
    xent_loss = original_dim * objectives.binary_crossentropy(x, x_decoded_mean)
    kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
    return xent_loss + kl_loss
#定義整個模型的損失函數,包括了讓採樣儘可能的靠近標準高斯分佈和隱含層的解碼值與原始樣本更加接近。
vae = Model(x, x_decoded_mean)
vae.compile(optimizer='rmsprop', loss=vae_loss)

# train the VAE on MNIST digits
(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))

vae.fit(x_train, x_train,
        shuffle=True,
        nb_epoch=nb_epoch,
        batch_size=batch_size,
        validation_data=(x_test, x_test))

這樣就可以實現VAE的訓練

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章