やったこと
関西で行われている『チームで学ぼう!TensorFlow(機械学習)実践編』でひらがなを認識するNNを作って学習させました。実際に手を動かして学習データを見ることで、単純パーセプトロンの動きがわかったのでまとめました。
https://soleildatadojo.doorkeeper.jp/events/51951
参考URL
TensorFlow : ML 初心者向けの MNIST (コード解説)
http://tensorflow.classcat.com/2016/03/09/tensorflow-cc-mnist-for-ml-beginners/
ここにもっと詳しく書いてあるので、正確に知りたいたいならこっちを読んでください。学習データが綺麗なひらがななので、可視化の結果はMNISTよりは理解しやすくなりました。
TensorFlowでアニメゆるゆりの制作会社を識別する
http://kivantium.hateblo.jp/entry/2015/11/18/233834
自分で用意した画像データをTensorflowで使うやり方がわかりやすく書いてありました。参考になりました。
学習データ
勉強会で確実に素性のわかっているデータセットを用意したほうが良いとアドバイスを受け、まずはWindowのフォントから抜き出しました。
https://github.com/natsutan/chihayaburu/blob/master/tools/hiragana_gen/hiragana_gen.py
ネットワーク
MNISTのチュートリアルを変更して、ひらがなの数に対応できるように増やしました。
https://github.com/natsutan/chihayaburu/blob/master/release/softmax/chihaya_softmax.py
学習結果の可視化
学習結果はそのまま読みだすことができないので、sees.runの引数にほしい変数を与え、戻り値として受け取ります。
acc, y_true, y_pred, W, b = sess.run([accuracy, y_true, y_pred, W, b], feed_dict={x: test_img, y_: test_label}) print(acc) np.savetxt('W.csv', W, delimiter=',') np.savetxt('b.csv', b, delimiter=',')
numpyの配列で返ってくるのでsavetxtでcsvに変換しました。
パラメータのWは784x46の行列です。784は28×28の画素数、46は今回の認識で使ったひらがなの数です。つまり、ひらがなの数だけ28x28の行列があるのでそれを画像に変更しました。
色をそれっぽく見せるために試行錯誤していますが、PIL.Imageを使ってpngに落としました。見やすいように拡大しています。
i = 0 for Wn in W.T: img = Image.new('RGB', (28,28)) for y in range(28): for x in range(28): v = Wn[y*28+x] v16 = min([int(v*500), 255]) if v < 0: col = (-v16 // 2, -v16 // 8, -v16 // 8) else: col = (0, 0, v16) img.putpixel((x,y), col) imgx8 = img.resize((28*8, 28*8)) img.save('weight/w_' + str(i) + '.png') imgx8.save('weight/w4_' + str(i) + '.png') i+=1
可視化の結果
TensorFlow : ML 初心者向けの MNIST (コード解説)と同じく、青くなっているところが正の値、赤くなっているところが負の値を示しています。
MNISTよりは何をやっているかがわかりやすいのではないでしょうか。「い」がわかりやすいです。
これと識別したい文字画像を比較して、青いところに文字があれば高い点を、赤いところに文字があればマイナスの点をつけます。最終的に全画素の点を合計した値にバイアス(b)を足したものがスコアになります。46文字全てに同じ計算を行い、一番高い値が単純パーセプトロンが認識した文字になります。
気がついたこと
- フォントの文字のように、綺麗なデータ、かつ位置決めがしかりできるなら単純パーセプトロンでも十分な精度がだせる。
- 「い」がわかりやすいが、「い」の右側が学習結果の位置からずれると「い」と認識されない。平行移動や拡大、縮小に弱い。学習データを増やす必要がある。CNNではどうやって回避しているのかが気になる。
- 学習、識別に使うデータが、白地に黒よりも、黒地に白の方が認識率が高い。Wx+bを大きくすることを考えた時に、黒い部分(輝度0)に重みをかけて大きな値に持っていくのが難しいからではないかと思う。僕の環境では、白地に黒だと86%、黒地に白だと91%の認識率。
- 仕組みを理解するためには、自分でデータを用意したほうが良い。
- CやVerilogでアルゴリズムを実装しようとすると仕組みがよくわかる。この程度であれば、重みは整数でも精度は変わらない。