Tensorflow基于minist数据集实现自编码器
Tensorflow實(shí)現(xiàn)自編碼器
- 自編碼器
- Denoising AutoEncoder(去噪自編碼器)
自編碼器
特征的稀疏表達(dá):使用少量的基本特征組合拼裝得到更高層抽象的特征。
如:圖像碎片可由少量的基本結(jié)構(gòu)稀疏表達(dá)。
自編碼器定義:
- 使用自身的高階特征編碼自己,目標(biāo)是使用稀疏的一些高階特征重新組合來重構(gòu)自己。
自編碼器特點(diǎn):
- 輸入節(jié)點(diǎn)和輸出節(jié)點(diǎn)的數(shù)量一致
- 使用自身的高階特征編碼自己,不只是復(fù)制像素點(diǎn)
自編碼器作用:
- 給監(jiān)督訓(xùn)練做無監(jiān)督的預(yù)訓(xùn)練,提取特征
- 可直接進(jìn)行特征提取和分析
自編碼器使用少量稀疏的高階特征來重構(gòu)輸入,所以加入幾種限制:
- 如果限制隱含層的數(shù)量,中間隱含層節(jié)點(diǎn)數(shù)量小于輸入輸出節(jié)點(diǎn)數(shù)量,相當(dāng)于降維的過程,只能學(xué)習(xí)輸入數(shù)據(jù)最重要的特征,將不太相關(guān)的內(nèi)容去除。
- 如果給數(shù)據(jù)加噪聲(通常是加性高斯噪聲Additive Gaussian Noise,AGN),那么就是Denoising AutoEncoder(去噪自編碼器),將從噪聲中學(xué)習(xí)出數(shù)據(jù)的特征,學(xué)習(xí)數(shù)據(jù)頻繁出現(xiàn)的模式和結(jié)構(gòu),將無規(guī)律的噪聲去除。
Denoising AutoEncoder(去噪自編碼器)
"""作者:Heart Sea功能:tessorflow實(shí)現(xiàn)去噪自編碼器Additive Gaussian Noise,AGNModel:1個(gè)輸入層, 加噪聲全連接1個(gè)隱含層, 激活全連接1個(gè)輸出層版本:1.0日期:10/10/2019 """import numpy as np # 導(dǎo)入常用庫numpy import sklearn.preprocessing as prep # 導(dǎo)入sklearn中的preprocessing模塊,負(fù)責(zé)預(yù)處理數(shù)據(jù)標(biāo)準(zhǔn)化 import tensorflow as tf # 導(dǎo)入tensorflow from tensorflow.examples.tutorials.mnist import input_data # 導(dǎo)入mnist數(shù)據(jù)集# 實(shí)現(xiàn)標(biāo)準(zhǔn)均勻分布的Xaiver初始化器(根據(jù)某一層網(wǎng)絡(luò)的輸入、輸出節(jié)點(diǎn)數(shù)量自動(dòng)調(diào)整最合適的權(quán)重分布) # Xaiver就是讓權(quán)值滿足:均值=0,方差=2/(n_in+n_out) # 分布可以用均勻分布或者高斯分布,這里采用均勻分布,方差=2/(n_in+n_out)=(max-min)^2/12 def xavier_init_(fan_in, fan_out, constant=1): # xavier_init_(self.n_input, self.n_hidden)""":param fan_in: 輸入節(jié)點(diǎn)的數(shù)量, 行數(shù):param fan_out: 輸出節(jié)點(diǎn)的數(shù)量, 列數(shù):param constant: 1:return: 返回一個(gè)比較適合softplus等激活函數(shù)的權(quán)重初始分布w1"""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)# 定義一個(gè)去噪自編碼的class,此類包括一個(gè)構(gòu)建函數(shù)_init_(),還有一些成員函數(shù) class AdditiveGaussianNoiseAutoencoder(object):def __init__(self, n_input, n_hidden, transfer_function=tf.nn.softplus,optimizer=tf.train.AdadeltaOptimizer(), scale=0.1):""":param n_input: 輸入變量數(shù):param n_hidden: 隱含層節(jié)點(diǎn)數(shù):param transfer_function: 隱含層激活函數(shù),默認(rèn)為softplus:param optimizer: 默認(rèn)為Adam:param scale: 高斯噪聲系數(shù),默認(rèn)0.1"""self.n_input = n_inputself.n_hidden = n_hiddenself.transfer = transfer_functionself.scale = tf.placeholder(tf.float32)self.training_scale = scalenetwork_weights = self._initialize_weights() # 使用_initialize_weights()函數(shù)初始化參數(shù),后面會(huì)定義self.weights = network_weights# 定義網(wǎng)格結(jié)構(gòu):輸入層,隱含層,輸出層# x每行是一個(gè)樣本,列是特征self.x = tf.placeholder(tf.float32, [None, self.n_input])# 建立能提取特征的隱含層,給輸入添加維度為(n_input,)的正態(tài)分布的噪聲# tf.random_normal((n_input,))里的小括號(hào)可換成中括號(hào),一行n_input列個(gè)正態(tài)隨機(jī)個(gè)數(shù),沒有設(shè)置隨機(jī)種子# self.x + scale * tf.random_normal((n_input,))相當(dāng)于每個(gè)樣本的n_input個(gè)特征都加了噪聲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'])# 定義自編碼器的損失函數(shù),用平方誤差作為cost,輸出與輸入之差再平方,求和,0.5self.cost = 0.5 * tf.reduce_sum(tf.pow(tf.subtract(self.reconstruction, self.x), 2.0)) # 使用平方誤差作為costself.optimizer = optimizer.minimize(self.cost) # 優(yōu)化器為損失進(jìn)行優(yōu)化init = tf.global_variables_initializer() # 初始化全部模型參數(shù)self.sess = tf.Session() # 建立Sessionself.sess.run(init)# 定義參數(shù)初始化函數(shù)_initialize_weights# 輸出層權(quán)重和偏置不含激活函數(shù),直接初始化為0def _initialize_weights(self):all_weights = dict() # 創(chuàng)建字典dictall_weights['w1'] = tf.Variable(xavier_init_(self.n_input, self.n_hidden)) # 返回一個(gè)比較適合softplus等激活函數(shù)的權(quán)重初始分布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_weightsdef partial_fit(self, X):"""aim: 定義計(jì)算損失cost及執(zhí)行一步訓(xùn)練的函數(shù)partial_fit:param X: 一個(gè)batch數(shù)據(jù):return: 當(dāng)前損失"""cost, opt = self.sess.run((self.cost, self.optimizer),feed_dict={self.x: X, self.scale: self.training_scale})return costdef calc_total_cost(self, X):"""aim: 定義一個(gè)只計(jì)算cost的函數(shù),主要是在訓(xùn)練完畢后,在測(cè)試集上對(duì)模型性能進(jìn)行測(cè)評(píng),不會(huì)觸發(fā)訓(xùn)練操作:param X: 測(cè)試集數(shù)據(jù):return: 平方誤差cost"""return self.sess.run(self.cost, feed_dict={self.x: X,self.scale: self.training_scale})def transform(self, X):"""aim: 定義transform函數(shù)(自編碼器的前半部分),目的是提供一個(gè)接口來獲取高階特征:param X::return: 返回自編碼器隱含層的輸出結(jié)果 hidden"""return self.sess.run(self.hidden, feed_dict={self.x: X,self.scale: self.training_scale})def generate(self, hidden=None):"""定義generate函數(shù)(自編碼器的后半部分),將transform提取的高階特征經(jīng)過重建層復(fù)原為原始數(shù)據(jù):param hidden: 隱含層的輸出結(jié)果:return: 高階特征經(jīng)過重建層復(fù)原為原始數(shù)據(jù)"""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):"""整體運(yùn)行transform和generate兩個(gè)過程:param X: 原始數(shù)據(jù):return: 復(fù)原的原始數(shù)據(jù)"""return self.sess.run(self.reconstruction, feed_dict={self.x: X,self.scale: self.training_scale})# 定義getWeights函數(shù),獲取隱含層的權(quán)重W1def getWeights(self):return self.sess.run(self.weights['w1'])# 定義getBiases函數(shù),獲取隱含層偏置系數(shù)b1def getBiases(self):return self.sess.run(self.weights['b1'])# 去噪自編碼器的類已經(jīng)定義完,包括神經(jīng)網(wǎng)絡(luò)的設(shè)計(jì)、權(quán)重的初始化mnist = input_data.read_data_sets('MNIST_data', one_hot=True) # 載入minist數(shù)據(jù)集# 定義standard_scale函數(shù),對(duì)訓(xùn)練、測(cè)試數(shù)據(jù)標(biāo)準(zhǔn)化, # 標(biāo)準(zhǔn)化即讓數(shù)據(jù)變成0均值,且標(biāo)準(zhǔn)差為1的分布。方法是先減去均值,再除以標(biāo)準(zhǔn)差 # 為保證訓(xùn)練、測(cè)試數(shù)據(jù)使用完全相同的Scaler,需要先在訓(xùn)練數(shù)據(jù)上fit出一個(gè)共用的Scaler,再將這個(gè)Scaler用到訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)上 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# 定義一個(gè)隨機(jī)取block數(shù)據(jù)的函數(shù) # random.randint(a, b),用于生成一個(gè)指定范圍a <= n <= b的整數(shù) # 將這個(gè)隨機(jī)數(shù)作為block的起始位置,順序取到一個(gè)batch size的數(shù)據(jù)。這屬于放回原樣,可以提高數(shù)據(jù)利用率 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)]# 使用standard_index函數(shù)標(biāo)準(zhǔn)化訓(xùn)練集,測(cè)試集 X_train, X_test = standard_scale(mnist.train.images, mnist.test.images)# 定義常用參數(shù) n_samples = int(mnist.train.num_examples) # 總訓(xùn)練樣本數(shù) training_epochs = 20 # 最大訓(xùn)練輪數(shù) batch_size = 128 # 批數(shù)據(jù),即多少個(gè)樣本作為一個(gè)batch display_step = 1 # 每隔一輪epoch顯示一次損失cost# 創(chuàng)建一個(gè)AGN自編碼器的實(shí)例,并設(shè)置輸入層節(jié)點(diǎn)數(shù)、隱含層節(jié)點(diǎn)數(shù)、隱含層激活函數(shù)、優(yōu)化器、噪聲系數(shù) autoencoder = AdditiveGaussianNoiseAutoencoder(n_input=784,n_hidden=200,transfer_function=tf.nn.softplus,optimizer=tf.train.AdamOptimizer(learning_rate=0.001),scale=0.01)# 開始訓(xùn)練 for epoch in range(training_epochs): # 迭代訓(xùn)練輪數(shù)# print(epoch)avg_cost = 0. # 每一輪開始時(shí),平均損失=0total_batch = int(n_samples / batch_size) # 樣本總數(shù)/batch大小=需要的batch數(shù)for i in range(total_batch): # 迭代一輪中所有的批數(shù)據(jù)# print(i)batch_xs = get_random_block_from_data(X_train, batch_size) # 隨機(jī)抽取block數(shù)據(jù)cost = autoencoder.partial_fit(batch_xs) # 使用partial_fit訓(xùn)練這個(gè)當(dāng)前的batch數(shù)據(jù)的平方誤差avg_cost += cost / n_samples * batch_size # 將當(dāng)前的cost整合到avg_cost,計(jì)算平均cost# 每一輪迭代后,顯示當(dāng)前的迭代數(shù)和這一輪迭代的acg_costif epoch % display_step == 0:print("Epoch:", '%04d' % (epoch + 1),"cost =", "{:.9f}".format(avg_cost))# 對(duì)測(cè)試集進(jìn)行測(cè)試,評(píng)價(jià)指標(biāo)仍然是平方誤差 print("Total cost: " + str(autoencoder.calc_total_cost(X_test)))Epoch: 0001 cost= 19708.600550000
Epoch: 0002 cost= 13143.029138636
。
。
。
從實(shí)現(xiàn)的角度而言,自編碼器其實(shí)和一個(gè)單隱含層的神經(jīng)網(wǎng)絡(luò)差不多,只是自編碼器在數(shù)據(jù)輸入時(shí)做了標(biāo)準(zhǔn)化處理,且加上了一個(gè)高斯噪聲,同時(shí)我們的輸出結(jié)果不是數(shù)字分類結(jié)果,而是復(fù)原的數(shù)據(jù),因此不需要用標(biāo)注過的數(shù)據(jù)進(jìn)行監(jiān)督訓(xùn)練。自編碼器作為一種無監(jiān)督學(xué)習(xí)方法,它與其他無監(jiān)督學(xué)習(xí)的區(qū)別主要在于:它不是對(duì)數(shù)據(jù)進(jìn)行聚類,而是把數(shù)據(jù)中最有用、最頻繁的高階特征提取出來,然后根據(jù)這些高階特征進(jìn)行重構(gòu)數(shù)據(jù)。在深度學(xué)習(xí)發(fā)展早期非常流行的DBN,也是依靠這種思想,先對(duì)數(shù)據(jù)進(jìn)行無監(jiān)督學(xué)習(xí),提取到一些有用的特征,將神經(jīng)網(wǎng)絡(luò)權(quán)重初始化到一個(gè)較好的分布,然后再使用有標(biāo)注的數(shù)據(jù)進(jìn)行監(jiān)督訓(xùn)練,即對(duì)權(quán)重進(jìn)行fine-tune。
現(xiàn)實(shí)生活中,大部分?jǐn)?shù)據(jù)是沒有標(biāo)準(zhǔn)信息的,但人腦比較擅長處理這些數(shù)據(jù),會(huì)提取出其中的高階抽象特征,并使用在別的地方。自編碼器作為深度學(xué)習(xí)在無監(jiān)督領(lǐng)域的應(yīng)用的確非常成功,同時(shí)無監(jiān)督學(xué)習(xí)也將成為深度學(xué)習(xí)一個(gè)重要發(fā)展方向。
總結(jié)
以上是生活随笔為你收集整理的Tensorflow基于minist数据集实现自编码器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python常用导入函数及其他操作备忘录
- 下一篇: Python之pandas,series