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

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

ディープラーニング実装 手書き数字認識率向上のため試行錯誤した話

フルスクラッチで作ったディープラーニング実装で数字認識の正解率をあげるために試行錯誤の話です。

 

学習効率向上策であるオプティマイザの変更やDropoutなどの導入でどの程度手書き数字認識率が向上するかを試してみました。

 

最初に作った「とりあえず動く版」は凍結して、再度、ゼロからちょっとマシな実装で、第二弾を作り直しました。

 

今度は、レイヤー単位でクラスにして、積み上げでニューラルネットワークを組めるようにしています。

 

学習時のオプティマイザも何種類か実装して、切り替えられるようにしたので、気楽に試せるようになりました。

 

それを、色々組み合わせて、MNISTを学習させて、どれくらいの正答率に差がでるのかをやってます。

 

CNN(Convolutional Neural Network)は使わずに、全結合だけのニューラルネットワークでやってみます。

 

画像を扱うにはCNN(Convolutional Neural Network)が優れているのは、どの本見てもそう書いてあるし、間違いないと思います。

 

なんですけど、画像認識に特化したディープラーニング実装が目的ではありませんし、天邪鬼なので、CNNが良いと言われると、じゃあ使わなかったらどうなんだという方に興味がいったりします。

 

なによりCNNにすると学習に時間がかかります。あれこれ試すのに根気が続かない・・というのが一番大きい動機ですかね。

 

ということで、パソコン1台で我慢できる学習時間という制約の中、全結合のみで、どうするとより良い結果がでるか?に焦点を絞ってやってみました。

 

ネットワークの改装は7層でやります。

 

一番最初に力技で実装した版で正解率97%が最高だったので、そこを最低ラインでスタートしたかったのですが、新しい実装で、最初にテストで4層でやってみると正解率約94%でした。

 

前より落ちるのは問題なので、7層に増やしました。それで平均97.3%位の成功率になりました。この7層ネットワークで学習回数を増やしただけでは改善しないのを確認して「壁」としておきます。

 

パラメータの更新手法の差

壁の突破のため、SGD一本でやっていた学習時のパラメータ更新手法を変えて、試してみました。

 

結果が良かった順にならべると、こうでした。

  1. AdaGrad(lr=0.01)
  2. Momentum(lr=0.01, momentum=0.9)
  3. SGD確率的勾配降下法(lr=0.01)
  4. Adam(lr=0.001, beta1=0.9, beta2=0.999)
  5. RMSprop(lr=0.01, decay_rate = 0.99)

うーん。ちょっと予測とは違いました。

Adamが1番で、SGDが最下位になると思っていたのですが。

 

ただ、AdamとRMSpropがSGDより下という結果は、理論的にはおかしいです。たぶん、"BOKU"の実装に問題があるか、使い方を間違っているのではないかと思います。

 

でも、そこを深掘りしだすと他のことができなくなるので、とりあえず、このアプローチのテストは中断します。

 

以後は、一番結果のでているAdaGradをベースに試行をすすめることにしました。オプティマイザの変更だけだと、最終的な正解率は、若干の改善はあったものの、97.5%位で頭打ちになりました。0.2%くらいなら誤差の範囲じゃないかと思います。

 

Dropoutを試す

続いて、本で、Dropout手法を使ったニューラルネットワークが、比較的浅い層で高い正解率(99%以上)を出しているという記事を読んだので、これも早速試してみました。

 

もっとも、それはCNNに適用したという実績です。全結合のみのニューラルネットワークでどうなるか?は未知数だったのですが、残念ながら、今回は単に学習の進み方が遅くなっただけで正解率をあげるところまではいきませんでした。

 

 

ハイパーパラメータの調整をしていけば、効果がでてくる可能性は感じるのですが、他に試してみたいこともあるので、いったん、このアプローチも中断することにしました。

 

学習データ水増しは効果あり

ここまでで、本とかを参考にしたアプローチは終わりです。なので、ここからは自分で考えたアプローチを試してみることにします。

 

まず考えたのは、学習データの水増し作戦です。

 

これは、MNISTの画像を学習する都度、元画像を少しずつずらす処理をして1枚の元画像から数枚の水増し画像を作り出して、それも学習させることで、学習データを数倍に増やして学習率をあげようというアプローチです。手順を、箇条書きにするとこのようになります。

  1. MNISTの画像をまず普通に学習する・
  2. 元画像を上にNバイトずらして学習する。
  3. 元画像を下にNバイトずらして学習する。
  4. 元画像を左にNバイトずらして学習する。
  5. 元画像を右にNバイトずらして学習する。
  6. この1~5を学習対象のデータすべてについて行う。

 

これで単純に学習データのバリエーションが5倍になります。

 

若干学習に時間はかかるようになったのですが、まあ許容範囲です。pythonでイメージ加工処理を実装し、ずらすNを少しずつ変えながら何回か試しました。

 

Nが1、2の時はあまり変化はなかったのですが、Nを3くらいから、結果が動きました。

 

今のところ、N=4のときが一番良い結果がでています。97.3~5%程度だった正解率が、98%前後がコンスタントにでるようになりました。

 

N=4の時の画像のイメージを例示してみます。真ん中がオリジナルです。微妙にずれているのがわかりますね。

f:id:arakan_no_boku:20161203001545j:plain

 

これだけで、約 0.5~0.7%位、正解率が改善したことになります。これは、なかなか良い結果ではないでしょうか。

 

この考え方は、学習データが少ないときにも有効な気がしますしね。ということで、これを今週の一番の成果とします。あと、いくつかアイディアはあるので、ぼちぼち試していこうと思ってます。

 

ちなみに、学習データを加工する方法は、プログラムの小ネタとして、番外編の方に書いています。興味のある方はどうぞ。

arakan-pgm-pb.hatenablog.com