自然言語処理お勉強教室-RNN-(2)

はじめに

この記事で取り扱うのはRNNです.RNNの記事や実装などはそこら中にあるので,これは私が勉強したよという備忘録となります.

RNN

リカレントニューラルネットワークと呼ばれるものです.こいつが役に立つのは時系列でデータを学習することができるということ.前のニューロンで学習したデータを次のニューロンに渡すことができるので便利だということです.さて,図は以下のような感じです.

f:id:tatsuya_happy:20210301183016p:plain

X_t-1というデータがあったときに,あるh_t-1というデータを予測します.そのときに用いられた,データが次のニューロンにも利用されます.そうすると,x_t-1で利用されたデータの値が,x_tで利用されることになります.四角の部分には足し算をします. 実際にこれを自然言語処理で取り扱ったときは以下のように書くことができ,文章の生成に応用することができます. f:id:tatsuya_happy:20210301183354p:plain 例えば,文章の

you say goodbye and I say hello

があった時のモデルを一部作りました.最初のyouの次の単語がsayとなりますので,これを予測します.x_t_-1にyou,h_t-1に予測するsayがきます.これを続けていくと,最後のhelloまでにたどり着きます.こうすることで,とある単語が来たときに,次のどのような単語が来るのか?ということを予測することができるモデルが構築されます.重みは2種類存在し,一つ目が,隠れ層に対しての重みWであり,二つ目が新しいデータに対してのVとなります.

単語のデータの表現方法は,例えば,one-hotベクトルで入力する方法があります.これを用いて,softmax関数と交差エントロピーでloss関数を計算すると学習が進みます.

#input_line=
#[
#[[0,0,1,0,0]],
#[[1,0,0,0,0]]
#] 3 dimention 1 dimention , word dimention
#targetがsayだとすると,outputもsayとなって欲しいように学習する.


n_hid = rnn.initHidden()
for i in range(len(input_line)):
    output,h_hid = rnn(input_line[0],n_hid) #input_line[0]  [[0,0,1,0,0]]
    loss = criterion(output,target)  
loss.backward()

挿入されたテキストごとにlossを計算し,最後にbackwardする感じで勾配の計算をすることができます.

数式を見てみます.

あまり込み入った計算をしないので,重要なところはh_t-1とx_tのデータを足し合わせるところです.

[tex:

ht=tanh(Wh_{t−1}+Vx_{t})

] *hatenablogの数式がうまくいかない.

まぁ,隠れ層から出力されたデータh_t-1と重みWを行列演算します.次に,新しいデータに対して,Vという重みとx_tを行列演算します.

#参考:
[https://qiita.com/tsubasa_hizono/items/d3095a4dc7e4cf91ffdb]


import torch
import torch.nn as nn

class RNN(nn.Module):
    def __init__(self,n_in,n_hid):
        super(RNN,self).__init__()
        self.n_hid = n_hid
        self.i2h=nn.Linear(n_in,n_hid)
        self.h2h=nn.Linear(n_hid,n_hid)

    def forward(self,x,n_hid):
    
        h_out=self.i2h(x)+self.h2h(n_hid) #足し算部分です.
        h_out=torch.tanh(h_out) #活性化関数で,勾配消失を抑制
        h_out=h_out.detach()
        output = self.dropout(h_out)
        output = self.softmax(h_out) #単語を予測するときにsoftmaxをする.softmaxをするときはnn.NLLossです.

        return output,h_out
    @classmethod
    def initHidden(self):
        return torch.zeros(1, self.n_hid)

こんな感じで実装すると,RNNが学習できると思います.いづれちゃんとした実装書いてkaggleのnotebookに投稿します.

終わりに

今回は古きモデルRNNをみました.難しいですね.