こんにちは、ニューラルネット老人こと糟谷勇児です。
最近、黄鉄鉱化したアンモナイトの化石を買ってみました。
化石は地面に埋まった骨や殻が、長い時間をかけて周りの地盤の成分に置換されていき、中身は元の成分ではなく、周りの成分に置き換わっているらしいです。
黄鉄鉱化したアンモナイトは黄鉄鉱に置き換わっているので、キラキラ金属質に輝いています。
しかし、パイライトディケイと言って、数年で酸化し風化してしまう運命だそうです。
その間にできるだけいろいろな人に見てほしいな、となんとなく思いました。
そんなことはどうでもいいのですが、前回はコンボリューショナルニューラルネットの一種、LeNetを作ってきました。しかし、作ってみましたというのと、83%で飛行機と船を見分けましたというところで力尽きてしまいました。
せっかく作ったので、今回はいろいろ分析していきましょう。
1.LeNetは本当に多層パーセプトロンより性能がいいのか
LeNetは2000枚ずつ程度ではあまり精度が良くなく、パーセプロトンとあまり変わらないことを前回の実験で紹介しました。
しかし、4000枚ずつ学習させたパーセプロトンも評価しなければ、不公平ですよね。
そんなわけで4000枚ずつ学習させた、パーセプトロンを評価しました。
パーセプトロンはいろいろなパラメーターを試してみて、中間層が(100,50,30,10)のものが比較的性能が良かったので選びました。
4000枚学習させるとパーセプトロンも性能が上がり77%くらいまでいきます。それでも4000枚を学習させたLeNetにはかなわないようです。
これ以外にもいろいろな設定を試してみましたが、80%を超えるパーセプロトンは今のところできていません。
もちろん初期値などによってはありうると思いますが、平均的に見るとLeNetのほうが精度が高く、コンボリューション層はやはり画像処理に有効であると言ってよさそうです。
ここで面白いのは、ReLUがSigmoidより性能が出るようになってきたことです。
だんだん複雑になってくるとやはりシンプルなReLUは強いですね。
2.コンボリューション層は何を学習しているのか
LeNetではコンボリューション層は5枚のフィルタ(5×5)の第一層と、3枚のフィルタ(5×5)の第三層を組み合わせて使用しています。
学習したフィルタをエクセルで可視化して見てみます。
一般的には、コンボリューション層はガボールフィルタのようなフィルタを学習するといわれています。
セルの中の数字は重みの係数で、その値が高いところを赤に、低いところを青に色付けしています。
例えば、左の上から二番目のフィルタは、真ん中に白い斜め線が入って、その上下は黒という画像に反応します。
実際に見てみると、角を検出しそうなフィルタ(右上)、横線や斜め線を検出するようなガボールフィルタライクなものなどを学習しているようです。面白いのは、毎回同じフィルタを学習するわけではなく、学習するたびにできるフィルタが変わることでした。
ということは、もっとフィルタを増やして最適な組み合わせができれば、より精度が上がるのではないでしょうか。
3.LeNetはReLUも使えるのか
LeNetはReLUよりも前に発表されているので、95年の論文では全結合層はSigmoid関数でした。
ここをReLUに変えても学習できるでしょうか。
実は問題なく学習でき、しかも精度はSigmoidより高いことも多かったです。
初期値によって変動ありますが、5回程度実験したところ、Sigmoidを使用していた時よりも、1~2%ReLUのほうが結果が良いか、同じ精度が得られました。
4.よりLeNetの性能を上げるには?
さて、フィルタを増やすことで性能が上がりそうなこと、ReLUのほうが性能がよさそうなことがわかってきました。
実際やってみましょう。
第一層のフィルタを10枚、第三層を5枚にします。
全結合層は最終層はsigmoidですが、それ以外の全結合層はReLUを使用しました。
前回83%だったところから精度がちょっと上がって87%まで行きました。
90%になるときもあったのですが、残念ながらその時の設定が消えてしまい、再現できなくなりました。
ディープラーニングではパラメーターの記録の残し方も重要ですね。
0.事前準備としての高速化
今回、効率的に実験を行えるようにまずは結構高速化を頑張りました。
下記を施すことで、最初は200msぐらい一回の学習にかかっていましたが、60msで学習できるようになりました。
効いたこと効かなかったことを書いていきます。
効いたもの
・一番下の層では次の層に伝搬するバックプロパゲーションを計算しないようにする
・コンボリューション層の次はMaxPooling層なので、バックプロパゲーションの係数が0になることが多いが、その時は計算を省く
・フィルタ処理の計算で、データをとってくる部分と掛け算をする部分を別のループにする(SIMD演算が使われやすくなったり、配列の長さチェックがなくなるなど最適化が効く)
・合計値を計算するときに、いきなり配列に+=していくのではなく、sumというような変数を作ってそれに加算し、最後に代入する(配列の添え字によるジャンプを防ぐ)
・バッチサイズを小さくする
あんまり効かなかったもの
・倍精度(double)の浮動小数点数を使っていたが、すべて単精度(float)で統一する(GPUでは単精度のほうが速いと聞くので伸びしろはあるのかも)
・.Net Frameworkから.Net Coreに変える(4%ぐらいは早くなったが)
勾配消失問題再び
さて、前々回、Sigmoid関数の勾配消失問題について書きましたが、高速化をしてみると実際にSigmoid関数の勾配消失が無視できなくなってきました。
特にバッチサイズを小さくすると勾配が一定方向にならず、学習が進みにくくなります。
また、単精度の浮動小数点数では非常に小さい勾配が丸められてしまうこともあります。
ちゃんとケアすれば、ある程度勾配消失問題は防げるのかもしれませんが、高速化と逆行するところがあり、実際にケアが面倒になってきてReLU族を使いたくなってきます。
そのうち、どういう条件で勾配消失が起こるのかより精緻に確認したり文献調査をしたりしたいですね。
次回
LeNetのコンボリューションは1枚の画像を5枚のフィルタで、5個の特徴平面に変換し、さらに3個のフィルタで、特徴平面を増やしていくといったものでした。
しかし、この方法だと、RGBの3平面の画像を入力にしたときに15の特徴平面が作られるだけで、それらが互いに交じりあうのは全結合層を待たなければいけません。
色情報を混然一体となって扱うにはより複雑なコンボリューションの計算が必要になります。
AlexNetではそのような方法を使用していますので、次回はそれを実装していきたいと思います。
▼本シリーズのほかの記事はこちら