機器學習-NLP之Word embedding 原理及應用


  • 概述

自然語言是非常復雜多變的,計算機也不認識咱們的語言,那么咱們如何讓咱們的計算機學習咱們的語言呢?首先肯定得對咱們的所有文字進行編碼吧,那咱們很多小伙伴肯定立馬就想出了這還不簡單嘛,咱們的計算機不都是ASCII編碼的嘛,咱直接拿來用不就好啦?我只能說too young too simple。咱們的計算機只是對咱們的“字母”進行ASCII編碼,並沒有對咱們的“Word”編碼。world應該是咱們處理自然語言的最基本的元素,而不是字母。那么世界上有千千萬萬的Word,咱們具體怎么表示呢?就算找出了一種方式來表示每一個Word,那么這些Word之間的關系如何來表示,畢竟有些詞匯在某種維度上是比較相似的,有些詞匯在某些維度上的距離則是比較遠的,那么咱們如何還找到他們的關系呢?還有一個問題就是咱們如何通過咱們的text corpus(training dataset)來最終來學習咱們的模型呢?等等這些問題都是咱們NLP的內容的最基礎也是最根本的問題。這一節主要就是解決這些問題的。

  • One-hot encoding Word Representation

首先咱們來看咱們如何在機器學習系統中表示咱們的詞匯,這里呢先說答案,那就是有兩種方式,一種就是One-hot encoding, 另外一種就是 Featured representation (word embedding)。首先咱們來看一下One-hot encoding,它是咱們定義的長度固定的vocabulary中賦予每一個Word一個index,例如vocabulary的長度是10000,其中“cat”的index是3202,那么咱們對於cat的表示方式就是[0,0,0,0,..........1.........,0], 其中只在3202的位置是1,其他的9999個位置都是0. 咱們也可以結合下面的圖片來更加直觀的展示一下Word的one-hot encoding。

 

上面的圖片是不是一目了然了什么是Word的one-hot encoding呢?那么問題來了?這種方式的representation有沒有什么缺點是避免不了的以至於咱們必須得用Word Embedding呢?當然有啦,其實one-hot encoding的主要的缺點主要有2個:第一個大家主要到沒有,one-hot encoding表示的方式是非常sparse的,每一個Word都必須要有更vocabulary長度一樣多的元素element,而且這些element絕大多是都是0,這是非常浪費資源的一種方式;第二個問題就更加嚴重了,那就是用one-hot encoding 的方式表示Word的話,那么所用的Word之間都是沒有任何聯系的,任何兩個Word之間的cosin值cos(word1,word2)都是0,這顯然是很不符合咱們的實際情況的,例如實際中cat和dog之間關系總是要比cat和book之間的關系要更加緊密才對啊,可是在one-hot encoding中cos(cat, dog) == cos(cat, book) ==0,表示它們之間的關系都是一樣的,這顯然不符合咱們的實際情況。

  •  Featured representation - word embedding

Word embedding 應該是咱們整個NLP中最最常用的一個技術點了,它的核心思想就是每一個Word都有一些維度,具體有多少維度咱們用戶自己定義,但是這些維度能保證相似的詞匯在這個多維的空間上的值是相似的,例如咱們用5維的空間來表示一個詞,那么cat可能是[1.0, 1.5, 0.0, 6.4, 0.0], dog可能是[0.95, 1.2, 0.11, 5.5, 0.0], book可能的值是[9.5, 0.0, 3.4, 0.3, 6.2]。從前面的幾個值咱們可以很顯然的看出cat和dog在這個五維空間是比較接近的,而他們跟book則在這個五維空間上的距離要遠的多,這也更加符合咱們的實際情況的認知,那么具體這個五維空間的每一個feature是什么,咱們不需要知道,在后面的部分我會介紹2紅算法來計算embedding的。那么下面就接着上面的例子,我畫一個圖片更加方便大家的理解

 

上面的這個圖片就是對咱們上面的例子的一個簡單的embedding的展示,大家現在不必糾結上面這些數據是怎么來的,大家只需要知道embedding的展現形式和意思就行了。還有一個大家也不需要被多維空間這個詞給嚇到了,其實就把它當做是多個features的就行,超過三維的數據咱們肉眼是無法通過形象的圖像展示的,所以你也不用費神在腦子里面想象多維數據是啥樣子了,你就把它看成多個features多個特征就行,至少每一個物體都有很多特性的,例如人有身高,體重,膚色,性別等等等很多的特性。然后咱們還有一個算法就是T-SNE算法可以將咱們多維的數據轉化成2維數據給展示出來,大家稍微知道有這么個東西就行,無需深究。

  • Embedding - Neural Network NLP modeling

首先咱們介紹第一個計算embedding的算法,那就是通過傳統的Neural Network來學習訓練咱們的embedding和neural network本身的參數的。那么咱們來看一下它的具體流程,在正式介紹之前咱們展示一下它的流程圖,然后在來解釋,畢竟這種方式要容易理解的多,咱們的大腦處理圖片的速度還是要比文字快的多滴。。。。。

上面的圖片我不但展示了用DNN的方式來求Embedding的流程並且應用這個embedding來訓練model的流程,同時我還配了一個例子來解釋這個流程。這個過程中,大家一定要注意的一點就是這里的Embedding 即作為這個模型的Input data,同時也是作為這個模型的parameters來不斷學習更新的。 那么咱們現在就來解釋這個模型學習的流程吧,首先第一步將咱們的語言sentence通過encoding的方式轉成sequences, 具體這個過程是如何實現的呢?其實是想根據咱們的語義集(text corpus)生成tokenizer, 然后用這個tokenizer來做encoding的工作,具體的代碼我會在最后的應用部分展示。然后第二步咱們來到咱們的embedding中找到前面sequences相對應的數據,並且將這些數據提出來,這里的embedding咱們根據用戶自定義它有多少個words多少個維度,然后這個embedding會隨機初始化一些數據出來;第三步咱們將咱們前面從embedding中提取出來的數據進行flatten處理,以便於咱們將數據feed到后面的DNN中;最后一步就是咱們的DNN訓練的過程,在這個訓練的過程中,咱們不但會訓練DNN自己的paramets,它同時會訓練並且更新前面從embedding中提取的數據。那么這個流程就是咱們用DNN的方式來計算embedding的方式。上面的I LOVE YOU在這里叫做context words, 用上面的方式來計算並且訓練embedding的時候,咱們的context words的數量一定得是固定的,否則咱們沒辦法flatten咱們的數據feed到同一個neural network(因為同一個neural network的input layer的units是固定的)。同時具體要選擇幾個context words也是隨便用戶自己定義的,但是一旦選定了context words,則后面的context words必須要遵循前面的規則,規則必須一致。例如咱們即可以選擇target的前4個words作為context words, 也可以選擇target前面的2個words作為context words,甚至可以選擇target的后2個數據作為context words。但是一旦選擇了,后面就必須一致。當然了,如果咱們data中的context words的長度不夠,咱們可以通過padded的方式補齊。

  •  Embedding - Skip-Grams

還有一種常用的embedding的算法,那就是應用Skip-Gram算法來計算咱們的embedding和模型。那么到底它是如何工作的呢?首先咱們還是先看一下這個算法的流程圖,然后咱們詳細解釋一下流程哈

 

咱們的skip-gram的算法,首先第一步是咱們在training data(text corpus)中的的sentence中任意選擇一個Word作為context Word;其次在咱們初始化的embedding中找到這個context Word對應的值ec,然后將咱們的e值帶入到咱們的softmax model中,softmax會計算咱們vocabulary所有的詞匯的概率,然后選擇概率最大的那個Word就是咱們根據這個模型選擇出來的target Word。上面是咱們應用skip-Grams的步驟,實際中的softmax model中的參數還有embedding是咱們通過上圖中的Loss函數的gradient descent來不斷的學習出來的。在這個算法中同樣的embedding即作為咱們softmax模型的input data同時也作為咱們softmax模型的參數parameter。這里面的關系容易混淆啊,上圖的softmax模型P(t|c)是咱們定義的模型,這個模型里面的參數和embedding是通過上圖中的Loss函數不斷的gradient descent得來的,咱們的training data是在咱們的text corpus中的每一行sentence中隨機選擇出來的一個context Word和在這個context Word前后一定范圍內隨機選擇的一個target Word。這就是這個Skip-Grams算法的核心,當然啦,如果要實踐這個算法,里面還有很多的細節需要處理的,但是這里面最核心的思想就是上面提到的步驟了。但是這個算法也有一個致命的弱點,那就是,這個算法需要大量的運算,咱們每走一個gradient descent,咱們就得計算出咱們所有的10000個words的值,實際中咱們word可能還遠遠不止10000個,可能是百萬都有可能。

  •  TensorFlow應用之Embedding (Text sentiment analysis)

上面說了半天的理論內容,着實有點無聊,現在咱們來看看如何用TensorFlow來用Embedding吧,雖然上面的理論內容很枯燥無聊,但其實還是很重要的,一來咱們偶爾可以裝B用,二來如果你不理解上面的理論,咱們在應用的時候你連參數都不知道怎么調,你怎么去優化你的模型啊??所以啊,這一塊還是有必要理解一下滴。好了,那咱們就來看一個用TensorFlow應用embedding的例子,假設咱們的需求是判斷大家對一部電影的review是好還是壞。谷歌自帶的dataset中給了咱們這些數據,咱們可以直接下載下來直接用的。這一個例子其實也是咱們的NLP中常用的一個場景叫做text sentiment analysis。好吧, 那咱們開始吧。

第一步:加載咱們的數據

import tensorflow as tf
import tensorflow_datasets as tfds
import numpy as np

imdb,info = tfds.load("imdb_reviews",with_info=True,as_supervised=True)

train_data = imdb["train"]
test_data = imdb["test"]

這一步很簡單,就是直接從咱們的谷歌的tfds中加載movie reviews的數據。

第二步:將dataset從TensorFlow中的數據對象轉成Python list並且分割出features 和 labels。

training_sentences = []
training_labels = []
test_sentences = []
test_labels = []


for s,l in train_data:
    training_sentences.append(str(s.numpy()))
    training_labels.append(l.numpy())
    
for s,l in test_data:
    test_sentences.append(str(s.numpy()))
    test_labels.append(l.numpy())

上面的代碼是遍歷了咱們training dataset和test dataset中的數據,並且把它們加載到Python中的list,同時將咱們數據中的features和labels分開。這一步算是數據准備階段, 接下來就是咱們來配置咱們的tokenizer參數的時候了

第三部:配置tokenizer信息

from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

max_length = 120
trunc_type="post"
oov_tok = "<OOV>"

#initialize a tokenizer
tokenizer = Tokenizer(num_words = vocab_size,oov_token = oov_tok)
#fit the text to create word index, result a dict of the word:index key-values
tokenizer.fit_on_texts(training_sentences)
word_index = tokenizer.word_index

#create a sequences of the training sentences based on the dictionary above(word-index)
training_sequences = tokenizer.texts_to_sequences(training_sentences)
#pad the sequences
training_padded_sequences = pad_sequences(training_sequences,maxlen=max_length,truncating=trunc_type)

#create a sequences of the test sentences based on the dictionary above(word-index)
test_sequences = tokenizer.texts_to_sequences(test_sentences)
#pad the sequences
test_padded_sequences = pad_sequences(test_sequences,maxlen=max_length,truncating=trunc_type)

這一步的主要功能是講咱們上面得到的原始的data(text)轉化成咱們的計算機熟悉的數字格式,從而每一個句子都是一個數字的sequence。其實就是encoding的過程,首先把咱們上面的training_sentences中所有出現的Word都賦予一個數字,這一步是通過fit_on_texts()函數來實現的,這一步咱們生成了一個dict對象word_index, 這個dict將training_sentences中出現的每一個Word(不重復)作為key, 每一個Word都對應一個value(不重復)。接下來第二步就是通過texts_to_sequences()這個函數,將咱們的所有的sentence都根據上面的word_index來一一對應從text轉化成數字的sequence。上面的代碼主要就是這兩個功能,整個過程,咱們稱之為encoding。這里有一個小細節,那就是咱們在配置tokenizer的時候設置了一個oov_tok參數,這個參數是干什么的呢?咱們雖然根據traininig dataset編碼了很多的word, 但是實際中總有一些詞是咱們training dataset中沒有出現過的,那么這種情況下,咱們就需要一個out-of-value (oov)來表示這些未見過的word啦,所以這里咱們就配置了oov_tok = "<oov>", 就是一旦將來遇到了生詞,咱們一致用“<oov>”這個詞表示,並且它在咱們的word_index中也有鍵值對,一般情況下,它個value是1。還有一個細節就是pad_sequences()函數,因為咱們的text的長度是不一樣的,為了保證將來能正確的feed到咱們的DNN中,它們的長度必須一樣長,這時候咱們就得用到pad技術了,他會將咱們所用的text同補充到max_length那么長。

第四步:配置神經網絡和embedding

這一步就是咱們的核心部分了,那就是配置咱們的embedding信息和咱們的DNN網絡

vocab_size = 10000
embedding_dim = 16

#define model structure
model = tf.keras.Sequential([
    
    tf.keras.layers.Embedding(vocab_size,embedding_dim,input_length=max_length),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(64,activation="relu"),
    tf.keras.layers.Dense(1,activation="sigmoid")
    
    ])
model.compile(loss="binary_crossentropy",optimizer="Adam",metrics=["accuracy"])
model.summary()

上面的embedding咱們配置的是一個10000長度,16個維度的embedding,這個embedding里面每一個Word都有16個維度。因為咱們的是一個binary classification的問題,output layer只有一個node,並且activation是sigmoid。通過summary()函數咱們看一下咱們的整個的網絡結構

 

 上面可以完整的看到咱們定義的網絡結構和一些參數。

第五步:train model

咱們既然已經有了復合格式的數據,也定義了咱們的模型,那么接下來咱們就用咱們的數據來訓練咱們的模型了

#training the model
model.fit(
    training_padded_sequences,
    training_labels_final,
    epochs=10,
    validation_data=(test_padded_sequences,test_labels_final)
    )

這一步跟前面章節講個訓練過程一模一樣,也很簡單這里就不細講了。上面五個步驟之后,咱們已經訓練好了咱們模型了,也是咱們在遇到text sentiment analysis這一類問題的主要流程,就是從數據加載,encoding,模型定義和訓練這幾個步驟。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM