1. 程式人生 > >【TensorFlow】TensorFlow 的多層感知器(MLP)

【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