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

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

適切な重みの初期値とOptimizerの種類と効果をGUIで体験:使い方6/ニューラルネットワークコンソール

CNNの重み(W)の初期値の与え方と、Optimizerの変更によって、学習精度がどのくらい変わっていくのかをプログラミング無しのGUIのみで体験してみます。

 

この記事の対象読者は、文系で数学は苦手でプログラムも得意ではないけど、人工知能・・特に深層学習(ディープラーニング)の技術には興味があるという方を想定しています。

 

また、続きもの的に前回からの引き続きで書いている部分もあるので、まだの方は、下記の一覧で使い方1から順番に読んでもらえると、よりわかりやすいかと思います。

arakan-pgm-ai.hatenablog.com

 

さて続けます。

 

今回は、前回からの続きです。

 

CNNという技術用語については、前回の記事でざっくり説明しているので、まだの方はそちらで確認してくださいね。 

arakan-pgm-ai.hatenablog.com

 

前回は、ラッキーなことに、答えの正確さが、99%まで行きました。

 

今回はそれをベースにして、さらに学習精度をあげられないかをやってみます。

 

レイヤーの選択と組み合わせが、一番影響が大きいのは事実なんですけど、プラスαの方法も、とても重要ですから。

 

まず、ニューラルネットワークコンソールを起動して、前回の最後で保存したプロジェクトを開きます。

f:id:arakan_no_boku:20170826132310j:plain

 

これですね。

 

最初に、「重み」パラメータ(W または w と表記されている)初期値のチューニングをやってみます。

 

この図の左下の部分に「重み」とある・・この部分ですね。

f:id:arakan_no_boku:20170825221728j:plain

 

上の図のように、ニューラルネットワークの学習とは、学習前の重みで計算した結果と正解を比較して、どのくらい差異があるか(損失率といいます)を求めて、その差異が小さくなる方向に重みの値を調整することです。

 

調整するといっても、いきなり正解にズバッと変更できるわけはありません。

 

ちょっとずつずらしながら正解に近づけていくという地道な作業が必要です。

 

だから、その出発点になる「重みの初期値」の値に何を設定するかで、学習が効率よくできるかどうかが左右されるのは当然ですね。

 

ニューラルネットワークコンソールで「重みの初期値」にどういう数値を与えるかを決めるのは、ConvolutionAffineの各レイヤーにある、「W.Initializer」という設定項目です。 

 

とはいえ、適切な初期値の問題をまともに考えると難しいです。

 

なんですが、ありがたいことに、すでに頭の良い人が考えた「効率的な初期値の規則」があります。

 

我々凡人は、ありがたく使わせていただきましょう。

 

まず、初期値の与え方にどのような種類があるかを、ニューラルネットワークコンソールのレイヤーリファレンスから引用します。

 

まず、convolutionの方です。

重みWの初期化方法を指定します
Uniform:-1.0~1.0の一様乱数で初期化します

UniformConvolutionGlorot:一様乱数にXavier Glorot提案の 係数をかけて初期化します

Normal:平均0.0、分散1.0であるガウス乱数で初期化します

NormalConvolutionHeForward:ガウス乱数にKaiming He提案の係数をかけて初期化します(Forward Case)

NormalConvolutionHeBackward:ガウス乱数にKaiming He提案の係数をかけて初期化します(Backward Case)

NormalConvolutionGlorot:ガウス乱数にXavier Glorot提案の 係数をかけて初期化します(デフォルト)

Constant:全ての要素を一定値(1.0)で初期化します

 

続いて、Affineの方です。

重みWの初期化方法を指定します
Uniform:-1.0~1.0の一様乱数で初期化します

UniformAffineGlorot:一様乱数にXavier Glorot提案の 係数をかけて初期化します

Normal:平均0.0、分散1.0であるガウス乱数で初期化します

NormalAffineHeForward:ガウス乱数にKaiming He提案の係数をかけて初期化します(Forward Case)

NormalAffineHeBackward:ガウス乱数にKaiming He提案の係数をかけて初期化します(Backward Case)

NormalAffineGlorot:ガウス乱数にXavier Glorot提案の 係数をかけて初期化します(デフォルト)

Constant:全ての要素を一定値(1.0)で初期化します

 

 上記のうち、説明に「Xavier Glorot提案」と書かれている種類が「Xavierの初期値」と呼ばれるものです。 

 

この「Xavierの初期値」は「Sigmoid」か「Tanh」に適している初期値として知られています。

 

つまり、「ReLU」には最適とはいえません。

 

なので「ReLU」を使う時は、それに適した初期値として「Kaiming He提案」と書かれている、「Heの初期値」を使います。

 

 これをざっくりまとめると以下のようになります。

  • Sigmoid 又は Tanhを使う時:デフォルトの「NormalConvolutionGlorot」または「NormalAffineGlorot」でいい。 
  • ReLU を使う時:「NormalConvolutionHeForward」または「NormalAffineHeForward」に変更する。

 

ただ、上の引用を見ると「Xavierの初期値」も、 「Heの初期値」も各2種類ずつあります。

 

なぜ、1種類だけまとめのところで選んだのか?

 

実は理論的裏付けなどではなく、自分が実際に試してみて、成績が総じて良かった方をチョイスしただけです。

 

だから、「もう一方の方がいいじゃないか!」という事もあるかもしれませんが、そのへんはご容赦くださいね。

 

さて、やってみましょう。

 

Convolutionレイヤーを選択し、左側の設定リストから「W.Initializer」を選んで、表示される選択肢から「NormalConvolutionHeForward」を選びます。

 

f:id:arakan_no_boku:20170827143117j:plain

 

Convolutionレイヤーに続くのが、「ReLU」だからですね。

 

同様に、その下のConvolutionレイヤーでも同じように、「W.Initializer」を変更します。

 

その下のAffineについては、後続が「Sigmoid」なので、デフォルトのままでいいです。

 

変更はこれだけです。

 

上書き保存して学習をやってみましょう。

 

学習結果のグラフはこんな感じです。

f:id:arakan_no_boku:20170827143223j:plain

 

評価結果は、99.2%になりました。

f:id:arakan_no_boku:20170827143300j:plain

 

初期値を変更しただけで、0.02%とはいえ、改善の方向に数字がうごきました。

 

実は、99%を超えてからの0.2%の改善は、狙ってやろうとすると結構大変なんですよ。

 

ちなみに、初期値を「NormalConvolutionHeBackward」に、変更すると結果は元の99%のままに戻ります。

f:id:arakan_no_boku:20170827144252j:plain

 

微妙ですけどね・・。

 

でも、初期値だけで結果が動くのが確認できます。

 

他にも、色々、初期値を変えてやってみると、面白いと思います。

 

次のチューニングポイントは「Optimizer」です。

 

図を再掲します。

f:id:arakan_no_boku:20170825221728j:plain

 

ここで、下の方に、学習とは「重み」のパラメータを「正解との差が小さくなる方向に、重みの数値を少しだけ増やすか減らす」と書いてます。

 

この「増やすか減らす幅」を決めるのが「Optimizer」だと、ざっくり理解すればいいと思います。

 

ひとくちに「Optimizer」と言っても、色々種類があります。

 

その種類によって、正解にたどり着くまでの試行錯誤の効率が違う・・と、考えてもれればいいんじゃないかと思います。

 

一番単純なのが、SGD確率的勾配降下法)です。

 

これは単純に一定の値を増やしたり、減らしたりするだけです。

 

シンプルですけど、効率はよいとは言えない場合があります。

 

上へ下へジグザグが大きくなる時があるわけですね。

 

それを改善して、ジグザグが小さくなる方向に幅を調整する「Momentum」。

 

学習の進むにつれて、学習係数を減衰させていく考え方で収束しやすくする考え方の「AdaGrad」。

 

その両方を融合させた「Adam」。

 

などが、工夫してあみだされてきました。

 

他にも色々ありますが、上記の「SGD」「Momentum」「AdaGrad」「Adam」の4つが代表的な「Optimizer」ですから、まあ、この4つを知ってれば、お勉強レベルなら大丈夫なはずです。

 

たいていの場合、一番すぐれているのは「Adam」です。

 

だから、ニューラルネットワークコンソールも、デフォルトは「Adam」です。

 

なので、チューニングのためにあえて変更する必要はないのですけど、遊び感覚で、Optimizerを変更して、学習の結果グラフがどう変わって、正解率がどう変わるか?

 

これを見るのは面白いと思って、とりあげてます。

 

やってみましょう。

 

変更は、COFIGタブで行います。

f:id:arakan_no_boku:20170827152527j:plain

 

左側のOptimizerを選択して、プルダウンで変更し、上書き保存するだけです。

 

今回、試しに「AdaGrad」を選んでやってみました。

f:id:arakan_no_boku:20170827152656j:plain

 

Adamの時に比べて、若干前半部分の凸凹が大きいのがわかりますか。

 

そんな大きな差ではありませんけどね。

 

ただ、正解率は98.4%と、0.6%下がりました。

f:id:arakan_no_boku:20170827152811j:plain

 

意外と微妙なものだということがわかりますね。

 

こんな感じで「input」のデータにあわせて、最適なレイヤーの組み合わせや階層の深さ、与える初期値、Optimizerの種類など、様々な要素で試行錯誤して、もっともよい結果が得られるパラメータを模索する。

 

そういう地道な作業が、ニューラルネットワークのチューニングには必要なのです。

 

だけど、このあたりの感覚は、いくら本を読んでも、実際にやってみないとわからないものなんですね。

 

自分も、実際に自分でやってみるまで、わからなかったですからね。

 

だから、このニューラルネットワークコンソールみたいに気軽に試して、結果をグラフィカルに確認できる環境があるってすごいことです。

 

プログラムの勉強からはいらなくても、ニューラルネットワークを組んで動かして、試行錯誤ができるのは、すごい勉強になりますから。

 

ぜひぜひ、お遊び気分で初期値やOptimizerなどを切り替えて、結果がどう変わるかを予測して、確認するのをおすすめします。

 

そうすると、ニューラルネットワークに対する理解が一気に深まると思いますよ。

 


前の記事

関連カテゴリの記事一覧(この一覧で使い方1から順番に読むのをおすすめします)

arakan-pgm-ai.hatenablog.com

f:id:arakan_no_boku:20170910161122j:plain