今夜は昨夜に引き続き、題名のとおりのことを実施します。
qiitaにも記事が多くあって、やりつくされているけど、ウワン的には再整理していきたいと思います。
ほぼ参考のとおり進めますが、備忘録としてなるべく丁寧に具体的に記載しようと思います。
【参考】
・FacebookのfastTextでFastに単語の分散表現を獲得する
必要なツールのインストール
$ sudo apt install make
$ sudo apt install g++
fasttextのインストール
$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText
$ make
c++ -pthread -std=c++11 -march=native -O3 -funroll-loops -DNDEBUG -c src/args.cc
...
c++ -pthread -std=c++11 -march=native -O3 -funroll-loops -DNDEBUG -c src/fasttext.cc
c++ -pthread -std=c++11 -march=native -O3 -funroll-loops -DNDEBUG args.o autotune.o matrix.o dictionary.o loss.o productquantizer.o densematrix.o quantmatrix.o vector.o model.o utils.o meter.o fasttext.o src/main.cc -o fasttext
wikipediaのダウンロード
attardi/wikiextractor
まず、Wikiextracor.pyという展開ツールを上記サイトから、以下のとおりgitします。
$ git clone https://github.com/attardi/wikiextractor.git
次に、Wikipediaの dump データは https://dumps.wikimedia.org/jawiki/latest/ にあるので,このページから以下をダウンロードします。
jawiki-latest-pages-articles.xml.bz2 02-Sep-2019 17:31 2930998407
そして、先ほどのwikiextractorでディレクトリに500MBずつのファイルに展開します。今回は記事116万ページ分6個のファイルができました。
$ python3 wikiextractor/WikiExtractor.py -b 500M -o path/to/cprpus jawiki-latest-pages-articles.xml.bz2
...
INFO: Finished 7-process extraction of 1164622 articles in 1158.8s (1005.1 art/s)
INFO: total of page: 1679026, total of articl page: 1164622; total of used articl page: 1164622
これら6個のファイルを以下のように1ファイルに合体します。
抽出されたテキストデータを1つのテキストファイルにまとめます。
$ cd ./path/to/corpus/AA
$ cat wiki_00 wiki_01 wiki_02 wiki_03 wiki_04 wiki_05 >wiki
次に合体したファイルをmecabにより、分かち書きして出力します。辞書は昨夜のmecab-ipadic-neologdを使います。
$ mecab -O wakati -d /usr/share/mecab/dic/mecab-ipadic-neologd wiki -o wiki_wakati
input-buffer overflow. The line is split. use -b #SIZE option.
input-buffer overflow. The line is split. use -b #SIZE option.
...
fasttext skipgramで学習
最初は、次元指定せずにやってみました。学習したmodelのサイズから100次元なようです。
ファイルが大きいので、300次元でやりました。学習は1時間40分程度かかりました。
$ ./fasttext skipgram -input ../wiki_wakati -output model300 -dim 300
Read 567M words
Number of words: 1011294
Number of labels: 0
Progress: 58.9% words/sec/thread: 39389 lr: 0.020538 avg.loss: 0.362351 ETA: 0h41m 4s
Progress: 100.0% words/sec/thread: 39451 lr: 0.000000 avg.loss: 0.215725 ETA: 0h 0m 0s
類似単語を出力する
上記参考と同じように類似単語を出力してみます。
from gensim.models import FastText
model=FastText.load_fasttext_format("model.bin")
print(model.most_similar("リンゴ"))
デフォルトで学習したものの結果は以下のとおりです。
ちょっと、リンゴ成分が少ない気がします。
$ python3 ex_fasttext_.py model.bin 1,595,207kB
[('イチゴ', 0.8332647085189819),
('トマト', 0.8174118399620056),
('ホロムイイチゴ', 0.8127106428146362),
('サクランボ', 0.8120944499969482),
('キャベツ', 0.8119571208953857),
('キュウリ', 0.8038774728775024),
('レタス', 0.801289439201355),
('木イチゴ', 0.7995303273200989),
('りんご', 0.7988823056221008),
('果物', 0.7899028062820435)]
300次元で学習したものは以下のとおりです。
リンゴに近いという意味ではこちらはいい感じの並びになっています。
$ python3 ex_fasttext_.py model300.bin 4,738,854kB
[('リンゴ酢', 0.7259324789047241),
('りんご', 0.7181535959243774),
('リンゴワイン', 0.6998193264007568),
('リンゴー', 0.6919084787368774),
('リンゴジュース', 0.6816540956497192),
('イチゴ', 0.6684622764587402),
('イヌリンゴ', 0.6634740233421326),
('リンゴ並木', 0.6623485684394836),
('果物', 0.6577243804931641),
('サクランボ', 0.6575568914413452)]
次に参考ではpython eval.py EXILEで類似度の高い単語が並んでいますが、そんなことはできないので、以下のように簡単なプログラムを書いてやってみました。
※ちなみに、現在提供されているeval.pyはファイル読み込みのアプリになっていてこういうことはできません
from gensim.models import FastText
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('model', type=str)
parser.add_argument('word', type=str)
args = parser.parse_args()
model=FastText.load_fasttext_format(args.model)
print(model.most_similar(args.word))
結果は以下のとおりになりました。
これは結構まともな結果になりました。
$ python3 word_eval.py model300.bin EXILE
[('EXILES', 0.8910697102546692),
('EXILE魂', 0.8796107172966003),
('GLAY×EXILE', 0.8737531900405884),
('週刊EXILE', 0.8262338638305664),
('月刊EXILE', 0.7968215942382812),
('劇団EXILE', 0.7787322998046875),
('MAKIDAI', 0.7554136514663696),
('ATSUSHI', 0.7457683086395264),
('TRIBE', 0.7340785264968872),
('EXI', 0.728649914264679)]
次の例がpython eval.py EXILE --negativeって、これもできないので、以下のコードを書きました。
from gensim.models import FastText
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('model', type=str)
parser.add_argument('--positive','-p', type=str, required=False, default='')
parser.add_argument('--negative','-n', type=str, required=False, default='')
args = parser.parse_args()
model=FastText.load_fasttext_format(args.model)
print(model.most_similar(positive=args.positive,negative=args.negative))
これで、一応以下のような結果が得られました。
しかし、どうも意味わかりません。
$ python3 word_eval.py model300.bin -n EXILE
[('寚', 0.11694395542144775),
('時東', 0.0812937468290329),
('永嶋', 0.07949072122573853),
('風伯', 0.07428240031003952),
('田牛', 0.06561749428510666),
('褞袍', 0.05880854278802872),
('いは', 0.05830223113298416),
('定村', 0.05788616091012955),
('邦助', 0.05730722099542618),
('目丸', 0.05564088374376297)]
まとめ
・WikipediaのArticlesを学習した
・学習したモデルを使って類似語を抽出してみた
・Negativeはなんとなくうまく抽出できなかったようだ
・学習精度を上げたいと思う
・やはり、この手のものは以下をやってみたいと思う
「フランス」-「パリ」+「東京」=「日本」
「男性-女性」を「おじ」や「王」に足すと、「おば」や「女王」になる