藏字閣

閱讀時間約 3 分鐘

1289 字

這篇文章會介紹怎麼下載維基語料,然後訓練中文跟英文的 word embedding,所有程式碼都會在 Github 上面(連結)。整個下載加上訓練的時間也是很久,所以我也附上了預訓練好的 embedding。預訓練好的連結在這裡:中文 Word2Vec中文 FastText英文 Word2Vec英文 FastText

Word embedding 做的事情是將每個詞投影到空間中,讓語意相近的詞在空間上也是相近的。怎麼做到的呢?假設一個詞的意思可以被他在文章中的上下文解釋,於是我們可以讓句子中相近的詞在空間中也相近,而不在同一個句子裡的詞把他們在空間中的距離拉遠就可以做到。FastText 比起 Word2vec 多考慮了所謂 “subword” 的資訊,以英文來說,有些字根字首是有意義的,那多考慮這些資訊可以讓一些比較少見的字可以靠字根字首推敲出他的意思,讓學出來的 embedding 效果更好。詳細的數學就不在這邊解釋了,我們就來看程式碼吧!

python train.py --model word2vec --lang zh --output data/zh_wiki_word2vec_300.txt

執行上面的程式會最自動下載中文維基,然後訓練 Word2vec,把結果存到 data/zh_wiki_word2vec_300.txt

哪裡下載維基語料?

這邊可以看到各個語言的維基百科備份狀況,這邊可以看英文有哪些日期的可以下載,選 lastest 就是最新的,裡面一堆檔案我們要抓的是 enwiki-latest-pages-articles-multistream.xml.bz2 這邊我用 Python requests 下載檔案,搭配 tqdm 可以看下載進度。注意這邊 2019 年 2 月下載的版本,英文的 wikidump 大概 16GB,中文的大概 1.7GB。 在執行 train.py 的時候,想訓練中文的就下參數 --lang zh,英文就下參數 --lang en

處理語料

from gensim.corpora.wikicorpus import WikiCorpus

class WikiSentences:
    def __init__(self, wiki_dump_path, lang):
        logging.info('Parsing wiki corpus')
        self.wiki = WikiCorpus(wiki_dump_path)
        self.lang = lang

    def __iter__(self):
        for sentence in self.wiki.get_texts():
            if self.lang == 'zh':
                yield list(jieba.cut(''.join(sentence), cut_all=False))
            else:
                yield list(sentence)

這邊用 gensim 提供的 function 來處理維基語料。__iter__ 是為了後面訓練模型的時候需要 iterator 跑過 WikiCorpus 裡面的每一句話。中文的話會需要用 jieba 處理斷詞。因為中文不像英文每個詞都是用空白分隔,所以需要把一句話的詞分開。像是「今天星期一」會斷成「今天」「星期一」兩個詞。英文的話就直接回傳 list(sentence) 就好了。 我使用的機器 CPU 是 Intel i5-8400,有 32G RAM 。 Constructor 跑完英文維基大概一百分鐘,中文維基大概要九分鐘。

訓練模型

import wiki as w

from gensim.models.fasttext import FastText
from gensim.models.word2vec import Word2Vec

wiki_sentences = w.WikiSentences(WIKIXML.format(lang=args.lang), args.lang)

if args.model == 'word2vec':
    model = Word2Vec(wiki_sentences, sg=1, hs=1, size=args.size, workers=12, iter=5, min_count=10)
elif args.model == 'fasttext':
    model = FastText(wiki_sentences, sg=1, hs=1, size=args.size, workers=12, iter=5, min_count=10)

訓練模型用 gensim 提供的 Word2Vec 跟 FastText 就可以了。size 是最後學出來的 embedding 有多少維,iter 是訓練幾個 iteration, min_count 是出現次數多少次的自我們覺得太少,要將它忽略。

以 Word2Vec 來看英文維基大概要訓練 22 小時,中文大概訓練 4 小時。FastText 的話英文大概訓練 33 小時,中文大概訓練 7 個小時。如果覺得太久的話可以調低 iteration 數,但可能效果會差一點。

實驗結果

python demo.py --lang zh --output data/zh_wiki_word2vec_300.txt

python demo.py --lang zh --output data/zh_wiki_fasttext_300.txt

python demo.py --lang zh --output data/cc.zh.300.vec

Facebook 釋出的中文 FastText embedding,可以在這裡下載

相似度的分數是 cosine 相似度。因為 FastText 多考慮的 subword 的資訊,所以以「太陽」為例的話,相似的詞都包含「太陽」兩個字,但 Word2Vec 就比較沒有。哪個比較好就看需求囉。至於出現「風太陽」、「表太陽」這種詞是因為斷詞的部份沒有處理好,可以從那邊下手解決這個問題。

這個是中文 Word2vec 用 PCA 降到二維的結果,因為 matplotlib 顯示中文上有點麻煩這邊就把他翻譯英文,但座標點還是用中文學出來的資料。可以看到國家跟首都彼此的相對關係是一致的,而且亞洲國家彼此聚在一起,歐洲國家彼此聚在一起。FastText 的結果也類似就不貼上來了。

參考資料

https://github.com/LasseRegin/gensim-word2vec-model/blob/master/train.py
http://zake7749.github.io/2016/08/28/word2vec-with-gensim/

comments powered by Disqus

最新文章

分類

標籤