機器學習-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。

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

    上面的圖片是不是一目瞭然了什麼是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的。那麼下面就接著上面的例子,我畫一個圖片更加方便大家的理解

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

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

    • Embedding - Neural Network NLP modeling

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

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

    上面的圖片我不但展示了用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和模型。那麼到底它是如何工作的呢?首先咱們還是先看一下這個算法的流程圖,然後咱們詳細解釋一下流程哈

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

    咱們的skip-gram的算法,首先第一步是咱們在training data(text corpus)中的的sentence中任意選擇一個Word作為context Word;其次在咱們初始化的embedding中找到這個context Word對應的值e c ,然後將咱們的e c 值帶入到咱們的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。好吧, 那咱們開始吧。

    第一步:加載咱們的數據

    <code>import tensorflow as tfimport tensorflow_datasets as tfdsimport numpy as npimdb,info = tfds.load("imdb_reviews",with_info=True,as_supervised=True)train_data = imdb["train"]test_data = imdb["test"]/<code>

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

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

    <code>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())/<code>

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

    第三部:配置tokenizer信息

    <code>from tensorflow.keras.preprocessing.text import Tokenizerfrom tensorflow.keras.preprocessing.sequence import pad_sequencesmax_length = 120trunc_type="post"oov_tok = ""#initialize a tokenizertokenizer = Tokenizer(num_words = vocab_size,oov_token = oov_tok)#fit the text to create word index, result a dict of the word:index key-valuestokenizer.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 sequencestraining_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 sequencestest_padded_sequences = pad_sequences(test_sequences,maxlen=max_length,truncating=trunc_type)/<code>

    這一步的主要功能是講咱們上面得到的原始的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 = "", 就是一旦將來遇到了生詞,咱們一致用“”這個詞表示,並且它在咱們的word_index中也有鍵值對,一般情況下,它個value是1。還有一個細節就是pad_sequences()函數,因為咱們的text的長度是不一樣的,為了保證將來能正確的feed到咱們的DNN中,它們的長度必須一樣長,這時候咱們就得用到pad技術了,他會將咱們所用的text同補充到max_length那麼長。

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

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

    <code>vocab_size = 10000embedding_dim = 16#define model structuremodel = 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()/<code>

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

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

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

    第五步:train model

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

    <code>#training the modelmodel.fit(    training_padded_sequences,    training_labels_final,    epochs=10,    validation_data=(test_padded_sequences,test_labels_final)    )/<code>

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


    分享到:


    相關文章: