【TensorFlow】TensorFlow 的多層感知器(MLP)

前面有幾篇博文講了使用 TensorFlow 實現線性迴歸邏輯斯蒂迴歸,這次來說下多層感知器(Multi-Layer Perceptron)的 TensorFlow 實現。

本篇博文的代碼及結果圖片等可以在這裏下載,裏面包含TensorFlow的實現和sklearn的實現,以及各自的結果圖片。


原理

多層感知器(Multilayer Perceptron,縮寫MLP)是一種前向結構的人工神經網絡,映射一組輸入向量到一組輸出向量。MLP是感知器的推廣,克服了感知器不能對線性不可分數據進行識別的弱點。

關於 MLP 的原理我就不再贅述,我用下面的一個圖來簡單說明下:

如上圖,實際上這就是一個前饋神經網絡,我畫的就是本篇博文所使用的結構(粗心少畫了一層隱藏層,實際上使用的是3層隱藏層……):

  1. 輸入層:有 3072 個輸入神經元,m=3072
  2. 隱藏層:有兩層(三層)隱藏層,每個隱藏層有 1024 個神經元,p=q=1024
  3. 輸出層:有10個神經元,n=10

輸入層和輸出層的神經元個數,是根據數據集來定的,而隱藏層的層數和每層隱藏層的神經元個數,這些都屬於超參數(hyperparameter),是事先通過某種方法確定的。


數據集

這次採用的數據集是著名的 CIFAR-10 圖像數據集,包含 6000032×32 的彩色RGB圖像,共有 10 類,每類有 6000 張圖像。完整數據集可以從這裏下載,注意選擇 Python 版本,大概是 163 MB。

下載好後解壓會看到有5個訓練文件和1個測試文件,還有一個說明文件(batches.meta),這個文件說明了每個數字類別(0-9)具體代表哪些類別。這幾個文件都是用 cPickle 打包好的,所以載入數據也要用 cPickle 來載入。注意Python2和Python3的載入方式稍微有些不同,具體見代碼。

目前在此數據集上做的實驗在沒有數據增加的情況下最低的錯誤率是 18%,數據增加的情況下最低的錯誤率是 11%,都是採用的卷積神經網絡(CNN)的結構。

數據集中的圖像和分類大致是這樣的:


代碼

以下代碼的運行環境是 Python2 + Ubuntu14.04 + Jupyter Notebook

from __future__ import print_function
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import cPickle as pickle
# seaborn非必需
import seaborn
# 如果不是在Jupyter Notebook上運行的話請註釋掉下面這句
%matplotlib inline


def unpickle(filename):
    ''' 解壓數據 '''
    with open(filename) as f:
        # for python3 
        # d = pickle.load(f, encoding='latin1')
        d = pickle.load(f)
        return d


def onehot(labels):
    ''' one-hot 編碼 '''
    n_sample = len(labels)
    n_class = max(labels) + 1
    onehot_labels = np.zeros((n_sample, n_class))
    onehot_labels[np.arange(n_sample), labels] = 1

    return onehot_labels

# 讀取數據
data1 = unpickle('cifar-10-batches-py/data_batch_1')
data2 = unpickle('cifar-10-batches-py/data_batch_2')
data3 = unpickle('cifar-10-batches-py/data_batch_3')
data4 = unpickle('cifar-10-batches-py/data_batch_4')
data5 = unpickle('cifar-10-batches-py/data_batch_5')

X_train = np.concatenate((data1['data'], data2['data'], data3['data'], data4['data'], data5['data']), axis=0)
label = np.concatenate((data1['labels'], data2['labels'], data3['labels'], data4['labels'], data5['labels']), axis=0)
y_train = onehot(label)

test = unpickle('cifar-10-batches-py/test_batch')
X_test = test['data']
y_test = onehot(test['labels'])

# 設置模型參數
learning_rate = 0.001
training_epochs = 500
batch_size = 500
display_step = 1
n_sample = X_train.shape[0]

n_input = X_train.shape[1]
n_hidden_1 = 1024
n_hidden_2 = 1024
n_hidden_3 = 1024
n_class = y_train.shape[1]

x = tf.placeholder('float', [None, n_input])
y = tf.placeholder('float', [None, n_class])


def multiplayer_perceptron(x, weight, bias):

    layer1 = tf.add(tf.matmul(x, weight['h1']), bias['h1'])
    layer1 = tf.nn.relu(layer1)
    layer2 = tf.add(tf.matmul(layer1, weight['h2']), bias['h2'])
    layer2 = tf.nn.relu(layer2)
    layer3 = tf.add(tf.matmul(layer2, weight['h3']), bias['h3'])
    layer3 = tf.nn.relu(layer3)
    out_layer = tf.add(tf.matmul(layer3, weight['out']), bias['out'])

    return out_layer


weight = {
    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),
    'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])), 
    'h3': tf.Variable(tf.random_normal([n_hidden_2, n_hidden_3])), 
    'out': tf.Variable(tf.random_normal([n_hidden_3, n_class]))
}
bias = {
    'h1': tf.Variable(tf.random_normal([n_hidden_1])),
    'h2': tf.Variable(tf.random_normal([n_hidden_2])), 
    'h3': tf.Variable(tf.random_normal([n_hidden_3])), 
    'out': tf.Variable(tf.random_normal([n_class]))
}

# 建立模型
pred = multiplayer_perceptron(x, weight, bias)

# 定義損失函數
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))

# 優化
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)

# 初始化所有變量
init = tf.initialize_all_variables()

correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))

# 訓練模型
with tf.Session() as sess:
    sess.run(init)

    for epoch in range(training_epochs):
        avg_cost = 0
        total_batch = int(n_sample / batch_size)

        for i in range(total_batch):
            _, c = sess.run([optimizer, cost], feed_dict={x: X_train[i*batch_size : (i+1)*batch_size, :], 
                                                          y: y_train[i*batch_size : (i+1)*batch_size, :]})
            avg_cost += c / total_batch

        plt.plot(epoch+1, avg_cost, 'co')

        if epoch % display_step == 0:
            print('Epoch:', '%04d' % (epoch+1), 'cost=', '{:.9f}'.format(avg_cost))

    print('Opitimization Finished!')

    # Test
    acc = accuracy.eval({x: X_test, y: y_test})
    print('Accuracy:', acc)

    plt.xlabel('Epoch')
    plt.ylabel('Cost')
    plt.title('lr=%f, te=%d, bs=%d, acc=%f' % (learning_rate, training_epochs, batch_size, acc))
    plt.tight_layout()
    plt.savefig('cifar-10-batches-py/MLP-TF14-test.png', dpi=200)

    plt.show()

結果

由於進行了500次迭代,結果太多,這裏我就不一一列出了,完整的可以在這裏連帶代碼一起下載,裏面也包含了我測試不同超參數組合的結果圖。

下面給出本次實驗的結果圖:

其中的縮寫仍然遵照我以前博文的習慣,

  • lr:learning rate,學習率
  • tr:training epochs,訓練迭代次數
  • bs:batch size,batch大小
  • acc:測試準確率

可以看到最終的準確率是 46.98%,如前所述,目前此數據集上最好的結果是 82%,用的是對圖像識別有巨大優勢的卷積神經網絡。當然,使用更深層的MLP也會提高準確率。


一些問題

  1. 學習率不能過大,這裏使用的 0.001 已經是極限,其他參數不變的情況下,再大例如 0.01,準確率會大幅下跌,跌至 10% 左右,此時無論再怎麼增加迭代次數準確率(包括訓練準確率)也不會提高,一直在 10% 左右,但是損失卻降得很厲害,此處還未徹底搞清楚。
  2. 我使用sklearn也測試了一下(代碼下載鏈接和上面一樣),最終準確率 46.25%。
  3. 本片博文只是爲了說明如何使用 TensorFlow 實現MLP,本次做的實驗並不一定是最優的實驗結果。
  4. 這篇博文 同樣使用CIFAR10數據集但是使用CNN模型,可以和本文做個對比。

END

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