1. 程式人生 > >學習筆記TF025:自編碼器

學習筆記TF025:自編碼器

去掉 fit 講解 works soft self ngx 訓練集 ces

傳統機器學習依賴良好的特征工程。深度學習解決有效特征難人工提取問題。無監督學習,不需要標註數據,學習數據內容組織形式,提取頻繁出現特征,逐層抽象,從簡單到復雜,從微觀到宏觀。

稀疏編碼(Sparse Coding),基本結構組合。自編碼器(AutoEncoder),用自身高階特征編碼自己。期望輸入/輸出一致,使用高階特征重構自己。

Hinton教授在Science發表文章《Reducing the dimensionality of data with neural networks》,講解自編碼器降維數據。基於深度信念網絡(Deep Belief Networks,DBN,多層 RBN堆疊),無監督逐層訓練貪心算法,逐層提取特征,極深網絡權重初始化到較好位置,輔助監督訓練。

1?限制中間隱含層節點數量,降維。中間隱含層權重加L1正則,根據懲罰系數控制隱含節點稀疏程度,懲罰系數越大,學到特征組合越稀疏,實際使用(非零權重)特征數量越少。
2?數據加入噪聲,Denoising AutoEncoder(去噪自編碼器),從噪聲學習數據特征。學習數據頻繁出現模式結構,略去無規律噪聲。加性高斯噪聲(Additive Gaussian Noise,AGN)。Nasking Noise,隨機遮擋噪聲,部分圖像像素置0,從其他像素結構推測被遮擋像素。

一隱含層自動編碼器類似主成分分析(PCA)。Hinton DBN 多個隱含層,每個隱含層是限制性玻爾茲曼機 RBM(Restricted Bltzman Machine,特殊連接分布神經網絡)。先對每兩層無監督預訓練(pre-training),多層自編碼器,網絡權重初始化到理想分布。通過反向傳播算法調整模型權重,使用經過標註信息做監督分類訓練。解決梯度彌散(Gradient vanishment)。

去噪自編碼器使用範圍最廣最通用。無噪聲自編碼器,去掉噪聲,保證隱含層節點小於輸入層節點。Masking Noise自編碼器,高斯噪聲改為隨機遮擋噪聲。Variational AutoEncoder(VAE),對中間節點分布強假設,有額外損失項,用特殊SGVB(Stochastic Gradient Variational Bayes)算
法訓練。

先導入常用庫NumPy,Scikit-lean preprocessing模塊(數據預處理、標準化)。MNIST數據加載模塊。

Xavier initialization 參數初始化方法,根據網絡輸入、輸出節點數量自動調整最合適分布。Xaiver Glorot和Yoshua Bengio提出,深度學習模型權重初始化太小,信號在每層傳遞逐漸縮小,失效;初始化太大,逐漸放大,發散、失效。Xavier初始化器,權重滿足0均值,方法為2/(nin+nout),分布用均勻分布或高斯分布。tf.random_uniform創建均勻分布,fan_in輸入節點數量,fan_out輸出節點數量。

去噪自編碼類,初始化函數__init__()。輸入,n_input(輸入變量數),n_hidden(隱含層節點數),transfer_function(隱含層激活函數,默認softplus),optimizer(優化器,默認Adam),scale(高斯噪聲系數,默認0.1)。

網絡結構,輸入x創建維度n_input placeholder。建立提取特征隱含層,輸入x加噪聲self.x+scale*tf.random_normal((n_input,)),tf.matmul相乘噪聲輸入和隱含層權重,tf.add加隱含偏置,self.transfer結果激活函數。輸出層數據復原、重建,建立reconstruction層,隱含層輸出self.hidden乘輸出層權重,加輸出層偏置。

自編碼器損失函數,平方誤差(Squared Error)作cost,tf.subtract計算輸出(self.reconstruction)與輸入(self.x)差,tf.pow求差平方,tf.reduce_sum求和。優化器self.optimizer優化損失self.cost。創建Session,初始化自編碼器全部模型參數。

參數初始化函數_initialize_weights,創建all_weights字典dict,權重、偏置存入,返回all_weights。隱含層權重用xavier_init函數初始化,傳入輸入節點數、隱含層節點數,xavier返回適合softplus激活函數權重初始分布。隱含層偏置用tf.zeros全部置0。輸出層self.reconstruction,權重、偏置都置為0。

函數partial_fit用batch數據訓練返回當前損失cost。Session執行損失cost、訓練過程optimizer計算圖節點,輸入feed_dict包括輸入數據x,噪聲系數scale。

求損失cost函數calc_total_cost,Session執行計算圖節點self.cost,傳入輸入數據x,噪聲系數scale,在測試集評測模型性能。

Transform函數,返回自編碼器隱含層輸出結果。提供獲取抽象特征,自編碼器隱含層最主要功能是學習出數據高階特征。

Generate函數,隱含層輸出結果為輸入,復原重建層提取高階特征為原始數據。

Reconstruct函數,整體運行復原過程,提取高階特征,再復原數據,transform和generate,輸入原始數據,輸出復原數據。

GetWeights函數獲取隱含層權重。

GetBiases函數獲取隱含層偏置系數。

TensorFlow讀取示例數據函數輸入MNIST數據集。

定義訓練、測試數據標準化處理函數。標準化,數據變成0均值且標準差1的分布。先減去均值,再除以標準差。sklearn.preprossing StandardScaler 類,訓練集上fit,在訓練數據和測試數據上必須用相同的Scaler。

獲取隨機block數據函數,取從0到len(data)-batch_size隨機整數,作為block起始位置,順序取batch size數據,不放回抽樣。

用standard_scale函數標準化交換訓練集和測試集。

定義總訓練樣本數,最大訓練輪數(epoch)20,batch_size 128,每隔一輪(epoch)顯示一次損失cost。

創建AGN自編碼器實例,定義模型輸入節點數n_input 784,自編碼器隱含節點數n_hidden 200,隱含層激活函數transfer_function softplus,優化器optimizer Adam,學習速率 0.001,噪聲系數scale 0.001。

每一輪循環開始,平均損失avg_cost設0,計算總共需要batch數(樣本總數除batch大小),不放回抽樣,不能保證每個樣本都被抽到參與訓練。每個batch循環,用get_random_block_from_data函數隨機抽取block數據,用partial_fit訓練batch數據,計算當前cost,整合到avg_cost。每輪叠代顯示當前叠代數和本輪平均cost。

性能測試,用cal_total_cost測試測試集X_test,評價指標平方誤差。

    import numpy as np
    import sklearn.preprocessing as prep
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    def xavier_init(fan_in, fan_out, constant = 1):
        low = -constant * np.sqrt(6.0 / (fan_in + fan_out))
        high = constant * np.sqrt(6.0 / (fan_in + fan_out))
        return tf.random_uniform((fan_in, fan_out),
                             minval = low, maxval = high,
                             dtype = tf.float32)
    class AdditiveGaussianNoiseAutoencoder(object):
        def __init__(self, n_input, n_hidden, transfer_function = tf.nn.softplus, optimizer = tf.train.AdamOptimizer(),
                 scale = 0.1):
            self.n_input = n_input
            self.n_hidden = n_hidden
            self.transfer = transfer_function
            self.scale = tf.placeholder(tf.float32)
            self.training_scale = scale
            network_weights = self._initialize_weights()
            self.weights = network_weights
            # model
            self.x = tf.placeholder(tf.float32, [None, self.n_input])
            self.hidden = self.transfer(tf.add(tf.matmul(self.x + scale * tf.random_normal((n_input,)),
                self.weights[w1]),
                self.weights[b1]))
            self.reconstruction = tf.add(tf.matmul(self.hidden, self.weights[w2]), self.weights[b2])
            # cost
            self.cost = 0.5 * tf.reduce_sum(tf.pow(tf.subtract(self.reconstruction, self.x), 2.0))
            self.optimizer = optimizer.minimize(self.cost)
            init = tf.global_variables_initializer()
            self.sess = tf.Session()
            self.sess.run(init)
        def _initialize_weights(self):
            all_weights = dict()
            all_weights[w1] = tf.Variable(xavier_init(self.n_input, self.n_hidden))
            all_weights[b1] = tf.Variable(tf.zeros([self.n_hidden], dtype = tf.float32))
            all_weights[w2] = tf.Variable(tf.zeros([self.n_hidden, self.n_input], dtype = tf.float32))
            all_weights[b2] = tf.Variable(tf.zeros([self.n_input], dtype = tf.float32))
            return all_weights
        def partial_fit(self, X):
            cost, opt = self.sess.run((self.cost, self.optimizer), feed_dict = {self.x: X,
                                                                            self.scale: self.training_scale
                                                                            })
            return cost
        def calc_total_cost(self, X):
            return self.sess.run(self.cost, feed_dict = {self.x: X,
                                                     self.scale: self.training_scale
                                                     })
        def transform(self, X):
            return self.sess.run(self.hidden, feed_dict = {self.x: X,
                                                       self.scale: self.training_scale
                                                       })
        def generate(self, hidden = None):
            if hidden is None:
                hidden = np.random.normal(size = self.weights["b1"])
            return self.sess.run(self.reconstruction, feed_dict = {self.hidden: hidden})
        def reconstruct(self, X):
            return self.sess.run(self.reconstruction, feed_dict = {self.x: X,
                                                               self.scale: self.training_scale
                                                               })
        def getWeights(self):
            return self.sess.run(self.weights[w1])
        def getBiases(self):
            return self.sess.run(self.weights[b1])
         
    mnist = input_data.read_data_sets(MNIST_data, one_hot = True)
    def standard_scale(X_train, X_test):
        preprocessor = prep.StandardScaler().fit(X_train)
        X_train = preprocessor.transform(X_train)
        X_test = preprocessor.transform(X_test)
        return X_train, X_test
    def get_random_block_from_data(data, batch_size):
        start_index = np.random.randint(0, len(data) - batch_size)
        return data[start_index:(start_index + batch_size)]
    X_train, X_test = standard_scale(mnist.train.images, mnist.test.images)
    n_samples = int(mnist.train.num_examples)
    training_epochs = 20
    batch_size = 128
    display_step = 1
    autoencoder = AdditiveGaussianNoiseAutoencoder(n_input = 784,
                                               n_hidden = 200,
                                               transfer_function = tf.nn.softplus,
                                               optimizer = tf.train.AdamOptimizer(learning_rate = 0.001),
                                               scale = 0.01)
    for epoch in range(training_epochs):
        avg_cost = 0.
        total_batch = int(n_samples / batch_size)
        # Loop over all batches
        for i in range(total_batch):
            batch_xs = get_random_block_from_data(X_train, batch_size)
            # Fit training using batch data
            cost = autoencoder.partial_fit(batch_xs)
            # Compute average loss
            avg_cost += cost / n_samples * batch_size
        # Display logs per epoch step
        if epoch % display_step == 0:
            print("Epoch:", %04d % (epoch + 1), "cost=", "{:.9f}".format(avg_cost))
    print("Total cost: " + str(autoencoder.calc_total_cost(X_test)))

參考資料:
《TensorFlow實踐》

歡迎付費咨詢(150元每小時),我的微信:qingxingfengzi

學習筆記TF025:自編碼器