word2vec + Juman/KNP で日本語Wikipediaモデルを作る

 日本語Wikipediaから、mecabを使ってword2vecでモデルを作る手法は、多くの記事に書いてありますが、Juman + KNP の基本句を利用してモデルを作る場合、ほとんど参考になる記事がなかったので、僕が作ったモデルを元にまとめていきます。
 

作り方

 日本語Wikipediaは予め wget して、WikiExtractorで前処理をして1つのtxtファイル(wiki_all.txt)にしておきます。
日本語版WikipediaのデータからWord2Vec用データをつくる(Mac対応) - Qiita

wiki_all.txtをそのままpyknpを利用して基本句の区切りで別ファイルに書き出すことは可能なのですが、これはかなり時間がかかる(数十日かかる計算でした)ので、並列処理させる必要がありました。

 並列処理させるために、まずwiki_all.txtを、split を使って複数のtxtに分割します。以下の例では297000行ごとに分割しています。

$ split -l 297000 -d --additional-suffix .txt wiki_all.txt ./tmp/wiki-

 そうすると、/tmp 以下に分割された分割txtファイルが出来上がるので、Linux の &(アンパサンド) を利用して、バックグランドジョブとして動かします。
 pythonの実行時引数にtxtのファイル番号を与えます。上の split の方法だと0でパディングする必要があるので注意してください。

#!/bin/bash

array=()
for i in `seq 0 50`; do
  zero_padding_i=`printf %02d ${i}`
  array+=(${zero_padding_i})
done

for num in ${array[@]}; do
    echo "wiki-${num}を実行"
    python knp_kihonku.py ${num} &
done


 実行するpythonのソース(knp_kihonku.py)は以下です。jumanpp を True にしておきます。
 このプログラムは、mecabの下のコマンドと同じことをやっています。

$ mecab -Owakati wiki_all.txt -o wiki_all_wakati.txt

 シェルスクリプトを使わなくとも、multiprocessingを使って改善したいところです。

from pyknp import KNP
import sys

txt_number = sys.argv[1]
f = open(f"./tmp/wiki-{txt_number}.txt", "r")
fw = open(f"./tmp_kihonku/wiki-kihonku-{txt_number}.txt", "w")

original_lines = f.readlines()
f.close()

knp = KNP(jumanpp=True)
for line in original_lines:
    line = line.replace("\n", "")
    sentense_lines = line.split("。")

    # 1行が長いとKNPがparseできないため、"。"で文を区切って、1文ごとに処理する
    for s in sentense_lines:
       # parseするとき稀にエラーが起きる場合があるため、例外処理をしておく
        try:
            result = knp.parse(s)
        except:
            continue

        # 1行に基本句区切りにした1文を書き込む
        for i, tag in enumerate(result.tag_list()):
            kihonku = "".join(mrph.midasi for mrph in tag.mrph_list())
            if i != len(result.tag_list())-1:
                fw.write(str(kihonku) + " ")
            else:
                fw.write(str(kihonku))

        fw.write("\n")

fw.close()


 50分割しても、およそ2日かかりました...
途中でプロセスを kill したいときは以下を実行。

$ ps aux | grep -e "python knp_kihonku.py" -e "knp" | grep -v grep | awk '{ print "kill -9", $2}' | sh

 /tmp_kihonku 以下に分割してできたファイル類をソートして、1つのtxtに結合させます。

$ cat `find ./tmp_kihonku -name 'wiki-kihonku-*.txt' | sort` > wiki-kihonku-all.txt


 ここまで出来たら、もう完成したようなものです。
gensimのword2vecで wiki_all_kihonku.txtを学習させます。ここでは、w2v_model というディレクトリにモデルを保存します。

from gensim.models import word2vec

sentences = word2vec.LineSentence("wiki-kihonku-all.txt")

print("word2vec 学習中")
model = word2vec.Word2Vec(sentences,
                          sg=1,
                          vector_size=200,
                          min_count=3,
                          window=10,
                          hs=1,
                          negative=0)

model.save("./w2v_model/wiki_kihonku_w2v.model")

モデルの評価

 最後に学習し終えたword2vecのモデルをテストしてみます。
ここでは、引数に渡した単語の類似単語を表示させてみます。

from gensim.models import word2vec
import sys

model = word2vec.Word2Vec.load("./w2v_model/wiki_kihonku_w2v.model")
results = model.wv.most_similar(positive=sys.argv[1], topn=10)

for result in results:
    print(result[0], result[1])

 引数に単語を入力して実行してみます。

$ python w2v_test.py 日本
着任まで. 0.6389426589012146
書紀. 0.6318142414093018
「日本 0.6283102631568909
(理事)。 0.610068142414093
バックギャモン 0.5828203558921814
国内. 0.5793983340263367
(にっぽん・ 0.5629969835281372
海驢。 0.56174635887146
ノハム 0.5569989681243896
インディアカ 0.5541244149208069

$ python w2v_test.py 乃木坂
乃木坂460.6801380515098572
けやき坂 0.6473163962364197
乃木坂46から 0.6271274089813232
欅坂 0.6226529479026794
AKB48の 0.6149648427963257
AKB48 0.611319124698638946は、 0.6041278839111328
AKB」 0.5939387679100037
キヨトの 0.5900636315345764
SUPER☆ 0.5880207419395447

 結果の通り、似ている単語も多く出ていますが、基本句区切りだと単語の区切りが微妙な結果となりました。
 そのため、word2vecでモデルを作りたい場合、基本句にする必要がない限りは、形態素の区切りで作った方がいいと思いました。

参考にしたページ

zenn.dev

ZOZOインターンがとても良かった

 2020年12月に10日間ほどZOZOテクノロジーズのインターンに参加してきました。参加してから、かなり間があいてしまいましたが、とてもいいインターンだったので、ここで記事にしていきたいと思います。

tech.zozo.com

応募する経緯

 インターンでインフラを勉強してみたいなと思い、色々探していたらZOZOのインターンを見つけたのがきっかけです。応募したのは「ユーザーフレンドリーな配信システムの構築、基盤のリプレイス」というコースです。いま上のリンクを見たらもうなくなってますね。また夏?に向けてインターンのページ自体が変わるかもしれません。

 9月下旬ぐらいにES(50文字程度に自由に書くタイプ)を提出し、10月上旬に面接をした記憶があります。面接官の人数が僕の中で過去最高で、結構緊張しました。その後合格をいただき、12月頭からオンラインで参加することになりました。
 あと内定承諾書の表紙が月面のイラストでした。

やったこと

 大人の事情で詳しくは書けませんが 、インフラを中心にAWSOSSのDigdagとかを触っていき、コースのタイトルにも書いてあるとおり、既存サービスのリプレイスを行いました。
 今まで僕は個人でLambdaやEC2などのAWSサービスを少し触ってきましたが、ガッツリ業務で触ったことがなかったので、CloudFormationの書き方や基本的なインフラ構成など、とても勉強になりました。
 業務はフルリモートで、いいスペックのMacBookProが届きます。

 またインターン中に中間発表と最終発表の2回プレゼンする機会があり、最終日には懇親会がありました。


良かった点

 このインターンに参加して良かったことは、技術を学べたこと以外にも多いです。

開発チームのdiscordに参加して作業できる。
 そのため、他の社員さんがどのような業務を進めているのかインターン生でも聞くことがき、リモートでしたが、オフィスで働いている感をすごい感じました。

多くの社員さんや他のインターン生と交流がある。
 ランチの時間に、色々な部署の社員の方や、ちょうど同じタイミングでインターンに参加していた方と話す機会がありました。

日程を自由に調整できる。
 たしか80時間以上90時間以下に収める必要があり、きっちり2週間ではないので、ゼミのある日はお休みしたり、午後から参加したりと、柔軟に日程を調整できました。

エンジニアとしての働き方を学べた。
 業務時間外にもインプットをされている方が多かったです。会社の技術ブログを書いたり、ランチ時に技術をアウトプット・共有するような文化があり、僕もインプット→アウトプットのライフサイクルを実践できるようにしてきたいです。

最終日の懇親会セットが豪華。
 ZOZOビールを飲めます!幕張で作っているらしいです。
他にも高級ポテトチップスなどのおつまみが届きます!!

最後に

 自分が知らないことを学べる上に、2週間でお給料20万円です!
今は載っているコースが少ないですが、今後時期によってはたくさん出ていると思うので、興味のあるコースがあればぜひ応募してみてください〜