人工智能 - 自編碼器(AutoEncoder)

 歡迎Follow我的GitHub

本文地址:http://blog.csdn.net/caroline_wendy/article/details/77639573

自編碼器,使用稀疏的高階特徵重新組合,來重構自己,輸入與輸出一致。

TensorFlow的框架,參考

源碼,同時,複製autoencoder_models的模型文件。

本文源碼的GitHub地址

AutoEncoder


工程配置

下載Python的依賴庫:scikit-learn==0.19.0scipy==0.19.1sklearn==0.0

scipy

如果安裝scipy出錯,則把scipy==0.19.1寫入requestments.txt,再安裝,錯誤如下:

THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.
    scipy from http://mirrors.aliyun.com/pypi/packages/63/68/c5098f3b6034e69d187e3f2e989f462143d9f8b524f5a4f9e13c4a6f5f47/scipy-0.19.1-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl#md5=72415e8da753eea97eb9820602931cb5:
        Expected md5 72415e8da753eea97eb9820602931cb5
             Got        073584eb2c597bbfb82a5865b7055787

或者,直接編寫requestments.txt,全部安裝

pip install -r requirements.txt

matplotlib

安裝matplotlib

pip install matplotlib -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com

如果安裝matplotlib報錯,如下:

RuntimeError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using (Ana)Conda please install python.app and replace the use of 'python' with 'pythonw'. See 'Working with Matplotlib on OSX' in the Matplotlib FAQ for more information.

則執行Shell命令

cd ~/.matplotlib
touch matplotlibrc

導入matplotlib

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

opencv

opencv的導入庫是cv2,安裝是opencv-python

sudo pip install opencv-python -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com

導入cv2,如果直接使用import cv2,則無法自動補全,導入時應該使用:

import cv2.cv2 as cv2

圖片存儲

獲取MNIST的圖片源,test表示測試集,train表示訓練集,images表示圖片集,labels表示標籤集。images的數據類型是ndarry,784維;labels的數據類型也是ndarray,one-hot類型。

# 加載數據
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
images = mnist.test.images  # 圖片
labels = mnist.test.labels  # 標籤

將784維的一階矩陣轉換爲28維的二階圖片,將one-hot標籤轉換爲數字(0~9),存儲test的前100張圖片。

# 存儲圖片
size = len(labels)
for i in range(size):
    pxl = np.array(images[i])  # 像素
    img = pxl.reshape((28, 28))  # 圖片
    lbl = np.argmax(labels[i])  # 標籤
    misc.imsave('./IMAGE_data/test/' + str(i) + '_' + str(lbl) + '.png', img)  # scipy的存儲模式
    if i == 100:
        break

合併100張圖片爲一張圖片,便於做對比。

# 合併圖片
large_size = 28 * 10
large_img = Image.new('RGBA', (large_size, large_size))
paths_list, _, __ = listdir_files('./IMAGE_data/test/')
for i in range(100):
    img = Image.open(paths_list[i])
    loc = ((int(i / 10) * 28), (i % 10) * 28)
    large_img.paste(img, loc)
large_img.save('./IMAGE_data/merged.png')

圖片的三種存儲方式:scipy、matplotlib(含座標)、opencv。

# 其他的圖片存儲方式
pixel = np.array(images[0])  # 784維的數據
label = np.argmax(labels[0])  # 找到標籤
image = pixel.reshape((28, 28))  # 轉換成28*28維的矩陣

# -------------------- scipy模式 -------------------- #
misc.imsave('./IMAGE_data/scipy.png', image)  # scipy的存儲模式
# -------------------- scipy模式 -------------------- #

# -------------------- matplotlib模式 -------------------- #
plt.gray()  # 轉變爲灰度圖片
plt.imshow(image)
plt.savefig("./IMAGE_data/plt.png")
# plt.show()
# -------------------- matplotlib模式 -------------------- #

# -------------------- opencv模式 -------------------- #
image = image * 255  # 數據是0~1的浮點數
cv2.imwrite("./IMAGE_data/opencv.png", image)
# cv2.imshow('hah', pixels)
# cv2.waitKey(0)
# -------------------- opencv模式 -------------------- #

自編碼器

讀取MNIST的數據

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

將訓練數據與測試數據標準化

X_train, X_test = standard_scale(mnist.train.images, mnist.test.images)

以訓練數據爲標準,計算均值和標準差,然後處理訓練數據與測試數據。

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

在StandardScaler中,mean_表示均值矩陣,與圖片維數一致;scale_表示標準差,也與圖片維數一致;矩陣中每一個數字都減去對應的均值,除以對應的標準差。

self.scale_ = _handle_zeros_in_scale(np.sqrt(self.var_))
X -= self.mean_
X /= self.scale_

設置訓練參數:n_samples全部樣本個數,training_epochs迭代次數,batch_size批次的樣本數,display_step顯示步數。

n_samples = int(mnist.train.num_examples)
training_epochs = 20
batch_size = 128
display_step = 1

AdditiveGaussianNoiseAutoencoder,簡稱AGN,加高斯噪聲的自動編碼器。n_input輸入節點數,與圖片維數相同,784維;n_hidden隱含層的節點數,需要小於輸入節點數,200維;transfer_function激活函數,tf.nn.softplusoptimizer優化器,AdamOptimizer,學習率是0.001;scale噪聲係數,0.01。

autoencoder = AdditiveGaussianNoiseAutoencoder(
    n_input=784, n_hidden=200, transfer_function=tf.nn.softplus,
    optimizer=tf.train.AdamOptimizer(learning_rate=0.001), scale=0.01)

關於激活函數softplus的原理如下:

mat = [1., 2., 3.]  # 需要使用小數
# softplus: [ln(e^1 + 1), ln(e^2 + 1), ln(e^3 + 1)]
print tf.Session().run(tf.nn.softplus(mat))

random_normal生成隨機的正態分佈數組

rn = tf.random_normal((100000,))  # 一行,指定seed,防止均值的時候隨機
mean, variance = tf.nn.moments(rn, 0)  # 計算均值和方差,預期均值約等於是0,方差是1
print tf.Session().run(tf.nn.moments(rn, 0))

AdditiveGaussianNoiseAutoencoder的構造器

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)  # 係數,待訓練的參數,初始的feed數據是training_scale
    self.training_scale = scale  # 高斯噪聲係數
    network_weights = self._initialize_weights()  # 初始化權重係數,輸入層w1/b1,輸出層w2/b2
    self.weights = network_weights  # 權重

    # model
    self.x = tf.placeholder(tf.float32, [None, self.n_input])  # 需要feed的數據
    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,0.5*(x - x_)^2,求和
    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)  # 執行圖

random_normal隨機生成矩陣,參數(n_input,),n_input行1列,均值爲0,方差爲1,tf.nn.moments,返回均值和方差。

rn = tf.random_normal((100000,))  # 一行,指定seed,防止均值的時候隨機
mean, variance = tf.nn.moments(rn, 0)  # 計算均值和方差,預期均值約等於是0,方差是1
print tf.Session().run(tf.nn.moments(rn, 0))

初始化權重,分爲兩層,將n_input維的數據轉換爲n_hidden維的數據,再反向轉換回去。初始權重初始化使用xavier_initializer(澤維爾初始化器),權重的均值爲1,方差爲1/(n_input+n_hidden)

def _initialize_weights(self):
    all_weights = dict()
    # 使用xavier_initializer初始化
    all_weights['w1'] = tf.get_variable("w1", shape=[self.n_input, self.n_hidden],
                                        initializer=tf.contrib.layers.xavier_initializer())
    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

訓練模型,輸出每個輪次的平均avg_cost,

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

隨機獲取起始位置,取區塊大小的一批數據。

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)]  # batch_size大小的區塊

調用autoencoder的partial_fit,向算法Feed數據,數據就是批次數據,高斯噪聲係數使用默認。

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

最終輸出整個測試集X_test的Cost值。

print("Total cost: " + str(autoencoder.calc_total_cost(X_test)))

原圖像的效果(100張):

MINST

自編碼器的效果(100張):

AutoEncoder的MINST

OK,that‘s all! Enjoy it!

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