目次
間違った画像を確認してみよう
こんにちは。
AI coordinatorの清水秀樹です。
以前からモデル評価時に間違った画像を確認してみたいと思っていたため、今回改めて実装してみました。
間違った画像を確認する方法を紹介しているサイトが見つからなかったので、実装に結構苦労しました。
(単純に筆者のスキルが無いだけですが・・・)
興味がある方は、ぜひ試してみてください。
MNISTで間違った画像を確認する方法
間違った画像を保存するフォルダを作成し、以下のソースを貼り付けるだけで、間違った評価をした画像を確認できるようになります。
from PIL import Image categories = [ "0","1", "2" , "3", "4" , "5", "6" , "7", "8" , "9"] pre = model.predict(X_test) for i,v in enumerate(pre): pre_ans = v.argmax() ans = y_test[i].argmax() dat = X_test[i] if ans == pre_ans: continue fname = "NG_photo/" + str(i) + "-" + categories[pre_ans] + \ "-ne-" + categories[ans] + ".png" dat *= 255 img = Image.fromarray(dat.reshape((28,28))).convert("RGB") img.save(fname)
MNISTソースコードの紹介
以下、ソースコードです。
そのままでも動くと思います。
from keras.datasets import mnist from keras.models import Sequential from keras.layers.core import Dense, Dropout, Activation from keras.optimizers import RMSprop from keras.utils import np_utils import matplotlib.pyplot as plt from PIL import Image import numpy as np categories = [ "0","1", "2" , "3", "4" , "5", "6" , "7", "8" , "9"] def build_model(): # モデルの作成 model = Sequential() model.add(Dense(512, input_shape=(784,))) model.add(Activation('relu')) model.add(Dropout(0.2)) model.add(Dense(512)) model.add(Activation('relu')) model.add(Dropout(0.2)) model.add(Dense(10)) model.add(Activation('softmax')) # 損失関数の定義 model.compile( loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) return model def plot_history(history): # 精度の履歴をプロット plt.plot(history.history['acc'],"o-",label="accuracy") plt.plot(history.history['val_acc'],"o-",label="val_acc") plt.title('model accuracy') plt.xlabel('epoch') plt.ylabel('accuracy') plt.legend(loc="lower right") plt.show() # 損失の履歴をプロット plt.plot(history.history['loss'],"o-",label="loss",) plt.plot(history.history['val_loss'],"o-",label="val_loss") plt.title('model loss') plt.xlabel('epoch') plt.ylabel('loss') plt.legend(loc='lower right') plt.show() if __name__ == "__main__": # MNISTのデータの読み込み # 訓練データ6万件、テストデータ1万件 # 28ピクセル × 28ピクセル = 784ピクセルのデータ # 色は0〜255 (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train.reshape(60000, 784).astype('float32') / 255 X_test = X_test.reshape(10000, 784).astype('float32') / 255 print('X_train shape:', X_train.shape) # 10次元配列に変換 //数字の5ならこんな感じ[0,0,0,0,1,0,0,0,0,0] y_train = np_utils.to_categorical(y_train, 10) y_test = np_utils.to_categorical(y_test, 10) # データで訓練 今回は時間省略のため5回で学習する model = build_model() history = model.fit(X_train, y_train, nb_epoch=5, batch_size=500, validation_data=(X_test, y_test) ) #学習モデルの保存 json_string = model.to_json() #モデルのファイル名 拡張子.json open('mnist.json', 'w').write(json_string) #重みファイルの保存 拡張子がhdf5 model.save_weights('mnist.hdf5') # 間違った画像を出力する。 pre = model.predict(X_test) for i,v in enumerate(pre): pre_ans = v.argmax() ans = y_test[i].argmax() dat = X_test[i] if ans == pre_ans: continue fname = "NG_photo/" + str(i) + "-" + categories[pre_ans] + \ "-ne-" + categories[ans] + ".png" dat *= 255 img = Image.fromarray(dat.reshape((28,28))).convert("RGB") img.save(fname) # モデルの評価を行う score = model.evaluate(X_test, y_test, verbose=1) print('loss=', score[0]) print('accuracy=', score[1]) # modelに学習させた時の変化の様子をplot plot_history(history)
MNISTの結果確認
どんな画像を間違えたか確認してみました。
なんの数字だか分かりますでしょうか?
正解は4です。
学習モデルは6と認識したようです。
その他に間違えた画像は以下のような画像がありました。
人間がみても4なのか9なのか、0なのか6なのか判断が難しいものがありますね。
こうやって間違った画像を確認してみると、学習モデルの精度が100%の認識率でないと使えないと思われがちになりますが、そもそも人間の目で確認しても正解が分からないような画像もあるので、100%の認識率でないからダメと見切りをつけるのは早計な気がしますね。
CIFAR-10でも試してみよう
続いてCIFAR-10 datesetでも試してみましょう。
こちらはConvolutional Neural Networkで構築した学習モデルで間違った画像を表示してみます。
なのでMNISTで紹介したソースコードとは若干異なります。
間違った画像を抽出するソースコードも多少異なります。
また、折角なので学習モデル図も作成するようにしています。
CIFAR-10用のソースコードは以下を参考にしてください。
# coding:utf-8 import numpy as np import scipy.misc import tensorflow as tf from keras.utils import np_utils from keras.models import Sequential, Model, model_from_json from keras.layers.core import Dense, Activation, Flatten, Dropout from keras.layers.convolutional import Convolution2D from keras.layers.convolutional import MaxPooling2D from keras.optimizers import SGD from keras.layers.normalization import BatchNormalization from keras.callbacks import EarlyStopping, TensorBoard, ModelCheckpoint from keras.datasets import cifar10 from keras.utils.visualize_util import plot import keras.backend.tensorflow_backend as KTF import matplotlib.pyplot as plt from PIL import Image #1024個の一層目を定義 in_shape = (32, 32, 3) #縦、横、RGB #クラスを指定 categories = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"] nub_classes = len(categories) #モデルの作成 def build_model(): model = Sequential() #畳み込み層の作成 #1層目の追加 1024個の層を最初に作り、フィルター3*3のフィルターを16個作成 model.add(Convolution2D(16, 3, 3, border_mode="same", input_shape=in_shape)) model.add(Activation("relu")) #2層目の畳み込み層 model.add(Convolution2D(16, 3, 3, border_mode="same")) model.add(Activation("relu")) #プーリング層 model.add(MaxPooling2D()) #Dropoutとは過学習を防ぐためのもの 0.5は次のニューロンへのパスをランダムに半分にするという意味 model.add(Dropout(0.5)) #3層目の作成 model.add(Convolution2D(32, 3, 3, border_mode="same")) model.add(Activation("relu")) #4層目の作成 model.add(Convolution2D(32, 3, 3, border_mode="same")) model.add(Activation("relu")) #プーリング層 model.add(MaxPooling2D()) model.add(Dropout(0.5)) #5層目 model.add(Convolution2D(64, 3, 3, border_mode="same")) model.add(Activation("relu")) #6層目 model.add(Convolution2D(64, 3, 3, border_mode="same")) model.add(Activation("relu")) #プーリング層 model.add(MaxPooling2D()) #Dropout model.add(Dropout(0.5)) #7層目 model.add(Convolution2D(128, 3, 3, border_mode="same")) model.add(Activation("relu")) #Dropout model.add(Dropout(0.5)) #平坦化 model.add(Flatten()) #8層目 全結合層 FC model.add(Dense(100)) model.add(Activation("relu")) #Dropout model.add(Dropout(0.5)) #8層目 引数nub_classesとは分類の数を定義する。 model.add(Dense(nub_classes)) model.add(Activation('softmax')) #ここまででモデルの層完成 #lossは損失関数を定義するところ model.compile(loss="categorical_crossentropy", metrics = ["accuracy"], optimizer = "adam" ) #学習モデル図の作成 plot(model, to_file='model.png') return model def plot_history(history): # 精度の履歴をプロット plt.plot(history.history['acc'],"o-",label="accuracy") plt.plot(history.history['val_acc'],"o-",label="val_acc") plt.title('model accuracy') plt.xlabel('epoch') plt.ylabel('accuracy') plt.legend(loc="lower right") plt.show() # 損失の履歴をプロット plt.plot(history.history['loss'],"o-",label="loss",) plt.plot(history.history['val_loss'],"o-",label="val_loss") plt.title('model loss') plt.xlabel('epoch') plt.ylabel('loss') plt.legend(loc='lower right') plt.show() if __name__ == "__main__": #ここに読み込み処理と関数呼び出しを行う #cifar10からデータを取得 10種類の画像データセットがある 計5万枚 (X_train, y_train), (X_test, y_test) = cifar10.load_data() print(X_train.shape, y_train.shape) print(X_test.shape, y_test.shape) y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) X_train = X_train.astype('float32') / 255 X_test = X_test.astype('float32') / 255 print("X_train", X_train.shape) print("y_train", y_train.shape) print("X_test", X_test.shape) print("y_test", y_test.shape) #ここからが上記で作成したモデルを呼び出す処理 model = build_model() history = model.fit(X_train, y_train, nb_epoch=10, #学習させる回数 今回は10 回数はお好みで pythonのnb_epochとはrangeの繰り返しのこと batch_size=500, #無作為に何枚学習に使用するか決定する。数字はなんでも良い validation_data=(X_test, y_test) ) # モデルの評価する pre = model.predict(X_test) for i,v in enumerate(pre): pre_ans = v.argmax() ans = y_test[i].argmax() dat = X_test[i] if ans == pre_ans: continue print("[NG]", categories[pre_ans], "!=", categories[ans]) print(v) fname = "NG_photo/" + str(i) + "-" + categories[pre_ans] + \ "-ne-" + categories[ans] + ".png" dat *= 256 img = Image.fromarray(np.uint8(dat)) img.save(fname) #学習モデルの保存 json_string = model.to_json() #モデルのファイル名 拡張子.json open('cifar10.json', 'w').write(json_string) #重みファイルの保存 拡張子がhdf5 model.save_weights('cifar10.hdf5') # モデルの評価evaluate score = model.evaluate(X_train, y_train) print("test loss", score[0]) print("test acc", score[1]) # modelに学習させた時の変化の様子をplot plot_history(history)
こちらも、そのままで動くはずです。
CIFAR-10の結果確認
それでは間違った画像を確認してみましょう。
今回はepoch=10なので、大した学習精度が出せていない状態での結果確認となります。
間違った画像の一部を紹介すると、
catをfrogと間違えたようです。
airplaneをshipと間違えたようです。
なるほどなるほど。
その他に間違えた画像の一例を載せておきます。
それではまた。
その他のDeepLearning記事はこちらから
いつも勉強させていただいています。
初心者の質問で大変恐縮ですが、MNISTのコードを実行したところ、以下のエラーがでます。
間違った写真を保存するフォルダをどのような名前で、どこに作成したらいいのでしょうか?
実行コードがあるファイルに『fname』というフォルダを作成したのですが、ダメでした。
ご教授いただければ幸いです。
Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] – 5s 79us/step – loss: 0.3839 – acc: 0.8797 – val_loss: 0.1583 – val_acc: 0.9514
Epoch 2/5
60000/60000 [==============================] – 4s 70us/step – loss: 0.1414 – acc: 0.9571 – val_loss: 0.0885 – val_acc: 0.9729
Epoch 3/5
60000/60000 [==============================] – 4s 72us/step – loss: 0.0915 – acc: 0.9712 – val_loss: 0.0813 – val_acc: 0.9750
Epoch 4/5
60000/60000 [==============================] – 4s 69us/step – loss: 0.0684 – acc: 0.9781 – val_loss: 0.0727 – val_acc: 0.9773
Epoch 5/5
60000/60000 [==============================] – 4s 70us/step – loss: 0.0532 – acc: 0.9832 – val_loss: 0.0663 – val_acc: 0.9815
—————————————————————————
FileNotFoundError Traceback (most recent call last)
in
92 dat *= 255
93 img = Image.fromarray(dat.reshape((28,28))).convert(“RGB”)
—> 94 img.save(fname)
95
96 # モデルの評価を行う
C:\Anaconda3\envs\tf140\lib\site-packages\PIL\Image.py in save(self, fp, format, **params)
1989 # Open also for reading (“+”), because TIFF save_all
1990 # writer needs to go back and edit the written data.
-> 1991 fp = builtins.open(filename, “w+b”)
1992
1993 try:
FileNotFoundError: [Errno 2] No such file or directory: ‘NG_photo/115-9-ne-4.png’
井上さん。
フォルダ名を「NG_photo」として頂ければ動くかと思います。
清水様
ありがとうございます。
無事できました。
お忙しいところ恐縮です。
今後とも宜しくお願い致します。
清水 様
なんども聞いてしまい大変申し訳ありません。
清水様のコードのおかげで、間違っている写真を取り出すことができ、大変勉強になっています。
現在、3種類のプランクトンに対して、各60枚の学習データと各30まいのテストデータに対して評価を行っています。
コードの最後に、
test loss 0.017122555635650513
test acc 0.99640522875817
と表示され、テストデータの正解率は99.6%と思ったのですが、NG_Photoには5枚の写真が入っていました。
テストデータは計90枚あったので、そのうち5枚の写真が間違っているなら、Test_accuracyは94.5%になると思うのですが、上述のように99.6%と表示されています。
この違いはなぜでしょうか?
ご教授いただければ幸いです。
井上さん
詳細は私もしっかり調べていないので分かりません。
epoch数やバッチサイズで式が変わってくるのかと思います。(想像ですが・・・)
清水様
ご教授ありがとうございます。
式等勉強します。
色々ありがとうございます。
清水様
いつもブログで勉強させていただいています。
先週質問させていただいた不正解写真の数と、表示されるTest_accuracyの違いですが、CIFAR-10のコードの178行目にX_train, y_trainとなっているのですが、表示には、180, 181行目のように’test_…’となっているのが原因ということが分かりました。
色々といつもありがとうございます。
今後も勉強させていただきます。