自然言語処理お勉強教室-seq2seq-(4)

はじめに

この記事ではseq2seqを取り扱います.seq2seqはweb上で様々な情報が公開されているます.そのため,この記事は私が勉強したよという備忘録です.

seq2seqがやりたいこと

前回の記事ではLSTMを勉強しました. tatsuya-happy.hatenablog.com LSTMはRNNで取扱えなかった,長い文章を取り扱えるように,開発されたアルゴリズムです(個人的にはそう思っている).長い文章を取扱えなかったのはRNNにおいて,過去の情報がほとんど失われるためです.そこで,LSTMは情報を出来るだけ失わないように,過去の情報を伝達できるモデルとなりました.seq2seqはこのLSTMモデルを応用することで,機械翻訳,文章生成などの分野に幅を見出そうとしました.

seq2seqのモデル構造.

web上で画像を見ていて構造が,一番わかりやすかったのが,以下の画像でした. f:id:tatsuya_happy:20210304143506p:plain seq2seqのモデル構造には「Encoder,Decoder」と呼ばれる重要な構造があります.この画像の場合は,文章生成の分野に該当し,入力文章は「how are you ?」です.この文章をEncoderに入力し,「how are you?」が意味しているベクトルを出力します.このベクトルが,Decoderに入力されます.Decoderは「how are you?」の情報を受け取り,「I am good」の文章を生成できるように学習します.これら一連の文章の流れを可能にさせているのがLSTMです.そのため,seq2seqは二つのLSTMのモデルにより構築されたモデルとなります. f:id:tatsuya_happy:20210304144623p:plain seq2seqは上記の画像のような割と単純な構造で,図に表すことができます.出力であるhは前述した「how are you?」の情報を含めたベクトルとなります.実装は以下のサイトでやられている奴が一番参考になるかと思います(PyTorchですが). qiita.com

#Encode
class Encoder(nn.Module):
    def __init__(self, vocab_size, embedding, hidden_dim):
        super(Encoder, self).__init__()
        self.hidden_dim = hidden_dim
        self.word_embeddings = nn.Embedding(vocab_size, embedding)
        self.lstm = nn.LSTM(embedding, hidden_dim, batch_first=True)

    def forward(self, sequence):
        embedding = self.word_embeddings(sequence)
        _, state = self.lstm(embedding)
        # state = (h, c)
        return state

# Decoderクラス
class Decoder(nn.Module):
    def __init__(self, vocab_size, embedding, hidden_dim):
        super(Decoder, self).__init__()
        self.hidden_dim = hidden_dim
        self.word_embeddings = nn.Embedding(vocab_size, embedding)
        self.lstm = nn.LSTM(embedding, hidden_dim, batch_first=True)
        self.hidden2linear = nn.Linear(hidden_dim, vocab_size)

    def forward(self, sequence, encoder_state):
        embedding = self.word_embeddings(sequence)
        output, state = self.lstm(embedding, encoder_state)
        output = self.hidden2linear(output)
        return output, state

このようにEncodeクラスとDecoderクラスを別々に作ります.中身と見ると,Encoderにはlstmがあり,確かに一つのモデルしかありません.返り値のstateは(h,c)です.LSTMの構造を見ても,事前情報で入力されるのは(h,c)でした.Encoderでは隠れ層を何次元にするか?の情報しか書かれていませんでしたが,おそらく内部的には,(h,c)でも受け取れるように構築されているのでしょう.

Decoderの部分はlstmで出力させたあと,Linear関数で次にどの単語がくるかを予測させるようにしています.nn.Linearの隠れ層の出力がvocab_sizeになっているのが確認できます.

さて,これを一つのモジュールとして表します.

class Seq2Seq(nn.Module):
    def __init__(self, encoder, decoder):
        super(Seq2Seq,self).__init__()
        
        self.encoder = encoder
        self.decoder = decoder
        
     
        
    def forward(self):
        
       ##まだ書いてません
        
        return outputs

こうしてしまえば,一つのモデルとして構築でき,学習させるコードを書くときにいちいちEncoderとかDecoderとかで出力する値を書く必要がなくなります.

実装

きちんとした実装はまた今後あげます.

終わりに

今回はseq2seqを勉強しました.LSTMの構造がわかっていれば,そこまで内容的には難しくないように思えます.次はこの技術を応用した,Luongが提案したAttentionの概念について勉強したいと思います.