ニューラルネットワークのC++プログラムの公開

作成したニューラルネットワークのC++プログラムを、
https://github.com/toyowa/neuralnet
に公開した。
Gnuのg++用のプログラムで、他では確かめていない。
ネットワーク全体は、Netクラスに、その層(レイヤー)はLayerクラスに、レイヤーの内容であるニューロンは、Neuronクラスになっている。それぞれ、オブジェクト化されて使われる。
細かい説明は、気が向いたらしよう。プログラムを使えるくらいの人は、見ればわかるだろうと思う。
余談だが、私は、このプログラムも含め、C++、JAVA、JAVASCRIPT、Html、PHPなどの開発は、全てNetbeans上でやっている。Netbeansは、最高の開発環境だと思っている。
このニューラルネットワークとバックプロパゲーションは、30年近く前に一度やっていたことなのだ。大きく変わったのは、コンピュータの凄まじい高速化だ。

MNIST手書き数字データで93%の識別率

作成した汎用ニューラルネットワークで、その辺りのパフォーマンスを図る標準データとなっているMNISTの手書き数字データをテストしてみた。
MNISTについては、
http://yann.lecun.com/exdb/mnist/
にデータそのものと解説がある。
手書き数字は、
こんな感じのもので、数字の一つ一つがデータ化されている。1ピクセルが1バイト(0-255)の値が与えられ、1文字、28X28ピクセルからできている。
データ数は、60000文字の学習用データと10000文字のテスト用データがある。それぞれ、ピクセルデータとそれが幾つの数字を表しているかというラベルデータがある。60000字でニューラルネットを学習させ、ネットワークウェイトを作成し、そのウェイトが、テスト用10000字を正しく認識するかどうかを調べるのである。
ニューラルネットワークは、入力レイヤーが、28X28の784ニューロン、隠れ層(中間レイヤー)は100ニューロン、出力は0から9までの値を出すので、10ニューロンにした。出力は、ネットワークがその画像について判定した値のニューロンだけが発火する(値1になる)ことを見越しているわけである。

78万4千個のウェイトからなる、従って、訓練手法であるバックプロパゲーション(誤差逆伝搬)で、6万個の文字について、毎回これだけのウェイトを微調整しながら最終的に望ましいウェイトを見つけるわけであるから、相当大きめのネットワークである。
データについては、それぞれのピクセルの値を、正ならば1層でないならば0に、ビット化したものと、(0-255)それぞれの値を0から1の間の数に正規化したものと2種類用意した。元のデータのままをネットワークに入れたら、途中で破綻している。正規化したものに全ての情報が入っているので、生データを使う必要はない。
予測的には、正規化して0から1の間の数字にした方が、情報を多く持っているので、良いパフォーマンスを示すのではないかと思われた。0と1にビット化すれば、情報を単純なものにしてしまうのだから。
学習に、3Gヘルツ、8コアの最高スペックのMac Proでも1時間以上かかった。と言ってもこのマックは16スレッド動かせるのだが、プログラムそのものがほとんど1スレッドで動かしているので、相当無駄にしているのだが。逆に、同時にいくつもの学習を同時にさせることはできる。
10000個のテスト用データのテスト結果は、以下のようである。
<正規化(0.0-1.0の間の値)されたデータを用いた場合>
正解数 = 9283 不正解数 = 717 正解率 = 0.9283
<ビット化(0.0か01.0の値)されたデータを用いた場合>
正解数 = 9300 不正解数 = 700 正解率 = 0.93
微妙に正解率がビット化した方がいい。誤差の範囲といってもいいが、何よりも、ビット化して情報を削ったにもかかわらず、正規化したものに匹敵するパフォーマンスを出していることが驚きである。MNISTに掲載されているパフォーマンスと比べるとやや低いが、何の微調整もしていない、ただ作成したものでいきなりテストしただけで、これだけのパフォーマンスを出せれば、私としては合格だ。
正解率は、最大出力を出したユニット番号が、その画像の数字に一致する場合に正解としているのだ、これだけでは、どこまで明確にその数字と判断しているのかがわかりにくい。そこで、正解の出力ユニットがどれくらいの値を出したのかをヒストグラムで示す。基本的にユニットは0から1の間の数字しか出さず、通常、関係ないときはほぼ0に近い値しか出さないことに注意されたい。
つまり、そのユニットが正解だという場合、ほぼ0.9以上の値を突然、出している(ニューロンが発火している)ということだ。このグラフを見ると、このヒストグラムで示されたパフォーマンスは、正規化されたデータの方が、より1に近い数字で、ヒストグラムがより高く立っているので、パフォーマンスが良いといってもいい。ビット化されたデータをそれよりやや低いところで、パフォーマンスを稼いでいる。
次は、ディープラーニングを組み込む。