1 開始之前:先懂 4 個觀念

結論:整份作業只建立在 4 個觀念上。這 4 個懂了,後面每一步都只是「把觀念寫成程式」。考試也最可能從這裡出題。

為什麼要先學這 4 個:後面每一節都會用到「詞向量」「相似度」「b − a + c」「前後文」這四個詞。先用小例子手算一次,後面看到 19,544 題的正確率才知道它是怎麼來的。

觀念 1:電腦只看得懂數字,所以要把字變成一串數字

電腦不知道 cat 是什麼。它只會做數學。

所以我們幫每個英文字準備一串數字,例如 100 個數字。這串數字叫 詞向量(word embedding)。

可以把這 100 個數字想成這個字在「意思地圖」上的座標。平常的地圖只有 2 個數字(經度、緯度),這張地圖有 100 個數字,所以人畫不出來,但電腦算得出來。(「座標」只是比喻,後面一律叫詞向量。)

把每個字的詞向量收集起來,就是一本字典:查一個字,得到它的詞向量。

觀念 2:詞向量方向越一致,意思越像

一份好的字典,會把 cat(貓)和 dog(狗)放得很近,把 cat 和 truck(卡車)放得很遠。

「多近」用相似度(cosine similarity,餘弦相似度)來量。它看的是兩個詞向量的「方向」有多一致。

相似度意思
接近 1方向幾乎一樣 → 很像
接近 0方向垂直 → 沒什麼關係
負的方向相反(注意:方向相反 ≠ 意思相反。反義詞的相似度可能很高,例如 good/bad 在 Wiki 20% 字典裡是 0.70,In [33],第 11 節)

手算一次相似度(拿紙筆跟著算)

前提:真的詞向量有 100 個數字,算不動。所以這裡假設每個字只有 2 個數字(我自己編的):cat=(3, 4)、dog=(4, 3)、truck=(4, −3)。步驟跟 100 個數字時完全一樣,只是數字少。

⟦IMG:toy_cosine⟧

第 1 小步:乘起來再加總(叫「內積」)。兩個字的第 1 個數字相乘,加上第 2 個數字相乘。

cat 和 dog:  3×4 + 4×3    = 12 + 12  = 24
cat 和 truck:3×4 + 4×(−3) = 12 − 12  = 0

第 2 小步:算每個字的「長度」。兩個數字各自平方、加起來、開根號。

cat:  √(3×3 + 4×4) = √25 = 5
dog:  √(4×4 + 3×3) = √25 = 5
truck:√(4×4 + 3×3) = √25 = 5

第 3 小步:內積 ÷(兩個長度相乘)。

相似度(cat, dog)  = 24 ÷ (5×5) = 0.96  → 很像
相似度(cat, truck)=  0 ÷ (5×5) = 0     → 沒關係

為什麼要除以長度:只想比「方向」,不想讓「數字比較大的字」佔便宜。除掉長度之後,結果一定在 −1~1 之間。

本文說的「近」「最像」,都是指方向(夾角小),不是兩點之間的距離。所以下面手算時,★ 跟 woman 位置不完全一樣,但方向幾乎一樣,相似度就接近 1。

這幾個數字由 make_toy_figures.py 算出來核對過。老師上課講的是同一個公式(W2 02:00:40「兩個向量之間算 cos 就是這個公式」)。

進階:程式怎麼寫
import numpy as np
cat, dog = np.array([3, 4]), np.array([4, 3])
print(cat @ dog / (np.linalg.norm(cat) * np.linalg.norm(dog)))   # 0.96
# gensim 裡直接寫:model.similarity("cat", "dog")

報告第 4 題「找最像的 5 個字」,就是把一個字跟字典裡每個字都算一次相似度,取最高的 5 個。這 5 個字本文叫「鄰居」(只用在這個意思)。

觀念 3:詞向量可以加減,加減代表「關係」

這是整份作業最核心的一點。看這張圖:

man 男人 woman 女人 king 國王 queen 女王 「變成女性」這一步 同一步 「變成皇室」 「變成皇室」

從 man 走到 woman 的那一步(紅色箭頭),跟從 king 走到 queen 的那一步,方向和長度大致一樣(老師原話:「不是這麼 exactly 是一樣的 pattern,但是趨勢非常的 close」,W3 00:32:03)。四個點大約排成一個平行四邊形。

所以只要知道三個點,就能推出第四個點:

queen − king + man ≈ woman
 (b)    (a)    (c)    (d)

白話:「把 king 變成 queen 的那一步」,套到 man 身上,就會走到 woman。這個公式本文叫 b − a + c(論文叫 3CosAdd)。

注意:作業規格 PDF 第 2 頁寫成「King + Queen − Man ≈ Woman」,那是筆誤。正確是 b − a + c(程式模板的提示寫的才對)。

作業的考卷 19,544 題,每一題都是這樣:給 a、b、c,叫電腦算出 d。

手算一次 b − a + c(拿紙筆跟著算)

前提:

⟦IMG:toy_analogy⟧

第 1 小步:做加減,算出一個新的點 ★。公式是 b − a + c,也就是 queen − king + man。兩個數字各自算:

第 1 個數字:3.2 − 1 + 1 = 3.2
第 2 個數字:4.1 − 4 + 1 = 1.1
所以 ★ = (3.2, 1.1)

圖上兩條紅色箭頭幾乎一樣長、一樣方向:「king 變 queen」和「man 變 woman」是同一步。從 man 走同一步,就走到 ★。

第 2 小步:算 ★ 跟每個候選字的相似度。照上面「手算相似度」的三小步做:

候選字① 內積② 長度③ 相似度
woman (3, 1)3.2×3 + 1.1×1 = 10.70★ 3.384;woman 3.16210.70 ÷ (3.384×3.162) = 1.000
girl (3, 0.3)3.2×3 + 1.1×0.3 = 9.93★ 3.384;girl 3.0159.93 ÷ (3.384×3.015) = 0.973
apple (−2, 3)3.2×(−2) + 1.1×3 = −3.10★ 3.384;apple 3.606−3.10 ÷ (3.384×3.606) = −0.254

數字由 make_toy_figures.py 算出,四捨五入到小數點後 2~3 位。woman 的 1.000 是四捨五入後的值,實際比 1 小一點點。

第 3 小步:相似度最高的就是答案。woman 1.000 最高,所以電腦答 woman,答對。

邊界情況 1:答案不能是題目自己的字

king、queen、man 是題目給的字,規定不能拿來當答案,所以第 2 小步只算剩下的字。gensim 的 most_similar 會自動排除它們。

為什麼要排除:★ 是從 man 出發走一小步得到的,所以 ★ 有可能離 man 自己很近。這個玩具例子裡 man 的相似度是 0.899(比 woman 低,沒有搶走第一名);但在真的 100 維字典裡,★ 不會剛好落在 woman 上,題目自己的字就可能排到前面。

邊界情況 2:題目的字不在字典裡

如果 a、b、c 有一個字典裡查不到(叫 OOV,查不到的字),第 1 小步就算不出來。這種題目在作業裡直接算答錯。

真的作業就是把這 3 小步,對 19,544 題每一題做一遍(候選字是字典收的所有字,Wiki 20% 字典約 30 萬個)。girl 0.973 也很接近 woman——在真的字典裡,「很像但不是答案」的字很多,所以不少題的正確答案排在第 2、3 名(第 12 節實驗 ④:前 3 名正確率比第 1 名多 13.14 個百分點)。

觀念 4:詞向量是電腦自己「看前後文」學出來的

沒有人一個一個去設定詞向量。電腦是讀了大量文章(教材)之後,自己算出來的。

它根據一句很有名的話:「看一個字的朋友,就知道它是什麼字。」常常出現在同樣前後文的字,意思通常很像。

例如「我養了一隻__,牠很可愛」,空格可以填貓、狗、兔子。這些字前後文很像,所以詞向量會很近。

這個「讀教材、看前後文、算詞向量」的過程叫 訓練。作業用的方法叫 Word2Vec,裡面又分兩種:

方法它在練習什麼例子
Skip-gram(老師投影片的重點)給中心字,猜前後文會出現哪些字看到「貓」,猜前後可能有「養」「可愛」
CBOW給前後文的字,猜中心字是什麼看到「養了一隻__很可愛」,猜中間是「貓」

練習的過程中,電腦會一直微調每個字的詞向量,讓猜測越來越準。練完之後,這些數字就是詞向量。

所以對你的影響是
字典好不好,取決於兩件事:電腦讀了什麼教材(讀多少、讀什麼種類、怎麼整理),和怎麼學(Skip-gram 或 CBOW、維度、window)。 報告第 2 題(讀多少)、第 3 題(讀什麼種類)、第 1 題(怎麼整理)、第 5 題(怎麼學),全部都是在問這件事。
這個觀念也解釋了詞向量的缺點
電腦學的是「誰出現在相似的前後文」,不是「意思」。good(好)和 bad(壞)意思相反,但前後文很像(「這部電影很__」,推論),Wiki 20% 字典裡兩者相似度 0.70(In [33])。 還有:apple 不管是水果還是公司,都只有一個詞向量。這就是後面幾週要教 BERT(會看整句前後文,給同一個字不同的詞向量)的原因。
考試可能問
① 相似度接近 1、0、負的,各代表什麼?(本節觀念 2 的表)
② 用 b − a + c 答「king : queen = man : ?」,a、b、c 各是哪個字?為什麼要排除這三個字?(本節兩個邊界情況;第 14 節 Q1)
③ 詞向量是怎麼學出來的?(觀念 4;第 14 節 Q3、Q6、Q7、Q8)

2 準備工作:要在哪裡跑、要裝什麼

結論:你有兩個選擇:Google Colab(老師推薦)或自己的電腦(我這次用的)。你的筆電比 Colab 免費版強很多,我建議在自己電腦跑,但交作業時要多附 requirements.txt、報告要寫電腦規格。

兩種做法比一比

Google Colab(免費版)自己的電腦(你的筆電)
要不要安裝不用,開瀏覽器就能用要裝 Python 和套件(下面有指令)
CPU(訓練詞向量只用 CPU)通常只有 2 核心i7-11800H,8 核心 16 執行緒
記憶體約 12 GB(外部知識,依 Colab 免費版一般配置)16 GB(系統顯示 15.7 GB)
斷線風險閒置太久或跑太久會被中斷,畫面上的結果會不見(外部知識)不會
模板指令能不能直接用可以(!wget、!gdown、!cat 都是 Linux 指令)不行,要改成 Python(我已經改好,見第 5 節)
交作業要多做什麼報告寫「Colab」+Python 版本報告寫作業系統、CPU、Python 版本;一定要附 requirements.txt

「Colab 通常只有 2 核心、訓練會慢很多」是我根據 Colab 免費版一般配置推的,這次沒有實際在 Colab 上計時。

顯示卡用不用得到?

用不到。這份作業用的 Gensim 只用 CPU 算。你的 RTX 3060、Colab 的免費 GPU,對這份作業都沒有幫助。

在自己電腦上準備環境(照抄就好)

在作業資料夾打開終端機,一行一行貼:

py -3.12 -m venv .venv
.venv\Scripts\python.exe -m pip install gensim pandas scikit-learn matplotlib tqdm gdown nltk jupyter
.venv\Scripts\python.exe -m jupyter notebook

這三行在做什麼:

  1. 建一個獨立的 Python 環境(.venv 資料夾)。好處是作業用的套件跟電腦裡其他東西分開,不會互相打架。
  2. 裝作業要用的套件。
  3. 打開 Jupyter(跟 Colab 長得很像的筆記本介面,只是在你電腦上跑)。

硬碟要準備多少空間

東西大小
維基百科 11 個壓縮檔6.93 GB(Windows 檔案總管會顯示約 6.45 GB,因為它用 1024 進位)
抽樣出來的 5%、10%、20% 文字檔,加上整理過的版本⟦R:sample_disk⟧
GloVe 字典+論壇教材約 0.4 GB(放在 C:\Users\你\gensim-data)
要小心:照模板「解壓縮+合併」會多吃很多空間
模板的做法是先解壓縮(而且保留壓縮檔),再把 11 個檔合併成一個。同一份教材等於存三份。 我改成「直接讀壓縮檔、邊讀邊抽樣」,不解壓、不合併,結果完全一樣。規定允許改「載入資料」的部分,所以這樣改不扣分。
所以對你的影響是:在自己電腦跑,交作業時要多做兩件事——附 requirements.txt、報告寫電腦規格。這兩件第 13 節都已經做好了。