Embedding的含義
根據tf.keras.layers.Embedding的解釋
是將正整數轉換為固定長度的連續向量,它和one-hot編碼的作用類似,都是對資料字符數值進行編碼,
不同之處是,embedding是將一個單純的數值轉換成一個長度唯一的概率分布向量,再避免one-hot編碼產生的特征稀疏性問題的同時,也能增加特征的描述,
需要注意的是,當embedding進行神經網路構建時,embedding層必須作為第一層對輸入資料進行embedding處理,其配置的引數如下
input_dim: 配置字典的長度,embedding 是針對詞頻字典中的索引進行處理的,因此需要配置字典的長度,
output_dim: 配置神經網路層輸出的維度,
embeddings_initializer: 配置embedding 矩陣的初始化
embeddings_regularizer: 配置embedding 矩陣的正則化方程
embedding_constraint: 配置embedding 的約束函式
mask_zero: 配置"0"是否為Padding的值,如果配置為True, 則將所有的"0"去掉
input_length: 配置輸入陳述句的長度,將不足長度的用0填充,
其中 input_dim 和 output_dim必須指定
當時,我看這個解釋還是比較懵逼,
舉個小例子吧,下面我們定義一個詞匯表為200的嵌入層(例如從0到199的整數編碼的字,包括0到199),一個32維的向量空間,其中將嵌入單詞,以及輸入檔案,每個單詞有50個單詞,
e = Embedding(input_dim=200, output_dim=32, input_length=50)
Embedding的實體
下面方法基于keras, 在tensorflow中我們可以使用 tf.keras.preprocessing.text.Tokenizer這個API庫下的相關方法
我們將定義一個小問題,我們有10個文本檔案,每個檔案都有一個學生提交的作業評論,每個文本檔案被分類為正的“1”或負的“0”,這是一個簡單的情感分析問題,
首先,我們將定義檔案及其類別標簽,
# define documents 定義檔案
docs = ['Well done!',
'Good work',
'Great effort',
'nice work',
'Excellent!',
'Weak',
'Poor effort!',
'not good',
'poor work',
'Could have done better.']
# define class labels 定義分類標簽
labels = [1,1,1,1,1,0,0,0,0,0]
接下來,我們來整數編碼每個檔案,這意味著把輸入,嵌入層將具有整數序列,我們可以嘗試其他更復雜的bag of word 模型比如計數或TF-IDF,
Keras提供one_hot()函式來創建每個單詞的散列作為一個有效的整數編碼,我們用估計50的詞匯表大小,這大大減少了hash函式的沖突概率,
# integer encode the documents 獨熱編碼
vocab_size = 50
encoded_docs = [one_hot(d, vocab_size) for d in docs]
print(encoded_docs)
[[6, 16], [42, 24], [2, 17], [42, 24], [18], [17], [22, 17], [27, 42], [22, 24], [49, 46, 16, 34]]
每個詞都能有0-49的一個索引值,例如 'well done' = [6, 16], 但是由于不同的序列有不同的長度,方便進行處理,因此我們需要進行padding, 將所有的輸入序列的長度填充為4.
# pad documents to a max length of 4 words 將不足長度的用0填充為長度4
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
[[ 6 16 0 0]
[42 24 0 0]
[ 2 17 0 0]
[42 24 0 0]
[18 0 0 0]
[17 0 0 0]
[22 17 0 0]
[27 42 0 0]
[22 24 0 0]
[49 46 16 34]]
我們現在準備將我們的嵌入層定義為我們的神經網路模型的一部分,
嵌入的詞匯量為50,輸入長度為4,我們將選擇一個8維的嵌入空間,
該模型是一個簡單的二元分類模型,重要的是,嵌入層的輸出將是每個8維的4個矢量,每個單詞一個,我們將其平鋪到一個32個元素的向量上以傳遞到密集輸出層,
# define the model 定義模型
model = Sequential()
model.add(Embedding(vocab_size, 8, input_length=max_length))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model 編譯
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
# summarize the model 列印模型資訊
print(model.summary())
進行到這,我們一直需要關注的是在進行維度的轉換,原本是10x4, 但是經過Embedding之后,其實會變成10x4x8.
input_dim: vocal_size = 50 字典的大小,因為我們在進行one-hot編碼時,每個詞都是由 0-49 中的某個值作為索引值, 因而字典大小為 49+1 = 50;
input_length: 4, 如果輸入的向量長度不足為4,就會給向量填充0,直到向量長度為4,
output_dim: 8 每個詞的向量長度,在embedding之前,每個詞只有一個索引值,因此我們需要將每個詞的索 引轉變成一個長度為8的概率分布向量,(10x4x1 => 10x4x8)
此處我們可以明白embedding到底做了什么,舉個栗子:
? “公主”和“王妃” 使用One-hot編碼 可能會得到: 公主 [1 0] 王妃 [0 1] ,
? One-hot編碼能夠得到完全獨立的兩個01向量,并且當如果文本集夠大,那就會導致稀疏矩陣,
? 由于兩者完全獨立,表達關聯特征的能力幾乎就為0, 但王妃和公主是有關系,最基本的她們都是女性,
? 而embedding會將one-hot編碼(稀疏態),通過一些線性變換,讓相互獨立向量變成了有內在聯系的關系 向量(密集態)即可能 公主 [ 1.0 0.25] 王妃 [ 0.6 0.75] ,
補充
使用tensorflow2.0中的tokenizer進行處理時,
# 定義word2vec的函式,通過統計所有訓練集中的字符出現頻率,構建字典,并使用字典中的碼值對訓練集中的陳述句進行替換
def tokenize(lang):
# 使用高階API tf.keras.preprocessing.text.Tokenize實體化一個轉換器,構建字典并使用字典中的碼值對訓練集中的陳述句進行替換, oov_token: 配置不在字典中的字符的替換數字,一般使用“3”來替換,
lang_tokenizer = tf.keras.preprocessing.text.Tokenizer(num_words=gConfig['enc_vocab_size'], oov_token=3)
# 使用fit_on_texts方法對訓練資料進行處理,構建字典
lang_tokenizer.fit_on_texts(lang)
# 轉換器使用已經構建好的字典,將訓練集的資料全部替換為字典的碼值
tensor = lang_tokenizer.texts_to_sequences(lang)
# 為了提高計算效率,將訓練陳述句的長度統一補全
tensor = tf.keras.preprocessing.sequence.pad_sequences(tensor, padding='post')
return tensor, lang_tokenizer
其實里面還有很多方法,可以參考該博客,
參考
- http://frankchen.xyz/2017/12/18/How-to-Use-Word-Embedding-Layers-for-Deep-Learning-with-Keras/
- https://machinelearningmastery.com/use-word-embedding-layers-deep-learning-keras/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/24855.html
標籤:其他
