CBOW 和 Skip-Gram

CBOW 和 Skip-Gram

本文地址:blog.lucien.ink/archives/501
參考文章:(二)通俗易懂理解——Skip-gram和CBOW算法原理

Word2Vec 是從大量文本語料中以無監督的方式學習語義知識的一種模型,它被大量地用在 NLP 中。其本質是將所有詞嵌入一個高維空間,使得語義上相似的詞在該空間內的距離很近。

Embedding 是一個映射,將詞從原先所屬的空間映射到新的多維空間中,也就是把詞從原先所在空間嵌入到一個新的空間中去。

一般地,一個詞原先所在空間的維度要大於嵌入的空間的維度,所以形象地稱之爲“嵌入”。

本文介紹的 CBOW 和 Skip-Gram 是生成 Embedding 矩陣比較著名的兩種無監督訓練方法。

1. 詞的表示

定義一個只有兩句話的數據集 SS

  1. Hello World
  2. Hello Machine learning

那麼數據集 SS 的詞典就是 ["hello", "world", "machine", "learning"],規定其對應的下標爲 [1, 2, 3, 4]

對每個詞進行 One-Hot 編碼:

Word One Hot Vector
hello [1, 0, 0, 0]
world [0, 1, 0, 0]
machine [0, 0, 1, 0]
learning [0, 0, 0, 1]

可以看到,在 Embedding 之前,數據集 SS 的詞向量空間的維度是 4 維。而對於更大的數據集來說,一般 Embedding 之前的維度會高達 10410 ^ 4 維甚至更多,通過 Embedding 可以將每個詞嵌入至低維空間中(比如 300 維)。

2. 詞嵌入

爲了書寫方便,將 1×N1 \times N 的矩陣成爲 NN 維向量。

假設我們要將數據集 SS 中的每個詞嵌入一個 2 維空間。

我們定義一個神經網絡,輸入層的 shape[1, 4],和每個單詞的 One Hot Vector 的維度一致;Embedding 層的 shape[4, 2];輸出層的 shape[2, 4]

最後的輸出結果爲一個 shape[1, 4] 的 Matrix,也就是一個 4 維的 Vector。

圖 2

其中,One Hot Vector 和 Embedding Layer 做矩陣乘法之後得到的 2 維向量就是嵌入後的詞向量。

3. 僞代碼

在給出僞代碼之前,先定義兩個函數。

3.1 one_hot(x)

  1. x 是一個單詞時,那麼 one_hot(x) 就是單詞 x 對應的 One Hot Vector。
  2. x 是一個句子時,那麼 one_hot(x) 就是這個句子中每個單詞的 One Hot Vector 的加和。

也就是說,第一句話的 One Hot Vector 是:[1, 1, 0, 0],第二句話的 One Hot Vector 是:[1, 0, 1, 1]

3.2 fit(x, y)

類似 keras 中的 Model.fit() 函數,在本文特指對第 2 節中定義的神經網絡進行監督訓練,其中 Embedding Layer 和 Output Layer 是 Trainable 的。

3.3 CBOW

CBOW 的理念就是用中心詞的上下文去預測中心詞。

舉個例子,對於句子 Hello Machine learning 來說,使用 CBOW 時的 Training Dataset 爲:

[
    [["machine", "learning"], "hello"],  # 中心詞爲 "hello"
    [["hello", "learning"], "machine"],  # 中心詞爲 "machine"
    [["hello", "machine"], "learning"]  # 中心詞爲 "learning"
]

僞代碼:

for sentence in dataset_s:
    for word in sentence:
        input_data = one_hot(sentence) - one_hot(word)
        label = one_hot(word)

        fit(x=input_data, y=label)

假設有 NN 個句子,平均每個句子有 MM 個單詞,那麼 CBOW 的複雜度爲 O(NM)O(NM)

3.4 Skip-Gram

Skip-Gram 的理念就是用中心詞去預測中心詞的上下文。

舉個例子,對於句子 Hello Machine learning 來說,使用 Skip-Gram 時的 Training Dataset 爲:

[
    ["hello", "machine"],  # 中心詞爲 "hello"
    ["hello", "learning"],  # 中心詞爲 "hello"
    ["machine", "hello"],  # 中心詞爲 "machine"
    ["machine", "learning"],  # 中心詞爲 "machine"
    ["learning", "hello"],  # 中心詞爲 "learning"
    ["learning", "machine"]  # 中心詞爲 "learning"
]

僞代碼:

for sentence in dataset_s:
    for i, word in enumerate(sentence):
        for j, target_word in enumerate(sentence):
            if i == j:
                continue
            input_data = one_hot(word)
            label = one_hot(target_word)

            fit(x=input_data, y=label)

假設有 NN 個句子,平均每個句子有 MM 個單詞,那麼樸素的 Skip-Gram 的複雜度爲 O(NM2)O(NM ^ 2)

3.4.1 複雜度優化

3.4.1.1 引入 window_size

引入 window_size 的目的就是縮短中心詞周圍的上下文,減少 fit 的次數。

舉個例子,對於句子 See you next time 來說,令 window_size = 1,使用 Skip-Gram 時的 Training Dataset 爲:

[
    ["see", "you"],  # 中心詞爲 "see"
    ["you", "see"],  # 中心詞爲 "you"
    ["you", "next"],  # 中心詞爲 "you"
    ["next", "you"],  # 中心詞爲 "next"
    ["next", "time"],  # 中心詞爲 "next"
    ["time", "next"]  # 中心詞爲 "time"
]

僞代碼:

規定:

  1. len(sentence)sentence 中單詞的數量。
  2. sentence[i]sentence 中的第 i 的單詞,下標從 0 開始。
for sentence in dataset_s:
    for i, word in enumerate(sentence):
        for j in range(
            max(0, i - window_size),
            min(len(sentence), i + window_size)
        ):
            if i == j:
                continue
            input_data = one_hot(word)
            label = one_hot(sentence[i])

            fit(x=input_data, y=label)

假設有 NN 個句子,平均每個句子有 MM 個單詞,記 window_size 的值爲 KK,那麼引入 window_size 的 Skip-Gram 的複雜度爲 O(NMK)O(NMK)

3.4.1.2 引入負採樣

摘自文章:理解 Word2Vec 之 Skip-Gram 模型,稍作修改和整理。

訓練一個神經網絡意味着要輸入訓練樣本並且不斷調整神經元的權重,從而不斷提高對目標的準確預測。每當神經網絡經過一個訓練樣本的訓練,它的權重就會進行一次調整。

正如我們上面所討論的,詞典的大小決定了我們的 Skip-Gram 神經網絡將會擁有大規模的權重矩陣,所有的這些權重需要通過我們數以億計的訓練樣本來進行調整,這是非常消耗計算資源的,並且實際中訓練起來會非常慢。

負採樣(Negative Sampling)解決了這個問題,它是用來提高訓練速度並且改善所得到詞向量的質量的一種方法。不同於原本每個訓練樣本更新所有的權重,負採樣每次讓一個訓練樣本僅僅更新一小部分的權重,這樣就會降低梯度下降過程中的計算量。

當我們用訓練樣本 {x: "hello",y: "world"} 來訓練我們的神經網絡時,"hello""world" 都是經過 One Hot 編碼的。當我們的詞典大小爲 10410 ^ 4 時,在輸出層,我們期望對應 "world" 單詞的那個神經元結點輸出 1,其餘 9999 個都應該輸出 0。在這裏,這 9999 個我們期望輸出爲 0 的神經元結點所對應的單詞我們稱爲 Negative Word。

當使用負採樣時,我們將隨機選擇一小部分的 Negative Words(比如選 5 個 Negative Words)來更新對應的權重。當然,我們也會對我們的 Positive Word 進行權重更新(在我們上面的例子中,這個單詞指的是 "world")。

在論文中,作者指出指出對於小規模數據集,選擇 5-20 個 Negative Words 會比較好,對於大規模數據集可以僅選擇 2-5 個 Negative Words。

舉個例子,假設詞典大小爲 10410 ^ 4,Embedding 空間的維度爲 300300,那麼輸出層權重矩陣的 shape 便爲 [300, 10000],節點數量爲 300×104=3×106300 \times 10 ^ 4 = 3 \times 10 ^ 6 個。

如果使用了負採樣的方法我們僅僅去更新我們的 Positive Word 的和我們選擇的其他 5 個 Negative Words 所對應的權重,共計 6 個神經元,相當於每次只更新 300×6=1800300 \times 6 = 1800 個節點的權重。

如此一來,相比不使用 Negative Sampling 時只計算了 300×6300×104×100%=0.06%\frac{ 300 \times 6 }{ 300 \times 10 ^ 4} \times 100\% = 0.06\% 的權重,這樣一來計算效率就可以大幅度提高。

4. 對 Embedding 層的解釋

在對上述神經網絡訓練完畢後,得到一個 shape[4, 2] 的 Embedding Layer,記 Embedding Layer 的權重矩陣爲 WW,即 WW 是一個 4×24 \times 2 的矩陣,第 i 行對應了詞典中第 i 個詞的詞向量。

4.1 爲什麼

Skip-Gram 時,對於第 i 個詞來說,輸入的 One Hot Vector 裏只有第 i 維是 1,其餘都是 0,這樣一來,在反向傳播時 WW 中只有第 ii 行的權重會被更新,其它行的權重都在前向傳播時被 One Hot Vector 裏的 0 Mask 掉了。

CBOW 同理,反向傳播時會更新上下文裏所有的詞對應的權重。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章