学習・評価の精度向上にはレイヤーの選択と組み合わせ(ようするに、ニューラルネットワークの組み方)が、一番影響が大きいのは事実です。
けど、同じネットワークでも、プラスαのチューニングの余地はあります。
特に効果があるのは、重み(W)の初期値の与え方と、Optimizerの変更です。
なので、今回は、CNN(Convolutional Neural Network)で重み(W)の初期値の与え方と、Optimizerの変更をすることで、どのくらい学習精度が変わっていくのかを試してみます。
2017/12/01追記
>以降の説明の画像はVersion1.00のものです。
>Version1.10で一部アイコンのデザイン等が変わっています。
>ですが、見たらわかる範囲と考えて特に画像の張替えはしていません。
まず、ベースになるCNNを組む
ニューラルネットワークコンソールを起動します。
例によって、シンプルなCNN(Convolutional Neural Network)を組みます。
これは、前回「使い方5」で組み方を説明したものと同じです。
前回保存したものを再利用するか、作る場合はこちらを参考にしてください。
重みの初期値で違いがでるわけ
最初に、「重み」パラメータ(W または w と表記されている)初期値のチューニングをやってみます。
この図の左下の部分に「重み」とある・・この部分ですね。
なぜ、重みの初期値が学習の精度に影響するかを考えてみます。
ニューラルネットワークの学習とは、ざっくり言えば重み等のパラメータを調整することです。
調整は、学習前の重みで計算した結果と正解を比較して、どのくらい差異があるか(損失率といいます)を求めて、その差異が小さくなる方向に重みの値を更新していくことで行います。
ただ、調整するといっても、いきなり正解にズバッと変更できるわけはありません。
ちょっとずつずらしながら正解に近づけていくという地道な作業が必要です。
だから、その出発点になる「重みの初期値」の値によって、調整に非常に時間がかかったりする可能性があるのは、なんとなくイメージできます。
重みの初期値
ニューラルネットワークコンソールで「重みの初期値」にどういう数値を与えるかを決めるのは、ConvolutionとAffineの各レイヤーにある、「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)で初期化します
平均0.0、分散1.0であるガウス乱数とかクラクラきそうな言葉がでてきます。
このへんが理解できているのが理想ですが、わからなくても、とりあえず「きれいな分布の乱数なんだな」位に理解しときます。
ここで重要なのは、どのネットワーク構成の時に、どの初期値を選ぶのが適切か・・ということをつかむことです。
Xavierの初期値
適切な初期値ををまともに考えると難しいです。
なんですが、ありがたいことに、すでに頭の良い人が考えた「効率的な初期値の規則」があります。
我々凡人は、ありがたく使わせていただきましょう。
有名なものとして「Xavierの初期値」というものがあります。
上記のうち、説明に「Xavier Glorot提案」と書かれている種類が「Xavierの初期値」と呼ばれるものです。
この「Xavierの初期値」は「Sigmoid」か「Tanh」に適している初期値として知られています。
つまり、「ReLU」には最適とはいえません。
Heの初期値
ReLUには「Xavierの初期値」は最適じゃない。
じゃあ、どうすんの?というと。
なので「ReLU」に適していると知られている「Heの初期値」があります。
レイヤーリファレンスで「Kaiming He提案」と書かれているものです。
初期値の選択ルールをまとめてみる
まとめると以下のようになります。
- Sigmoid 又は Tanhを使う時:デフォルトの「NormalConvolutionGlorot」または「NormalAffineGlorot」でいい。
- ReLU を使う時:「NormalConvolutionHeForward」または「NormalAffineHeForward」に変更する。
ただ、上の引用を見ると「Xavierの初期値」も、 「Heの初期値」も各2種類ずつあります。
どちらでも、良さそうではありますが、自分が実際に試してみたら、「・・Forward」の方が精度が良かったので、一旦、オススメはそちらにしてます。
だから、ケースによって「もう一方の方がいいじゃないか!」という事もあるかもしれませんが、そのへんはご容赦くださいね。
初期値を変更して試してみる
さて、やってみます。
Convolutionレイヤーを選択し、左側の設定リストから「W.Initializer」を選んで、表示される選択肢から「NormalConvolutionHeForward」を選びます。
Convolutionレイヤーに続くのが、「ReLU」だからですね。
同様に、その下のConvolutionレイヤーでも同じように、「W.Initializer」を変更します。
その下のAffineについては、後続が「Sigmoid」なので、デフォルトのままでいいです。
変更はこれだけです。
上書き保存して学習をやってみます。
学習結果のグラフはこんな感じです。
評価結果は、99.2%になりました。
初期値を変更しただけで、0.02%とはいえ、改善の方向に数字がうごきました。
実は、99%を超えてからの0.2%の改善は、狙ってやろうとすると結構大変なんですよ。
ちなみに、初期値を「NormalConvolutionHeBackward」に、変更すると結果は元の99%のままに戻ります。
微妙ですけどね・・。
でも、初期値だけで結果が動くのが確認できます。
他にも、色々、初期値を変えてやってみると、面白いと思います。
今度はOptimizerをチューニングする
次のチューニングポイントは「Optimizer」です。
図を再掲します。
前の方で、学習とは「重み」のパラメータを「正解との差が小さくなる方向に、重みの数値を少しだけ増やすか減らす」ことで調整します。
この「増やすか減らす幅」は学習係数で指定するのですけど、その方向や実際の幅を調節するのが「Optimizer」だと、ざっくり理解すればいいと思います。
Optimizerのざっくりした種類
ひとくちに「Optimizer」と言っても、色々種類があります。
その種類によって、正解にたどり着くまでの試行錯誤の効率が違う・・と、考えてもれればいいんじゃないかと思います。
これは単純に一定の値を増やしたり、減らしたりするだけです。
シンプルですけど、効率はよいとは言えない場合があります。
上へ下へジグザグが大きくなる時があるわけですね。
それを改善して、ジグザグが小さくなる方向に幅を調整する「Momentum」。
学習の進むにつれて、学習係数を減衰させていく考え方で収束しやすくする考え方の「AdaGrad」。
その両方を融合させた「Adam」。
などが、工夫してあみだされてきました。
他にも色々ありますが、上記の「SGD」「Momentum」「AdaGrad」「Adam」の4つが代表的な「Optimizer」ですから、まあ、この4つを知ってれば、お勉強レベルなら大丈夫なはずです。
たいていの場合、一番すぐれているのは「Adam」です。
だから、ニューラルネットワークコンソールも、デフォルトは「Adam」です。
なので、チューニングのためにあえて変更する必要はないのですけど、遊び感覚で、Optimizerを変更して、学習の結果グラフがどう変わって、正解率がどう変わるか?
これを見るのは面白いと思って、とりあげてます。
Optimizerの変更で影響があるかを試す
やってみましょう。
変更は、COFIGタブで行います。
左側のOptimizerを選択して、プルダウンで変更し、上書き保存するだけです。
今回、試しに「AdaGrad」を選んでやってみました。
Adamの時に比べて、若干前半部分の凸凹が大きいのがわかりますか。
そんな大きな差ではありませんけどね。
ただ、正解率は98.4%と、0.6%下がりました。
意外と微妙なものだということがわかりますね。
適切な設定には地道な作業が必要だったりします
こんな感じで「input」のデータにあわせて、最適なレイヤーの組み合わせや階層の深さ、与える初期値、Optimizerの種類など、様々な要素で試行錯誤して、もっともよい結果が得られるパラメータを模索する。
そういう地道な作業が、ニューラルネットワークのチューニングには必要なのです。
だけど、このあたりの感覚は、いくら本を読んでも、実際にやってみないとわからないものなんですね。
だから、このニューラルネットワークコンソールみたいに気軽に試して、結果をグラフィカルに確認できる環境があるってすごいことです。
ありがたいですねえ
ではでは。
2017/12/01追記
ニューラルネットワークコンソールのVersion1.10でアイコンデザインが変更になったのはここです。
次の記事