学習の記事はあっても推論まで書いてる記事は少ない気がしたのでまとめます。
はじめに
①自前の画像使って学習・モデル保存→②保存したモデル使って推論
までの流れをやりたいと思います。
環境作るところは割愛します。足りないものはpip installしてみてください。
なぜKerasをつかうのか
理由はずばり、簡単だからです。
普段pytorchやtensorflowも使っていますが、書き方がわかりやすいのは断然Keras。一番ドキュメントわかりやすくて充実してるのもそうな気がします。自分で書いてみるディープラーニングのファーストステップにおすすめです。
①学習
ResNet50を使って画像の分類をやっていきます。
学習はこのあたりの記事と図書のコードが参考です
ResNetをFine Tuningして自分が用意した画像を学習させる
詳解ディープラーニング
コード全文
importosimportrandomimportglobimportmatplotlib.pyplotaspltfromkeras.preprocessing.imageimportImageDataGeneratorfromkeras.applications.resnet50importResNet50fromkeras.modelsimportSequential,Modelfromkeras.layersimportInput,Flatten,Densefromkerasimportoptimizersfromkeras.callbacksimportModelCheckpoint,EarlyStoppingclasses=['1','2','3','4','5']nb_classes=len(classes)#train val dir
train_dir='./data/train'val_dir='./data/val'model_dir='./model'#num samples
train_samples=glob.glob(train_dir+'/*/*.jpg')val_samples=glob.glob(val_dir+'/*/*.jpg')train_samples=len(train_samples)val_samples=len(val_samples)print(train_samples)print(val_samples)#img size
img_w,img_h=224,224#keras image data generator
train_datagen=ImageDataGenerator(rescale=1.0/255,zoom_range=0.2,horizontal_flip=True)val_datagen=ImageDataGenerator(rescale=1.0/255)train_generator=train_datagen.flow_from_directory(train_dir,target_size=(img_w,img_h),color_mode='rgb',classes=classes,class_mode='categorical',batch_size=5)val_generator=val_datagen.flow_from_directory(val_dir,target_size=(img_w,img_h),color_mode='rgb',classes=classes,class_mode='categorical',batch_size=5)#TO save model
checkpoint=ModelCheckpoint(filepath=os.path.join(model_dir,'model_{epoch:02d}.hdf5'),save_best_only=True)#TO early stopping
early_stopping=EarlyStopping(monitor='val_loss',patience=3,verbose=0,mode='auto')### model ###
#ResNet50
input_tensor=Input(shape=(img_w,img_h,3))## train skratch ==>> weights=None ##
ResNet50=ResNet50(include_top=False,weights=None,input_tensor=input_tensor)#def softmax
top_model=Sequential()top_model.add(Flatten(input_shape=ResNet50.output_shape[1:]))top_model.add(Dense(nb_classes,activation='softmax'))model=Model(input=ResNet50.input,output=top_model(ResNet50.output))#hyper param
model.compile(loss='categorical_crossentropy',optimizer=optimizers.SGD(lr=1e-3,momentum=0.9),metrics=['accuracy'])#train
epoch=10history=model.fit_generator(train_generator,steps_per_epoch=train_samples,epochs=epoch,validation_data=val_generator,callbacks=[checkpoint,early_stopping])print(history.history)#plot
acc=history.history['accuracy']val_acc=history.history['val_accuracy']loss=history.history['loss']val_loss=history.history['val_loss']epochs=epochplt.figure()plt.plot(range(1,epochs+1),acc,'b',label='traning accracy')plt.plot(range(1,epochs+1),val_acc,'r',label='validation accracy')plt.title('Training and validation accuracy')plt.legend()plt.savefig('result_acc')plt.figure()plt.plot(range(1,epochs+1),loss,'bo',label='Training loss')plt.plot(range(1,epochs+1),val_loss,'ro',label='Validation loss')plt.title('Training and validation loss')plt.legend()plt.savefig('result_loss')plt.show()
大まかな解説
クラス・ディレクトリの指定と画像の準備
この部分はご本家様の解説が詳しいのでそちらを読んでみてください。順を追って詳しく解説してくださっているのでその流れに乗って真似してみるのみです。
今回のコードでは自分の環境に合わせるため、画像の数の取り方の部分などをちょっと変更してます。
ResNetをFine Tuningして自分が用意した画像を学習させる
今回はdataディレクトリの下に、train,val,testというディレクトリを作り、それぞれの下に1,2,3,4,5というクラスのディレクトリを作ってそれ以下にそれぞれのクラスの画像を保存します。
#クラスを指定する(フォルダ名と同じにする)
classes=['1','2','3','4','5']#クラスの数を取得
nb_classes=len(classes)#trainの画像・validationの画像のディレクトリ指定
train_dir='./data/train'val_dir='./data/val'#モデルを保存するディレクトリの指定
model_dir='./model'#画像のリストを取得
train_samples=glob.glob(train_dir+'/*/*.jpg')val_samples=glob.glob(val_dir+'/*/*.jpg')#画像の数を取得
train_samples=len(train_samples)val_samples=len(val_samples)#確認のためのprint
print(train_samples)print(val_samples)#インプットする画像のサイズを定義(w,hが同じになるようにする)
img_w,img_h=224,224#画像にかける前処理を定義する
#train...0-1で正規化、画像ズーム、水平反転
train_datagen=ImageDataGenerator(rescale=1.0/255,zoom_range=0.2,horizontal_flip=True)#validation...0-1で正規化
val_datagen=ImageDataGenerator(rescale=1.0/255)#学習のためのイテレーター定義
train_generator=train_datagen.flow_from_directory(train_dir,target_size=(img_w,img_h),color_mode='rgb',classes=classes,class_mode='categorical',batch_size=5)#validationのためのイテレーター定義
val_generator=val_datagen.flow_from_directory(val_dir,target_size=(img_w,img_h),color_mode='rgb',classes=classes,class_mode='categorical',batch_size=5)
モデルの保存とearly stopping
これは書籍を参考にしました。4章と付録部分です。
詳解ディープラーニング
モデル保存はベストのモデルのみを保存するようにしています。save_best_only=Falseに変えるとすべてのepochのモデルを保存してくれます。
アーリーストッピングはvalidationのlossを見てstopかけてくれるようにしています。細々はドキュメンテーション読むのがはやそうです。
Kerasドキュメント-コールバック
#モデル保存のコールバック定義
checkpoint=ModelCheckpoint(filepath=os.path.join(model_dir,'model_{epoch:02d}.hdf5'),save_best_only=True)#アーリーストッピングのコールバック定義
early_stopping=EarlyStopping(monitor='val_loss',patience=3,verbose=0,mode='auto')
モデルの定義と学習
この部分もご本家様の解説が詳しいのでそちらを読んでみてください
kerasのResNet50モデル定義を読み込んで学習します。
ResNetをFine Tuningして自分が用意した画像を学習させる
#インプットの定義
input_tensor=Input(shape=(img_w,img_h,3))#スクラッチから学習させたいときはweights=None
#imagenetの重み使いたいときはweights='imagenet'などとする
ResNet50=ResNet50(include_top=False,weights=None,input_tensor=input_tensor)#全結合層を新しく作る
top_model=Sequential()top_model.add(Flatten(input_shape=ResNet50.output_shape[1:]))top_model.add(Dense(nb_classes,activation='softmax'))model=Model(input=ResNet50.input,output=top_model(ResNet50.output))#ハイパーパラメータの定義
model.compile(loss='categorical_crossentropy',optimizer=optimizers.SGD(lr=1e-3,momentum=0.9),metrics=['accuracy'])#学習する
epoch=10history=model.fit_generator(train_generator,steps_per_epoch=train_samples,epochs=epoch,validation_data=val_generator,callbacks=[checkpoint,early_stopping])
結果をplotする
print(history.history)してみるとhistoryの中には4つの要素が辞書形式で入っていることがわかります。
{'val_loss':[751238512640.0],'val_accuracy':[0.23999999463558197],'loss':[65.4847153377533],'accuracy':[0.344]}
これを使ってプロットしていきます。
プロットはより良い形があると思うのでむしろいろいろ教えてください。
acc=history.history['accuracy']val_acc=history.history['val_accuracy']loss=history.history['loss']val_loss=history.history['val_loss']epochs=epochplt.figure()plt.plot(range(1,epochs+1),acc,'b',label='traning accracy')plt.plot(range(1,epochs+1),val_acc,'r',label='validation accracy')plt.title('Training and validation accuracy')plt.legend()plt.savefig('result_acc')plt.figure()plt.plot(range(1,epochs+1),loss,'bo',label='Training loss')plt.plot(range(1,epochs+1),val_loss,'ro',label='Validation loss')plt.title('Training and validation loss')plt.legend()plt.savefig('result_loss')plt.show()
②推論
コード全文
fromkeras.modelsimportload_modelfromkeras.preprocessing.imageimportload_img,img_to_arrayimportnumpyasnpimportglobimportmatplotlib.pyplotasplt#test and model dir
test_dir='./data/test'model_dir='./model'#num samples
test_samples=glob.glob(test_dir+'/*/*.jpg')print(test_samples)#img size
img_w,img_h=224,224###model###
model=load_model(model_dir+'/model_07.hdf5')foriinenumerate(test_samples):print(i[1])x=load_img(i[1],color_mode='rgb',target_size=(img_w,img_h))x=img_to_array(x)/255x=x[None,...]predict=model.predict(x,batch_size=1,verbose=1)print(predict)
大まかに解説
前半は割愛します。
モデルの読み込み
モデルの読み込みめっちゃ簡単でした。
fromkeras.modelsimportload_modelmodel=load_model(model_dir+'/model_07.hdf5')
こんだけ!!こんだけで学習したものを全部読み込めます。すごい。
今回は10epoch学習したうちの7epochめの重みが一番良かったのでそれを読み込んでます。
推論
今回はフォルダ内の画像を1枚ずつ読み込んで、それぞれに対する推論値を出してほしかったのでこのようにしています。
x=x[None,...]で次元数を変えるのは今回初めて知りました。以下の解説が詳しいです。
pythonの文法について
foriinenumerate(test_samples):print(i[1])x=load_img(i[1],color_mode='rgb',target_size=(img_w,img_h))#画像の正規化
x=img_to_array(x)/255#入力次元を合わせるため3次元から4次元にする
x=x[None,...]predict=model.predict(x,batch_size=1,verbose=1)print(predict)
こんなかんじで結果が出てきたら成功です。
./data/test\1\000001.jpg
1/1 [==============================] - 2s 2s/step
[[1. 0. 0. 0. 0.]]
./data/test\1\000002.jpg
1/1 [==============================] - 0s 258ms/step
[[1. 0. 0. 0. 0.]]
./data/test\1\000003.jpg
1/1 [==============================] - 0s 247ms/step
[[0. 1. 0. 0. 0.]]
./data/test\1\000004.jpg
1/1 [==============================] - 0s 232ms/step
[[0. 1. 0. 0. 0.]]
./data/test\1\000005.jpg
おわりに
Kerasで書くの、らくちんだったから慣れていきたい