天天看點

教你用TensorFlow和自編碼器模型生成手寫數字(附代碼)

自編碼器是一種能夠用來學習對輸入資料高效編碼的神經網絡。若給定一些輸入,神經網絡首先會使用一系列的變換來将資料映射到低維空間,這部分神經網絡就被稱為編碼器。

然後,網絡會使用被編碼的低維資料去嘗試重建輸入,這部分網絡稱之為解碼器。我們可以使用編碼器将資料壓縮為神經網絡可以了解的類型。然而自編碼器很少用做這個目的,因為通常存在比它更為有效的手工編寫的算法(例如 jpg 壓縮)。

此外,自編碼器還被經常用來執行降噪任務,它能夠學會如何重建原始圖像。

什麼是變分自編碼器?

有很多與自編碼器相關的有趣應用。

其中之一被稱為變分自編碼器(variational autoencoder)。使用變分自編碼器不僅可以壓縮資料--還能生成自編碼器曾經遇到過的新對象。

使用通用自編碼器的時候,我們根本不知道網絡所生成的編碼具體是什麼。雖然我們可以對比不同的編碼對象,但是要了解它内部編碼的方式幾乎是不可能的。這也就意味着我們不能使用編碼器來生成新的對象。我們甚至連輸入應該是什麼樣子的都不知道。

而我們用相反的方法使用變分自編碼器。我們不會嘗試着去關注隐含向量所服從的分布,隻需要告訴網絡我們想讓這個分布轉換為什麼樣子就行了。

通常情況,我們會限制網絡來生成具有機關正态分布性質的隐含向量。然後,在嘗試生成資料的時候,我們隻需要從這種分布中進行采樣,然後把樣本喂給解碼器就行,解碼器會傳回新的對象,看上去就和我們用來訓練網絡的對象一樣。

下面我們将介紹如何使用 Python 和 TensorFlow 實作這一過程,我們要教會我們的網絡來畫 MNIST 字元。

第一步加載訓練資料

首先我們來執行一些基本的導入操作。TensorFlow 具有非常便利的函數來讓我們能夠很容易地通路 MNIST 資料集。

定義輸入資料和輸出資料

MNIST 圖像的次元是 28*28 像素,隻有單色通道。我們的輸入資料 X_in 是一批一批的 MNIST 字元,網絡會學習如何重建它們。然後在一個占位符 Y 中輸出它們,輸出和輸入具有相同的次元。

Y_flat 将會在後面計算損失函數的時候用到,keep_prob 将會在應用 dropout 的時候用到(作為一種正則化的方法)。在訓練的過程中,它的值會設為 0.8,當生成新資料的時候,我們不使用 dropout,是以它的值會變成 1。

lrelu 函數需要自及定義,因為 TensorFlow 中并沒有預定義一個 Leaky ReLU 函數。

定義編碼器

因為我們的輸入是圖像,是以使用一些卷積變換會更加合理。最值得注意的是我們在編碼器中建立了兩個向量,因為編碼器應該建立服從高斯分布的對象。

一個是均值向量

一個是标準差向量

在後面你會看到,我們是如何「強制」編碼器來保證它确實生成 了服從正态分布的資料點,我們可以把将會被輸入到解碼器中的編碼值表示為 z。在計算損失函數的時候,我們會需要我們所選分布的均值和标準差。

定義解碼器

解碼器不會關心輸入值是不是從我們定義的某個特定分布中采樣得到的。它僅僅會嘗試重建輸入圖像。最後,我們使用了一系列的轉置卷積(transpose convolution)。

現在,我們将兩部分連在一起。

計算損失函數,并實施一個高斯隐藏分布

為了計算圖像重構的損失函數,我們簡單地使用了平方差(這有時候會使圖像變得有些模糊)。這個損失函數還結合了 KL 散度,這確定了我們的隐藏值将會從一個标準分布中采樣。關于這個主題,如果想要了解更多,可以看一下這篇文章(https://jaan.io/what-is-variational-autoencoder-vae-tutorial/)。

訓練網絡

現在我們終于可以訓練我們的 VAE 了!

每隔 200 步,我們會看一下目前的重建是什麼樣子的。大約在處理了 2000 次疊代後,大多數重建看上去是挺合理的。

生成新資料

最驚人的是我們現在可以生成新的字元了。最後,我們僅僅是從一個機關正态分布裡面采集了一個值,輸入到解碼器。生成的大多數字元都和人類手寫的是一樣的。

教你用TensorFlow和自編碼器模型生成手寫數字(附代碼)

<code></code>

一些自動生成的字元

總結

這是關于 VAE 應用一個相當簡單的例子。但是可以想象一下更多的可能性!神經網絡可以學習譜寫音樂,它們可以自動地建立對書籍、遊戲的描述。借用創新思維,VAE 可以為一些新穎的項目開創空間。

全部 VAE 代碼:

https://github.com/FelixMohr/Deep-learning-with-Python/blob/master/VAE.ipynb

原文釋出時間為:2017-11-21

繼續閱讀