採用Keras 堆棧式自編碼器(SAE)實現Mnist的多分類問題

堆棧式自編碼器的原理請看:
https://blog.csdn.net/hjimce/article/details/49106869
這裏直接進行代碼的實現
代碼結構分爲:1.mnist的讀取,2.數據預處理,3.模型的訓練過程。

1.mnist的讀取

''' 採用keras的堆棧式Autoencode 將mnist的圖片進行分類'''
import numpy as np
import os
import struct
np.random.seed(2018)

from keras.datasets import mnist
from keras.models import Model
from keras.layers import Dense,Input
from keras.utils.np_utils import to_categorical
import matplotlib.pyplot as plt

# 訓練集 shape (60,000,28*28) 測試集 shape (10000,)
def load_mnist(path,kind='train'):
    ''' load MNIST data from path'''
    labels_path=os.path.join(path,'%s-labels.idx1-ubyte' % kind)
    images_path=os.path.join(path,'%s-images.idx3-ubyte' % kind)

    with open(labels_path,'rb') as lbpath:
        magic,n=struct.unpack('>II',lbpath.read(8))
        labels=np.fromfile(lbpath,dtype=np.uint8)
    with open(images_path,'rb') as impath:
        magic,num,rows,cols=struct.unpack('>IIII',impath.read(16))
        images=np.fromfile(impath,dtype=np.uint8).reshape(len(labels),784)
    return images,labels

X_train,y_train=load_mnist('F:\pycharm\MNIST_dataset','train')
X_test,y_test=load_mnist('F:\pycharm\MNIST_dataset','test')
y_train_cate= to_categorical(y_train, num_classes=10)
y_test_cate= to_categorical(y_test, num_classes=10)

# 顯示mnist圖片
# 圖形2*5 灰度值
fig,ax=plt.subplots(nrows=2,ncols=5,sharex=True,sharey=True)
ax=ax.flatten()
for i in range(10):
    img=X_train[y_train==i][1].reshape(28,28)
    ax[i].imshow(img,cmap='Greys',interpolation='nearest')

ax[0].set_xticks([])
ax[0].set_yticks([])
plt.tight_layout()
plt.show()

當然也可以直接採用keras中的函數 mnist.load_data()獲取數據,但是由於數據量比較大,有可能直接下載不成功,所以我們直接採用將數據下載到本地文件夾中,然後再進行讀取。數據下載鏈接:http://yann.lecun.com/exdb/mnist/
在數據讀取過程中,需要特別注意的地方數據格式是idx1-ubyte,idx3-ubyte的格式,需要進行轉換。
詳細解釋代碼:
load_mnist 函數返回兩個數組, 第一個是一個 n x m 維的 NumPy array(images), 這裏的 n 是樣本數(行數), m 是特徵數(列數). 訓練數據集包含 60,000 個樣本, 測試數據集包含 10,000 樣本. 在 MNIST 數據集中的每張圖片由 28 x 28 個像素點構成, 每個像素點用一個灰度值表示. 在這裏, 我們將 28 x 28 的像素展開爲一個一維的行向量, 這些行向量就是圖片數組裏的行(每行 784 個值, 或者說每行就是代表了一張圖片). load_mnist 函數返回的第二個數組(labels) 包含了相應的目標變量, 也就是手寫數字的類標籤(整數 0-9).
爲了理解這兩行代碼, 我們先來看一下 MNIST 網站上對數據集的介紹:

TRAINING SET LABEL FILE (train-labels-idx1-ubyte):

[offset] [type]          [value]          [description] 
0000     32 bit integer  0x00000801(2049) magic number (MSB first) 
0004     32 bit integer  60000            number of items 
0008     unsigned byte   ??               label 
0009     unsigned byte   ??               label 
........ 
xxxx     unsigned byte   ??               label
The labels values are 0 to 9.

通過使用上面兩行代碼, 我們首先讀入 magic number, 它是一個文件協議的描述, 也是在我們調用 fromfile 方法將字節讀入 NumPy array 之前在文件緩衝中的 item 數(n). 作爲參數值傳入 struct.unpack 的 >II 有兩個部分:

: 這是指大端(用來定義字節是如何存儲的); 如果你還不知道什麼是大端和小端, Endianness 是一個非常好的解釋. (關於大小端, 更多內容可見<<深入理解計算機系統 – 2.1 節信息存儲>>)
I: 這是指一個無符號整數.
通過執行下面的代碼, 我們將會從剛剛解壓 MNIST 數據集後的 mnist 目錄下加載 60,000 個訓練樣本和 10,000 個測試樣本.

爲了瞭解 MNIST 中的圖片看起來到底是個啥, 讓我們來對它們進行可視化處理. 從 feature matrix 中將 784-像素值 的向量 reshape 爲之前的 28*28 的形狀, 然後通過 matplotlib 的 imshow 函數進行繪製。

2.數據預處理

# 數據預處理
X_train=X_train.astype('float32')/255-0.5 # minmax_normalized(歸一化在(-0.5,0.5))之間
X_test=X_test.astype('float32')/255-0.5 # minmax_normalized
X_train_len=X_train.shape[0]
X_test_len=X_test.shape[0]

X_train=X_train.reshape((X_train_len,-1))
X_test=X_test.reshape((X_test_len,-1))

print(X_train.shape,X_test.shape)

主要是將灰度圖像值進行(-0.5,0。5)的歸一化

3.模型訓練

自編碼網路結構採用(784,128,64,10,10,64,128,684)的結構進行無監督訓練。

nput_img=Input(shape=(784,))
# 編碼層
encoded=Dense(128,activation='relu',name='encoded_hidden1')(input_img)
encoder_output=Dense(64,activation='relu',name='encoded_hidden2')(encoded)
LR=Dense(10,activation='softmax',name='LR')(encoder_output)

# 解碼層
decoded=Dense(64,activation='relu',name='decoded_hidden2')(encoder_output)
decoded=Dense(128,activation='relu',name='decoded_hidden3')(decoded)
decoded=Dense(784,activation='tanh',name='decoded_output')(decoded)

# 構建自編碼模型
autoencoder=Model(inputs=input_img,outputs=decoded)

# complile autoencoder 設置自編碼的優化參數
autoencoder.compile(optimizer='adam',loss='mse')
# train
hist=autoencoder.fit(X_train,X_train,epochs=20,batch_size=250,shuffle=True)

中間設置一個LR層,進行後面的多分類輸出層。
下面是多分類的模型訓練過程:

採用編碼層的網絡結構,從新構成一個新的model,此model的參數跟原來autoencode的訓練的參數一樣。
encoder=Model(inputs=input_img,outputs=LR)
encoder.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['categorical_accuracy'])
encoder.fit(X_train,y_train_cate,epochs=20,batch_size=250,shuffle=True)
core=encoder.evaluate(X_test,y_test_cate)
print(score)
print(encoder.summary())

評估結果與網絡參數如下:

score:
[0.09663939199754969, 0.9704]
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 784)               0         
_________________________________________________________________
encoded_hidden1 (Dense)      (None, 128)               100480    
_________________________________________________________________
encoded_hidden2 (Dense)      (None, 64)                8256      
_________________________________________________________________
LR (Dense)                   (None, 10)                650       
=================================================================
Total params: 109,386
Trainable params: 109,386
Non-trainable params: 0

可以看出準確率與loss都很好。
參考鏈接:
http://yann.lecun.com/exdb/mnist/
https://www.cnblogs.com/wzdLY/p/9683657.html
https://blog.csdn.net/simple_the_best/article/details/75267863
https://blog.csdn.net/hjimce/article/details/49106869

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