"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

RNNの種類/サンプルでシンプルRNNの「elman_net」を体験する/Neural Network Consoleの使い方

CNNなどは、「今、現在」の状態だけを扱う前提です。 

でも、時系列の変化を扱いたいデータもあります。 

例えば、年間の温度変化や降雨量のデータとか、月ごとの売上データとか。 

そんな用途に使えるモデルのことをRNN(Recurrent Neural Network)といいます。

今回は、それについて。

f:id:arakan_no_boku:20190326212937j:plain

2017/12/01追記

>以降の説明の画面は、Version1.00のものです。

>Version1.10で一部のアイコンのデザインが変更になっています。

>しかし、見てわかる程度と判断して、特に張替えてません。

 

RNNの種類をかんたんに

  

大きな種類としては以下の3つです。

  • elman_net
  • LSTM(long_short_term_memory)
  • GRU(gated_recurrent_unit)

簡単に違いを整理しておきます。 

 

elman_net

 

一番、シンプルなRNNが「elman_net」です。 

SimpleRNNの代表的なものでもあります。 

時系列データを学習できます。

しかし、時系列が長くなると勾配消失(これ以上学習できない状態になってしまう)になるので、長期間にわたる時系列データを扱うには不適切です。 

 

LSTM

 

RNNに「ゲート」という機能を導入することで、長期間の時系列データにも対応できるようにしたのが、LSTMです。

LSTMは長期の時系列にも短期の時系列にも対応できます。

なので。

RNNといえばLSTMという位、実際にはよく使われています。

ただ、パラメータの数が多くて使うのが若干難しいという面と、学習に時間がかかるという問題があります。 

 

GRU

 

LSTMと同じ様に長期と短期の時系列の両方が扱えます。

LSTMと同じように「ゲート」の機能を持ちます。

ただ、LSTMが2つのラインを使うところをGRUは1つであるなど、シンプルにすることで、LSTMよりパラメータも少なく、学習時間を短くできるように工夫されてます。 

これだけ書くと、GRUが最強!・・に見えるのですが、実際のところは、何をするかによってLSTMが勝る場合と、GRUが勝る場合があって、一概に決められないそうですし、研究などの高度な学習には、LSTMかその亜種が使われる方多いみたいです。

ただ、データセットのサイズが小さい場合で繰り返し試行錯誤が必要なケースだと、学習速度が速いGRUが有利ということではあります。

 

理論的なことにはふれません

 

例によって。

詳しい仕組み(ゲートとは何なのか?とか)や、何故、時系列データの学習ができるか等の理論的なことは、ここではふれません。 

興味があれば「どういう用途に使えるか観点」でもう少し詳しく解説しているこちらの記事も面白いと思います。

qiita.com

 

ニューラルネットワークコンソール付属のRNNサンプル

 

ニューラルネットワークコンソールに、RNNのサンプルはたくさん用意されてます。 

RNN(Recurrent Neural Network)のサンプルプロジェクトとして、用意されているものを下に列挙します。

  • bidirectional_elman_net.sdcproj
  • elman_net.sdcproj
  • elman_net_with_attention.sdcproj
  • gated_recurrent_unit(GRU).sdcproj
  • long_short_term_memory(LSTM).sdcproj
  • LSTM_auto_encoder.sdcproj
  • stacked_GRU.sdcproj

  

 

シンプルRNNを動かしてみる

 

とりあえず、ニューラルネットワークコンソールでサンプルを動かしてみます。 

といっても、LSTNやGRUのサンプルはかなり複雑です。 

なので、比較的短い時間で学習と評価の結果が確認できる「elman_net」を動かしてみようかなと思います。 

 

elman_net.sdcprojを開く

 

ニューラルネットワークコンソールを立ち上げます。 

プロジェクト一覧から、「elman_net.sdcproj」を探して開きます。

f:id:arakan_no_boku:20170924221436j:plain

 

赤枠の部分が、特徴的ですよね。 

 

SimpleRNNの構造

 

RecurrentInputからReccurentOutputの間を時系列データの時間軸で繰り返すわけですね。 

SimpleRNNの構造は、入力があって、真ん中に状態を表す隠れ層があって、そこに前回の状態が接合(concatenate)されて新しい状態を更新することで時系列を扱い、時系列の最後までいったら最新の状態から出力する・・っていう、シンプルな構造になってます。

f:id:arakan_no_boku:20170924225055j:plain

 

それがまんま、レイヤーで表現されている感じなので、わかりやすいですよね。 

イメージ図には、遅延(Delay)がでてきませんが、ここで一定時間保持することで、過去(前回)の状態の結合を実現するために必要な仕組みとでも理解してもらえればと思います。

 

学習の実行

 

学習してみます。 

とりあえず、今回はサンプルを何も変更せずに、そのまま動かしてみます。

f:id:arakan_no_boku:20170923104852j:plain

 

このサンプルの入力データは、MNIST(手書き数字の画像)データです。 

画像データを時系列データとみなして、動かすってことですかね。 

学習結果はこんな感じです。

f:id:arakan_no_boku:20170924225814j:plain

 

評価の実行

 

評価してみます。

f:id:arakan_no_boku:20170923104852j:plain

 

結果はこうです。

f:id:arakan_no_boku:20170924230012j:plain

 

うーん。 

正直、この結果を見て、RNNならではのトピックは感じませんねえ。 

CNNと何が違うの?・・って感じです。

内部的には全然違う・・と言われても、ピンときません。

次は、もう少しRNNっぽいテーマでやってみないとですね。

 

おまけ

 

そう思っていたら、ここで面白いコメントを見つけました。

groups.google.com

 

SquaredErrorへの変更

 

この「elman_net.sdcproj」をベースに、SquaredErrorに変えて、AUTOENCODERっぽく変えてみるというのを試している人がいたのですね。 

元のままだと、「RecurrentOutput」以下がもともとはこんな感じで、「BinaryCrossEntropy」で終わっています。

 

f:id:arakan_no_boku:20171005201723j:plain

 

これを以下のように、最後を「SquaredError」で終わるように変えているみたいです。

f:id:arakan_no_boku:20171005201549j:plain

 

SquaredErrorにしたときの留意点

 

注意すべきは、単純に「SquaredError」に変えただけだと、学習時にエラーになってしまうという点です。 

回避方法は簡単で、SquaredErrorの「T.Dataset」プロパティが「y」になっていたのを、inputのそれと同じ名前(このケースの場合は x )に変更すれば、エラーはでなくなります。 

でも、回答にかかれている「AutoEncoderの場合、InputレイヤーのDatasetプロパティ、およびSquaredErrorのT.Datasetプロパティにそれぞれ同じ変数名を指定します。」の部分って、自分では中々気づかないよなあ・・と思いました。 

 

 

2017/12/01追記

Version1.10では、このあたりのアイコンのデザインが変更になってます。 

f:id:arakan_no_boku:20171130202351j:plain