Tuesday, July 7, 2015

IRNN vs LSTM

I was planing to make posts on experiments Neural Network one by one when I started this blog, so I started with simple MNIST example, but I was lazy keeping up my original plan, and today's post ends up talking about Recurrent Neural Network, which sounds very advanced from the last post, but the dataset I am using is still MNIST.

このブログはニューラルネットワークを一つ一つ実験しながら段階を踏んで学ぶ目的で始めたのだけれど、記録を残すことには怠惰になってしまった。そんなわけで、この投稿はリカレントニューラルネットワークについてのものになった。前回の投稿に比べると随分と進んだトピックだけれど、MNIST のデータセットを使っている点ではそう変わっていない。

There is a type of RNN called IRNN proposed in this paper. I made a variant of the experiment they conducted on MNIST dataset, using Keras. When I made a pull request, François suggested to compare it against LSTM implementation. So I did it and this post is the result.

IRNN と呼ばれる RNN がこの論文で提案された。論文内で行われた MNIST のデータを使った実験の設定を少し変えたものを Keras を使って実装してみた。それのプルリクエストを作成したところ、フランソワから LSTM との比較も行ってみては?と言われたのでやってみた。この投稿はその結果になる。

The code I used for the experiment is already merged in Keras, and here is the link. By using SimpleRNN class, IRNN can be implemented in few lines of codes as bellow.

まず実験に使用したコードは既に統合されているのでそのリンクをここに貼っておく。 IRNN の実装は SimpleRNN クラスを応用するだけで、数行程で以下のように書ける。

IRNN

model = Sequential()
model.add(SimpleRNN(input_dim=1, output_dim=100,
                    init=lambda shape: normal(shape, scale=0.001),
                    inner_init=lambda shape: identity(shape, scale=1.0),
                    activation='relu', truncate_gradient=28*28))
model.add(Dense(100, 10))
model.add(Activation('softmax'))

LSTM

model = Sequential()
model.add(LSTM(input_dim=1, output_dim=100,
               init='glorot_uniform', inner_init='orthogonal', forget_bias_init='one',
               activation='tanh', inner_activation='hard_sigmoid',
               weights=None, truncate_gradient=-1, return_sequences=False))
model.add(Dense(100, 10))
model.add(Activation('softmax'))

As the optimizer for the experiment, I used RMSProp instead of SGD. This is because SGD fails to optimize the network, depending on momentum value. Worse, actually I couldn't make it work on IRNN. Instead of finding the good momentum value and decay rate with grid search, I used RMSprop with the same starting learning rate. I run the first few dozens of epochs with different seed value for random initialization, and it could be observed that RMSprop works pretty well, and is faster and steadier than SGD.

最適化には、論文の実験とは違って RMSprop を用いた。これは SGD はモーメンタムの値次第で最適化が失敗するからだ。というより、IRNN で数種類の値を試したのだけれどどれも全く上手くいかなかった。この適切な値を探索する代わりに、初期学習率を同じに設定した RMSprop を使ってみると反応は良好だった。重みをランダムに初期化する際の乱数生成器のシードの値を変えながら、実験の最初数十回分だけイタレーションを実行してみると、どれも上手く学習しているように見えた。実際のところ SGD に比べると RMSprop の方が学習が速くて、損失の減衰具合がより安定していた。

I used different batch size, 32 than the original paper, 16. This is done for making GPU computation time reasonable. As Keras process training data batch by batch, when it runs on GPU, batch size must be large enough to compensate for the time required to forward batch to GPU memory.

バッチ数が元の論文の 16 から 32 に変更されているのは GPU で計算する際にはある程度バッチ数を大きくしないと CPU よりも遅くなるからだ。これは GPU のメモリにバッチ単位で学習データを転送することに起因する。

In IRNN I truncated BPTT after 28*28 timesteps, which is identical to actual length of input sequence, but applying the same setting to LSTM did not work. I ended up not using BPRR truncation in LSTM. I have not figured out why. (By the way, IRNN also fails without enabling BPTT. It's interestingly opposite.)

IRNN では BPTT の打ち切り回数をシーケンスの長さと同じの 28 * 28 に設定したけれど、LSTM で同じように設定すると学習が上手くいかなかった。結局 LSTM ではBPTT を使わなかった。原因はまだ突き止めていない。(ちなみに IRNN の方で BPTT を無効にすると、これまた上手くいかない。不思議だ。)

The docstring of SimpleRNN class says "Not a particularly useful model, included for demonstration purposes". But I think that it's thanks to Keras' highly sophisticated design principle that IRNN, which should be conceptually simple could be actually implemented very simply.

SimpleRNN クラスのドックストリングには「特に便利なクラスではないが実装方法の紹介のために載せておく」と書かれているけれど、「シンプルなアーキテクチャでいい結果が得られる。」と主張する元の論文を、実際にシンプルに実装できるのは Keras のアーキテクチャが特段優れているからではないだろうかと思った。

The following is the result. The experiment with LSTM is not finished yet, so the figure is not finalized, but the same tendency as the original paper can be observed. In this experiment, batch size is 32 so the number of steps in one epoch is 1875.

以下が実験の結果になる。LSTM の方はまだ終わっていないので途中経過でしかないのだけれど、論文と似た傾向は観察できる。この実験ではバッチサイズが 32 なので、1エポックのステップ数が 1875 になる。


In this experiment, computation time required to finish one epoch with IRNN was much smaller than that of LSTM. This might depend on library implementation, but using above code with Keras on K520 GPU (in AWS EC2 g2.2xlarge instance), IRNN took about 440 seconds to finish one epoch, and LSTM took 1700 seconds. Taking these into account, the following is the learning curve based on computation time.

この実験では IRNN は LSTM よりも1エポックの計算にかかる時間が短かった。これはライブラリの種類や実装方法によるのかもしれないけれど、Keras で上記のコードを使った場合、IRNN では1エポック約 440 秒に対して LSTM では 1700 秒かかった。これらを加味して、計算時間を元にした学習の様子をプロットすると次のようになる。



The result so far is very interesting. IRNN is architecturally very simple and, though I am not sure if that is causing but, learns very fast. I became however rather skeptic about the validity of using sequential MNIST for this experiment. Even though I set BPTT truncation to 28*28 timesteps, but does it have that long dependency? Further experiment will be needed to verify this.

ここまでの結果は面白いものになった。IRNN はモデルがシンプルで、それ故かどうかわからないが学習がとても速い。しかしながら、MNIST をこの実験で使うのはそれほど妥当なのだろうかという疑問を抱いた。BPTT を 28*28 ステップに設定はしたが、このデータセットはそれほど長い依存性を持っているのだろうか?これを確かめるためには他のデータセットで実験をしてみる必要があるだろう。

No comments:

Post a Comment