基於文本的深度學習方法的TensorFlow實現(1)——詞嵌入

詞嵌入

用數字表示文本

機器學習模型以向量(數字數組)作爲輸入,爲了使用文本,需要將字符串轉爲數字,即向量化。

三種向量化策略

  • One-hot編碼
    向量長度等於詞彙量,在詞彙對應的索引置1,其他置0
    例如:
    The cat sat on the mat.
    cat (0,1,0,0,0,0)
    ……
    缺點:效率低下,向量稀疏
  • 整數編碼
    用唯一的數字給詞編碼
    例如:
    The cat sat on the mat.
    (1,2,3,4,5,6)
    缺點:
    編碼不能表示單詞之間的關係;單詞之間的相似性與編碼的相似性無關,編碼的權重組合無意義。
  • 詞嵌入
    高效,密集,且相似的單詞具有相似的編碼
    自動嵌入浮點數密集向量(向量長度需指定),具體的數值是可以訓練的參數。高維的嵌入可以捕獲單詞間的細粒度關係,同時需要更多的數據來學習。

使用Embedding層

Keras提供詞嵌入的方法,即Embedding層。
可以將詞嵌入看爲查找表,它從代表單詞的整數索引映射到單詞嵌入的密集向量。

embedding_layer = layers.Embedding(1000, 5)

創建嵌入層時,嵌入的權重會隨機初始化。在訓練過程中,通過反向傳播逐漸調整嵌入值。經過訓練後,詞嵌入可以學習編碼詞之間的相似性。
對於文本或序列,Embedding層的輸入爲2維整數張量(samples, sequence_length),每個條目爲一個整數序列。
Embedding層可以嵌入可變長度的序列。
返回的張量比輸入多一維,嵌入的向量和最後一維對齊。
例如:
輸入維度(2,3),輸出維度爲(2,3,5)。
爲了從可變長度的序列轉換爲固定的表示形式,可以有多種方法,比如RNN,Attention或pooling層。

從頭開始學習嵌入

首先加載文本數據集。
對於長度不同的文本,使用padded_batch標準化文本的長度。

padded_shapes = ([None],())
train_batches = train_data.shuffle(1000).padded_batch(10, padded_shapes = padded_shapes)
test_batches = test_data.shuffle(1000).padded_batch(10, padded_shapes = padded_shapes)

通過在句尾補0填充到批處理中例子最長的長度。

  1. 使用keras的API創建一個簡單的模型
embedding_dim=16
model = keras.Sequential([
  layers.Embedding(encoder.vocab_size, embedding_dim),
  layers.GlobalAveragePooling1D(),
  layers.Dense(1, activation='sigmoid')
])
model.summary()

首先,使用“連續詞袋”樣式模型,嵌入層採用整數編碼的詞彙表,併爲每個單詞索引查找嵌入向量。
然後,GlobalAveragePooling1D()通過對序列維進行平均,爲每個樣本返回固定長度的輸出向量。
固定長度的輸出向量通過16個隱藏單元的完全連接層進行管道傳輸。最後一層與單個輸出節點緊密相連。
使用S形激活函數,表示置信度。

  1. 編譯和訓練模型
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])
history = model.fit(
    train_batches,
    epochs=10,
    validation_data=test_batches, validation_steps=20)

檢索學習的詞嵌入

首先,檢索學習到的詞嵌入。

e = model.layers[0]
weights = e.get_weights()[0]
print(weights.shape) # shape: (vocab_size, embedding_dim)

然後,將權重寫入磁盤。使用Embedding Prijector將以製表符分隔的格式上傳兩個文件:一個向量文件(包含嵌入)和一個元數據文件(包含單詞)。

encoder = info.features['text'].encoder

import io
encoder = info.features['text'].encoder
out_v = io.open('vecs.tsv', 'w', encoding='utf-8')
out_m = io.open('meta.tsv', 'w', encoding='utf-8')
for num, word in enumerate(encoder.subwords):
  vec = weights[num+1] # skip 0, it's padding.
  out_m.write(word + "\n")
  out_v.write('\t'.join([str(x) for x in vec]) + "\n")
out_v.close()
out_m.close()

可視化詞嵌入

打開Embedding Prijector,可以搜索單詞找到其最近的鄰居。

參考鏈接

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