Word2vec
簡介
- 依照輸入的詞的集合計算出詞與詞之間的距離
- 將詞轉為向量,把對文章內容的處理簡化為向量空間中的向量運算,計算出向量空間上的相似度
- 計算的是 cosine 值(餘弦值),cosine 值越大,代表兩個詞關聯度越高
- CBOW vs. Skip-gram 算法
- CBOW(Continues Bag of Words): 給定上下文,預測 input word
- Skip-gram: 給定 input word,預測上下文
實作
Requirements
在這次的實作中,我們使用的 Python 版本是 3.5.2,另外也會需要以下幾個 package:
- gensim
- jieba
1 | # create virtual environment |
資料前處理
首先,我們需要先將資料進行前處理,在這次的實作中,我們是以 Dcard 的資料來訓練 word2vec model.
資料已經先處理為每行都是一篇文章的內容,將每篇文章進行斷詞,並過濾 stopwords,最後將斷詞後的結果存為檔案以便後續訓練 word2vec model.
1 | # preprocessing.py |
1 | $ python3 preprocessing.py -f './data/data.rec' |
資料處理完之後,會輸出至data/data.rec.out
,檔案內容如下:
1 | 發問 淘寶 新手 付款 集運 疑問 聽 玩 模型 前輩 ... |
每篇文章都被轉換為多個詞的集合,接著我們就可以用這些處理過的資料來訓練 word2vec model.
訓練 word2vec model
處理完資料之後,利用 gensim
的 word2vec
來訓練 word2vec model:
1 | # train.py |
1 | $ python3 train.py -f './data/data.rec.out' -o './data/word2vec.mdl' |
這裡的程式碼最主要其實只有三行 (分別是第11、12和15行),就能夠訓練出 word2vec model 並將 model 儲存。最重要的是第12行: model = word2vec.Word2Vec(sentences, size=300, min_count=15)
,我們先看一下word2vec.Word2Vec()
的原型:
1 | class gensim.models.word2vec.Word2Vec(sentences=None, size=100, alpha=0.025, window=5, \ |
參數說明:
- sentences: 要訓練的句子,可以是 list,對於較大量的訓練資料,建議使用 BrownCorpus, Text8Corpus 或 LineSentence.
- size: 詞向量的維度,預設是 100,較大的 size 會需要更多的訓練資料,也會需要更多的記憶體空間,但是效果會比較好。
- alpha: 機器學習中的學習率,會逐漸收斂到 min_alpha.
- window: 往左右各看幾個字,預設是 5.
- min_count: 忽略出現的次數小於 min_count 的詞
- max_vocab_size: 設定詞向量構建期間的RAM限制,如果詞的總數超過
max_vocab_size
的值,則會去除出現頻率最低的。設為None
表示沒有限制。 - workers: 執行緒數目
- sg: sg=1 表示採用 skip-gram, sg=0 表示採用 CBOW, 預設是 0.
- hs: hs=1 表示採用 hierarchical softmax, hs=0 表示使用 negative sampling, 預設是 0.
- negative: 如果 > 0, 則會採用 negative sampling. 此值表示
noise words
的數量。 - cbow_mean: cbow_mean=0 採用上下文詞向量的總和, cbow_mean=1 採用均值,預設是 1。這個值只有在使用 CBOW 時才有作用。
- hashfxn: hash function 來初始化權重,預設使用 Python 的 hash function.
- iter: 迭代次數,預設是 5.
- trim_rule: 用來設定詞的整理規則,指定哪些詞要被刪除、哪些要保留,預設是 word count <
min_count
的詞會被刪除。 - sorted_vocab: 預設是 1, 在分配 word index 時會依照詞頻做降序排序。
- batch_words: 每次處理的詞的數量。
其中 sentences
是一定要有的參數,其他的可以依照需求再做調整~
如果訓練完 word2vec model 後,在載入 model 或是查詢時出現 MemoryError
的問題,可以試著增加 min_count
,忽略出現次數過少的詞,以減少訓練的詞量,降低記憶體需求。
結果
訓練完之後,來測試一下效果如何:
載入模型
1
2
3from gensim.models import word2vec
model = word2vec.Word2Vec.load('./data/word2vec.mdl')取得前20個相關詞及其機率:
1
similar = model.most_similar(positive=query, topn=20)
執行結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22query: 蔡英文
馬英九 0.7758316397666931
小英 0.7685800194740295
馬總統 0.741024911403656
蔡英文總統 0.7397772073745728
洪秀柱 0.7373905777931213
朱立倫 0.7315630912780762
民進黨政府 0.7311826944351196
民進黨 0.7303115725517273
林全 0.7250531315803528
馬英九總統 0.7208837270736694
總統 0.7105945348739624
宋楚瑜 0.7093351483345032
選前 0.7067139148712158
吳敦義 0.7047908902168274
新政府 0.7000598311424255
賴清德 0.6969730854034424
李登輝 0.6749316453933716
選後 0.6709515452384949
國民黨 0.6695643067359924
綠營 0.6688911914825441
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22query: 珍珠奶茶
珍奶 0.8230817317962646
波霸奶茶 0.7711058855056763
木瓜牛奶 0.7707912921905518
奶綠 0.7704713344573975
芒果冰沙 0.7543411254882812
鮮奶茶 0.7471712231636047
西瓜汁 0.7412415146827698
芋頭牛奶 0.7387706637382507
手搖飲料 0.7384251356124878
水果茶 0.7374613881111145
四季春 0.736596941947937
抹茶拿鐵 0.7361791133880615
綠豆沙 0.7361130714416504
檸檬紅茶 0.7228580713272095
五十嵐 0.7211850881576538
凍檸茶 0.7128199934959412
迷克夏 0.708733320236206
手搖 0.7055209875106812
酪梨牛奶 0.7013069987297058
冬瓜茶 0.70111662149429321
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22query: 阿里山
合歡山 0.8092970848083496
日月潭 0.804085373878479
清境 0.7589331865310669
北海岸 0.7464619278907776
武嶺 0.7462913990020752
擎天崗 0.7406344413757324
清境農場 0.7399024367332458
太平山 0.7287646532058716
忘憂森林 0.7182701826095581
高美 0.7161029577255249
三仙台 0.7141523957252502
奮起湖 0.7141432762145996
七星潭 0.710894763469696
高美濕地 0.7108360528945923
平溪 0.710108757019043
南投 0.7075525522232056
拉拉山 0.7046494483947754
鵝鑾鼻 0.7046091556549072
六十石山 0.7044894099235535
蘇澳 0.6968797445297241取得兩個詞之間的相關度
1
result = model.similarity(word1, word2)
執行結果:
1
2
3
4
5
6
7
8珍珠奶茶, 奶茶
0.698616829611946
蔡英文, 賴清德
0.6969730854034424
電腦, 程式
0.5202557530895322
從以上幾個例子來看,效果還算OK。
當然,我們還可以再想辦法優化模型訓練的效果:
在訓練的過程中,很重要的一部份是斷詞,透過斷詞來決定哪些詞出現在一起的,所以斷詞的效果好,整體訓練結果才會更好。jieba
斷詞其實還有不足的地方,所以也可以試著選擇其他斷詞器,或者是調整辭典中的詞的權重、增加自定義辭典來改善斷詞效果。
另外一部份就是在訓練時的參數調整,如果對於 word2vec 已經很熟悉,也可以試著調整 word2vec model 的參數,讓訓練的效果可以更好~