Rでニューラルネットワークを用いた手書き数字認識

アイディア

  • 元々のアイディアはCodeZineの記事ニューラルネットワークを用いたパターン認識で公開されていたJavaアプレット
  • 学習精度を上げるために、自分で書いた文字を元に学習させる。
    • それぞれの数を10回ずつ手書き入力させ、データを用意し、それを元にニューラルネットワークを学習させる
  • Rで用意されているneuralパッケージを使用する

手書き入力データの用意

  • CodeZineさんの記事のように、手書き入力した数字を7×11のグリッドで表現

  • 作成したJavaアプレットを用い、RBFモデルのネットワークで学習するための、入力層のユニットは7×11の計77、出力層のユニットに0から9の数を設定したデータを用意する。
  • 0〜9間での数字をそれぞれ10回ずつ書いて、以下のような学習用のcsvファイル(data.csv)を作成
cell0 cell1 cell2 ... cell76 ans0 ans1 ans2 ... ans9
0.1 0.1 0.1 ... 0.1 0.9 0.1 0.1 ... 0.1
... ... ... ... ... ... ... ... ... ...
0.1 0.1 0.1 ... 0.1 0.1 0.9 0.1 ... 0.1
... ... ... ... ... ... ... ... ... ...
    • 塗りつぶされたcellは0.9、空白だったセルは0.1で一次元配列にして保存
    • それぞれの値に対応するansの値が0.9、それ以外が0.1となるように
  • 同様に、0〜9までのテスト用のcsvファイル(test.csv)も作成
cell0 cell1 cell2 ... cell76
0.1 0.1 0.1 ... 0.1
0.1 0.1 0.1 ... 0.9
... ... ... ... ...

Rを使ったRBFモデルのニューラルネットワーク

  • 今回のように高次の交互作用が存在する課題は、ユニット内の変換にラジアル基底関数(RBF)など釣り鐘式の関数を利用すると学習が容易に成立する事が知られている。
  • package neuralをRにインストール
options(CRAN="http://cran.r-project.org")
install.packages("neural")
    • 通常ならば以上のようにパッケージをインストールできるが、neuralは古くなっためか退避されていていたため、zipを直接ダウンロードしてインストールする。
データを読み込む
  • neural libraryを読み込んで、dataに学習用csvを読み込み
  • inputに7×11の配列データ、outputにそれぞれに対応する数を読み込む
library(neural)
data<-read.csv("data.csv",header=T)
input<-as.matrix(data[0:77])
output<-as.matrix(data[78:87])
neuralのGUIを使ってネットワークの分析
  • 初期値のシードを固定し、中間層を2層(5個と3個)で学習の最大繰り替えし数を300回に指定
set.seed(1)
learn0<-mlptrain(input, neurons=c(5,3), output$ans1, it=300)
learn1<-mlptrain(input, neurons=c(5,3), output$ans2, it=300)
...
learn9<-mlptrain(input, neurons=c(5,3), output$ans9, it=300)
  • すると以下のようなGUIが表示されるため、startをクリック

  • 自分のノートパソコンでだいたい、それぞれ10分程度。
    • 終了すると、出力ユニットボックスが赤くなるので、そうしたらexit

学習データのセーブ

  • 以下のようにセーブできる
save(learn0, file="learn0.dat") 
save(learn1, file="learn1.dat") 
...
save(learn9, file="learn9.dat") 

精度テスト

  • テスト用csvを読み込んで、学習の完了したネットワークで値予測を行う
    • それぞれの予測値を取り込み、ひとつに結合し、表示、csv出力
test<-read.csv("test.csv",header=T)
testdata<-as.matrix(test[0:77])

applied0<-mlp(testdata, learn0$weight, learn0$dist,learn0$neurons, learn0$actfns)
applied1<-mlp(testdata, learn1$weight, learn1$dist,learn1$neurons, learn1$actfns)
...
applied9<-mlp(testdata, learn9$weight, learn9$dist,learn9$neurons, learn9$actfns)

result<-cbind(applied0,applied1,applied2,applied3,applied4,applied5,applied6,applied7,applied8,applied9)
result

write.csv(result,"result.csv")
  • 結果は以下のようになった。
prediction\actual # 0 1 2 3 4 5 6 7 8 9
0 0.838 0.088 0.087 0.090 0.094 0.091 0.091 0.099 0.085 0.302
1 0.090 0.594 0.123 0.140 0.093 0.103 0.087 0.096 0.085 0.091
2 0.142 0.127 0.907 0.092 0.109 0.099 0.108 0.093 0.109 0.764
3 0.088 0.096 0.146 0.768 0.106 0.096 0.094 0.108 0.093 0.129
4 0.104 0.110 0.091 0.089 0.882 0.100 0.146 0.095 0.114 0.106
5 0.092 0.099 0.105 0.088 0.101 0.937 0.100 0.091 0.107 0.090
6 0.108 0.102 0.102 0.237 0.122 0.349 0.860 0.092 0.090 0.090
7 0.107 0.184 0.186 0.094 0.159 0.252 0.097 0.760 0.102 0.236
8 0.100 0.093 0.089 0.089 0.594 0.087 0.088 0.096 0.106 0.093
9 0.088 0.297 0.091 0.130 0.177 0.102 0.089 0.113 0.094 0.852
  • 8を除いた全ての値でそれなりの精度の予測ができた。
  • 改善点はこれらの作業をJAVAから全自動化