當前位置:
首頁 > 最新 > 用深度學習實現自然語言處理:word embedding,單詞向量化

用深度學習實現自然語言處理:word embedding,單詞向量化

前幾年,騰訊新聞曾發出一片具有爆炸性的文章。並不是文章的內容有什麼新奇之處,而是文章的作者與眾不同,寫文章的不是人,而是網路機器人,或者說是人工智慧,是演算法通過分析大量財經文章後,學會了人如何編寫財經報道,然後根據相關模式,把各種財經數據組織起來,自動化的生成一篇文章,當人閱讀時,根本無法意識到文章不是人寫,而是電腦生成的。

從本節開始,如何使用神經網路構造出一個能閱讀,理解人類文本含義的智能程序。就如同前一章講述的圖像識別網路,本質上並不是網路能像人一樣看懂了圖片內涵,而是網路通過讀取大量圖片數據,從數據中抽取出某種固定規律,我們本章要開發的神經網路也同理,它會從大量的文本數據中分析抽取出其潛在的固定模式或規律。

要想讓網路能夠分析文本,我們首先要做的是將文本進行數據化。它主要包含幾個方面的內容:一種方法是將文本分割成片語,並將片語轉變為向量。一種方法是將文本分割成一系列字元的組合,然後用向量表示每個字元。第三種方法是把若干個詞或字元組合成一個集合,然後將他們轉換成向量。無論何種情況,我們都把被向量化的對象成為token,而把整篇文章分解成token的過程叫tokenization。

舉個具體例子,假設我們有一條英文句子」The cat jump over the dog」,如果我們採用第一種方法,那麼我們把句子分解成多個單詞:』The』,』cat』,』jump』,』over』,』the』,』dog』。然後通過演算法為每個單詞構造一個向量:

『the』->[0.0, 0.0, 0.4,0.0,1.0,0.0]

『cat』->[0.5, 1.0, 0.5, 0.2, 0.5, 0.5, 0.0]等,後面我們會研究單詞是如何轉換成向量的。

有一種把單詞向量化的簡單方法叫one-hot-encoding,我們在前面章節看過這種向量,它所有元素都是0,只有某個位置是1,例如上面例句中總共有5個不同單詞,於是我們可以用含有5個元素的向量來表示:

『The』 -> [1,0,0,0,0], 『cat』->[0,1,0,0,0], 『jump』->[0,0,1,0,0]以此類推。

我們看一段如何將單詞進行one-hot-encoding的代碼:

import numpy as npsamples = ["The cat jump over the dog", "The dog ate my homework"]#我們先將每個單詞放置到一個哈希表中token_index = {}for sample in samples: #將一個句子分解成多個單詞 for word in sample.split(): if word not in token_index: token_index[word] = len(token_index) + 1#設置句子的最大長度max_length = 10results = np.zeros((len(samples), max_length, max(token_index.values()) + 1))for i, sample in enumerate(samples): for j, word in list(enumerate(sample.split()))[: max_length]: index = token_index.get(word) results[i, j, index] = 1. print(" -> ".format(word, results[i, j]))

上面代碼運行後結果如下:

其實這種」臟活累活「不需要我們親自動手,keras框架提供了一系列介面幫我們省卻了這些麻煩,下面代碼同樣能實現相同內容:

from keras.preprocessing.text import Tokenizersamples = ["The cat jump over the dog", "The dog ate my homework"]#只考慮最常使用的前1000個單詞tokenizer = Tokenizer(num_words = 1000)tokenizer.fit_on_texts(samples)#把句子分解成單詞數組sequences = tokenizer.texts_to_sequences(samples)print(sequences)one_hot_vecs = tokenizer.texts_to_matrix(samples, mode="binary")word_index = tokenizer.word_indexprint("當前總共有%s個不同單詞"%len(word_index))

上面代碼運行後,結果如下:

[[1, 3, 4, 5, 1, 2], [1, 2, 6, 7, 8]]當前總共有8個不同單詞

one_hot_vecs對應兩個含有1000個元素的向量,第一個向量的第1,3,4,5個元素為1,其餘全為0,第二個向量第1,2,6,7,8個元素為1,其餘全為0.

接下來我們要看自然語言處理中一個極為關鍵的概念叫word embedding,也就是用非零向量來表示每一個單詞。one-hot-vector對單詞進行編碼有很多缺陷,一是冗餘過多,一大堆0,然後只有一個1,二是向量的維度過高,有多少個單詞,向量就有多少維度,這會給計算帶來很多麻煩,word-embedding把原來高維度的冗餘向量轉換為低緯度的,信息量強的向量,轉換後的向量,無論單詞量多大,向量的維度一般只有256維到1024維。

單詞向量化的一個關鍵目標是,意思相近的單詞,他們對應的向量之間的距離要接近,例如」good」,」fine」都表示「好」的意思,因此這兩個單詞對應的向量在空間上要比較接近的,也就是說意思相近的單詞,他們對應的向量在空間上的距離應該比較小。假設給定4個單詞:『cat』, 『dog』, 『wolf』, 『tiger』,其中前兩個貓和狗相似性強,後兩個狼和狗相似性強,因此當他們轉換成向量時,在空間距離上會形成兩個集合,例如下圖:

給定一個單詞,我們如何生成對應向量呢?我們可以構造一個網路來實現這個目標,假設有兩個單詞,」good」, 「fine」,我們隨機給他們賦值兩個向量,然後不斷的訓練網路,讓這兩個向量之間的距離變得越來越小,好在我們不用從零開始開發這樣的網路,keras框架給我們提供了現成可用的類似網路,我們看下面一段代碼:

from keras.layers import Embedding#Embedding對象接收兩個參數,一個是單詞量總數,另一個是單詞向量的維度embedding_layer = Embedding(1000, 64)

上面代碼創建一個叫Embedding的網路層,它接收的參數格式如(samples, sequence_length),假設我們現在有32條句子,每條句子最多包含10個單詞,那麼我們提交的輸入參數就是(32, 10),Embedding一開始會給每個單詞隨意生成一個含有64個元素的向量,然後通過讀入大量的數據,調整每個單詞對應的向量,讓意思相近的單詞所對應的向量在空間上的距離越來越近。

詳細理論不多說,我們先跑起來一個例子,看看如何分析影評文本所展現的情緒,我們使用的還是以前見過的IMDB數據,我們只抽取每篇影評的前20個單詞,然後為單詞向量化,由於影評中只有兩種情緒,好和壞,好影評中所用到的單詞大多含有「好」的意思,因此對應的向量在空間上會聚合在一起形成一個集合,壞影評使用的單詞大多都包含「壞」的意思,於是他們對應的向量就會聚合到一起形成另一個集合,當遇到新影評時,我們也把它的前20個單詞向量化,然後看這些向量靠近哪一個集合,如果靠近第一個集合,我們就預測該影評包含正能量,如果靠近第二個集合,我們就認為影評包含負能量。我們看看代碼的實現:

from keras.models import Sequentialfrom keras.layers import Flatten, Densemodel = Sequential()#在網路中添加Embedding層,專門用於把單詞轉換成向量model.add(Embedding(10000, 8, input_length=maxlen))"""我們給Embeding層輸入長度不超過maxlen的單詞向量,它為每個單詞構造長度為8的向量它會輸出格式為(samples, maxlen, 8)的結果,然後我們把它轉換為(samples, maxlen*8)的二維格式"""model.add(Flatten())#我們在頂部加一層只含有1個神經元的網路層,把Embedding層的輸出結果對應成兩個類別model.add(Dense(1, activation="sigmoid"))model.compile(optimizer="rmsprop", loss="binary_crossentropy", metrics = ["acc"])model.summary()history = model.fit(x_train, y_train, epochs = 10, batch_size = 32, validation_split=0.2)

運行上面代碼後,我們把結果繪製出來,看看網路對檢驗是數據集的識別準確率:

import matplotlib.pyplot as pltacc = history.history["acc"]val_acc = history.history["val_acc"]loss = history.history["loss"]val_loss = history.history["val_loss"]epochs = range(1, len(acc) + 1)#繪製模型對訓練數據和校驗數據判斷的準確率plt.plot(epochs, acc, "bo", label = "trainning acc")plt.plot(epochs, val_acc, "b", label = "validation acc")plt.title("Trainning and validation accuary")plt.legend()plt.show()plt.figure()#繪製模型對訓練數據和校驗數據判斷的錯誤率plt.plot(epochs, loss, "bo", label = "Trainning loss")plt.plot(epochs, val_loss, "b", label = "Validation loss")plt.title("Trainning and validation loss")plt.legend()plt.show()

上面代碼運行後結果如下:

我們從上圖可以看到藍色實線看出,僅僅通過將影評的前20個單詞向量化,在沒使用任何調優手段的情況下,網路對校驗是數據的識別準確率就達到75%左右。

還記得前面我們使用預先訓練好的網路大大提升圖片識別率嗎,單詞向量化也一樣,有人使用上面提到的Embedding網路層分析讀取大量文本後,為常用的英文單詞都建立了對應的向量。我們自己運用神經網路處理具體問題時,一大困難在於數據量太少,巧婦難為無米之炊,數據量太小,神經網路的精確度會受到極大的制約,如果我們手上的文本數量很少,那麼為單詞建立的向量就不會很準確,要彌補這些缺陷,我們可以使用別人訓練好的結果。

網路時代的一大優勢就是,有人願意把自己的勞動果實無償分享出來。當前實現單詞向量化的最好演算法是由Google研究員Mikolov在2013年發明的Word2Vec演算法,有人或組織就使用該演算法分析大量英文文本後,為常用的單詞建立向量,並把這些向量信息放在網上供人下載。另一個常用的單詞向量資料庫叫」GloVe」,是由斯坦福教授根據單詞的統計特性開發的向量化演算法對常用單詞向量化後形成的資料庫。

在下一節我們將看看,如何使用預先訓練的單詞向量化數據」GloVe」實現原始文本的分割,量化並進行有效的分析。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Coding迪斯尼 的精彩文章:

自製Monkey編程語言編譯器:增加數組操作API和Mapsh數據類型

TAG:Coding迪斯尼 |