Skip to content

[NLP][Python] 使用 FastText 訓練詞向量

Last Updated on 2021-06-22 by Clay

FastText 是由 Facebook AI Research Lab (FAIR) 所開發的『詞嵌入』以及『文本分類』,支援 294 種語言,並且使用類神經網路訓練詞嵌入模型。

基本上 FastText 的演算法是基於以下這兩篇論文:

不過介紹了這麼多,今天我主要的目的是要介紹如何在 Python 中透過 Gensim 套件快速地調用 FastText 訓練一個 Word Embedding 的模型。基本上流程都與 Gensim 中本來訓練 Word2Vec 極度相像。

以下就直接來看程式碼。值得一提的是,由於我之前寫過使用 Gensim 訓練 Word2Vec 模型,所以有部份相同的流程我是直接從那邊抄來的 XDD


安裝 Gensim

首先,如果你的環境裡沒有 Gensim,使用以下指令安裝:

pip3 install gensim

下載 WIKI 語料

這裡以 Wiki 上的中文資料為訓練語料,Wiki 上的資料可是相當優秀的。不僅量多、而且詞彙涵蓋範圍廣,可以應用在許多不同的任務上。

可以從這個網址找到下載處:https://zh.wikipedia.org/wiki/Wikipedia:%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8B%E8%BD%BD

進入之後可以直接選擇一個日期,那是不同時間點的資料備份。

比如說我選擇了 20200101 這個時間點的資料,那麼,我要下載的資料則為:zhwiki-20200101-pages-articles-multistream.xml.bz2

要注意的是,你的日期可能與我不同,不過同樣都是這份檔案。

下載之後不用解壓縮,可以使用 Gensim 裡的工具直接提取文章。


WikiCorpus

WikiCorpus 是 Gensim 裡面的一個模組,專門用於清理 Wiki 資料庫中語料不必要的標籤,使其恢復成乾淨的文本。

# coding: utf-8
"""
Extracted the content in the wiki_database
"""
from gensim.corpora import WikiCorpus


# Load data
wiki_corpus = WikiCorpus('../data/zhwiki-latest-pages-articles-multistream.xml.bz2', dictionary={})


# Save data
with open('wiki_text.txt', 'w', encoding='utf-8') as f:
    print('Start to preprocess.')
    for times, text in enumerate(wiki_corpus.get_texts()):
        f.write(' '.join(text)+'\n')

        if (times+1) % 10000 == 0:
            print(times+1)



順帶一提,WikiCorpus() 函式當中的路徑為我下載的語料資料,你的名稱可能與我不同、也需要對應到你下載的路徑。

儲存之後的效果應如下:


斷詞

『斷詞』這項工作指的是文本分成以『詞』為單位的句子。斷詞的工具有很多種,基本上可以參考我之前寫過的:

如果想要對繁體中文斷詞效果最好,首推 CKIP;如果是要斷詞速度的話,那非 Jieba 莫屬。在這裡以 Jieba 示範。

(註:Wiki 的資料當中許多地方是簡繁混雜的,可以考慮使用 OpenCC 這項工具來轉換。詳細的作法可以參閱我之前撰寫過的《中文繁簡轉換的便利工具 —— OpenCC》

# coding: utf-8
"""
Tokenize
"""
import jieba
from opencc import OpenCC


# Initial
cc = OpenCC('s2t')


# Tokenize
with open('wiki_text_seg.txt', 'w', encoding='utf-8') as new_f:
    with open('wiki_text.txt', 'r', encoding='utf-8') as f:
        for data in f:
            data = cc.convert(data)
            data = jieba.cut(data)
            data = [word for word in data if word != ' ']
            data = ' '.join(data)

            new_f.write(data)


斷詞結果展示如下:

歐幾


西元前
三世
紀的
古希臘
數學家
現在

認為

幾何
之父
此畫
為拉斐爾

作品
雅典
學院
數學

利用

最後,終於來到呼叫 FastText 來訓練模型了。


使用 FastText 訓練模型

# coding: utf-8
from gensim.models import word2vec, fasttext


# Settings
seed = 666
sg = 0
window_size = 10
vector_size = 100
min_count = 1
workers = 8
epochs = 5
batch_words = 10000


# Train
train_data = word2vec.LineSentence('wiki_text_seg.txt')
model = fasttext.FastText(
    train_data,
    min_count=min_count,
    size=vector_size,
    workers=workers,
    iter=epochs,
    window=window_size,
    sg=sg,
    seed=seed,
    batch_words=batch_words,
)


model.save('fasttext.model')



這裡也解釋一下模型中各個參數的意義:

  • seed: 亂數種子
  • sg: Word2Vec 有兩種算法,CBOW 以及 Skip-gram,這裡選擇了訓練比較快的 CBOW
  • window_size: 周圍詞彙要看多少範圍
  • size: 轉成向量的維度
  • min_count: 詞頻少於 min_count 之詞彙不會參與訓練
  • workers: 訓練的並行數量
  • iter: 訓練的迭代次數
  • batch_words:每次給予多少詞彙量訓練

訓練結束以後,我將模型儲存為 "fasttext.model"。


測試模型效果

# coding: utf-8
"""
Test the w2v model
"""
from gensim.models import word2vec


# Load the model
model = word2vec.Word2Vec.load('models/fasttext.model')


# Test
print(model['生物'].shape)

for item in model.most_similar('生物'):
    print(item)

model.save('fasttext.model')



Output:

(100,)
('若好', 0.9359757900238037)
('身半', 0.9298930764198303)
('過金', 0.9281899929046631)
('低等生物', 0.9252755641937256)
('腐生物', 0.9232699275016785)
('過金魅', 0.9228056073188782)
('生物能', 0.9225305914878845)
('捉酸蟲', 0.9221773743629456)
('非生物', 0.9185526371002197)
('過金貝', 0.9147799015045166)

不知道是不是我的錯覺,我覺得 Gensim 訓練 Word2Vec 模型感覺效果比較好。


References


Read More

2 thoughts on “[NLP][Python] 使用 FastText 訓練詞向量”

Leave a Reply