閱讀767 返回首頁    go 阿裏雲 go 技術社區[雲棲]


兩個小例子帶你詞嵌入層學習入門——Keras版

更多深度文章,請關注雲計算頻道:https://yq.aliyun.com/cloud


詞嵌入提供了詞的密集表示及其相對含義。最簡單的理解就是:將詞進行向量化表示,實體的抽象成了數學描述,就可以進行建模了。它們是對較簡單的單詞模型表示中使用的稀疏表示的改進。

a7873b5532337a632ab766fd6fa432e5a112a368

Word嵌入可以從文本數據中學習,並在項目之間重用。它們也可以作為在文本數據上擬合神經網絡的一部分。

在本教程中,你將學到如何使用PythonKeras來學習詞嵌入。

完成本教程後,你將學會:

·         關於詞嵌入的相關介紹,並且使用Keras通過嵌入層完成字嵌入。

·         如何在擬合神經網絡時進行詞嵌入。

·         如何將預先訓練的詞嵌入運用到神經網絡中。

教程概述

本教程分為3部分他們是:

1.    詞嵌入。

2.    Keras嵌入層。

3.    學習嵌入的例子。

4.    使用預培訓的GloVe嵌入示例。

1.詞嵌入

詞嵌入是使用密集向量表示來表示單詞和文檔的一類方法。這是對傳統的袋型(bag-of-word)模型編碼方案的改進,其中使用大的稀疏向量來表示每個單詞或向量中的每個單詞進行數字分配以表示整個詞匯表。這些表示是稀疏的,因為詞匯是廣泛的,這樣一個給定的單詞或文檔將由一個主要由零值組成的向量幾何表示。

相反,在詞嵌入中,詞由密集向量表示,其中矢量表示單詞投射到連續向量空間中。

一個單詞在向量空間中的位置是從文本中學習的,並且基於使用該文本時的單詞。在學習向量空間中的單詞的位置稱為嵌入位置。

從文本中學習詞嵌入的兩個流行方法包括:

·         Word2Vec

·         GloVe

除了這些精心設計的方法之外,詞嵌入也可以作為深度學習模型的一部分。這可能是一種較慢的方法。

2.Keras嵌入層

Keras提供了一個嵌入層,可用於處理文本數據的神經網絡。它要求輸入數據進行整數編碼,以便每個單詞都由唯一的整數表示。該數據準備步驟可以使用提供有KerasTokenizer API來執行。

嵌入層使用隨機權重初始化,並將學習所有數據集中詞的嵌入。

它是一個靈活的層,可以以各種方式使用,如:

1.它可以單獨使用來學習一個字嵌入,以後可以在另一個模型中使用。

2.它可以用作深度學習模型的一部分,其中嵌入與模型本身一起被學習。

3.它可以用於加載預訓練的詞嵌入模型,一種遷移學習。

嵌入層被定義為網絡的第一個隱藏層。它必須指定3個參數:

它必須指定3個參數:

1.input_dim:這是文本數據中詞匯的大小。例如,如果你的數據是整數編碼為0-10之間的值,則詞表的大小將為11個字。

2.output_dim:這是嵌入單詞的向量空間的大小。它為每個單詞定義了該層的輸出向量的大小。例如,它可以是32100甚至更大。根據你的問題來定。

3.input_length:這是輸入序列的長度,正如你為Keras模型的任何輸入層定義的那樣。例如,如果你的所有輸入文檔包含1000個單詞,則為1000

例如,下麵我們定義一個詞匯量為200的嵌入層(例如,從0199(包括整數)的整數編碼單詞),將詞嵌入到32維的向量空間中,以及每次輸入50個單詞的輸入文檔。

e = Embedding(200, 32, input_length=50)

嵌入層的輸出是一個二維向量,每個單詞對應一個輸入序列(輸入文檔)。如果希望連接密集層直接到嵌入層,必須首先壓扁2D輸出矩陣。

現在,我們來看看我們如何在實踐中使用嵌入層。

3.學習嵌入的例子

我們定義一個小問題,我們有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]

接下來我們可以對每個文檔進行整數編碼,作為輸入,嵌入層將具有整數序列。我們可以嚐試其他更複雜的單詞模型編碼,如計數或TF-IDF

Keras提供one_hot()函數,它創建每個單詞的哈希值作為有效的整數編碼。我們估計有50個詞匯大小,這遠遠大於減少哈希函數碰撞概率所需的大小。如果你的詞匯很多的話,我建議你使用這個函數。

# integer encode the documents
vocab_size = 50
encoded_docs = [one_hot(d, vocab_size) for d in docs]
print(encoded_docs)

序列具有不同的長度,並且Keras更喜歡被矢量化的所以輸入具有相同的長度。我們將所有輸入序列的長度設為4。再次,我們可以使用內置的Keras函數(在這種情況下為pad_sequences)來執行此操作

# pad documents to a max length of 4 words
max_length = 4
padded_docs=pad_sequences(encoded_docs,maxlen=max_length, padding='post')
print(padded_docs)

我們現在可以將我們的嵌入層定義為神經網絡模型的一部分。該嵌入具有50詞匯及輸入長度為4,我們將選擇8尺寸的小嵌入空間。

該模型是一個簡單的二進製分類模型。重要的是,嵌入層的輸出將是4個向量,每個向量8個維度,每個單詞一個。我們將其平坦化為一個32維度的向量,以傳遞到Dense輸出層。

# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))

最後,我們可以訓練和評估該分類模型。

# 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())

完整的代碼清單如下:

from keras.preprocessing.text import one_hot
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers.embeddings import Embedding
# 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]
# integer encode the documents
vocab_size = 50
encoded_docs = [one_hot(d, vocab_size) for d in docs]
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
# 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())
# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))

運行示例首先打印整數編碼的文檔

[[6, 16], [42, 24], [2, 17], [42, 24], [18], [17], [22, 17], [27, 42], [22, 24], [49, 46, 16, 34]]

然後打印每個文檔的填充版本,使其均勻一致:

[[ 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]]

定義網絡後,我們可以看到,如預期的那樣,嵌入層的輸出是4×8矩陣,並且由Flatten層壓縮到32維向量。

______________________________________________________________
Layer (type)                 Output Shape              Param #
===========================================================
embedding_1 (Embedding)      (None, 4, 8)              400
______________________________________________________________
flatten_1 (Flatten)          (None, 32)                0
______________________________________________________________
dense_1 (Dense)              (None, 1)                 33
===========================================================
Total params: 433
Trainable params: 433
Non-trainable params: 0

最後,查看訓練模型的準確性,表明它完美地學習了訓練數據集:

Accuracy: 100.000000

你可以將學習的權重從嵌入層中保存到文件中,以備以後在其他模型中使用。

你也可以使用此模型來對在測試數據集中看到的具有相同種類詞匯表的其他文檔進行分類。

接下來,我們來看看在Keras中加載一個預先訓練的詞嵌入。

4.使用預培訓的GloVe嵌入示例

自然語言處理領域中常見的是學習,保存和匯嵌入。例如,GloVe方法背後的研究人員根據公共領域許可證在其網站上提供了一套預先訓練有素的詞匯嵌入。

·         GloVeWord表示的全局向量

嵌入式最小的包是822Mb,稱為“glove.6B.zip”。它被訓練在十萬個詞匯(詞)的數據集上,詞匯量為四十萬字。有幾種不同的嵌入矢量大小,包括50,100,200300維。

你可以下載此嵌入式集合,此示例來自Keras項目中的示例:

pretrained_word_embeddings.py

下載和解壓縮後,你將看到一些文件,其中之一是“glove.6B.100d.txt”,其中包含一個100維版本的嵌入。

如果你認真看文件,則會在每行上看到令牌(單詞),後跟權重(100個數字)。例如,下麵是嵌入的ASCII文本文件的第一行,顯示the的嵌入。

8ae832ca36a9b63cd5a46b876097429cb6c63494

如前一節所述,第一步是定義,將其編碼為整數,然後將序列設置為相同的長度。

在這種情況下,我們需要能夠將單詞映射到整數以及整數到單詞。

Keras提供了一個標記生成器類,可以配合訓練數據,可以將文本轉換為序列,通過調用texts_to_sequences()的方法標記生成器的類,並提供訪問字的字典映射到整數在word_index屬性。

# 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]
# prepare tokenizer
t = Tokenizer()
t.fit_on_texts(docs)
vocab_size = len(t.word_index) + 1
# integer encode the documents
encoded_docs = t.texts_to_sequences(docs)
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)

接下來,我們需要將整個GloVe字嵌入文件作為字嵌入數組的字典加載到內存中。

# load the whole embedding into memory
embeddings_index = dict()
f = open('glove.6B.100d.txt')
for line in f:
	values = line.split()
	word = values[0]
	coefs = asarray(values[1:], dtype='float32')
	embeddings_index[word] = coefs
f.close()
print('Loaded %s word vectors.' % len(embeddings_index))

這個過程很慢。接下來,我們需要為訓練數據集中的每個單詞創建一個嵌入矩陣。我們可以通過枚舉Tokenizer.word_index中的所有唯一的字,並從加載的GloVe嵌入中定位嵌入權重向量。

# create a weight matrix for words in training docs
embedding_matrix = zeros((vocab_size, 100))
for word, i in t.word_index.items():
	embedding_vector = embeddings_index.get(word)
	if embedding_vector is not None:
		embedding_matrix[i] = embedding_vector

現在我們可以像以前那樣定義我們的模型,訓練和評估。

關鍵區別是嵌入層可以用GloVe字嵌入權重進行遷移。我們選擇了100維版本,因此嵌入層必須用output_dim定義為100。最後,我們不更新此模型中學習的單詞權重,因此我們將將模型的可訓練屬性設置為False

e= Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False)

完整的工作示例如下所示:

from numpy import asarray
from numpy import zeros
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers import Embedding
# 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]
# prepare tokenizer
t = Tokenizer()
t.fit_on_texts(docs)
vocab_size = len(t.word_index) + 1
# integer encode the documents
encoded_docs = t.texts_to_sequences(docs)
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
# load the whole embedding into memory
embeddings_index = dict()
f = open('../glove_data/glove.6B/glove.6B.100d.txt')
for line in f:
	values = line.split()
	word = values[0]
	coefs = asarray(values[1:], dtype='float32')
	embeddings_index[word] = coefs
f.close()
print('Loaded %s word vectors.' % len(embeddings_index))
# create a weight matrix for words in training docs
embedding_matrix = zeros((vocab_size, 100))
for word, i in t.word_index.items():
	embedding_vector = embeddings_index.get(word)
	if embedding_vector is not None:
		embedding_matrix[i] = embedding_vector
# define model
model = Sequential()
e = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False)
model.add(e)
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())
# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))

這運行起來時間可能會很長。運行結果:

[[6, 2], [3, 1], [7, 4], [8, 1], [9], [10], [5, 4], [11, 3], [5, 1], [12, 13, 2, 14]]
[[ 6  2  0  0]
 [ 3  1  0  0]
 [ 7  4  0  0]
 [ 8  1  0  0]
 [ 9  0  0  0]
 [10  0  0  0]
 [ 5  4  0  0]
 [11  3  0  0]
 [ 5  1  0  0]
 [12 13  2 14]]
Loaded 400000 word vectors.
______________________________________________________________
Layer (type)                 Output Shape              Param #
===========================================================
embedding_1 (Embedding)      (None, 4, 100)            1500
______________________________________________________________
flatten_1 (Flatten)          (None, 400)               0
______________________________________________________________
dense_1 (Dense)              (None, 1)                 401
===========================================================
Total params: 1,901
Trainable params: 401
Non-trainable params: 1,500
______________________________________________________________
Accuracy: 100.000000

在實踐中,我鼓勵你嚐試使用固定的預訓練嵌入學習,因為它涉及到的東西更全麵。

如果你想了解更深入,本部分將提供有關該主題的更多資源。

1.Word嵌入維基百科

2.Keras嵌入層API

3.2016年的Keras模型中使用預先訓練的詞嵌入

4.Keras中使用預先訓練的GloVe嵌入的示例

5.GloVe嵌入

6.詞匯嵌入及其與分布式語義模型的連接概述2016

7.2014深度學習,NLP和表示

作者信息

c4859050f41c5bdd8935a467b8e0474d6188616d

本文由北郵@愛可-愛生老師推薦,阿裏雲雲棲社組織翻譯。

文章原標題《use-word-embedding-layers-deep-learning-keras

作者:Dr.Jason Brownlee譯者:袁虎,審閱:

文章為簡譯,更為詳細的內容,請查看原文














最後更新:2017-10-06 17:33:17

  上一篇:go  阿裏雲推薦碼2017阿裏雲ECS服務器八折推薦碼
  下一篇:go  Linux shell 基礎之Vim編輯器