1. 程式人生 > >tensorflow實現自編碼網路

tensorflow實現自編碼網路

一、自編碼網路

自編碼,又稱自編碼器(autoencoder),也是神經網路的一種,經過訓練後能嘗試將輸入複製到輸出。自編碼器內部有隱藏層,通過編碼和解碼來還原輸入資料。該網路可以看作由兩部分組成:一個函式h=f(x)表示編碼器和一個解碼器r=g(h)。

自編碼器是一個3層或大於3層的神經網路,它的作用是將輸入樣本壓縮到隱藏層,然後解壓,在輸出端還原輸入樣本。最終輸出層神經元數量等於輸入層神經元數量。自編碼器屬於無監督學習,訓練自編碼網路不需要類標。

自編碼網路主要由兩個部分構成:壓縮和解壓。壓縮依靠的是輸入資料(圖片、文字、聲音)本身存在不同程度的冗餘資訊,自編碼網路通過學習來去掉這些冗餘資訊,提取出有用的特徵,來實現壓縮。壓縮過程與機器學習演算法中的PCA(主成分分析)有些類似。在自編碼網路中,如果啟用函式不使用sigmoid等非線性函式,而使用線性函式,就是PCA模型。壓縮是通過限制隱藏層神經元的數量,使得隱藏層輸出神經元的數量小於輸入神經元的數量,來提取有意義的特徵。解壓網路輸入和輸出的神經元數目與壓縮的輸入和輸出神經元數目相反。

二、如何來構造一個自編碼網路

想要設計一個神經網路,我們首先需要明確的就是代價函式如何定義。對於自編碼網路,我們的目的是使得輸出儘可能與輸入相同,當然不是單純的複製,那樣整個網路就沒有任何意義。所以,我們定義輸出與輸入平方誤差的均值作為代價函式

在設計自編碼網路的時候,我們可以考慮使用多個隱藏層。如果有多個隱藏層,網路就能更好的學習更高層的特徵。對於輸入資料為圖片時,低層的網路提取的特徵可能是直線、菱角、邊緣、顏色等,而高層的網路則可以學習如何去組合這些特徵。

三、實現一個自編碼網路

整個自編碼網路是通過MNIST手寫數字資料集來訓練的,在自編碼網路訓練完成之後通過從測試集中取出10張圖片測試,從結果來看通過對輸入圖片進行壓縮和解壓之後基本還原了輸入圖片。

1、網路引數設定

import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt

'''
編碼器解碼器引數設定
'''
class Config(object):
    #設定學習率
    learning_rate = 0.001
    #訓練輪數
    training_epochs = 20
    #設定batch size
    batch_size = 256
    #設定每多少輪輸出一次訓練結果
    print_epoch = 1
    #從測試集選擇多少張圖片驗證結果
    test_to_show = 10
    #設定第一層隱藏層神經元的個數
    n_hidden1 = 256
    #設定第二層隱藏層神經元的個數
    n_hidden2 = 128
    #設定輸入神經元的個數
    n_input = 784

2、自編碼網路結構

'''
設定編碼器和解碼器的結構
'''
class Encoder_Decoder(object):
    def __init__(self,config):
        self.config = config
        #定義輸入
        self.input_x = tf.placeholder("float",[None,config.n_input])
        self.weights = {
            #設定第一層編碼器權重
            "encoder_w1":tf.Variable(tf.random_normal([self.config.n_input,self.config.n_hidden1])),
            #設定第二層編碼器權重
            "encoder_w2":tf.Variable(tf.random_normal([self.config.n_hidden1,self.config.n_hidden2])),
            #設定第一層解碼器權重
            "decoder_w1":tf.Variable(tf.random_normal([self.config.n_hidden2,self.config.n_hidden1])),
            #設定第二層解碼器權重
            "decoder_w2":tf.Variable(tf.random_normal([self.config.n_hidden1,self.config.n_input]))
        }
        self.biases = {
            #設定第一層編碼器偏置
            "encoder_b1":tf.Variable(tf.random_normal([self.config.n_hidden1])),
            #設定第二層編碼器偏置
            "encoder_b2":tf.Variable(tf.random_normal([self.config.n_hidden2])),
            #設定第一層解碼器偏置
            "decoder_b1":tf.Variable(tf.random_normal([self.config.n_hidden1])),
            #設定第二層解碼器偏置
            "decoder_b2":tf.Variable(tf.random_normal([self.config.n_input]))
        }
        #編碼
        self.encoder()
        #解碼
        self.decoder()
        #定義平方差損失函式
        self.loss = tf.reduce_mean(tf.pow(self.input_x - self.decoder_layer2,2))
        #最小化損失函式
        self.Adam = tf.train.AdamOptimizer(config.learning_rate).minimize(self.loss)
    #編碼器模型
    def encoder(self):
        #第一層編碼器
        self.encoder_layer1 = tf.nn.sigmoid(
            tf.matmul(self.input_x,self.weights["encoder_w1"])+self.biases["encoder_b1"])
        #第二層編碼器
        self.encoder_layer2 = tf.nn.sigmoid(
            tf.matmul(self.encoder_layer1,self.weights["encoder_w2"])+self.biases["encoder_b2"])

    #解碼器模型
    def decoder(self):
        #第一層解碼器
        self.decoder_layer1 = tf.nn.sigmoid(tf.matmul(
            self.encoder_layer2,self.weights["decoder_w1"])+self.biases["decoder_b1"])
        #第二層解碼器
        self.decoder_layer2 = tf.nn.sigmoid(tf.matmul(
            self.decoder_layer1,self.weights["decoder_w2"])+self.biases["decoder_b2"])

3、訓練模型

def training():
    #獲取資料集
    mnist_data = input_data.read_data_sets("/MNIST_data")
    #初始化網路設定引數
    config = Config()
    #初始化網路
    encode_decode = Encoder_Decoder(config)
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        #計算總的迭代次數
        total_batch = (mnist_data.train.num_examples-1) // config.batch_size + 1
        for epoch in range(config.training_epochs):
            for i in range(total_batch):
                batch_xs,batch_ys = mnist_data.train.next_batch(config.batch_size)
                _,loss = sess.run([encode_decode.Adam,encode_decode.loss],
                                  feed_dict={encode_decode.input_x:batch_xs})
            if epoch % config.print_epoch == 0:
                print("epoch:%d,loss:%.3f"%(epoch+1,loss))
        #對測試集的進行編碼
        test_encode_decode = sess.run(encode_decode.decoder_layer2,
                        feed_dict={encode_decode.input_x:mnist_data.test.images[:config.test_to_show]})
        #比較測試集和編碼解碼後的結果
        f,a = plt.subplots(2,10,figsize=(10,2))
        for i in range(config.test_to_show):
            #測試集的原始圖片
            a[0][i].imshow(np.reshape(mnist_data.test.images[i],(28,28)))
            #編碼解碼後的圖片
            a[1][i].imshow(np.reshape(test_encode_decode[i],(28,28)))
        f.show()
        plt.draw()
        plt.waitforbuttonpress()

4、輸出結果

四、自編碼器應用

從上面的例子來看,我們先將輸入的圖片進行壓縮再解壓,好像自編碼器沒有很多的作用。實則不然,通過編碼網路我們可以將輸入資料從784維壓縮到128維,然後通過解碼網路將編碼後的資料從128維還原到784維,基本還原了輸入資料。自編碼器的主要應用是降維資訊檢索。通過自編碼器,我們可以提取資訊的主要特徵,來減少資訊量,提高資訊檢索的效率。通過自編碼器,可以對資料進行壓縮,來減少資料量。