文本數據嵌入
在之前的學習之中,我們已經簡單地學習了如何進行文本數據的處理:
- 使用 tf.data.TextLineDataset 加載文本數據;
- 使用編碼將數據進行編碼。
而在這節課之中,我們將詳細地了解將文本數據編碼的各種方法,并且對最常用的字詞嵌入方法進行深入研究,最后我們會給出一個完整的模型來對電影評價進行分類。
1. 文本數據編碼的方法
在機器學習領域,所有模型的處理數據都是數字類型的數據。因此在文本處理的過程之中,如何將文本數據轉化為數字類型數據是一個重要的研究課題??v觀所有的數據編碼方法,我們可以將常用的編碼方法大致可以分為三類:
- 簡單編碼處理;
- 簡單編碼后獨熱處理;
- 字詞嵌入處理。
1.1 簡單編碼處理
假如我們有一個英文句子:
s = "How are you"
那么簡單編碼處理就是對每個單詞賦予一個獨特的數字,用來表示該數字。比如:
"How" = 0
"are" = 1
"you" = 2
那么我們便可以將字符串s編碼為:
s_1 = [0, 1, 2]
相應的“How you are”快就可以編碼為:
s_2 = [0, 2, 1]
這種編碼方式最大的好處是簡單,非常容易理解,而且占用的空間資源很少。
但是這種方法也有缺點:
- 那就是這種編碼方式無法識別兩個單詞之間的關系,也就是說兩個數字之間的關系不能代表實際的兩個單詞的關系,比如我們直觀理解 How 和 You 的關系更近一些,然而 How 和 You 的編碼距離是 2 ,而 are 和 you 的距離卻是 1 。
- 同時也正是因為上面的原因,導致不同的編碼規則會產生截然不同的效果,因為我們的“How are you”完全可以編碼為 [111, 222, 333] ,而這會導致編碼后的數據只能依靠固定的編碼規則使用。
1.2 簡單編碼的獨熱化
這種編碼和上述編碼方式一樣,只是進行了一些獨熱化處理,因為獨熱化處理能夠讓模型在分類任務上擁有更好的性質。
比如上述的例子:
s = "How are you"
按照獨熱編碼可以看作是:
"How" = [1, 0, 0]
"are" = [0, 1, 0]
"you" = [0, 0, 1]
雖然獨熱編碼具有更好的性值,但是它仍然沒有解決上面的問題,也就是說它依然無法表示兩個單詞之間的關系。不僅如此,它還引入了新的問題:存儲空間開銷巨大。因為每個單詞的存儲大小都是一個所有詞匯量大小的一個數組。
1.3 字詞嵌入
這種處理方式我們之前有過稍微的接觸,字詞嵌入會根據相關指定的參數來為每個單詞生成一個固定長度的向量。
比如上面的英文句子:
s = "How are you"
編碼后可能變為:
s_3 = [[1.9, 0.4,-0.3],[0.74, 0.23, -0.3],[0.5, 0.6, 0.7]]
通過這種形式的編碼處理,我們已經很難通過肉眼來看出原來的句子了,但是對于機器學習的網絡模型來說,它卻可以進行更快速的處理,同時它其中也包含著不同單詞之間的距離信息。
2. 使用 tf.keras.layers.Embedding 進行字詞嵌入
該嵌入函數API的常用參數如下所示:
tf.keras.layers.Embedding(
input_dim, output_dim, embeddings_initializer='uniform',
embeddings_regularizer=None
)
這幾個參數的具體含義包括:
- input_dim: 輸入的維度,對于字詞嵌入來說就是詞匯量的大??;
- output_dim: 產出的維度,簡單來說就是對單詞嵌入產生的向量的長度;
- embeddings_initializer: 如何對嵌入進行初始化;
- embeddings_regularizer: 嵌入的正則化項,比如之前的L2正則化。
通過這些參數,我們可以發現,我們在進行字詞嵌入之前謂一需要做的就是找到詞匯量的大小,而這一般是人為規定的。
我們可以通過一個簡單的示例來看一下它是如何工作的:
layer = tf.keras.layers.Embedding(100, 5) # 100表示詞匯量大小,5表示產出維度
print(layer(tf.constant([1,2,3,4,5])).numpy())
我們可以得到輸出:
[[-0.00772538 -0.00696523 -0.0306471 0.01268767 -0.0099443 ]
[-0.00331452 -0.00279518 -0.03783524 0.00927589 -0.02038437]
[ 0.03577108 0.01887624 -0.00056656 -0.00773742 0.03503906]
[ 0.02601126 0.02511038 0.01170179 -0.02206317 -0.03981184]
[-0.00608523 0.03906326 0.02454172 -0.0453696 -0.00303098]]
可以看到,我們的嵌入層已經成功進行了嵌入。
3. 使用字詞嵌入進行電影評論分類
我們這里還是使用之前的電影評價進行分類,在這里,我們不僅僅使用了嵌入層進行處理,我們還手動規定了最大的詞匯量為 10000 (這是為了避免一些生僻的單詞的不利影響,同時降低運算量),同時我們將單詞數據提前填充到了相同的長度 256 ,具體代碼展示如下:
import tensorflow as tf
# 使用內置API獲取數據,同時規定最大的詞匯量為10000
(train_data, train_labels), (test_data, test_labels) = tf.keras.datasets.imdb.load_data(num_words=10000)
# 文本數據對齊
train_data = tf.keras.preprocessing.sequence.pad_sequences(train_data, value=0, padding='post', maxlen=256)
test_data = tf.keras.preprocessing.sequence.pad_sequences(test_data, value=0, padding='post', maxlen=256)
# 模型構建與編譯
model = tf.keras.Sequential([
tf.keras.layers.Embedding(10000, 32),
tf.keras.layers.GlobalAveragePooling1D(),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
model.summary()
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# 訓練與測試
history = model.fit(train_data, train_labels, epochs=30, batch_size=64)
results = model.evaluate(test_data, test_labels)
print(results)
最終,我們可以得到結果:
Model: "sequential_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_3 (Embedding) (None, None, 32) 320000
_________________________________________________________________
global_average_pooling1d_2 ( (None, 32) 0
_________________________________________________________________
dense_4 (Dense) (None, 64) 2112
_________________________________________________________________
dense_5 (Dense) (None, 1) 65
=================================================================
Total params: 322,177
Trainable params: 322,177
Non-trainable params: 0
_________________________________________________________________
Epoch 1/30
391/391 [==============================] - 3s 7ms/step - loss: 0.5101 - accuracy: 0.7729
Epoch 2/30
391/391 [==============================] - 3s 7ms/step - loss: 0.2611 - accuracy: 0.8996
..........
Epoch 29/30
391/391 [==============================] - 3s 7ms/step - loss: 0.0013 - accuracy: 1.0000
Epoch 30/30
391/391 [==============================] - 3s 7ms/step - loss: 0.0010 - accuracy: 1.0000
782/782 [==============================] - 1s 1ms/step - loss: 1.6472 - accuracy: 0.8312
[1.6471874713897705, 0.8312000036239624]
可以發現我們的模型準確率最終達到了 83% 的準確率,這是一個比較可以接收的結果。同時我們也可以發現模型的參數主要集中在嵌入層當中。
4. 總結
在這節課之中,我們學習了文本嵌入的三種方法,同時我們對最常用的字詞嵌入的方法進行了詳細的了解,最后我們根據一個電影評價分類的例子來進行了聯系。