在介紹各種不明覺厲(雖然不是很明白,但是聽起來很厲害)的模型之前,要先講講這個詞向量 (Word Vectors)。詞向量的目的,是要讓電腦可以讀懂人類的文字,不管是英文的 「The cat is cute」 或是中文的「那隻貓好可愛」,到底要怎麼轉換成電腦可以理解、方便運算的數學形式呢?
這邊先介紹兩種經典的將文字轉換成向量的方法: one-hot encoding
與 Word2Vec
One-hot Encoding
One-hot encoding 的概念很單純,舉個中文的例子來說明大家應該很容易就懂了。
如果我們希望電腦處理的只有這兩個句子:「我養了一隻貓」,「這隻貓很可愛」,總共需要處理的詞只有「我」、「養」、「了」、「一」、「隻」、「貓」、「這」、「很」、「可愛」。
接下來,我們可以建立一個只有這些詞的字典,這個字典共有九個詞,於是我們可以把它轉換成只有九維的向量,這個向量在代表每個詞時,只有一個維度為 1 其餘為 0,這個方法,就是 one-hot encoding 了。
我 = [1 0 0 0 0 0 0 0 0]
養 = [0 1 0 0 0 0 0 0 0]
了 = [0 0 1 0 0 0 0 0 0]
...
補充說明一下,在這系列文章講到「字」時,指的是一個個的中文字,例如「很」、「可」、「愛」,而詞指的是一個或多個中文字組成,具有完整意思的文字單位,例如「很」、「可愛」,在做詞向量時,中文大多會以「詞」為單位,而非以「字」為單位。
以英文來說就更明顯了, 「The cat is cute 」的 「The」、「cat」、「is」、「cute」就是詞 (word),「t」、「h」、「e」就是字 (character)。而英文因為詞之間有空格容易分詞,中文的話就需要如結巴或是中研院釋出的 ckiptagger 等工具來幫忙進行分詞。
介紹完 one-hot encoding 後,大家應該可以很直觀的想像,詞向量的維度會隨字典的大小增加而增加,而這個向量含有的資訊密度是相當低的。另外,每個向量兩兩之間的內積皆為 0 ,也就是說我們無法從這些詞向量中得知詞與詞之間的關係。
Word Embedding
為了改善 one-hot encoding 的種種缺點,發展出了一套稱為 Word Embedding
的學問。 Word embedding 的目的是希望把原本資訊密度低、維度高的向量,改成資訊密度高、維度少(實務上會高於 50 維,但比 one-hot encoding 的方式少得多)的向量來代表一個詞。
這個低維度的向量空間與空間中的詞向量有著一個特性,當詞與詞的意思越相近,他們在向量空間中就會越接近、兩者的夾角會越小。至於判斷詞與詞意思相近的方式,其背後的核心概念可以用一句話來說明:
"You shall know a word by the company it keeps" (J. R. Firth 1957:11)
也就是說,你可以透過一個詞的上下文來理解這個詞的意思。更具體一點來說,當兩個詞常出現在相似的上下文中,那麼這兩個詞的兩個詞向量,在向量空間中會是接近的,由下圖 word embedding 的例子應該可以更明白這個意思。
圖片出處: 李宏毅教授 Word Embedding 課程
(若想知道更多 one-hot encoding 到 word embedding 中間的各種模型與演進,推薦大家看李宏毅教授 Word Embedding 課程以及 Stanford NLP with DL word vectors 課程)
Word2Vec
Word2Vec 則是學習 word embedding 的一套經典模型,這個模型在 2013 年由 Google 的 Tomas Mikolov 等人提出。這個模型值得一提的是,他不是讀完一次大量文本就得到最後的詞向量,而是迭代的讀了一次又一次,逐漸將模型中的詞向量更新,以趨近最佳結果。
Word2Vec 中又有兩種稍微不同的模型: CBOW 與 Skip-gram,簡單來說,CBOW 透過上下文 (context words) 來預測中間的詞 (center word) ,而 Skip-gram 是希望利用中間的詞去預測上下文。
圖片出處:Efficient Estimation of Word Representations in Vector Space
以 CBOW 為例,假設我們只看這個詞前後兩個詞 (window size = 2) ,從上下文計算得到中間的詞的機率。也就是對文本中所有位置的 t ,給定 w(t-2), w(t-1), w(t+1), w(t+2) 去算 w(t) 的機率為何。每次迭代不斷調整詞的向量,使得得到的機率越大越好。
Likelihood(t)
= P(w(t)|w(t-2)) * P(w(t)|w(t-1)) * P(w(t)|w(t+1)) * P(w(t)|w(t+2))
Skip-gram 則是相反,由中間詞計算得到上下文的機率,也就是給定 w(t) 去算 w(t-2), w(t-1), w(t+1), w(t+2) 的機率。
Likelihood(t)
= P(w(t-2)|w(t)) * P(w(t-1)|w(t)) * P(w(t+1)|w(t)) * P(w(t+2)|w(t))
以上大致介紹完了 CBOW 與 Skip-gram 的原理,下面我會講更多 Word2Vec 如何更新向量的數學,如果有興趣的人可以繼續往下讀。如果想要直接實作,了解以上概念其實就差不多了,現在的工具大多都幫你把數學包得好好的,可以參考 gensim-word2vec 這個工具直接進行實作。
==以下數學多,慎入==
延續剛剛提到的機率,以 Skip-gram 為例,可以把它寫成下面的 L(θ) ,θ 表示所有我們需要最佳化的變數,也就是函式的參數。將 L(θ) 取 log 後除以 T 作平均,轉換成數學上較易計算的另一個函式 J(θ)。我們的目標是使 L(θ) 越大越好,等同於使 J(θ) 越小越好。
圖片出處: Stanford NLP with DL word vectors 課程
首先,我們要計算 P(w(t+j)|w(t);θ) ,也可以寫成給予中間詞得到上下文的詞的機率 P(o|c),這個機率可以用下圖的第一個式子代表,其中 u, v 皆為詞向量。
若眼尖的人可以發現,這個式子其實就是在對詞向量內積後的值作 softmax ,將其轉換成我們要的機率分佈。
圖片出處: Stanford NLP with DL word vectors 課程
當我們得到 J(θ) 的數學式後,便可以利用 chain rule 計算其微分,以 gradient descent 的方式更新詞向量,至於 gradient descent 又是另一個主題了,有興趣的人可以直接參考 李宏毅教授 gradient descent 課程 。
以上,我們終於介紹完了近代 NLP 的基礎 - Word Vectors ,接下來可以開心的來看不明覺厲的各種模型了!