one-hot編碼是將標記轉換為向量最常用、最基本的方法。它將每個單詞與一個唯一的整數索引相關聯,然後將這個整數索引
i
i
i轉為為長度為
N
N
N的二進位制向量(
N
N
N是詞表大小),這個向量只有第
i
i
i個元素是1,其餘元素都為0。當然,也可以進行字元級的one-hot編碼。
# 單詞級的one-hot編碼import numpy as np
samples =['The cat sat on the mat.','The dog ate my homework.']
token_index ={}# 構建資料中所有標記的索引# 為每個唯一單詞指定一個唯一索引。注意,沒有為索引編號0指定單詞。for sample in samples:for word in sample.split():if word notin token_index:
token_index[word]=len(token_index)+1# 對樣本進行分詞。只考慮每個樣本前max_length個單詞
max_length =10
results = np.zeros(shape=(len(samples), max_length,max(token_index.values())+1))for i, sample inenumerate(samples):for j, word inlist(enumerate(sample.split()))[:max_length]:
index = token_index.get(word)
results[i, j, index]=1.print(results)
# 字元級的one-hot編碼import string
import numpy as np
samples =['The cat sat on the mat.','The dog ate my homework.']
characters = string.printable # 所有可列印的ASCII字元
token_index =dict(zip(characters,range(1,len(characters)+1)))
max_length =50
results = np.zeros((len(samples), max_length,max(token_index.values())+1))for i, sample inenumerate(samples):for j, character inenumerate(sample):
index = token_index.get(character)
results[i, j, index]=1.print(results)
注意,Keras的內建函式可以對原始文字資料進行單詞級或字元級的one-hot編碼。你應該使用這些函式,因為它們實現了許多重要的特性,比如從字串中去除特殊字元、只考慮資料集中前
N
N
N個最常見的單詞(這是一種常用的限制,以避免處理非常大的輸入向量空間)。
# 用Keras實現單詞級的one-hot編碼from keras.preprocessing.text import Tokenizer
samples =['The cat sat on the mat.','The dog ate my homework.']
tokenizer = Tokenizer(num_words=1000)# 建立一個分詞器(tokenizer),設定為只考慮前1000個最常見的單詞。
tokenizer.fit_on_texts(samples)# 構建單詞索引
sequences = tokenizer.texts_to_sequences(samples)# 將字串轉換為整數索引組成的列表# 得到one-hot二進位制表示。這個分詞器也支援除one-hot編碼外的其他向量化模式。
one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')
word_index = tokenizer.word_index # 找回單詞索引print('Found %s unique tokens.'%len(word_index))
# 使用雜湊技巧的單詞級的one-hot編碼import numpy as np
samples =['The cat sat on the mat.','The dog ate my homework.']# 將單詞儲存為長度1000的向量。如果單詞數量接近1000個(或更多),那麼會遇到很多雜湊衝突,這會降低這種編碼方法的準確性。
dimensionality =1000
max_length =10
results = np.zeros((len(samples), max_length, dimensionality))for i, sample inenumerate(samples):for j, word inlist(enumerate(sample.split()))[:max_length]:
index =abs(hash(word))% dimensionality
results[i, j, index]=1.print(results)
僅僅將嵌入序列展開並在上面訓練一個Dense層,會導致模型對輸入序列中的每個單詞單獨處理,而沒有考慮單詞直接的關係和句子結構(模型可能會將this movie is a bomb和this movie is the bomb兩條都歸為負面評論)。更好的做法是在嵌入序列上新增迴圈層或一維卷積層,將每個序列作為整體來學習特徵。
有許多預計算的詞嵌入資料庫,你都可以下載並在Keras的Embedding層中使用。word2vec就是其中之一。另一個常用的是GloVe(global vectors for word representation, 詞表示全域性向量),由史丹佛大學的研究人員於2014年開發。這種嵌入方法基於對詞共現統計矩陣進行因式分解。其開發者已經公開了數百萬個英文標記的預計算嵌入,它們都是從維基百科資料和Common Crawl資料得到的。
# 解析Glove詞嵌入檔案
glove_dir ="../data"
embeddings_index ={}
f =open(os.path.join(glove_dir,'glove.6B.100d.txt'),'r', encoding='utf-8')for line in f:
values = line.strip().split()
word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
embeddings_index[word]= coefs
f.close()print('Flound %s word vectors.'%len(embeddings_index))
接下來,需要構建一個可以載入到Embedding層中的嵌入矩陣。它必須是一個形狀為(max_words, embedding_dim)的矩陣,對於單詞索引(在分詞時構建)中索引為
i
i
i的單詞,這個矩陣的元素
i
i
i就是這個單詞對應的embedding_dim維向量。注意,索引0不應該代表任何單詞或標記,它只是一個佔位符。
# 準備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)# 嵌入索引(embedding_index)中找不到的詞,其嵌入向量全為0if embedding_vector isnotNone:
embedding_matrix[i]= embedding_vector