《tensorflow》實戰學習筆記(一)——實現自編碼器

1 自編碼器簡介

        傳統的機器學習很大程度上依賴於好的特徵工程,比如對數值型,日期時間型,種類型等特徵的提取,特徵工程往往是非常耗時耗力的。尤其是在圖像,語音和視頻中提取到有效的特徵就更難了。深度學習則可以解決人工難以提取有效特徵的問題,它可以大大緩解機器學習模型對特徵工程的依賴。深度學習早期一度被認爲是一種無監督的特徵學習。模仿了人腦的特徵逐層抽象提取的過程。這其中有兩點很重要:一是無監督學習,即不需要標註數據就可以對數據進行一定程度的學習,這種學習是對數據內容的組織形式的學習,提取的是頻繁出現的特徵;二是逐層抽取,特徵是需要不斷抽象的,就像人總是從簡單基礎的概念開始學習,再到複雜的概念。
        自編碼器是一種能夠通過無監督學習,學到輸入數據高效表示的人工神經網絡。輸入數據的這一高效表示稱爲編碼,其維度一般遠小於輸入數據,使得自編碼器可用於降維。更重要的是,自編碼器可作爲強大的特徵檢測器(feature detectors),應用於深度神經網絡的預訓練。此外,自編碼器還可以隨機生成與訓練數據類似的數據,這被稱作生成模型(generative model)。

2 tensorflow實現自編碼器

        去噪自編碼器的使用範圍最廣也最通用。因此本節實現的是最具代表性的去噪自編碼器。

import numpy as np
import sklearn.preprocessing as prep
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 參數初始化方法,Xavier初始化器在Caffe的早期版本中被頻繁使用,它的特點是會根據某一層網絡的輸入輸出節點數量自動調整最合適的分佈
# 如果深度學習模型的權重初始化的太小,那信號將在每層間傳遞時竹間縮小而難以產生作用;如果權重初始化得太大,那信號將在每層間傳遞時逐漸放大並導致發散和失效。
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
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

        # 定義網絡結構
        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'])

        # 定義自編碼器的損失函數
        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

    # 用一個batch數據進行訓練並返回當前的損失cost
    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 transfrom(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'])

    # 獲取隱含層的偏執係數b1
    def getBiases(self):
        return self.sess.run(self.weights['b1'])

# 利用mnist數據集進行性能測試
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

# 定義一個對訓練/訓練數據進行標準化處理的函數,標準化即讓數據變成0均值,且標準差爲1的分佈。
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
# 定義一個獲取隨機block數據的函數(不放回抽樣,可提高數據的利用效率)
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

# 創建一個AGN自編碼器的實例
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)
    for i in range(total_batch):
        batch_xs = get_random_block_from_data(X_train, batch_size)

        cost = autoencoder.partial_fit(batch_xs)
        avg_cost += cost/n_samples*batch_size

    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)))

參考:
[1]: https://www.cnblogs.com/royhoo/p/Autoencoders.html
(x_x)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章