fbpx

Keras 教學 - 訓練 IMDB Reviews CNN 網路模型

Keras 教學 - 利用二元分類器訓練 IMDB 深度學習演算法

前一篇文章介紹了機器學習最基本的 Hello World = MNIST 模型訓練。今天換一個 IMDB Reviews 的 Play Data 例子玩看看,對於如何透過 Keras 訓練神經網路的基本概念,可以參考前一篇「Keras MNIST 手寫辨識 x 深度學習的 HelloWorld」文章介紹。

二元分類或稱兩類分類可能是在機器學習中應用最廣泛問題。只要處理的問題只有兩個結果,就可以適用。在這個例子中,我們將根據 IMDB 評論的文本內容將電影評論分為「正面」評論和「負面」評論。

關於 IMDB Dataset 資料集

IMDB Dataset 是來自 Internet 電影數據庫 50,000 條評論文字。他們分為 25,000 條訓練數據和 25,000 條測試數據,每組皆包含包括 50% 的負面評論和 50% 的正面評論。

我們可以直接透過 Keras Datasets 函式庫載入已經整理好的資料集。這些資料集已經經過處理,會將評論依據單詞順序,排列為整數序列,其中每個整數代表字典中的特定單詞。如下:

from keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)

num_words=10000 表示我們只採用前 10000 個常出現的字詞,此外在 label 中 0 表示負評 1 表示正評。

max([max(sequence) for sequence in train_data])

也可以透過字典檔,將資料組合回評論文字。

word_index = imdb.get_word_index()
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
decoded_review = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])

# show
decoded_review

IMDB Reviews 資料前處理

我們無法將代表字典檔索引位置的整數資料直接送進網路進行訓練,因此需要對資料進行轉換。由於我們只採用前 10000 常用字詞作為資料集,因此輸入資料可以轉換為 10000 維度的 one-hot-encode,例如 [3, 18] 表示一個全部都是 0 的陣列,只有 index 3, 18 是 1。我們會將這樣的資料格式作為張量進行訓練,轉換如下:

import numpy as np

def vectorize_sequences(sequences, dimension=10000):
    # Create an all-zero matrix of shape (len(sequences), dimension)
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.  # set specific indices of results[i] to 1s
    return results

# Our vectorized training data
x_train = vectorize_sequences(train_data)
# Our vectorized test data
x_test = vectorize_sequences(test_data)

將結果標記進行正規化

# Our vectorized labels
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')

建立 CNN 網路架構

這裡我們預計使用三層網路,全連接層僅使用兩層 16 個神經元的網路,啟動函數設定為 relu,連接最後使用一個神經元輸出(表示正評或負評),並使用 sigmoid 作為最後輸出的啟動函數。由下而上網路架構如下:

3 layer CNN

預計採用的 CNN 詳細定義如下:

  • 訓練 Dataset:25,000
  • 測試 Dataset:25,000
  • 優化器:RMSprop
  • 損失函數:二元分類
  • Batch Size:512
  • Epochs:100
from keras import models
from keras import layers

model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

將優化器設定為 rmsprop,損失函數使用 binary_crossentropy,將網路進行 Compile

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])

訓練 CNN 模型

先將準備訓練的 25000 筆資料集,抽出 10000 筆資料集用在訓練時期的驗證資料,好讓我們監控訓練過程的準確性變化。如下:

x_val = x_train[:10000]
partial_x_train = x_train[10000:]

y_val = y_train[:10000]
partial_y_train = y_train[10000:]

開始訓練模型

history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=100,
                    batch_size=512,
                    validation_data=(x_val, y_val))

如果是是透過 Colab 的 GPU 進行訓練,每一個 Epoch 差不多 3 秒多一點,訓練結果如下:

IMDB-Reviews-CNN-training

訓練的過程會把相關資訊存放在 history,透過事後分析訓練過程的資訊可以幫助我們優化參數。

history_dict = history.history
history_dict.keys()

訓練結果圖表分析

透過上面的方法可以取得訓練 History 包含的資訊,然後我們將資訊繪製成為圖表,首先觀察 loss 變化,如下:

#@title
import matplotlib.pyplot as plt

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()

執行結果:

training-loss-chart

接著透過以下程式產生圖表來觀察正確率的變化:

plt.clf()   # clear figure
acc_values = history_dict['accuracy']
val_acc_values = history_dict['val_accuracy']

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()

執行結果:

IMDB-Reviews-Accuracy.

由上面的數據可以看出來,以現在的網路架構,其實在第 3 次 Epoch 就已經獲得最佳的結果,之後的訓練已經造成過度擬合 (Over Fitting),因此在這個案例中將 Epoch 設定為 3 或 4 是取得最佳訓練模型的方法。今天的範例程式可以在 GitHub 取得 ipynb 檔案,需要請自行下載。

原來算比較久不一定比較好 R~實務上,建議透過訓練過程的監控,可以選擇某一個 Epoch 獲得表現最好的 Model 作為最佳解。此外,模型的參數也是很重要的,下一篇文章我們就來介紹一下各種參數的使用情境,敬請期待.......