第10課: 變分自編碼器(VAE)
變分推斷(Variational Inference)
關(guān)于變分推斷的基礎(chǔ)概念可以先參照這篇文章制轰。
學(xué)習(xí)未知的變量
圖像由數(shù)百萬像素組成倚喂,但可能有更緊湊的內(nèi)容表示方式(對象、位置等)油狂。
找到這個表示的映射可以使我們找出語義相似的圖像,甚至生成新的圖像衅码。
我們叫這種緊湊表示為z损同,它對應(yīng)的像素點集合為x。我們的N張圖片都是一樣的結(jié)構(gòu)逐纬。
假設(shè)模型中的x由隱含變量z生成,我們想要找到解釋數(shù)據(jù)的隱含變量削樊。
但是我們不能直接計算數(shù)據(jù)的最大似然豁生,因為它取決于隱含變量z而我們不知道它們的值。
θ* = argmax P_θ(x) = argmax ∫ P_θ(x|z)P(z) dz
我們定義一個先驗假設(shè)P(z),它是z的分布沛硅。
我們感興趣的是后驗概率P(z|x)眼刃,它依賴于相應(yīng)的數(shù)據(jù)點x。
變分下界: 概覽
迭代優(yōu)化近似的后驗概率Q(z)直到Q(z) ≈ P(z|x)
Q(z)的目標是變分下界
\begin{aligned} lnP(x) &≥ E_{Q(z)}[lnP(x,z) ? lnQ(z)] \\ &= E_{Q(z)}[lnP(x|z) + lnP(z) ? lnQ(z)] \\ &= E_{Q(z)}[lnP(x|z)] ? D_{KL}[Q(z)||P(z)] \end{aligned}
這是一個下界因為KL散度是非負的摇肌。
取 Q(z) ? ?? 為可微的采樣,常常取高斯分布仪际。KL散度是一個正則項围小。
變分下界: 算法
將隱含的P(z)初始化為固定的先驗概率,比如說0均值單位方差的高斯分布树碱。
初始化網(wǎng)絡(luò)權(quán)值 θ 和 Q(z) 的 μ 和 σ 肯适。
記住目標函數(shù) lnP(x) ≥ E_{Q(z)}[lnP_θ(x|z)] ? D_{KL}[Q(z)||P(z)]
迭代直到收斂:
- 從Q(z)中取樣一個z,z = σε + μ ??(ε ~ N(0, 1))
- 用神經(jīng)網(wǎng)絡(luò)計算 P_θ(x|z)
- 計算Q(z)和P(z)的KL散度
- 計算目標函數(shù)的梯度來優(yōu)化 θ, μ, σ
分段推斷: 概覽
我們可以通過梯度下降的方法成榜,為每個數(shù)據(jù)點學(xué)習(xí)足夠的Q(z)統(tǒng)計量框舔。但是每個數(shù)據(jù)點都需要多個求梯度的步驟,即使是在評價時赎婚。
我們可以使用一個編碼器網(wǎng)絡(luò)Q(z|x)學(xué)習(xí)這個過程的結(jié)果刘绣。想象一下怎樣為所有的數(shù)據(jù)點推斷隱含變量,反向傳播優(yōu)化編碼器的權(quán)重挣输,而不是后驗的統(tǒng)計量μ,σ纬凤。
分段推斷: 算法
將隱含的P(z)初始化為固定的先驗概率,比如說0均值單位方差的高斯分布撩嚼。
初始化編碼器的權(quán)值 ? 和解碼器的權(quán)值 θ 停士。
記住目標函數(shù) lnP(x) ≥ E_{Q(z)}[lnP_θ(x|z)] ? D_{KL}[Q_?(z|x)||P(z)]
迭代直到收斂:
- 選擇數(shù)據(jù)點x并用編碼器計算 Q?(z|x) 。
- 從Q(z|x)中取樣一個z完丽,z = σε + μ ??(ε ~ N(0, 1))
- 用解碼器計算 P_θ(x|z)
- 計算Q(z)和P(z)的KL散度
- 計算目標函數(shù)的梯度來優(yōu)化 θ, ?
變分自編碼器(VAE, Variational Auto-Encoder)
編碼器用來分段推斷出Q(z|x), 解碼器用來生成模型P(x|z)恋技。
變分下界目標函數(shù) E_{Q(z|x)}[lnP(x|z)] ? D_{KL}[Q(z|x)||P(z)]。
通過梯度下降訓(xùn)練端到端模型逻族。
貝葉斯神經(jīng)網(wǎng)絡(luò)
獨立隱含的Q(θ)是對角高斯分布蜻底。
條件生成模型P_θ(y|x)。
變分下界目標函數(shù):E_{Q(θ)}[lnP_θ(y|x)] ? D_{KL}[Q(θ)||P(θ)]
將KL項除以數(shù)據(jù)集大小瓷耙,因為整個數(shù)據(jù)集的參數(shù)是共享的朱躺。
通過梯度下降訓(xùn)練一個端到端的模型。
TensorFlow實現(xiàn)
TensorFlow中的概率分布: 概覽
在TensorFlow中概率編程很容易搁痛!
Probabilistic programming made easy!
tfd = tf.contrib.distributions
mean = tf.layers.dense(hidden, 10, None)
stddev = tf.layers.dense(hidden, 10, tf.nn.softplus)
dist = tfd.MultivariateNormalDiag(mean, stddev)
samples = dist.sample()
dist.log_prob(samples)
other = tfd.MultivariateNormalDiag(
tf.zeros_like(mean), tf.ones_like(stddev))
tfd.kl_divergence(dist, other)
TensorFlow中的概率分布: 回歸的例子
tfd = tf.contrib.distributions
hidden = tf.layers.dense(inputs, 100, tf.nn.relu)
mean = tf.layers.dense(hidden, 10, None)
dist = tfd.MultivariateNormalDiag(mean, tf.ones_like(mean))
loss = -dist.log_prob(label) # Squared error
optimize = tf.train.AdamOptimizer().minimize(loss)
TensorFlow中的概率分布: 分類的例子
tfd = tf.contrib.distributions
hidden = tf.layers.dense(inputs, 100, tf.nn.relu)
logit = tf.layers.dense(hidden, 10, None)
dist = tfd.Categorical(logit)
loss = -dist.log_prob(label) # Cross entropy
optimize = tf.train.AdamOptimizer().minimize(loss)
VAE的TensorFlow實現(xiàn): 概覽
tfd = tf.contrib.distributions
images = tf.placeholder(tf.float32, [None, 28, 28])
prior = make_prior()
posterior = make_encoder(images)
dist = make_decoder(posterior.sample())
elbo = dist.log_prob(images) - tfd.kl_divergence(posterior, prior)optimizer = tf.train.AdamOptimizer().minimize(-elbo)
samples = make_decoder(prior.sample(10)).mean() # For visualization
VAE的TensorFlow實現(xiàn): Prior & encoder
def make_prior(code_size=2):
mean, stddev = tf.zeros([code_size]), tf.ones([code_size])
return tfd.MultivariateNormalDiag(mean, stddev)
def make_encoder(images, code_size=2):
images = tf.layers.flatten(images)
hidden = tf.layers.dense(images, 100, tf.nn.relu)
mean = tf.layers.dense(hidden, code_size)
stddev = tf.layers.dense(hidden, code_size, tf.nn.softplus)
return tfd.MultivariateNormalDiag(mean, stddev)
VAE的TensorFlow實現(xiàn): 網(wǎng)絡(luò)
def make_decoder(code, data_shape=[28, 28]):
hidden = tf.layers.dense(code, 100, tf.nn.relu)
logit = tf.layers.dense(hidden, np.prod(data_shape))
logit = tf.reshape(logit, [-1] + data_shape)
return tfd.Independent(tfd.Bernoulli(logit), len(data_shape))
tfd.Independent(dist, 2)
告訴TensorFlow將最后兩維視為數(shù)據(jù)維度长搀,而不是批處理維度。
這說明dist.log_prob(images)
對每張圖片返回一個數(shù)字而不是每個點鸡典。
正如名稱tfd.independent()
所表示源请,它只是將像素對數(shù)概率相加。
VAE的TensorFlow實現(xiàn): 結(jié)果
貝葉斯網(wǎng)絡(luò)的TensorFlow實現(xiàn)
def define_network(images, num_classes=10):
mean = tf.get_variable('mean', [28 * 28, num_classes])
stddev = tf.get_variable('stddev', [28 * 28, num_classes])
prior = tfd.MultivariateNormalDiag(
tf.zeros_like(mean), tf.ones_like(stddev))
posterior = tfd.MultivariateNormalDiag(mean, tf.nn.softplus(stddev))
bias = tf.get_variable('bias', [num_classes]) # Or Bayesian, too
logit = tf.nn.relu(tf.matmul(posterior.sample(), images) + bias)
return tfd.Categorical(logit), posterior, prior
dist, posterior, prior = define_network(images)
elbo = (tf.reduce_mean(dist.log_prob(label)) -
tf.reduce_mean(tfd.kl_divergence(posterior, prior))