リムナンテスは愉快な気分

徒然なるままに、言語、数学、音楽、プログラミング、時々人生についての記事を書きます

単語→ID変換

Chainerで機械翻訳 (python) 第7回

私はてっきり、分かち書きされた文章をぶち込めば勝手に全部やってくれるのかと思っていたのですが、どうやら単語ごとにIDを振らねばならぬようで。


このあたりを参考に…
qiita.com
qiita.com
コーパスから単語ーID辞書を作成→コーパス中の文章をID変換
というのを実装していきたいと思います。

collections.defaultdict(lambda: len(enc_dict))

のような感じで空の辞書を作ります。この辞書のkeyからvalueを取り出そうとするとき、keyが存在しなければ、そのkeyとvalueを新たに辞書に加える…らしい。
例えば、

>>> import collections
>>> w2v = collections.defaultdict(lambda: len(w2v))
>>> w2v["foo"]
0
>>> w2v["bar"]
1
>>> w2v["hogefuga"]
2
>>> dict(w2v)
{'hogefuga': 2, 'foo': 0, 'bar': 1}

のような感じで、単語に対して勝手に連番を付与してくれるので非常に楽。
この要領でencode側の言語、decode側の言語、それぞれの辞書を作成します。

enc_dict = collections.defaultdict(lambda: len(enc_dict))
dec_dict = collections.defaultdict(lambda: len(dec_dict))

# default値入力
# <unk> = 0 (unknown)
# <s> = 1 (start of script)
# </s> = 2 (end of script)
enc_dict["<unk>"]
enc_dict["<s>"]
enc_dict["</s>"]
dec_dict["<unk>"]
dec_dict["<s>"]
dec_dict["</s>"]

は未知の単語に対して割り振られます。まあ学習段階で教師データに振ることは無いと思いますがね…
についてはそれぞれ文章開始、文章終了記号として用います。[文章]のように。終了記号(eos)の方はdecodeの終了判定に用いるのですが、開始記号の方はぶっちゃけ要らないような(参照元では入れてたので入れてみた)…どういうつもりで開始記号使ってるんだろう、定数項みたいなやつかな。


というわけで、辞書作成をコーパスデータ加工部に無理やりねじ込みました。

def make_data():
    data = []

    print('making encode dictionary')
    with open(argvs[1], 'r') as f_enc:
        enc_reader = csv.reader(f_enc)
        for enc_row in enc_reader:
            data.append([[1] + [enc_dict[word.lower()] for word in enc_row[0].split()] + [2]])
    output_dict(dict(enc_dict), 'JEC_bs_en_id')

    print('making decode dictionary')
    with open(argvs[2], 'r') as f_dec:
        dec_reader = csv.reader(f_dec)
        ct = 0
        for dec_row in dec_reader:
            data[ct].append([1] + [dec_dict[word] for word in dec_row[0].split()] + [2])
            ct += 1
    output_dict(dict(dec_dict), 'JEC_bs_ja_id')

    return data

辞書を元に単語→ID変換、文章開始記号および終端記号の付加、データのパッキング、辞書の吐き出しまで。
ようやく次回はモデルの学習に入れそう。