1. 程式人生 > >關於FV(Fisher Vector)和變分自編碼VAE(Variational Autoencoder)的原理簡介

關於FV(Fisher Vector)和變分自編碼VAE(Variational Autoencoder)的原理簡介

1. FV(Fisher Vector)

    FV的思想用一句話概括就是:用所有的聚類中心的線性組合去表示每個特徵點

簡單來說,假設樣本各特徵符合獨立同分布(i.i.d)則樣本的概率分佈可以由各個特徵維度的概率分佈的乘積得到。對該式取對數的話,就可以將乘法運算轉換為加法運算,即

Fisher vector就是對上式求偏導的結果歸一化後構成的。具體數學推導過程請參考點選開啟連結。fv的虛擬碼實現過程如下:

    接下來是本文的重點部分,變分自編碼器。

2. VAE(Variational Autoencoder)

    VAE的基本思想是:為每個樣本構造專屬的正態分佈,然後利用取樣重構

    由於我們若能瞭解一組資料的概率分佈,就可以通過分佈對其進行取樣直接得到所有的可能資料,VAE就是採用了一種迂迴的方式去實現這一思想。對於每個樣本X,利用神經網路提取出該樣本的正態分佈引數(均值,方差)從而可以構建出每個樣本的專屬的正態分佈P(X)再取樣重構。然而直接對X取樣是比較困難的,因此假設存在變數Z服從標準正態分佈,就可以利用下式

先從標準正太分佈中取樣Z,然後根據Z來計算 X,即對於對應的取樣變數Z,利用生成器生成樣本X hat,即為X的重構值。

    為了防止噪聲對重構過程產生影響,同時還應保證該模型具有生成能力,需要使所有的P(Z|X)都接近標準正態分佈,這是因為

此時滿足Z是標準正態分佈的先驗條件,可以從標準正態分佈中取樣Z來重構X。為了實現這一點,VAE採用的方式是在重構誤差項後面額外添加了誤差項。因為當Z逼近標準正態分佈時其均值應趨近於0,取對數後的方差也趨近於0(方差趨近於1),則二者對應的損失項應為各自值的範數的平方,利用KL散度合併二者得到該額外損失項的表示式為

    至此,就是VAE的大體思路了。

    接下來就是VAE另一非常重要的思想(技巧),即重引數技巧 Reparameterization Trick

    由於取樣操作的不可導,為了反向優化提取提取均值和方差的模型,根據下式

就可以通過引數變換的方式取樣

取樣操作將不需要直接參與梯度下降過程,而是改為取樣結果參與,使模型可訓練。

    最終的變分自編碼實現過程的虛擬碼為

    最後補充說明幾點:

1.當噪聲為0時,變分自編碼器將退化為普通自編碼器,因此KL散度不應完全為0

2.該方法中使用的正態分佈能夠有效的保證KL散度在重構誤差表示式中的正常應用,使用其他概率分佈可能易出現kl散度接近無窮大的情況

3.variational(變分)體現在引入KL散度這一泛函的處理上

4.將label加入來輔助生成樣本,可以實現通過控制均值來生成某類影象,該方法稱為Conditional VAE,即CVAE

網上看到的VAE程式碼(來源github),較為簡單易懂,如下所示:

import itertools
import matplotlib as mpl
import numpy as np
import os
import tensorflow as tf
import tensorflow.contrib.slim as slim
import time
import seaborn as sns

from matplotlib import pyplot as plt
from scipy.misc import imsave
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets

# sns.set_style('whitegrid')

distributions = tf.distributions

flags = tf.app.flags
flags.DEFINE_string('data_dir', '/tmp/dat/', 'Directory for data')
flags.DEFINE_string('logdir', '/tmp/log/', 'Directory for logs')


flags.DEFINE_integer('latent_dim', 100, 'Latent dimensionality of model')
flags.DEFINE_integer('batch_size', 64, 'Minibatch size')
flags.DEFINE_integer('n_samples', 1, 'Number of samples to save')
flags.DEFINE_integer('print_every', 1000, 'Print every n iterations')
flags.DEFINE_integer('hidden_size', 200, 'Hidden size for neural networks')
flags.DEFINE_integer('n_iterations', 100000, 'number of iterations')

FLAGS = flags.FLAGS

# 提取mu和sigma的神經網路
def inference_network(x, latent_dim, hidden_size):
  """Construct an inference network parametrizing a Gaussian.
  Args:
    x: A batch of MNIST digits.
    latent_dim: The latent dimensionality.
    hidden_size: The size of the neural net hidden layers.
  Returns:
    mu: Mean parameters for the variational family Normal
    sigma: Standard deviation parameters for the variational family Normal
  """
  with slim.arg_scope([slim.fully_connected], activation_fn=tf.nn.relu):
    net = slim.flatten(x)
    net = slim.fully_connected(net, hidden_size)
    net = slim.fully_connected(net, hidden_size)
    gaussian_params = slim.fully_connected(
        net, latent_dim * 2, activation_fn=None)
  # The mean parameter is unconstrained
  mu = gaussian_params[:, :latent_dim]
  # The standard deviation must be positive. Parametrize with a softplus
  sigma = tf.nn.softplus(gaussian_params[:, latent_dim:])
  return mu, sigma

#利用取樣的z重構x的生成器
#因為資料集是二值影象,因此採用伯努利分佈為x|z的分佈形式,從而可以利用神經網路(全連線層)得到生成模型q(x|z)
def generative_network(z, hidden_size):
  """Build a generative network parametrizing the likelihood of the data
  Args:
    z: Samples of latent variables
    hidden_size: Size of the hidden state of the neural net
  Returns:
    bernoulli_logits: logits for the Bernoulli likelihood of the data
  """
  with slim.arg_scope([slim.fully_connected], activation_fn=tf.nn.relu):
    net = slim.fully_connected(z, hidden_size)
    net = slim.fully_connected(net, hidden_size)
    bernoulli_logits = slim.fully_connected(net, 784, activation_fn=None)
    bernoulli_logits = tf.reshape(bernoulli_logits, [-1, 28, 28, 1])
  return bernoulli_logits


def train():
  # Train a Variational Autoencoder on MNIST

  # Input placeholders
  with tf.name_scope('data'):
    x = tf.placeholder(tf.float32, [None, 28, 28, 1])
    tf.summary.image('data', x)

  with tf.variable_scope('variational'):
    q_mu, q_sigma = inference_network(x=x,
                                      latent_dim=FLAGS.latent_dim,
                                      hidden_size=FLAGS.hidden_size)
    # The variational distribution is a Normal with mean and standard
    # deviation given by the inference network
    q_z = distributions.Normal(loc=q_mu, scale=q_sigma)
    assert q_z.reparameterization_type == distributions.FULLY_REPARAMETERIZED

  with tf.variable_scope('model'):
    # The likelihood is Bernoulli-distributed with logits given by the
    # generative network
    p_x_given_z_logits = generative_network(z=q_z.sample(),
                                            hidden_size=FLAGS.hidden_size)
    p_x_given_z = distributions.Bernoulli(logits=p_x_given_z_logits)
    posterior_predictive_samples = p_x_given_z.sample()
    tf.summary.image('posterior_predictive',
                     tf.cast(posterior_predictive_samples, tf.float32))

  # Take samples from the prior
  # 取樣
  with tf.variable_scope('model', reuse=True):
    p_z = distributions.Normal(loc=np.zeros(FLAGS.latent_dim, dtype=np.float32),
                               scale=np.ones(FLAGS.latent_dim, dtype=np.float32))
    p_z_sample = p_z.sample(FLAGS.n_samples)
    p_x_given_z_logits = generative_network(z=p_z_sample,
                                            hidden_size=FLAGS.hidden_size)
    prior_predictive = distributions.Bernoulli(logits=p_x_given_z_logits)
    prior_predictive_samples = prior_predictive.sample()
    tf.summary.image('prior_predictive',
                     tf.cast(prior_predictive_samples, tf.float32))

  # Take samples from the prior with a placeholder
  with tf.variable_scope('model', reuse=True):
    z_input = tf.placeholder(tf.float32, [None, FLAGS.latent_dim])
    p_x_given_z_logits = generative_network(z=z_input,
                                            hidden_size=FLAGS.hidden_size)
    prior_predictive_inp = distributions.Bernoulli(logits=p_x_given_z_logits)
    prior_predictive_inp_sample = prior_predictive_inp.sample()

  # Build the evidence lower bound (ELBO) or the negative loss
  kl = tf.reduce_sum(distributions.kl_divergence(q_z, p_z), 1) #按行求和
  expected_log_likelihood = tf.reduce_sum(p_x_given_z.log_prob(x),
                                          [1, 2, 3])#????

  elbo = tf.reduce_sum(expected_log_likelihood - kl, 0)

  optimizer = tf.train.RMSPropOptimizer(learning_rate=0.001)

  train_op = optimizer.minimize(-elbo)

  # Merge all the summaries
  summary_op = tf.summary.merge_all()

  init_op = tf.global_variables_initializer()

  # Run training
  sess = tf.InteractiveSession()
  sess.run(init_op)

  mnist = read_data_sets(FLAGS.data_dir, one_hot=True)

  print('Saving TensorBoard summaries and images to: %s' % FLAGS.logdir)
  train_writer = tf.summary.FileWriter(FLAGS.logdir, sess.graph)

  # Get fixed MNIST digits for plotting posterior means during training
  np_x_fixed, np_y = mnist.test.next_batch(5000)
  np_x_fixed = np_x_fixed.reshape(5000, 28, 28, 1)
  np_x_fixed = (np_x_fixed > 0.5).astype(np.float32)

  t0 = time.time()
  for i in range(FLAGS.n_iterations):
    # Re-binarize the data at every batch; this improves results
    np_x, _ = mnist.train.next_batch(FLAGS.batch_size)
    np_x = np_x.reshape(FLAGS.batch_size, 28, 28, 1)
    np_x = (np_x > 0.5).astype(np.float32)
    sess.run(train_op, {x: np_x})

    # Print progress and save samples every so often
    if i % FLAGS.print_every == 0:
      np_elbo, summary_str = sess.run([elbo, summary_op], {x: np_x})
      train_writer.add_summary(summary_str, i)
      print('Iteration: {0:d} ELBO: {1:.3f} s/iter: {2:.3e}'.format(
          i,
          np_elbo / FLAGS.batch_size,
          (time.time() - t0) / FLAGS.print_every))
      t0 = time.time()

      # Save samples
      np_posterior_samples, np_prior_samples = sess.run(
          [posterior_predictive_samples, prior_predictive_samples], {x: np_x})
      for k in range(FLAGS.n_samples):
        f_name = os.path.join(
            FLAGS.logdir, 'iter_%d_posterior_predictive_%d_data.jpg' % (i, k))
        imsave(f_name, np_x[k, :, :, 0])
        f_name = os.path.join(
            FLAGS.logdir, 'iter_%d_posterior_predictive_%d_sample.jpg' % (i, k))
        imsave(f_name, np_posterior_samples[k, :, :, 0])
        f_name = os.path.join(
            FLAGS.logdir, 'iter_%d_prior_predictive_%d.jpg' % (i, k))
        imsave(f_name, np_prior_samples[k, :, :, 0])

      # Plot the posterior predictive space
      if FLAGS.latent_dim == 2:
        np_q_mu = sess.run(q_mu, {x: np_x_fixed})
        cmap = mpl.colors.ListedColormap(sns.color_palette("husl"))
        f, ax = plt.subplots(1, figsize=(6 * 1.1618, 6))
        im = ax.scatter(np_q_mu[:, 0], np_q_mu[:, 1], c=np.argmax(np_y, 1), cmap=cmap,
                        alpha=0.7)
        ax.set_xlabel('First dimension of sampled latent variable $z_1$')
        ax.set_ylabel('Second dimension of sampled latent variable mean $z_2$')
        ax.set_xlim([-10., 10.])
        ax.set_ylim([-10., 10.])
        f.colorbar(im, ax=ax, label='Digit class')
        plt.tight_layout()
        plt.savefig(os.path.join(FLAGS.logdir,
                                 'posterior_predictive_map_frame_%d.png' % i))
        plt.close()

        nx = ny = 20
        x_values = np.linspace(-3, 3, nx)
        y_values = np.linspace(-3, 3, ny)
        canvas = np.empty((28 * ny, 28 * nx))
        for ii, yi in enumerate(x_values):
          for j, xi in enumerate(y_values):
            np_z = np.array([[xi, yi]])
            x_mean = sess.run(prior_predictive_inp_sample, {z_input: np_z})
            canvas[(nx - ii - 1) * 28:(nx - ii) * 28, j *
                   28:(j + 1) * 28] = x_mean[0].reshape(28, 28)
        imsave(os.path.join(FLAGS.logdir,
                            'prior_predictive_map_frame_%d.png' % i), canvas)
        # plt.figure(figsize=(8, 10))
        # Xi, Yi = np.meshgrid(x_values, y_values)
        # plt.imshow(canvas, origin="upper")
        # plt.tight_layout()
        # plt.savefig()

  # Make the gifs
  if FLAGS.latent_dim == 2:
    os.system(
        'convert -delay 15 -loop 0 {0}/posterior_predictive_map_frame*png {0}/posterior_predictive.gif'
        .format(FLAGS.logdir))
    os.system(
        'convert -delay 15 -loop 0 {0}/prior_predictive_map_frame*png {0}/prior_predictive.gif'
        .format(FLAGS.logdir))


def main(_):
  if tf.gfile.Exists(FLAGS.logdir):
    tf.gfile.DeleteRecursively(FLAGS.logdir)
  tf.gfile.MakeDirs(FLAGS.logdir)
  train()


if __name__ == '__main__':
  tf.app.run()

———————————————————————————

第一次寫部落格,作為科研小白,才學疏淺,還請多多指教~

相關推薦

關於FV(Fisher Vector)編碼VAEVariational Autoencoder原理簡介

1. FV(Fisher Vector)     FV的思想用一句話概括就是:用所有的聚類中心的線性組合去表示每個特徵點 簡單來說,假設樣本各特徵符合獨立同分布(i.i.d)則樣本的概率分佈可以由各個特徵維度的概率分佈的乘積得到。對該式取對數的話,就可以將乘法運算轉換為加

【Learning Notes】編碼Variational Auto-Encoder,VAE

近年,隨著有監督學習的低枝果實被採摘的所剩無幾,無監督學習成為了研究熱點。VAE(Variational Auto-Encoder,變分自編碼器)[1,2] 和 GAN(Generative Adversarial Networks) 等模型,受到越來越多的關注

從零上手編碼VAE

閱讀更多,歡迎關注公眾號:論文收割機(paper_reader) Kingma D P, Welling M. Auto-encoding variational bayes[J]. arXiv preprint arXiv:1312.6114, 2013. Rez

LearningNotes 編碼 VariationalAutoEncoder VAE

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

VAE----編碼器Keras實現

這篇部落格用來記錄我自己用keras實現(抄寫)VAE過程中,掉進的一個坑。。。。。。 最近這幾天在網上看了很多VAE的介紹,並且看了一下keras中的實現。自我感覺良好,就想按著官方的程式碼自己也去寫一遍。不寫不知道,一寫嚇一跳!!我跳進了一個很大坑中(笑哭),我在把程式碼寫完以後,開始訓

分貝葉斯、編碼遷移

目錄 變分法簡介 變分推斷 變分貝葉斯 變分自編碼 變分與遷移 :heart: 一些資料 變分法簡介 變分法是研究依賴於某些未知函式的積分型泛函極值的一門科學。也就是求泛函極值的方法稱為變分法。 典型例子最速降線

編碼編碼大雜燴

1.變分自編碼          變分是數學上的概念,大致含義是尋求一箇中間的函式,通過改變中間函式來檢視目標函式的改變。變分推斷是變分自編碼的核心,那麼變分推斷是要解決的是什麼問題?? 問題描述如下,假如我們有一批樣本X,這個時候,我們想生成一批和它類似的樣本,且分佈相同,這個時候我們該怎麼辦呢? 1

編碼網路的實現

1、VAE跟Gan有點類似,都是可以通過一些輸入,生成一些樣本資料。不同點是VAE是假設在資料的分佈是服從正態分佈的,而GAN是沒有這個假設的,完全是由資料驅動,進行訓練得出規律的。 下面是變分自編碼網路的程式碼: import numpy as np import te

[深度學習]半監督學習、無監督學習之Variational Auto-Encoder編碼器(附程式碼)

論文全稱:《Auto-Encoding Variational Bayes》 論文地址:https://arxiv.org/pdf/1312.6114.pdf 論文程式碼: keras 版本:https://github.com/bojone/vae pytorch 版本:https

Autoencorder理解(5):VAEVariational Auto-Encoder,編碼

reference: http://blog.csdn.net/jackytintin/article/details/53641885 近年,隨著有監督學習的低枝果實被採摘的所剩無幾,無監督學習成為了研究熱點。VAE(Variational Auto-Encode

Variational Autoencoder編碼

使用通用自編碼器的時候,首先將輸入encoder壓縮為一個小的 form,然後將其decoder轉換成輸出的一個估計。如果目標是簡單的重現輸入效果很好,但是若想生成新的物件就不太可行了,因為其實我們根本不知道這個網路所生成的編碼具體是什麼。雖然我們可以通過結果去對比不同的物件,但是要理解

白話Variational Autoencoder編碼

本文將簡單介紹一下Variational Autoencoder。作者也在學習當中,如有不正確的地方,請大家指正,謝謝~原始的autoencoder一般分為兩個部分encoder part和decoder part。 encoder是將input轉化為encoding vec

【TensorFlow-windows】學習筆記六——編碼

前言 對理論沒興趣的直接看程式碼吧,理論一堆,而且還有點複雜,我自己的描述也不一定準確,但是程式碼就兩三句話搞定了。 國際慣例,參考博文 理論 基礎知識 似然函式(引自百度百科) 似然函式是關於統計模型中的引數的函式,

編碼VAE及程式碼解讀

這幾天在看GAN模型的時候,順便關注了另外一種生成模型——VAE。其實這種生成模型在早幾年就有了,而且有了一些應用。著名黑客George Hotz在其開源的自主駕駛專案中就應用到了VAE模型。這其中的具體應用在我上一篇轉載的部落格comma.ai中有詳細介紹。在對VAE基本原

VAE編碼器的一點理解

前言 網上很多關於VAE的教程都包含大量枯燥難懂的數學公式,如果有大佬特別喜歡推導這些公式,很高興能夠附上以下連結。然而,今天只是想簡單的談下自己的理解,只有圖片,沒有公式。 主要內容 如下圖所示,其實VAE的主要思想就是以均值方差計算模組來作為Enc

你瞭解編碼器嗎? 請看這裡

10.9  變分自編碼器前面所描述的自編碼器可以降維重構樣本,在這基礎上我們來學習一個更強大的自編碼器。10.9.1  什麼是變分自編碼器變分自編碼器學習的不再是樣本的個體,而是要學習樣本的規律。這樣訓練出來的自編碼器不單單具有重構樣本的功能,還具有了仿照樣本的功能。聽起來這

HDU的一些二分的一些題目大部分模擬

大家如果對於二分和三分沒有把握的話可以多練練,我其他的部落格文章裡面也有關於二分和三分的一些解釋。Can you solve this equation?(HDU 2199)   Strange fuction(HDU 2899)    Pie(HDU 1969)    To