TensorFlow實操之--電影評論文本分類

問題描述

從電影的影評中獲取對電影的評價是一件有意義的事情。電影的影評一般分爲正面(positive)或負面(nagetive)兩類。這是一個二元(binary)或者二分類問題,一種重要且應用廣泛的機器學習問題。在網絡電影數據庫(Internet Movie Database)的 IMDB 數據集(IMDB dataset)中包含了影評文本和標籤,如何從這些數據中獲取電影評價模型是問題的核心。IMDB 數據集包含 50,000 條影評文本。從該數據集切割出的25,000條評論用作訓練,另外 25,000 條用作測試。訓練集與測試集是平衡的(balanced),意味着它們包含相等數量的積極和消極評論。

解決思路

思路還是一般神經網絡的步驟,那就是

  1. 獲取數據,包括訓練數據和測試數據。在有些情況下還需要對數據進行處理,即數據處理。
  2. 模型建立
  3. 訓練
  4. 模型驗證

代碼實現

1. 數據獲取與處理
在獲取數據之前,首先要配置一下環境。

from __future__ import absolute_import, division, print_function, unicode_literals#該行要放在第一行位置
import warnings#忽略系統警告提示
warnings.filterwarnings('ignore')
import tensorflow as tf
from tensorflow import keras

基本配置設定完畢後,可以下載數據集。IMDB 數據集已經打包在 Tensorflow 中。該數據集已經經過預處理,評論(單詞序列)已經被轉換爲整數序列,其中每個整數表示字典中的特定單詞。具體代碼如下:

imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
#參數 num_words=10000 保留了訓練數據中最常出現的 10,000 個單詞。爲了保持數據規模的可管理性,低頻詞將被丟棄。

該數據集是經過預處理的:每個樣本都是一個表示影評中詞彙的整數數組。每個標籤都是一個值爲 0 或 1 的整數值,其中 0 代表消極評論,1 代表積極評論。評論文本被轉換爲整數值,其中每個整數代表詞典中的一個單詞。
既然文本能轉換爲整數值,那麼整數值一定可以轉換回去文本,操作方法如下:

#一個映射單詞到整數索引的詞典
word_index = imdb.get_word_index()#建立詞典索引
#保留第一個索引
word_index = {k:(v+3) for k,v in word_index.items()}
word_index["<PAD>"] = 0#這裏0代表<PAD>
word_index["<START>"] = 1#這裏1代表<START>
word_index["<UNK>"] = 2#這裏2代表<UNK>(unknown)
word_index["<UNUSED>"] = 3#這裏3代表<UNUSED>

print(word_index)
print(train_data[1])
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
def decode_review(text):
    return ' '.join([reverse_word_index.get(i, '?') for i in text])

由於神經網絡的輸入必須是張量形式,因此影評需要首先轉換爲張量,然後纔可以進行學習,轉換的方式有兩種:
1、 將數組轉換爲表示單詞出現與否的由 0 和 1 組成的向量,類似於 one-hot 編碼。例如,序列[3, 5]將轉換爲一個 10,000 維的向量,該向量除了索引爲 3 和 5 的位置是 1 以外,其他都爲 0。然後,將其作爲網絡的首層——一個可以處理浮點型向量數據的稠密層。不過,這種方法需要大量的內存,需要一個大小爲 num_words * num_reviews 的矩陣。
2、 我們可以填充數組來保證輸入數據具有相同的長度,然後創建一個大小爲 max_length * num_reviews 的整型張量。我們可以使用能夠處理此形狀數據的嵌入層作爲網絡中的第一層。

在本示例中,我們將使用第二種方法。
由於電影評論長度必須相同,我們將使用 pad_sequences 函數來使長度標準化:

train_data = keras.preprocessing.sequence.pad_sequences(train_data,
                                                        value=word_index["<PAD>"],
                                                        padding='post',
                                                         maxlen=256)
#測試數據長度設置爲256
test_data = keras.preprocessing.sequence.pad_sequences(test_data,
                                                       value=word_index["<PAD>"],
                                                       padding='post',
                                                        maxlen=256)

2. 模型建立
通過keras的Sequential創建模型,並添加神經網絡的層次

vocab_size = 10000
model = keras.Sequential()#搭建層
model.add(keras.layers.Embedding(vocab_size, 16))#embedding 是一個將單詞向量化的函數,嵌入(embeddings)輸出的形狀都是:(num_examples, embedding_dimension)
model.add(keras.layers.GlobalAveragePooling1D())#添加全局平均池化層
model.add(keras.layers.Dense(16, activation = 'relu'))
model.add(keras.layers.Dense(1, activation = 'sigmoid'))

model.summary()

可以看到模型的結構如下圖:

Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 16)          160000    
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 16)                272       
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 17        
=================================================================
Total params: 160,289
Trainable params: 160,289
Non-trainable params: 0

第一層是嵌入(Embedding)層。該層採用整數編碼的詞彙表,並查找每個詞索引的嵌入向量(embedding vector)。這些向量是通過模型訓練學習到的。向量向輸出數組增加了一個維度。得到的維度爲:(batch, sequence, embedding)。
embedding 是一個將單詞向量化的函數,嵌入(embeddings)輸出的形狀都是:(num_examples, embedding_dimension)

接下來,GlobalAveragePooling1D 將通過對序列維度求平均值來爲每個樣本返回一個定長輸出向量。這允許模型以儘可能最簡單的方式處理變長輸入。

該定長輸出向量通過一個有 16 個隱層單元的全連接(Dense)層傳輸。

最後一層與單個輸出結點密集連接。使用 Sigmoid 激活函數,其函數值爲介於 0 與 1 之間的浮點數,表示概率或置信度。

3. 模型配置,訓練和驗證

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


x_val = train_data[:10000]#取訓練數據集前10000個進行訓練和驗證
partial_x_train = train_data[10000:]
y_val = train_labels[:10000]#同理取前10000個標籤
partial_y_train = train_labels[10000:]
#以 512 個樣本的 mini-batch 大小迭代 40 個 epoch 來訓練模型。這是指對 x_train 和 y_train 張量中所有樣本的的 40 次迭代。在訓練過程中,監測來自驗證集的 10,000 個樣本上的損失值(loss)和準確率(accuracy):
history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=15,
                    batch_size=512,
                    validation_data=(x_val, y_val),
                    verbose=1)


results = model.evaluate(test_data,  test_labels, verbose=2)
print(result)

我們來看一下模型的性能如何。將返回兩個值。損失值(loss)(一個表示誤差的數字,值越低越好)與準確率(accuracy)。可以看到準確率爲86%左右

[0.3407367579460144, 0.86448]

總結

從影評分類的例子可以看出,我們花在文本處理上的筆墨非常多,在網絡模型建立方面,尤其是在引進使用keras之後,花費的篇幅相對較少。由此可以看到,數據處理在整個項目中的分量。如果在有了網絡模型(事實上,由於開源,網絡模型已經是有了,而且並且不斷更新創新),那麼數據將是關鍵(當你的重點不是網絡模型創新的學術研究,而是工程應用的話)。

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