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

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

モデルの学習と試験

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


バグとの闘いの末、無事に学習まで漕ぎ着けました…
さて、第6回で準備しておいたコーパスを食わせてモデルを学習させましょう。

とりあえず使用したコーパス京都大学の「日英中基本文データ」の英、日。
日英中基本文データ - KUROHASHI-KAWAHARA LAB
文章数だいたい5000、語彙数だいたい5750(英)、6500(日)くらい。
埋め込み層300、隠れ層150、バッチサイズ256で学習させました。流石に教師データが少ないので60世代くらいやってみた。


で、実際に学習したモデルを使って試しに翻訳してみようと思うのですが、forwardを少々改修した以下のコードを使います。

# coding:utf-8

import numpy as np
from seq2seq import Seq2Seq
from chainer import Variable, serializers
import sys, os, csv

sd = os.path.dirname(__file__)
sys.path.append(sd)

argvs = sys.argv
argc = len(argvs)

print(argvs)
print(argc)
if(argc != 4):
    print("usage: python train.py [model] [enc_dict] [dec_dict]")
    quit()


def inport_dict(filename):
    indict = {}
    with open('%s'%(filename), 'r') as fd:
        reader = csv.reader(fd)
        for row in reader:
            indict.update({row[0]:int(row[1])})
    return indict

def translate(enc_words, model, ARR, batch_size):
    # modelの勾配をリセット
    model.reset()
    # 発話リスト内の単語をVariable型に変更
    # enc_words = Variable(ARR.array([[-1]*(256-len(enc_words)) + enc_words], dtype='int32'))
    enc_words = [Variable(ARR.array([word], dtype='int32')) for word in enc_words]
    # print(enc_words)
    # エンコードの計算
    model.encode(enc_words)
    # <eos>をデコーダーに読み込ませる?
    # eos = Variable(ARR.array([1 for _ in range(batch_size)], dtype='int32'))
    eos = Variable(ARR.array([1], dtype='int32'))

    y1 = eos
    dec_words = []
    while len(dec_words)<50:
        # 1単語ずつデコードする
        # print(y1, "1")
        y2 = model.decode(y1)
        # print(y2, "5")
        y2 = y2.data.argmax(1)[0]
        dec_words.append(y2)
        # print(y2, "6")
        if(y2 == 2):
            break
        # y1 = Variable(ARR.array([y2 for _ in range(batch_size)], dtype='int32'))
        y1 = Variable(ARR.array([y2], dtype='int32'))

    return dec_words


# 辞書の読み込み
enc_dict = inport_dict(argvs[2])
dec_dict = inport_dict(argvs[3])
out_dict = dict([(v, k) for k, v in dec_dict.items()])


input_words = '0'
while(1):
    input_words = raw_input('入力 > ')

    if(input_words == 'q'):
        quit()

    # 分かち書き
    input_words = input_words.split()
    # 単語id変換
    enc_words = []
    for item in input_words:
        enc_words.append(enc_dict[item])

    # print(enc_words)

    # こいつらの意味があるかはちとわからん
    VOCAB_SIZE = 8192
    EMBED_SIZE = 300
    HIDDEN_SIZE = 150
    BATCH_SIZE = 1

    # モデルの読み込み
    model = Seq2Seq(vocab_size=VOCAB_SIZE,
                    embed_size=EMBED_SIZE,
                    hidden_size=HIDDEN_SIZE,
                    batch_size=BATCH_SIZE)
    serializers.load_npz(argvs[1], model)

    dec_words = translate(enc_words, model, np, BATCH_SIZE)
    sys.stdout.write('出力 > ')
    outputs = [unicode(out_dict[a], "utf-8") for a in dec_words]
    for a in range(0, len(outputs)):
        sys.stdout.write(outputs[a].encode('utf-8') + ' ')
    print('')

いろいろあってpython2系で書いてしまった…unicode周りがまじでめんどくさいことに…
モデルの読み込みは serializers.load_npz() でやります。先に model の実体(Seq2Seq)を忘れずに作っておくように。
なお実際に翻訳するときは1文入力→1文出力なので、BATCH_SIZEは1です。他は全部学習時の値と同じ。

元の教師データに入ってる文章を試しに入力してみましょうか。
"I am in love with my sister."→「僕が妹に恋をする。」となったら成功。私は姉萌えです。
結果、

入力 > i am in love with my sister .
1 > </s> 
2 > 彼 が が の を し ます 。 </s> 
3 > 彼 が X に は の を し ます 。 </s> 
4 > 彼 が X に 、 、 X を し ます 。 </s> 
5 > 彼 が X を し ます 。 </s> 
6 > 彼 が X を 見 た 。 </s> 
7 > 彼 が X を 見 た 。 </s> 
8 > X が 、 X に は 、 思わず の 声 を 行い ます 。 </s> 
9 > X が 、 私 の 人 を し ます 。 </s> 
10 > それ が X を し ます 。 </s> 
11 > 私 は 、 その 人 の 人 を 紹介 し ます 。 </s> 
12 > 私 は 、 その 人 の 人 を 紹介 し ます 。 </s> 
13 > 私 は 、 その 情報 を 見 た 。 </s> 
14 > それ が 、 自分 の 人 を 紹介 し ます 。 </s> 
15 > 私 は X に は 、 思わず 思わず 顔 を かけ た 。 </s> 
16 > 私 は 、 その 情報 を 推進 し て い ます 。 </s> 
17 > 私 は 、 その 情報 を 推進 し ます 。 </s> 
18 > 私 は 、 その 情報 を 使用 し て い ます 。 </s> 
19 > 私 は 、 その 旨 を 聞か た 。 </s> 
20 > 私 は 、 その 旨 を 使っ た 。 </s> 
21 > 私 は 、 その 旨 を 使っ た 。 </s> 
22 > 私 は 、 その 旨 を 出し て いる 。 </s> 
23 > 私 は 、 初めて 多く の 人 の 名前 を 見る 。 </s> 
24 > その よう な 人 が 、 私 に は 有る 。 </s> 
25 > 私 は 、 初めて 多く の 人 の 名前 を 見る 。 </s> 
26 > 私 は 初めて 関係 を た 。 </s> 
27 > 彼 が 思わず 窓 の 家 に 行く 。 </s> 
28 > 私 は 、 初めて 乗っ を 出し て いる 。 </s> 
29 > 私 は 初めて 関係 の 仕事 を 使い ます 。 </s> 
30 > すぐ に 海 が 必要 だ 。 </s> 
31 > 私 は 初めて 関係 の 仕事 を 使い ます 。 </s> 
32 > すぐ に 元 の 機能 が 必要 だ 。 </s> 
33 > すぐ に 元 の 機能 が 必要 だ 。 </s> 
34 > すぐ に 相手 を 辞め ない 。 </s> 
35 > お 届け の 方 に は いつも 頭 の 方 が 良い 。 </s> 
36 > 彼 が ゆっくり と 自転車 を 交わし た 。 </s> 
37 > すぐ に 元 の 機能 が 低下 し まし た 。 </s> 
38 > お 届け の 方 から 、 思わず 感嘆 の 声 が 有る 。 </s> 
39 > お 届け の 方 から お 届け の 結果 を 頂き ます 。 </s> 
40 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
41 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
42 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
43 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
44 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
45 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
46 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
47 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
48 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
49 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
50 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
51 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
52 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
53 > お 届け まで に 多少 お 時間 を 頂き ます 。 </s> 
54 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
55 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
56 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
57 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
58 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
59 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 
60 > お 届け まで に 多少 日数 を 頂き ます 。 </s> 

うーんなんか変なところに収束したなあ…
他の文でもやってみる。

入力 > he will carefully open his pocket .
1 > </s> 
2 > 彼 が が の を し ます 。 </s> 
3 > 彼 が X に は の を し ます 。 </s> 
4 > 彼 が X に 、 、 X を し ます 。 </s> 
5 > 彼 が X を し ます 。 </s> 
6 > 彼 が X を 見 た 。 </s> 
7 > 彼 が X を 見 た 。 </s> 
8 > 彼 が X を そのまま し た 。 </s> 
9 > 彼 が X を そのまま し ます 。 </s> 
10 > 彼 が X を そのまま し ます 。 </s> 
11 > 彼 が X を そのまま し ます 。 </s> 
12 > 彼 が X を そのまま し ます 。 </s> 
13 > 彼 が X を そのまま し ます 。 </s> 
14 > 彼 が X を そのまま し ます 。 </s> 
15 > 彼 が X を そのまま し ます 。 </s> 
16 > 彼 が X を そのまま し ます 。 </s> 
17 > 彼 が X を そのまま し ます 。 </s> 
18 > 彼 が すぐ に 、 自分 の 姿 を 見る 。 </s> 
19 > 彼 が すぐ に 、 自分 の 姿 を 見る 。 </s> 
20 > 彼 が すぐ に 、 自分 の 姿 を 見る 。 </s> 
21 > 彼 が すぐ に 、 自分 の 姿 を 思い出し た 。 </s> 
22 > 彼 が すぐ に 、 自分 の 姿 を 思い出し た 。 </s> 
23 > 彼 が 一緒 に 、 ゆっくり と 顔 を 上げる 。 </s> 
24 > 彼 が すぐ に 、 自分 の 姿 を 思い出し た 。 </s> 
25 > 彼 が すぐ に 、 自分 の 姿 を 思い出し た 。 </s> 
26 > 彼 が 思わず 窓 の 曲 を 見る 。 </s> 
27 > 彼 が 思わず 窓 の 曲 を 見 た 。 </s> 
28 > 彼 が すぐ に 家 に 入っ た 。 </s> 
29 > 彼 が すぐ に 海 に 入っ た 。 </s> 
30 > 彼 が 一緒 に 海 に 入っ た 。 </s> 
31 > 彼 が 初めて 名 を 自分 で 書く 。 </s> 
32 > 彼 が すぐ に 担任 の 効果 を 感じ ます 。 </s> 
33 > 彼 が 初めて 名 を 自分 に する 。 </s> 
34 > 彼 が 初めて 名 を た 。 </s> 
35 > 彼 が 初めて 名 を 超える 。 </s> 
36 > 彼 が 初めて 名 を 超える 。 </s> 
37 > 彼 が 初めて 同期 の た 。 </s> 
38 > 彼 が 初めて 近く の 世界 を 買っ た 。 </s> 
39 > 彼 が 初めて 近く の 世界 を 上げ た 。 </s> 
40 > 彼 が 初めて 後ろ に 直接 られ まし た 。 </s> 
41 > 彼 が 初めて 世界 を 選ぶ 。 </s> 
42 > 彼 が 初めて ビッグ まし た 。 </s> 
43 > 彼 が 初めて 後ろ から 直接 で ご飯 を かけ た 。 </s> 
44 > 彼 が 初めて 同期 を 一 人 で 書く 。 </s> 
45 > 彼 が 再び バス で システム を 行う 。 </s> 
46 > 彼 が 初めて 成功 を 2 枚 し まし た 。 </s> 
47 > 彼 が この 日 の 準備 を 見る 。 </s> 
48 > 彼 が 初めて 成功 を 2 枚 し まし た 。 </s> 
49 > 彼 が 初めて 成功 を 2 枚 し まし た 。 </s> 
50 > 彼 が 初めて 近く の 世界 に 行き まし た 。 </s> 
51 > 彼 が 初めて 近く の 世界 に 行き まし た 。 </s> 
52 > 彼 が 初めて 近く の 世界 に 行き まし た 。 </s> 
53 > 彼 が 初めて 成功 を ゆっくり と まし た 。 </s> 
54 > 彼 が 初めて 近く の 世界 に 行き まし た 。 </s> 
55 > 彼 が 初めて 近く の 世界 に 行き まし た 。 </s> 
56 > 彼 が 初めて 馬 に 乗り まし た 。 </s> 
57 > 彼 が バンド の 夜 を 選ぶ 。 </s> 
58 > 彼 が 初めて 近く の 世界 に 行き まし た 。 </s> 
59 > 彼 が 初めて 近く の 世界 に 行き まし た 。 </s> 
60 > 彼 が しっかり と 一緒 に 風呂 に 自分 の ページ を 作る 。 </s> 

んー収束してない感。どう考えても層が厚すぎる。初めてっていうのがcarefullyの誤訳かはたまたopenの誤訳か。
heだけしかまともに訳せてない。圧倒的教師データの少なさ(と質)。ちょっとこいつは改修しないとだめですね。

まだattentionとか作ってないし、精度上げるのは今後の課題か。

あとキリバス語のコーパスを作りたい。