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

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

Chainerでseq2seq構築

Chainerで機械翻訳 (python)の第2回

ChainerでSeq2SeqのEncoder、Decoderを作るの続き。

EncoderとDecoderを合体させてSeq2Seqを作る。

大枠はこんな感じ。

# coding: utf-8

import numpy as np
from chainer import Chain
import chainer.functions as F
import chainer.links as L
from encoder import LSTM_Encoder
from decoder import LSTM_Decoder

class Seq2Seq(Chain):
    def __init__():
        super(Seq2Seq).__init__()
        with self.init_scope:

    def encode():

    def decode():

    def reset():

encoderとdecoderのインスタンス作成。その他変数の初期化をする。
ミニバッチって何だろうと思ったけど、ランダムなn個のデータから損失を計算して学習するやつのことらしいですね。

news.mynavi.jp

ここによると、ミニバッチの損失関数(評価関数?)は、
 \displaystyle L(t_{1:n}, x{1:n}; w) = \frac{1}{n} \sum_{i=1}^{n} L(t_{i}, x_{i}; w)

CUDAは導入していない気がするので、普通にnumpyで計算してもらう。

# coding: utf-8

import numpy as np
from chainer import Chain
import chainer.functions as F
import chainer.links as L
from encoder import LSTM_Encoder
from decoder import LSTM_Decoder

class Seq2Seq(Chain):
    def __init__(self, vocab_size, embed_size, hidden_size, batch_size):
        """
        初期化
        vocab_size: 語彙数
        embed_size: 単語ベクトルのサイズ
        hidden_size:中間ベクトルのサイズ
        batch_size: ミニバッチのサイズ
        """
        super(Seq2Seq,self).__init__()
        with self.init_scope:
            # encoder, decoderのインスタンス化
            encoder = LSTM_Encoder(vocab_size, embed_size, hidden_size)
            decoder = LSTM_Decoder(vocab_size, embed_size, hidden_size)
        self.vocab_size = vocab_size
        self.embed_size = embed_size
        self.hidden_size = hidden_size
        self.batch_size = batch_size
        self.ARR = np

    def encode():
        """
        Encoder計算部分
        words:  単語が記録されたリスト
        """
        #         

    def decode():

    def reset():

これで初期化部分は完成。残りを作る。


encodeについて。
chainer.Variableというやつを使って内部メモリと中間ベクトルの初期化をするようで。

chainer.Variable — Chainer 3.4.0 documentation

Array with a structure to keep track of computation.

計算過程を保存できるってことかね。

decodeとresetもそんな感じで組んでいく。
勾配の初期化はchainer.Chain.zerograds()

# coding: utf-8

import numpy as np
from chainer import Chain, Variable
import chainer.functions as F
import chainer.links as L
from encoder import LSTM_Encoder
from decoder import LSTM_Decoder

class Seq2Seq(Chain):
    def __init__(self, vocab_size, embed_size, hidden_size, batch_size):
        """
        初期化
        vocab_size: 語彙数
        embed_size: 単語ベクトルのサイズ
        hidden_size:中間ベクトルのサイズ
        batch_size: ミニバッチのサイズ
        """
        super(Seq2Seq, self).__init__()
        with self.init_scope:
            # encoder, decoderのインスタンス化
            encoder = LSTM_Encoder(vocab_size, embed_size, hidden_size)
            decoder = LSTM_Decoder(vocab_size, embed_size, hidden_size)
        self.vocab_size = vocab_size
        self.embed_size = embed_size
        self.hidden_size = hidden_size
        self.batch_size = batch_size
        self.ARR = np

    def encode(self, words):
        """
        Encoder計算部分
        words:  単語が記録されたリスト(入力)
        """
        # 内部メモリ、中間ベクトルの初期化
        c = Variable(self.ARR.zeros((self.batch_size, self.hidden_size), dtype='float32'))
        h = Variable(self.ARR.zeros((self.batch_size, self.hidden_size), dtype='float32'))

        # エンコーダーに単語を順番に読み込ませる
        for w in words:
            c, h = self.encoder(w, c, h)

        # 中間ベクトルをインスタンス変数にして、デコーダーに引継ぎ
        self.h = h

        # 内部メモリは初期化
        self.c = Variable(self.ARR.zeros((self.batch_size, self.hidden_size), dtype='float32'))

    def decode(self, w):
        """
        Decoder計算部分
        w:  単語
        return: 単語数サイズのベクトルを出力
        """
        t, self.c, self.h = self.decoder(w, self.c, self.h)
        return t

    def reset(self):
        """
        中間ベクトルh、内部メモリc、勾配の初期化
        """
        self.h = Variable(self.ARR.zeros((self.batch_size, self.hidden_size), dtype='float32'))
        self.c = Variable(self.ARR.zeros((self.batch_size, self.hidden_size), dtype='float32'))
        self.zerograds()


次は順伝搬。

次:第3回 順伝搬