2019年1月26日 星期六

深度學習 - IMDb數據集 - 原始文本結合GloVe預訓練詞嵌入模型

在上一篇 深度學習 - IMDb數據集 - 文本與序列預處理 將處理好的文本,接續將詞嵌入Glove模型加入。

https://nlp.stanford.edu/projects/glove 下載文件名為 glove.6B.zip 的檔案(822MB),裡面包含400,000 個單詞(或非單詞的標記)的100 維嵌入向量

讀取該文件看看內容長甚麼樣子,比較好理解接下來要做什麼。
import os
glove_dir = 'C:\\Users\\Lido_Lee\\Downloads\\glove.6B'
#'cp950' error 需在open中加入(encoding = 'utf-8-sig')
f = open(os.path.join(glove_dir, 'glove.6B.100d.txt'), encoding = 'utf-8-sig')
i=0
word=[]
for line in f:
    values = line.split()
    print(values)
    word.append(values)
    i += 1
    if i >= 4:
        break
f.close()



可以看到Values[0] 都對應一個文字,分別是"the",",(逗號)",".(句號)","of"
看一下每個word含意:
>>>len(word[0])
101
這邊可以看出,每個字都是由100個tensor表示。
了解了之後,接著我們建構一個嵌入矩陣
#構建一個可以加載到Embedding 層中的嵌入矩陣
import numpy as np
import os
glove_dir = 'C:\\Users\\Lido_Lee\\Downloads\\glove.6B'
embeddings_index = {}
#'cp950' error 需在open中加入(encoding = 'utf-8-sig')
f = open(os.path.join(glove_dir, 'glove.6B.200d.txt'), encoding = 'utf-8-sig')
for line in f:
    values = line.split()
    word = values[0]
    coefs = np.asarray(values[1:], dtype='float32')
    embeddings_index[word] = coefs
f.close()
print('Found %s word vectors.' % len(embeddings_index))
Found 400000 word vectors.

#準備GloVe 詞嵌入矩陣
embedding_dim = 100
embedding_matrix = np.zeros((max_words, embedding_dim))
for word, i in word_index.items():
    if i < max_words:
        embedding_vector = embeddings_index.get(word)
        if embedding_vector is not None:
            embedding_matrix[i] = embedding_vector

#定義模型
from keras.models import Sequential
from keras.layers import Embedding, Flatten, Dense
model = Sequential()
model.add(Embedding(max_words, embedding_dim, input_length=maxlen))
model.add(Flatten())
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.summary()

#將預訓練的詞嵌入加載到Embedding 層中
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False

#選擇優化器、損失函數、指標
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['acc'])
#丟進fit訓練模型
history = model.fit(x_train, y_train,
                    epochs=15,
                    batch_size=32,
                    validation_data=(x_val, y_val))

#將訓練好的模型保存起來
model.save_weights('pre_trained_glove_model.h5')

#畫出訓練過程
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()

 驗證精度大概在70%左右。

如果不使用Glove 預訓練的詞嵌入,將之mark起來。
"""
#將預訓練的詞嵌入加載到Embedding 層中
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False
"""

 可以看到精度約為85%左右。


若使用Glove 預訓練的詞嵌入,且讓Glove的權重是可以跟隨著訓練過程來調整,會是怎樣的情況?
#將預訓練的詞嵌入加載到Embedding 層中
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = True
 其精度在84%左右。

這邊發生了什麼事情!? 為何預訓練的驗證精度比自己訓練的精度還要低?

這邊猜想是,預訓練的模型在處理少量資料的時候,可以藉由詞向量的特徵是可遷移的性質,在少量資料表現是比較好的,因為新的模型在少量資料時根本沒有提取到任何特徵。但是在處理大量資料(如IMDb)時,新的模型根據大量資料提取的特徵,會是處理這類問題的重要特徵,而不是預訓練模型是屬於較泛化的特徵。


沒有留言:

張貼留言