ニューラルネットワークを書く #2
概要
前回作った1層全結合NNをベースに1層全結合NNでMNISTを試しました。Python歴はおおむね3週間です。numpyの使い方をちょっとだけ覚えました。
MNIST
親の顔より見た手書き数字データ どこのご家庭にもあるMNIST
元データはバイナリファイルらしいですがとりあえずscikit-learnを使います。
参考
実装の参考というより1層でMNISTをやっていたので条件を再現しました。
https://weblabo.oscasierra.net/python/keras-mnist-sample.html
書いたもの
github.com
20エポックでテストデータの精度が92.5%ということでほぼ参考元の精度が出せました。
ただしげきおそ
前回実装した関数
MSE 平均二乗誤差
nはサンプル番号
yは推測値、tは正解ラベル
全て足したものが全体の誤差(loss)になるようです。
SGD 確率的勾配降下法
ミニバッチ処理を使わないとSGDではないらしいので正確には勾配降下法ですかね。
Yは推測値、tは正解ラベル
ΔEは勾配
wは重み
εは学習率
モメンタム
SGDのモメンタム利用のもの。
こんな感じで前回の重み更新量を用いて次の重みを決定するらしいです。 μは0.9とか0.8とか。
今回実装したもの
クロスエントロピー
クラス分類で誤差を出すのはこっちらしいです。
nはサンプル(今回はトレーニングなら60000枚の画像)番号
Kはクラス(今回は10クラス分類)番号
yは推測値、tは正解ラベル
だそうです。これの総和がそのエポックの全体の誤差(loss)になるみたいです。
ソフトマックス関数
活性化関数なのでyをzに変換します。
例えば5分類の場合ソフトマックス関数の出力は[p1, p2, p3, p4, p5]になるので、誤差を取るためにMNISTの正解ラベルも[1, 0, 0, 0, 0]のone-hotベクトルの形にします。
計算でを使いますがzの値によってはオーバーフローを起こしてしまうので対策が必要ならしいです。具体的にはzの数列の中で最大の値をz全体から引いています。
RMSProp
前回はSGDでしたが今回はRMSPropというのを使います。
学習が進むとgが大きくなるので学習率が小さくなり重みの更新が抑えられるみたいな仕組みのようです。
0で割る場面が出てきてこれに結構ハマりました。他人の実装は見ないようにしてましたが最後はググりました無念。非常に小さい値(今回は1e-8)を加算することで0で割ることを回避します。
ミニバッチ処理
今回はデータが多いのと再現元のKerasでミニバッチ処理をしていたので実装しました。
変更点とか
入力層ってそもそもいらないことに気づいたから削除 。入力データにバイアス足したものをそのまま次の層の入力に使えばいいのか…。
ΔEの求め方とか色々2次元配列と複数出力に対応させました。
他
numpyを途中まで使わないつもりでしたがトレーニング・テストデータ分割をscikit-learnでやったところ出力がndarrayだったのでその辺でnumpy使うかーってなって結果リストとndarrayと変換が変に混ざった怪しいコードになりました。次回はうまく使い分けたいです。
Kerasで同じことしたものに対してひじょーに遅いので色々書き方が悪いんだと思いますけどつらいので次に行きます…。
次回
3層NNを実装します。バックプロパゲーションの実装頑張ります。
今回MNISTでデータが多すぎてちゃんと書けてるのか確かめるのが時間かかるという問題があったのでDIGISTでやってみようかなとか思います。
その道に詳しい人のご指導ご鞭撻お待ちしてます。