社畜エンジニア発掘戦線

駆けだしAIエンジニア

MNIST手書き数字の画像識別(隠れ層NNの評価)

前回はMNISTの画像識別を行うためのニューラルネットワークに隠れ層を追加して学習を行いました。訓練の結果は80%そこそこであんまり向上した感じがなかったですが、とりあえずテストデータで精度を評価してみます。コードの流れは前回評価したときと同じです。

CONTENTS

コーディング

前回、学習済みのパラメータを保存するところまではやってしまったので、そのロードからです、まずはMNISTのデータセット

#load dataset
import pickle

save_file = '/Users/FUTOSHI/Desktop/MNIST_test/mnist.pkl'

with open(save_file, 'rb') as f:
    dataset = pickle.load(f)

train_img,train_label,test_img,test_label = dataset

完全にコピペなので、コメントはしょります。

続いて、学習済みのパラメータをロードします。

save_file = '/Users/FUTOSHI/Desktop/MNIST_test/Hidden.pkl'

with open(save_file, 'rb') as f:
    parameters = pickle.load(f)

Wh,Bh,Wo,Bo = parameters

パラメータの数が4つになっているので、順番と添字だけ間違えないようにご注意。

あとはほとんど同じなのでテンポよくいきます、詳しくは前回の記事をご参考。


まずはライブラリのインポート、

#library import
import numpy as np
import matplotlib.pyplot as plt
import time

次にMNISTデータの前処理(正規化とOne-Hot化)です。

#pixel normalization
X_train, X_test = train_img/255, test_img/255

#transform_OneHot
T_train = np.eye(10)[list(map(int,train_label))] 
T_test = np.eye(10)[list(map(int,test_label))]

それから関数の定義、

#function
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def softmax(z):
    return np.exp(z) / np.sum(np.exp(z), axis=1, keepdims=True)

def loss(y, t):
    delta = 1e-7
    return -np.sum(np.multiply(t, np.log(y+delta)) + np.multiply((1 - t), np.log(1 - y+delta)))

正解と不正解の画像を振り分ける空行列を作っておきます。

correct_img = np.empty((0,784))
error_img = np.empty((0,784))


では、10000枚のテスト画像で正解率を計算していきます。

start_time = time.time()
num_of_test = X_test.shape[0] #10000

#test start
for i in range(num_of_test):

今回は隠れ層があるので、Hを計算してから出力Yを求めます。

    #forward prop
    H = sigmoid(np.dot(X_test[i],Wh)+Bh)
    Y = softmax(np.dot(H, Wo)+Bo)

では正解かどうかを判断して、それぞれの行列に振り分けます。

    #set accuracy
    Y_accuracy = np.argmax(Y)
    T_accuracy = np.argmax(T_test[i])

    if Y_accuracy == T_accuracy:
        correct_img = np.vstack((correct_img,X_test[i]))

    else:
        error_img = np.vstack((error_img,X_test[i]))

いちおう、計算時間を測定するコードも添えておきます。

end_time = time.time()


最後に評価結果を出力するprintを書いておきます。

print(correct_img.shape)
print(error_img.shape)
print(100*correct_img.shape[0]/num_of_test)
print(end_time - start_time)

今回も、
・正解画像枚数
・不正解画像枚数
・正解率
・計算時間
を出力させます。

これでコードが完成です。

プログラム実行

ではプログラムを走らせてみます。

(8708, 784) #正解枚数
(1292, 784) #不正解枚数
87.08 #正解率
196.74863386154175 #計算時間

相変わらずそこそこ計算時間がかかります。エンター押したら死んだ魚の目で正座待機です。

10000枚中、正解枚数は8708枚ということで、前回より若干良くなった気がしますが、ほとんど同じです。プログラム(アルゴリズム)自体は基礎問題で何度もトライした内容ですし、間違ってはいなさそう。前回もちらっと書きましたが、学習回数が足りてないのでは説があります。

ということで、学習(イテレーション)回数を変化させて正解率がどう変化するかこちらで検証してみました。

まとめ

今回は隠れ層を追加したシンプルなニューラルネットワークがどれほどの正解率を出すのか検証してみました。結果については考察の余地が残っているのでなんとも言えないところですが、ひとまずアルゴリズムとコードは書き上げることができました。

次回からはCNN(コンボリューション・ニューラルネットワーク)というものにチャレンジしていこうと思います。しかしながらこの手法、画像を画像のままニューラルネットワークに突っ込むという、けっこう複雑なアルゴリズムでできているので、コードを書くのもひと苦労ですし、愚直に書いているとミスを連発してしまいます。そこで、具体的にトライしていく前にいくつかのアルゴリズムを関数化して、外部ライブラリで保管して使えるようにしたいと思います。

このあたりのネタをコラム的にしばらくまとめていくことになりそうです。


アメリカの生活(仕事)がけっこう忙しくなってきて、ディープラーニングに割く時間が削られてきている現状なんですが、まぁマイペースで進めていきたい今日このごろです。

全体コード
github.com

元の記事
週末のディープラーニング - 社畜エンジニア発掘戦線

Twitter
世界の社畜 (@sekai_syachiku) | Twitter