自編碼器,做主成分提取,了解一下
- 2019 年 10 月 7 日
- 筆記
今天我們一起學一下深度網絡中的自編碼器.
自編碼器是在無監督(訓練集未標註)的情況下,能夠學習有效表示數據(稱為編碼)的一種深度人工網絡。這些編碼一般跟輸入數據比起來有更低的維度,這使得自編碼器在數據降維方面比較有用。更重要的是,自編碼器可以作為強大的特徵檢測器,它可以在深度網絡中用於無監督的預訓練。最後,它可以隨機產生和訓練數據相似的新數據,這叫做生成模型。例如,我們可以訓練一個人臉圖像上的自編碼器,那麼它能夠產生新的人臉圖像。
咋一看,自編碼器的工作就是學會簡單的把輸入值copy到輸出,然而,訓練網絡的時候,可以從各個角度進行約束網絡,使它不能夠做簡單的複製,進而能夠訓練出有效的網絡。比方說,我們可以限制內部呈現的大小,或者在輸入圖像上加些噪聲來訓練網絡恢復原始輸入。這些約束可以防止網絡玩障眼法,或者說防止網絡去簡單的複製輸入到輸出。這就強制它去學習表示數據的有效方法。簡而言之,編碼是自編碼器在一些約束下嘗試學習恆等方程而得到的副產品。 接下來,我們將更進一步的學習自編碼器的工作原理,不管是在降維,特徵提取,無監督預訓練,還是生成模型,以及可以實施哪些約束,以及如何在tensorflow中實現。
有效的數據表示
我們來看兩組數字,下面哪一組數更好記呢?
• 40, 27, 25, 36, 81, 57, 10, 73, 19, 68 • 50, 25, 76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20
咋一看,感覺應該是第一組數據更好記一些,因為第一組短一點嘛。然而仔細看第二組數據就會發現,這條數據是有規律的,即:如果是偶數的話,那麼它後面跟的是該偶數的一半,如果是奇數的話,後面跟的是該數的3倍加1(其實該序列為希爾頓序列)。一旦我們發現了這個規律,那麼第二組數據就更為好記了。
關於記憶,感知和模式匹配的關係在 20 世紀 70 年代早期由 William Chase 和 Herbert Simon 研究。他們注意到,專業的棋手能夠通過觀察棋盤5秒鐘就記住所有棋子的位置,這個任務,大多數人都會認為不可思議。然而也只是在正常比賽中才會是這種情況,而不是隨機放置位置。這也就說明了,專業棋手並不是記憶力比我們好很多,而是由於豐富的經驗,他們更看到棋子背後的模式,也就是說模式能夠幫他們更為高效的存儲信息。
就像上面說的專業棋手一樣,自編碼器將輸入轉換成一種高效的內部模式呈現,並且輸出一些跟輸入很似接近的東西。一個自編碼器通常由兩部分組成:編碼(識別網絡)用來將輸入轉換成一個內部表示,解碼(生成網絡)用來將內部表示轉換為輸出,如下圖:

正如我們上圖看到的一樣,除了自編碼器的輸入輸出必須一致以外,一個自編碼器基本上跟多層感知機(MLP)有着相同的架構。在上面的例子中,僅僅有一個包含兩個神經元的隱藏層(編碼),和一個由三個神經元組成的輸出層(解碼)。由於自編碼器在儘力的恢復輸入數據,所以輸出通常也被稱為重構。損失函數為重構損失,往往會在跟輸入不一致的時候懲罰模型。
由於這個內部呈現跟輸入數據比起來維度更低,所以自編碼器被認為是不完整的,一個不完整的自編碼器不能簡單的複製輸入到編碼,也就是說,它必須找到一個模式來輸出輸入的近似。這就強制它去學習輸入數據的一些重要的特徵,而拋棄不重要的特徵。
現在,我們一起看一下,如何用不完整的自編碼器來實現降維的。
用不完整的線性編碼器實現PCA
如果自編碼器僅僅使用線性激活函數,並且用MSE作為損失函數的話,則它將最終收斂為我們之前學過的PCA(主成分分析)模型(見下鏈接)。 機器學習三人行(系列十)—-機器學習降壓神器(附代碼)
我們一起看下如何創建一個簡單的線性自編碼器來實現PCA,將一個三維數據映射到兩維:
import tensorflow as tf from tensorflow.contrib.layers import fully_connected n_inputs = 3 # 3D inputs n_hidden = 2 # 2D codings n_outputs = n_inputs learning_rate = 0.01 X = tf.placeholder(tf.float32, shape=[None, n_inputs]) hidden = fully_connected(X, n_hidden, activation_fn=None) outputs = fully_connected(hidden, n_outputs, activation_fn=None) reconstruction_loss = tf.reduce_mean(tf.square(outputs - X)) # MSE optimizer = tf.train.AdamOptimizer(learning_rate) training_op = optimizer.minimize(reconstruction_loss) init = tf.global_variables_initializer()
這段代碼跟我們之前學的MLP基本一致,需要注意的是:
- 神經元的輸入數量和輸出數量一致。
- 為了實現PCA,這裡設置activation_fn=None,並且損失函數為MSE。
現在我們將加載數據,在訓練集上訓練模型,並且用模型去編碼測試數據(投影到2D):
X_train, X_test = [...] # load the dataset n_iterations = 1000 codings = hidden # the output of the hidden layer provides the codings with tf.Session() as sess: init.run() for iteration in range(n_iterations): training_op.run(feed_dict={X: X_train}) # no labels (unsupervised) codings_val = codings.eval(feed_dict={X: X_test})
下圖顯示了原始數據(左側),和自編碼器的隱藏層的輸出(編碼層,右圖),正如我們看到的,自編碼器找到了將數據投影到數據上的最佳二維平面,保留了數據的儘可能多的差異(就像 PCA 一樣)。
