アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うことを書いてます。

RNN(Recurrent Neural Network)をざっくり理解して、ちょっと使ってみる:使い方15/ニューラルネットワークコンソール

画像にしても、テキストデータにしても。

分類などをするときには、「今、現在」の状態だけを扱うことになります。 

でも、実際にはそれだけでは不十分な時があります。

時系列の変化を扱わないと難しいデータがありますから。 

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

こういうのを学習させて、未来を予測させるとか、そういう用途に使えるモデルのことをRNN(Recurrent Neural Network)といいます。

 

2017/12/01追記

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

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

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

 

ニューラルネットワークコンソール付属の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の種類をかんたんに解説します

  

サンプルはいろいろありますが、大きな種類としては以下の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が良い場合があるらしいです。

試してみて、良い方を使うって感じなのでしょうか。

なお。

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

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

qiita.com

 

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

 

RNNの概要はこれくらいにして、とりあえず、ニューラルネットワークコンソールでサンプルを動かしてみます。 

といっても、LSTNやGRUのサンプルはかなり複雑で、学習にも時間がかかります。 

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

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

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

f:id:arakan_no_boku:20170924221436j:plain

 

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

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ならではのトピックは感じませんねえ。 

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

groups.google.com

 

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

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

 

f:id:arakan_no_boku:20171005201723j:plain

 

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

f:id:arakan_no_boku:20171005201549j:plain

 

これのどこが面白かったかというと、単純に「SquaredError」に変えただけだと、学習時にエラーになってしまうという点です。 

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

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

"BOKU"も知りませんでしたし。 

いや、たまたま、「elman_net.sdcproj」を触ってて、ひとつ賢くなったな。 

ちょっと得した気分です。

 

2017/12/01追記

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

f:id:arakan_no_boku:20171130202351j:plain

関連記事

ニューラルネットワークコンソール関連の記事一覧はこちらです。

arakan-pgm-ai.hatenablog.com

 

NNabla(Neural Network Libraries)関連の記事一覧はこちらです。

arakan-pgm-ai.hatenablog.com

f:id:arakan_no_boku:20171115215731j:plain