文章目錄
說在前面:
- 本文提到時,有可能指將一個詞轉換成(稠密)向量這一過程,也可能指轉換的結果,即得到的詞的向量,每個地方的具體含義需要根據上下文來確定。
- 下面的術語在本文中具有相同的含義:,
詞向量
One-Hot Encoding
學習資料
- https://flashgene.com/archives/66661.html
要點
例如詞彙表大小,則用一個維的one-hot向量來表示一個詞,每個詞的one-hot中的位置就對應了該詞在詞彙表的索引。
缺點
- 語義鴻溝:其無法通過詞向量來衡量相關詞之間的距離關係,即這樣的表徵方法無法反映詞之間的相似程度,因爲任意兩個向量的相似度是相同的。例如
- 維度災難:高維情形下將導致數據樣本稀疏,距離計算困難,這對下游模型的負擔是很重的。
Word2Vec
學習資料
- https://zhuanlan.zhihu.com/p/27234078
- https://www.bilibili.com/video/av41393758/?p=2
- https://flashgene.com/archives/66661.html
- https://github.com/iamxpy/nlp-tutorial/tree/master/1-2.Word2Vec
- https://zhuanlan.zhihu.com/p/32965521
- https://github.com/iamxpy/word2vecpy
- https://code.google.com/archive/p/word2vec/
- Word2Vec原始論文
要點
Word2Vec包括Skip-Gram(SG)和CBOW。SG模型需要根據target來預測上下文的詞(即target左右的詞,稱爲context);而CBOW相反,需要根據context來預測target,準確來說,是使用規定窗口範圍內的context的平均(或求和)來預測target。
SG的訓練過程:
當window size爲2時,表示取center的左右各兩個context。那麼從Coupus中的一個句子構造訓練樣本的過程可以圖示爲如下(只演示到target爲fox就停止了)。
CBOW的訓練過程:
這裏需要特別注意SG和CBOW的區別,其實他們的本質區別不在於用context來預測target還是用target來預測context。例如,如果以同樣的句子來構造CBOW的樣本,假設我們不對context取平均(這並不是真正的CBOW!),而是每個context都構造一個<context, target>樣本,那麼target從“The”到“fox”所得到的所有樣本如下圖,並且,我們可以與SG得到的樣本進行對比,發現訓練集幾乎是一樣的,<jumps, brown>, <jumps, fox>等樣本隨着兩個模型的窗口繼續移動也會得到匹配,也就是說從整個corpus來看,用SG和用不對context取平均的“CBOW”得到的訓練集是一樣的,所以SG和“CBOW”是等價的。
其實這一現象在StackOverflow上也有討論:CBOW v.s. skip-gram: why invert context and target words?。
那麼SG的CBOW的區別在哪?沒錯,就是在對context取平均。不信?來看看FastText的官方文檔是怎麼介紹這兩種word2vec模型的。(P.S. FastText由Tomas Mikolov團隊開發,這一團隊正是在2013年提出word2vec的團隊。)
引用鏈接: skipgram versus cbow
FastText provides two models for computing word representations: skipgram and cbow (‘continuous-bag-of-words’).
The skipgram model learns to predict a target word thanks to a nearby word. On the other hand, the cbow model predicts the target word according to its context. The context is represented as a bag of the words contained in a fixed size window around the target word.
Let us illustrate this difference with an example: given the sentence ‘Poets have been mysteriously silent on the subject of cheese’ and the target word ‘silent’, a skipgram model tries to predict the target using a random close-by word, like ‘subject’ or ‘mysteriously’. The cbow model takes all the words in a surrounding window, like {been, mysteriously, on, the}, and uses the sum of their vectors to predict the target. The figure below summarizes this difference with another example.
可以看到,FastText文檔在介紹SG和CBOW時,都介紹爲“根據nearby word/context來預測target word”,看下面的圖,也可以發現這裏講的SG是用context來預測target。是不是作者搞錯了?肯定不是,作者所在團隊就是提出這些模型的團隊,現在在Facebook的AI research團隊,怎麼可能搞錯?實際上,我在前面已經解釋了,用context來預測target和用target來預測context得到的訓練集幾乎沒有區別,所以這篇文章在介紹兩個模型時都直接使用了“用context來預測target”這一語言模型任務。但是SG和CBOW是有區別的,那就是對context取平均這一操作。這一操作會帶來什麼影響呢?
- 訓練的速度不同。從訓練集的樣本數量來說,CBOW的樣本數量比SG樣本數量少得多。假設有n個target,窗口大小爲w(target左右取w個context word),那麼SG的樣本數量接近,而CBOW的樣本數量近似爲.
- 訓練的效果不同。Mikolov的話意譯過來就是:SG適用於相對少量的訓練數據,對於稀有詞的效果更好(可以得到表徵能力很好的embedding)。CBOW比SG的訓練速度快了幾倍,而其常用詞的表徵的效果要比SG好一點。
Skip-gram: works well with small amount of the training data, represents well even rare words or phrases.
CBOW: several times faster to train than the skip-gram, slightly better accuracy for the frequent words
原始Word2Vec的問題以及解決辦法:
- 最後的SoftMax層計算量過大:改用層次Softmax(Hierarchical Softmax)、負採樣(Nagative Sampling)。
- 高頻但意義不大的Stop Word(例如The)充斥訓練樣本:對於我們在訓練原始文本中遇到的每一個單詞,它們按照一定概率保留,保留的概率與單詞的頻率成反相關。
超參數的選擇對Word2Vec的效果影響:
- 對高頻詞進行下采樣(sub-sampling)可以提高精度與速度,其對應的sample參數通常在 到 之間,默認
- 負採樣的參數選擇:對於小規模數據集,選擇5-20個negative words會比較好,對於大規模數據集可以僅選擇2-5個negative words
- 通常來說Embedding維度越高,效果越好,但不是總是這樣
- 窗口大小,SG常使用10左右,而CBOW常使用5左右
負採樣(negative sampling)與分層softmax(hierarchical softmax)
負採樣原理見本小節(後面省略,默認指對應小節的)學習資料1,分層softmax(後稱h-softmax)原理見學習資料5,代碼實現見學習資料6。
要點:
下面討論時,以CBOW爲背景,即我們要根據多個context的embedding的平均作爲輸入,來預測center。
負採樣和分層softmax都是將原來的多分類問題(設類別數爲)轉化爲了個二分類問題,其中遠遠小於。(在負採樣中,是固定的,一般在2~20中取;在h-softmax中,是變化的,平均情況下,)。
我們仍然有兩個參數矩陣,和。就是context的lookup table,即的每一行/列就對應了一個單詞的embedding。而在兩種方法中作用不一樣:在負採樣中是center的lookup table;在h-softmax中,存放的是個二分類器的參數。
負採樣時,對於1個正確的樣本,假設context對應的向量爲,center對應。然後我們採樣得到個(錯誤的)center,與context組成個(錯誤的),然後從中取出center對應的向量,那麼我們可以得到個二分類問題,即和個.
h-softmax中,我們對於個詞彙(類別)根據其在corpus中出現的頻率進行哈夫曼編碼,那麼對應的哈夫曼樹有個葉子結點,分別對應了每一個詞彙,並有個內部結點,對應了個二分類器(每個分類器的參數就是的每行/每列,i.e., h-softmax中的含義不再是center的lookup table)。
例如上圖中的center詞彙對應的哈夫曼編碼爲(假設規定是向左爲1),那麼我們從中得到該條路徑上的3個非葉子結點對應的向量,那麼我們就可以得到3個二分類問題: 。
代碼分析:
'''
下面的代碼以CBOW爲基礎,提供negative sampling和h-softmax兩種訓練方法
代碼中的syn0與syn1分別指的是前文所提到的W和W`
'''
# 計算neu1,即多個context詞彙的embedding取平均
neu1 = np.mean(np.array([syn0[c] for c in context]), axis=0)
assert len(neu1) == dim, 'neu1 and dim do not agree'
# Init neu1e with zeros
neu1e = np.zeros(dim)
# Compute neu1e and update syn1
if neg > 0: # neg訓練時傳入的參數,指的是負樣本個數,大於0代表使用負採樣
# token是真實的center,target是採樣得到的center,一共有(neg+1)個二分類器
classifiers = [(token, 1)] + [(target, 0) for target in table.sample(neg)]
else: # 使用h-softmax
# path是由路徑上的內部結點的編號所組成的list
# 例如給前面例子中y2對應的內部結點編號1、2、4,則path=[1,2,4],後面將作爲W`的索引使用
# code是token(即真實center)的哈夫曼編碼,對應了每個內部結點應該向左還是向右
# 例如前面例子中y2的哈夫曼編碼爲110,則code=[1,1,0],後面將作爲二分類的label使用
classifiers = zip(vocab[token].path, vocab[token].code)
for target, label in classifiers: # 對每個二分類器計算損失並更新syn1(即W`)的參數
# 邏輯斯諦迴歸的前向和反向傳播
z = np.dot(neu1, syn1[target])
p = sigmoid(z)
g = alpha * (label - p)
neu1e += g * syn1[target] # Error to backpropagate to syn0
syn1[target] += g * neu1 # Update syn1
# 更新syn0(即W)的參數
for context_word in context:
syn0[context_word] += neu1e
h-softmax和負採樣的(實驗)效果對比:
- h-softmax對生僻詞的訓練效果更好
- 負採樣對常用詞的效果更好,並且在Embedding維度較低的限制下效果比h-softmax更好
對於 “hierarchical softmax對生僻詞很不友好” 的觀點,我專門寫了一篇博客來反對:hierarchical softmax對生僻詞很不友好?扯淡!
FastText
學習資料
- https://zhuanlan.zhihu.com/p/32965521
- http://albertxiebnu.github.io/fasttext/
- https://blog.csdn.net/feilong_csdn/article/details/88655927
- https://arxiv.org/pdf/1607.04606.pdf (原始論文)
- https://www.kaggle.com/nzw0301/simple-keras-fasttext-val-loss-0-31 (代碼實現)
要點
在word2vec中,我們需要計算target與context(分別記爲和)的相似度score,一般使用內積,即(分別來自兩個lookup table)。
在FastText中,每個詞w都是由字符級的n-gram加上<w>(即自己)來表示的。首先在詞的兩邊加上尖括號“<”和“>”,好處是使得模型能夠從character n-gram中區分出前後綴。另外,每個詞還要加上自身加上尖括號的結果(爲了學習每個詞的表徵)。例如對於where,當時,其對應的character n-grams爲["<wh", “whe”, “her”, “ere”, “re>”],而 where 的Embedding由自身<where>以及所有字符級n-gram的Embedding相加得到。
假設我們由corpus得到的character n-gram加上<word>組成集合,對於內每一個,我們在lookup table都有一個表徵 。那麼對於一個詞,假設其character n-gram加上<w>組成了集合,那麼在FastText中,score的計算公式改爲:
另外,FastText除了訓練詞向量,更重要的一個功能是可以文本分類。
FastText特點小結如下:
1、對於一個詞,將其字符級 n-gram 的Embedding與該詞的Embedding求和作爲原詞的最終Embedding,作用:
- 爲生僻詞生成更好的Embedding,即使一個單詞出現的次數很少,組成該單詞的字符和其他單詞也有共享的部分,而那些字符級n-gram可以通過對常用詞來訓練得很好.
- 爲未登錄詞(OOV)提供更好的Embedding,即使單詞沒有出現在訓練語料庫中,仍然可以從字符級n-gram中構造單詞的詞向量
2、爲了節省內存,對哈希到同一個位置的字符n-gram使用相同的Embedding,哈希函數使用的是FNV函數(具體來說是衍生版本Fowler–Noll–Vo 1a).
3、在分類任務中,使用詞語級別的n-gram,與Text-CNN很類似,都是基於n-gram理論,可以捕捉到詞序信息
Glove
學習資料
- https://blog.csdn.net/u014665013/article/details/79642083
- https://www.bilibili.com/video/av41393758/?p=3
- https://zhuanlan.zhihu.com/p/56382372
要點
在統計共現矩陣之後,對其進行奇異值分解(SVD),得到的左奇異矩陣就是我們想要的Embedding矩陣。但是對一個巨大的共現矩陣進行SVD的代價很大,所以我們想辦法利用神經網絡的方式將共現矩陣“分解”(用神經網絡來擬合共現矩陣中的信息)。
Glove先從corpus統計共現矩陣,然後使用神經網絡來擬合共現矩陣,目標函數如下:
最後我們對於一個詞的target embedding和context embedding,就是它對應的和求和(和來自不同的lookup table)。
權重函數的設計:
- 應該滿足,主要出於兩點考慮。首先,從數值計算的角度來說,當爲0,此時爲負無窮,若(其實需要取極限,沒有定義),則在計算時不用計算的項。其次,更重要的是,從權重函數的含義來看,對於從來沒有共現的和,他們應該不參與到目標函數的計算當中去,所以不計算對應的項也是非常自然的。
- 對於過大的stop word,如果不控制權重,由於長尾效應,其他更有意義的詞將會被忽略。所以應該滿足當大於一個閾值時,不至於過大(例如設爲定值)。
- 在設計時,還要注意的是應該是單調不減函數,因爲我們希望更大的項,對應的權重也越大。
最後的設計如下,論文中的取100,取0.75:
Glove對比Word2Vec
- 訓練方式的不同。Glove在共現矩陣的非零數據上訓練,有效地利用了語料庫的全局統計信息,而Word2Vec是利用語料庫的上下文窗口的數據來訓練。
- Glove僅需要全局統計信息來訓練,所以在訓練時收斂更快,訓練週期較word2vec較短且效果更好。
- Glove可拓展性好,對於很小或很大的corpus都可以有效地訓練;另外,對於限制embedding維度更低的情況,Glove也表現很好。
- 如果單純從是否需要人工標註數據來看,Glove與Word2Vec都是無監督學習。但本質上它們的訓練過程都是有label的,只不過這些label不是人工標註的,而是訓練數據(corpus)本身的內部信息。所以我認爲可以把它們當做特殊的無監督學習。
ELMo、GPT、BERT
學習資料
- https://www.bilibili.com/video/av56235038
- http://jalammar.github.io/illustrated-transformer/
- http://jalammar.github.io/illustrated-bert/
- https://zhuanlan.zhihu.com/p/49271699
- https://zhuanlan.zhihu.com/p/75391062
- https://zhuanlan.zhihu.com/p/56382372
- https://zhuanlan.zhihu.com/p/49271699
- ELMo原始論文
- GPT原始論文
- BERT原始論文
要點
不難發現其實所有的Embedding方式都是Transfer Learning的模式,先在預訓練(pre-training)階段利用語言模型(LM)或其他任務訓練得到詞的representation,然後在下游任務中,只需要將之前訓練好的Embedding Matrix(lookup table)加載到下游任務的Embedding Layer,然後,既可以fix(frozen)Embedding層的參數,也可以將這些參數與下游任務的其他參數一起訓練,即fine-tune的過程。注意,pre-training階段一般是利用LM,可以利用大量無標籤的corpus,即unsupervised的方式;而下游任務一般是supervised的,即一般使用有標籤的corpus。
只不過,之前介紹的Embedding方法有個最大的缺陷就是,它們都只能爲每個詞學習到單個固定的,因此也是上下文無關(context independent)的representation。然而一個單詞,可能有多種詞性或者多種詞義,甚至每種詞性都有多種含義。我們希望得到embedding可以很好地對一詞多義現象進行建模,包括語法( syntax)和語義(semantics)兩方面,即多種詞性、多種語義。
第一個做到這點(併爲大家所熟知)的是ELMo模型,後面相繼出了GPT、BERT、XLNet等模型。這些模型都需要面對兩個難題:
難題一
預訓練階段應該使用哪些tasks或optimization objectives?
目前尚不清楚使用何種task來學習文本的representation在遷移到下游任務時最有效,爲了預訓練模型的通用性,目前大家一般用language model作爲預訓練階段的task
ELMo的task是標準的LM,只不過ELMo訓練了兩個LM—— 一個forward LM
,一個backward LM(在BERT的論文中被稱爲left-to-right LM和right-to-left的LM)。
(圖片來源:A Step-by-Step NLP Guide to Learn ELMo for Extracting Features from Text)
給定一個N個token的序列,forword LM就是給定前個token,預測序列中的後一個token,用公式來表達它對句子分佈的建模如下:
而backward LM類似,只是方向相反,即給定後個token,模型需要預測序列中的前一個token,用公式來表達它對句子分佈的建模如下:
特別需要指出的是,ELMo中,每個LM在預測下一個token(後一個或前一個)時,都沒有利用到句子的另一半段/另一個方向/另一個LM的信息,這一點與BERT很容易混淆,需要注意區分。
GPT的task也是標準的LM,只不過與ELMo的區別有二:
- 只訓練了一個前向的LM
- 特徵提取器使用的是Transformer Decoder。
細節見學習資料。
BERT的task有兩個:
一是Masked LM(MLM),隨機選擇輸入序列中15%的WordPiece(設爲),然後使用這15%的WordPiece的輸出用於預測輸入。另外,爲了緩和pre-training與fine-tuning階段的mismatch(pre-training階段有[MASK]字符,而fine-tuning階段沒有),對於選中的15%,按80%概率將其替換爲特殊字符[MASK],按10%概率將其替換爲一個隨機的token,按10%概率不做任何替換。
二是 Next Sentence Prediction (NSP),在將兩個序列用特殊字符[SEP]拼接起來,然後在開頭加上特殊字符[CLS]表示分類(classification),然後使用[CLS]對應的輸出用於預測這兩個序列是否是相鄰的。
難題二
如何將得到的representation運用/遷移到下游任務中?目前尚無公認最好的方式,其中流行的有兩種策略,分別是feature-based和fine-tuning.
feature-based: 固定預訓練模型的參數,抽取預訓練模型的hidden states作爲下游任務的額外/輔助的特徵(additional / auxiliary features),與下游任務的embedding拼接起來。優點在於非常靈活,幾乎不必改動下游任務的網絡架構,所以適用於所有下游任務。
fine-tuning: 在預訓練模型的適當位置加上分類層(FFNN+Softmax),直接將其作爲下游任務的網絡架構,並將下游任務的數據集做適當的轉換使其符合預訓練模型的輸入方式。優點在於需要train from scratch的參數非常少,所以需要的訓練時間更少,也往往效果更好,特別是下游任務數據集較小時。
feature-based示意圖(ELMo):
(圖片來源(右邊部分經修改):Improving a Sentiment Analyzer using ELMo)
fine-tuning示意圖(GPT與BERT):
下面表格是一個小結。
特徵提取器 | 預訓練階段的任務 | 將得到的representation運用到下游任務的策略 | |
---|---|---|---|
ELMo | 2個單向雙層 LSTM | biLM: forward LM + backward LM | feature-based |
GPT | Transformer Decoder | unidirectional LM | fine-tuning |
BERT | Transformer Encoder | Masked LM + Next Sentence Prediction | fine-tuning |
注意:
- BERT的語言模型是MLM,並不是“用之前看到的詞預測下一個詞”這種語言模型任務,而是需要看到整句話(除了15%被mask的詞),因此需要用Transformer Encoder。
- ELMo沒有使用雙向LSTM,原文指出:We tie the parameters for both the token represen-tation and Softmax layer in the forwardand backward direction while maintaining separate parameters for the LSTMs in each direction
- ELMo並非直接將預訓練得到的biLM的參數固定,而是在應用到具體的任務之前,先用該任務的數據集(如果有label則忽略label)當做LM的語料來fine-tune參數(只需要訓練一個epoch),然後再固定biLM的參數,用於抽取representation。
- GPT以及BERT運用到下游任務的策略是fine-tuning,這與平時所說的fine-tune是有區別的。一般的fine-tune可以譯爲“微調”,其含義參考:遷移學習與fine-tuning有什麼區別?,例如ELMo在用於下游任務時也要fine-tune。而GPT和BERT的fine-tuning其實等價於GPT的論文中task-specific input transformation,專門用於指這種將得到預訓練得到的representation運用到下游任務的策略。
- 在BERT的作者看來(見BERT論文的Introduction部分),ELMo的biLM本質上也是unidirectional language model(單向語言模型),稱之爲“a shallow concatenation of independently trained left-to-right and right-to-left LMs.”,而BERT纔是“deeply bidirectional”的。
句子、文章的表示
BoW、TF-IDF
學習資料
- https://blog.rocuku.cc/bow-tfidf-vsm/
要點
Vector Space Model(VSM),即向量空間模型,使用一個向量表示一個文本。每一維都代表一個詞。如果某個詞出現在了文檔中,那它在向量中的值就非零。有幾種常見方法計算這個值:
- 0 / 1(0 代表這個詞沒有出現,1 代表這個詞出現了)
- 詞頻(見後面 的BoW)
- TF-IDF(見後面 TF-IDF )
BoW
Bag-of-Words(BoW)又叫詞袋模型,用於文檔特徵表示。BoW 忽略文本的語法和語序,用一組無序的單詞來表示這段文本。即 BoW 不會保留單詞在句子裏的順序/位置信息。
TF-IDF
TF-IDF(term frequency–inverse document frequency)是一種統計方法,用以評估一個字詞對於其所在的文檔的重要程度。字詞的重要性隨着它在文檔中出現的次數成正比,但同時會隨着它在語料庫(所有文檔)中出現的頻率成反比。爲了反映這種思想,TF-IDF由TF與IDF相乘得到,TF表示詞頻,IDF表示逆文檔頻率。
LSA、pLSA、LDA
學習資料
- https://www.cnblogs.com/pinard/p/6805861.html (這篇博客其實參考了[2])
- Latent Semantic Indexing (LSI) A Fast Track Tutorial(介紹了LSI的具體計算過程, 包括如何對一篇新的文檔計算其潛在語義空間內的座標)
- 短句歸一化–LSI模型 和 Latent Semantic Analysis(LSA/ LSI)算法簡介 對比了傳統的VSM模型/詞袋模型和LSI模型。
- https://blog.csdn.net/xpy870663266/article/details/102950268 (個人對於truncated SVD的筆記)
Latent Semantic Analysis/Indexing (LSA/ LSI) 對比VSM
常用的VSM文本表示模型中有兩個主要的缺陷:
- 該模型假設所有特徵詞條之間是相互獨立、互不影響的(樸素貝葉斯也是這個思想),即該模型還是基於“詞袋”模型(應該說所有利用VSM模型沒有進行潛在語義分析的算法都是基於“詞袋”假設)。
- 沒有進行特徵降維,特徵維數可能會很高,向量空間可能很大,對存儲和計算資源要求會比較高。
LSI的基本思想是文本中的詞與詞之間不是孤立的,存在着某種潛在的語義關係,通過對樣本數據的統計分析,讓機器自動挖掘出這些潛在的語義關係,並把這些關係表示成計算機可以”理解”的模型。它可以消除詞匹配過程中的同義和多義現象。它可以將傳統的VSM降秩到一個低維的語義空間中,在該語義空間中計算文檔的相似度等。總的說來,LSI就是利用詞的語義關係對VSM模型進行降維,並提高分類的效果。