MNIST文字認識ニューラルネットワークを手書きでゴリゴリ書いてみる
[python] [jupyter notebook] [MNIST] [keras] [tensorflow] [使わない]
新人研修時、MNISTの手書き文字を認識するニューラルネットワークのコードをkerasやtensorflowなどのライブラリを使わずに書いてみろと言われました。いろいろなサイトを覗きながら写経しようにも、そもそもkerasやtensorflowなどを使わずにニューラルネットワークを書いている人がいないのでとても困りました。ニューラルネットワークの原理を理解するのに1カ月、コードを書くのに半月かかりましたかね。
いまSEの研修を受けていて、同じ痛い目にあっている人のために記事を書こうと思います。原理を完全に理解していなくても読み進めて書き移せば最後には文字認識AIができている、、、、はず、、、、、
一応GitHubにもコード全文を載せておきます。
ライブラリをimport
28×28のtrainデータが60000個。その正解ラベルが60000個。
28×28のtestデータが10000個。その正解ラベルが10000個
trainデータの正解ラベルの中身は[5、0、4 ….5、6、8]
おい!kerasを早速使ってるじゃないか!Using Tensorflow backendとはどうなっとるんだ!という声が聞こえてきそうですが、MNISTの文字データセットがkerasの中に入っているのでこればっかりは使うしかありません。kerasを動かすのにtensorflowが必要なので、これも致し方ありません。もうこれ以上は使いません。ごめんなさい。
入出力、バイアス、重みが入る配列を作る
入力が784(28×28)、中間層15層、出力層10層のニューラルネットワークを作成していきます。
re_bias、re_weightは逆伝搬を伝えるときに使います。
weightとre_weightの配列を初期化するときは必ず[[0 for i in range()]for i in range()]を使用してください。その理由は前回記事を読んでもらえばわかります。 weight= [[0]*784]*15で初期化してしまうと大変なことになります。
設計当初、biasを設置するのを忘れてしまいましたが一応学習はしました。もちろん精度はそんなに良くなかったですが、、、
関数の設置
今回、中間層の活性化関数はsigmoid関数を使用します。
back_propagation関数の中にあるglobal weight,biasはweight,biasの値を関数内だけではなくコード全体に反映させることができます。globalの詳しい使い方はこちらをご覧ください。
delta関数とback_propagation関数の部分を理解してコードを書くのに約3週間かかりました。誤差逆伝播法の詳しい書き方はこちらをご覧ください
重み、バイアスの初期値を決める
np.random.rand()は0.0以上、1.0未満の乱数を
np.random.randn()は 平均0、分散1(標準偏差1)の乱数を発生させます。
初期値は0.1をかけるなどして、小さい値にするのがポイントです。
学習させる
for文以下がニューラルネットワークの本体です。
Input0は中間層に入る前の値(入力に重みをかけてバイアスを足す)
Output0は中間層から出てきた値(活性化関数から出力されたもの)
Input1は出力層に入る前の値(Output0に重みをかけてバイアスを足す)
Output1は出力された値(softmax関数から出力されたもの)
true_num = [0]*10
true_num[y_train[k*100+j]] = true_num[y_train[k*100+j]]+1
の2行で正解ラベルを0か1のone hot 表現にしています。
つまり正解ラベルが4なら→[0,0,0,0,1,0,0,0,0,0]という表現になります。
学習曲線をグラフに出力する
上記のコードで学習の様子が可視化でき、保存できます。
素人感丸出しのコードですいません。
testデータでモデルを評価する
予測するコードは学習させるコードから誤差逆伝播の関数を取り除いてあげれば大丈夫です。
素人が書いたコードなのでプロから見たらツッコミどころ満載だとは思いますが、まあ一応学習と予測はできるのでこれで良しとしましょう。
コード部分を上から素直に読んでいけばニューラルネットワークの構造もつかめるようになっているはずです。