もものきとPythonでディープラーニング・犬と猫を畳み込んでみよう!

もものきとPythonでディープラーニング・犬と猫を畳み込んでみよう!

Keras/Tensorflowを使った犬と猫の画像分類(CNN転移学習)




学習済みモデルVGG16を利用して、転移学習を実践してみよう

ナノネ、ディープラーニングを実践練習をまたやってみよう!

今回も手書き文字MNISTの画像分類をやるの?

今回は犬と猫の画像だよ。kaggleでデータセットで超有名なやつだよ。

犬猫なら手書き文字より癒されるね~

実行環境は今回もGoogle Colaboratoryを使うね。扱う画像データはファイル形式なので、Google Driveを利用してみたよ。

In [0]:
# ********************************
# Google Colaboratory利用環境  ***
# ********************************
# @2019/05  
# Ubuntu 18.04.2 LTS
# Python 3.6.7
# :Keras 2.2.4
# :tensorflow 1.13.1
# :numpy 1.16.3
# :matplotlib 3.0.3
In [0]:
# **************************
# Google Colaboratory準備 ****
# **************************

# Google Driveマウント
from google.colab import drive
drive.mount('/content/drive')

# cd '/content/drive/'My Drive/'Colab Notebooks'
%cd '/content/drive/'My Drive/images
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
/content/drive/My Drive/images

画像用のディレクトリは以下の構成にしているよ。KerasのImageDataGeneratorを使って画像を取得する際、この構成にしておく必要があるんだよ。

画像データのディレクトリ構成

画像データのディレクトリ構成

訓練用(train)、検証用(validation)、評価用(test)を準備するんだね。

大事なのでは、カテゴリごとサブディレクトリを作って、そこに該当ファイルを入れるんだよ。もし評価用で正解ラベルが無い場合でも、なんらかの名称のサブディレクトリに画像を入れてね(今回はunknownとしたよ)。

オリジナルのデータセットは、Train用25,000、Test用として12,500画像あるんだ。でも全部処理するのは大変なので、今回はTrain画像から一部だけ抜粋して使うことにするね。

In [0]:
# <Colaboratory環境での確認> training data 1500x2
!ls ./data/train/cats | wc -l
!ls ./data/train/dogs | wc -l
1500
1500
In [0]:
# <Colaboratory環境での確認> validation data1 400x2
!ls ./data/validation/cats | wc -l
!ls ./data/validation/dogs | wc -l
500
500
In [0]:
# <Colaboratory環境での確認> test data 
!ls ./data/test/unknown | wc -l
30

今回は訓練用(train)3000枚、検証用(validation)1000枚、評価用(test)30枚を準備したんだね。

分類はCNNを使うんだけど、今回はVGG16という学習済みモデルをベースに転移学習を試してみよう。

VGG16っていうのは、なんなの?

VGG16というのは、「ImageNet」と呼ばれる大規模画像データセット(1000クラス)で学習された、16層からなるCNNモデルだよ。画像分類の競技会でも優秀な成績を収め、様々な研究で利用されている有名な学習済みモデルの1つなんだよ。

優秀な画像分類モデルをベースにするなら、心強いね。

しかも、VGG16はKerasから簡単に利用できるんだよ。(モデルの実装に関しては、以下の記事が大変わかりやすかったので、参考にさせていただきましたm(_ _ )m)

さっそくだけど、モデルを構築して犬猫が分類できるように訓練してみよう!(動かすのに苦戦したレベルなので、細かい説明はとてもできないけど、動作した記録として残すね)

ラジャー!

CNNモデル構築(VCC16転移学習)と訓練

In [0]:
# ************************
# モデル構築(CNN)  *******
# ************************

from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.applications.vgg16 import VGG16
from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization
from keras.models import Model, Sequential
from keras.callbacks import EarlyStopping, ModelCheckpoint, CSVLogger
import numpy as np

# 乱数固定 ----------
import keras.backend as K
import tensorflow as tf

np.random.seed(seed=0)

session_conf = tf.ConfigProto(
    intra_op_parallelism_threads=1,
    inter_op_parallelism_threads=1)

tf.set_random_seed(0)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)

# 画像ファイルパス ----------
train_data_dir = "data/train/" # training dir path
validation_data_dir = "data/validation/" # validation dir path

# モデル条件設定 ----------
img_width, img_height = 150, 150 # モデル画像サイズ
nb_train_samples = 3000 # training data (1500x2)
nb_validation_samples = 1000 # validation data (500x2)
epochs = 50 # エポック数
batch_size = 32 # バッチ数
nb_category = 2 # カテゴリ数(cat, dog)

# 画像データのジェネレータ ----------

# 訓練用
train_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
        train_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode="categorical")
# 検証用
validation_datagen = ImageDataGenerator(rescale=1. / 255)
validation_generator = validation_datagen.flow_from_directory(
        validation_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode="categorical")

# モデル定義 ----------

# モデルVGG16(not include Top)
input_tensor = Input(shape=(img_width, img_height, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)

# モデルTop
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu', kernel_initializer='he_normal'))
top_model.add(BatchNormalization())
top_model.add(Dropout(0.5))
top_model.add(Dense(nb_category, activation='softmax'))

# vgg16とtop_modelを連結
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))

# layer14までの重みパメータを固定する(訓練で更新しない)
for layer in model.layers[:15]:
    layer.trainable = False

# コールバック

# early_stopping_cb = EarlyStopping(
#    monitor='val_acc', patience=10, verbose=1, mode='max')

# checkpoint_cb = ModelCheckpoint(
#    './{epoch:03d}-{val_acc:.5f}.hdf5', save_best_only=True)

csvlogger_cb = CSVLogger('./history.csv') 

# コンパイル ----------
model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.rmsprop(lr=5e-7, decay=5e-5),
              metrics=['accuracy'])

model.summary()


# *******************
# 訓練実行  *********
# *******************

history = model.fit_generator(
      train_generator,
      steps_per_epoch=nb_train_samples // batch_size,
      epochs=epochs,
      validation_data=validation_generator,
      validation_steps=nb_validation_samples // batch_size,
      callbacks=[csvlogger_cb])

# モデルを保存
model.save("model.h5")
Found 3000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_3 (InputLayer)         (None, 150, 150, 3)       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 150, 150, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 150, 150, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 75, 75, 64)        0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 75, 75, 128)       73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 75, 75, 128)       147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 37, 37, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 37, 37, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 37, 37, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 37, 37, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 18, 18, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 18, 18, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 18, 18, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 18, 18, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 9, 9, 512)         0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 9, 9, 512)         2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 9, 9, 512)         2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 9, 9, 512)         2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 4, 4, 512)         0         
_________________________________________________________________
sequential_3 (Sequential)    (None, 2)                 2098946   
=================================================================
Total params: 16,813,634
Trainable params: 9,177,858
Non-trainable params: 7,635,776
_________________________________________________________________
Epoch 1/50
93/93 [==============================] - 19s 200ms/step - loss: 1.1064 - acc: 0.5370 - val_loss: 0.8288 - val_acc: 0.5938
Epoch 2/50
93/93 [==============================] - 16s 172ms/step - loss: 1.0188 - acc: 0.5642 - val_loss: 0.7551 - val_acc: 0.6281
Epoch 3/50
93/93 [==============================] - 16s 173ms/step - loss: 0.9052 - acc: 0.6034 - val_loss: 0.6685 - val_acc: 0.6715
Epoch 4/50
93/93 [==============================] - 17s 186ms/step - loss: 0.8277 - acc: 0.6428 - val_loss: 0.6204 - val_acc: 0.7004
Epoch 5/50
93/93 [==============================] - 16s 173ms/step - loss: 0.7518 - acc: 0.6648 - val_loss: 0.5692 - val_acc: 0.7355
Epoch 6/50
93/93 [==============================] - 16s 171ms/step - loss: 0.6960 - acc: 0.6973 - val_loss: 0.5469 - val_acc: 0.7469
Epoch 7/50
93/93 [==============================] - 16s 172ms/step - loss: 0.6713 - acc: 0.7031 - val_loss: 0.5079 - val_acc: 0.7810
Epoch 8/50
93/93 [==============================] - 16s 171ms/step - loss: 0.6348 - acc: 0.7217 - val_loss: 0.4850 - val_acc: 0.7779
Epoch 9/50
93/93 [==============================] - 17s 185ms/step - loss: 0.5880 - acc: 0.7572 - val_loss: 0.4674 - val_acc: 0.8037
Epoch 10/50
93/93 [==============================] - 16s 172ms/step - loss: 0.5629 - acc: 0.7595 - val_loss: 0.4397 - val_acc: 0.8110
Epoch 11/50
93/93 [==============================] - 16s 171ms/step - loss: 0.5674 - acc: 0.7630 - val_loss: 0.4384 - val_acc: 0.8089
Epoch 12/50
93/93 [==============================] - 18s 189ms/step - loss: 0.5160 - acc: 0.7762 - val_loss: 0.4418 - val_acc: 0.8099
Epoch 13/50
93/93 [==============================] - 16s 171ms/step - loss: 0.4888 - acc: 0.7849 - val_loss: 0.4143 - val_acc: 0.8244
Epoch 14/50
93/93 [==============================] - 17s 186ms/step - loss: 0.4659 - acc: 0.7961 - val_loss: 0.4354 - val_acc: 0.8110
Epoch 15/50
93/93 [==============================] - 16s 171ms/step - loss: 0.4835 - acc: 0.7995 - val_loss: 0.3715 - val_acc: 0.8481
Epoch 16/50
93/93 [==============================] - 16s 171ms/step - loss: 0.4619 - acc: 0.7996 - val_loss: 0.3980 - val_acc: 0.8378
Epoch 17/50
93/93 [==============================] - 16s 171ms/step - loss: 0.4146 - acc: 0.8218 - val_loss: 0.3499 - val_acc: 0.8595
Epoch 18/50
93/93 [==============================] - 16s 172ms/step - loss: 0.4356 - acc: 0.8142 - val_loss: 0.3849 - val_acc: 0.8512
Epoch 19/50
93/93 [==============================] - 18s 191ms/step - loss: 0.4263 - acc: 0.8247 - val_loss: 0.3736 - val_acc: 0.8481
Epoch 20/50
93/93 [==============================] - 16s 171ms/step - loss: 0.4037 - acc: 0.8202 - val_loss: 0.3741 - val_acc: 0.8564
Epoch 21/50
93/93 [==============================] - 16s 172ms/step - loss: 0.3959 - acc: 0.8314 - val_loss: 0.3653 - val_acc: 0.8481
Epoch 22/50
93/93 [==============================] - 16s 171ms/step - loss: 0.3576 - acc: 0.8491 - val_loss: 0.3457 - val_acc: 0.8636
Epoch 23/50
93/93 [==============================] - 16s 175ms/step - loss: 0.3973 - acc: 0.8353 - val_loss: 0.3675 - val_acc: 0.8564
Epoch 24/50
93/93 [==============================] - 17s 183ms/step - loss: 0.3473 - acc: 0.8508 - val_loss: 0.3201 - val_acc: 0.8781
Epoch 25/50
93/93 [==============================] - 16s 171ms/step - loss: 0.3550 - acc: 0.8468 - val_loss: 0.3641 - val_acc: 0.8574
Epoch 26/50
93/93 [==============================] - 16s 172ms/step - loss: 0.3435 - acc: 0.8547 - val_loss: 0.3355 - val_acc: 0.8605
Epoch 27/50
93/93 [==============================] - 16s 171ms/step - loss: 0.3407 - acc: 0.8576 - val_loss: 0.3257 - val_acc: 0.8760
Epoch 28/50
93/93 [==============================] - 16s 176ms/step - loss: 0.3333 - acc: 0.8564 - val_loss: 0.3460 - val_acc: 0.8616
Epoch 29/50
93/93 [==============================] - 17s 182ms/step - loss: 0.3107 - acc: 0.8719 - val_loss: 0.3280 - val_acc: 0.8688
Epoch 30/50
93/93 [==============================] - 16s 172ms/step - loss: 0.3168 - acc: 0.8632 - val_loss: 0.3289 - val_acc: 0.8698
Epoch 31/50
93/93 [==============================] - 18s 189ms/step - loss: 0.3188 - acc: 0.8654 - val_loss: 0.3283 - val_acc: 0.8729
Epoch 32/50
93/93 [==============================] - 16s 173ms/step - loss: 0.3080 - acc: 0.8676 - val_loss: 0.3201 - val_acc: 0.8729
Epoch 33/50
93/93 [==============================] - 17s 180ms/step - loss: 0.2971 - acc: 0.8775 - val_loss: 0.3268 - val_acc: 0.8700
Epoch 34/50
93/93 [==============================] - 17s 178ms/step - loss: 0.2892 - acc: 0.8812 - val_loss: 0.3157 - val_acc: 0.8729
Epoch 35/50
93/93 [==============================] - 16s 172ms/step - loss: 0.2900 - acc: 0.8795 - val_loss: 0.3225 - val_acc: 0.8688
Epoch 36/50
93/93 [==============================] - 16s 171ms/step - loss: 0.2686 - acc: 0.8927 - val_loss: 0.2989 - val_acc: 0.8740
Epoch 37/50
93/93 [==============================] - 16s 172ms/step - loss: 0.2894 - acc: 0.8795 - val_loss: 0.3023 - val_acc: 0.8791
Epoch 38/50
93/93 [==============================] - 18s 190ms/step - loss: 0.2498 - acc: 0.8980 - val_loss: 0.3328 - val_acc: 0.8626
Epoch 39/50
93/93 [==============================] - 16s 175ms/step - loss: 0.2669 - acc: 0.8926 - val_loss: 0.3060 - val_acc: 0.8688
Epoch 40/50
93/93 [==============================] - 16s 173ms/step - loss: 0.2489 - acc: 0.8955 - val_loss: 0.3071 - val_acc: 0.8698
Epoch 41/50
93/93 [==============================] - 16s 172ms/step - loss: 0.2548 - acc: 0.8907 - val_loss: 0.2963 - val_acc: 0.8760
Epoch 42/50
93/93 [==============================] - 16s 172ms/step - loss: 0.2338 - acc: 0.9064 - val_loss: 0.2891 - val_acc: 0.8822
Epoch 43/50
93/93 [==============================] - 17s 183ms/step - loss: 0.2460 - acc: 0.8970 - val_loss: 0.3019 - val_acc: 0.8698
Epoch 44/50
93/93 [==============================] - 16s 173ms/step - loss: 0.2500 - acc: 0.8918 - val_loss: 0.3146 - val_acc: 0.8719
Epoch 45/50
93/93 [==============================] - 16s 172ms/step - loss: 0.2363 - acc: 0.9022 - val_loss: 0.2766 - val_acc: 0.8771
Epoch 46/50
93/93 [==============================] - 16s 172ms/step - loss: 0.2210 - acc: 0.9115 - val_loss: 0.3072 - val_acc: 0.8791
Epoch 47/50
93/93 [==============================] - 16s 172ms/step - loss: 0.2300 - acc: 0.9069 - val_loss: 0.2899 - val_acc: 0.8771
Epoch 48/50
93/93 [==============================] - 17s 183ms/step - loss: 0.2326 - acc: 0.9047 - val_loss: 0.2897 - val_acc: 0.8760
Epoch 49/50
93/93 [==============================] - 16s 174ms/step - loss: 0.2226 - acc: 0.9071 - val_loss: 0.2830 - val_acc: 0.8771
Epoch 50/50
93/93 [==============================] - 18s 189ms/step - loss: 0.2177 - acc: 0.9086 - val_loss: 0.3039 - val_acc: 0.8812

時間(画像ファイルのキャッシュ有無でも違うけど、20~10分位所要)かかったけど、無事に訓練が終ったみたい。犬猫の分類できるようになったかな?

50エポック訓練して、訓練データの正答率(acc)が0.90で、検証データでの正答率(val_acc)は0.88という結果。データ数も絞っているから、まずまずの結果じゃないかな?

訓練履歴を簡単なグラフでプロットしてみよう。

In [0]:
# *******************************
# 訓練履歴をグラフで可視化  *****
# *******************************

import matplotlib.pyplot as plt
import pandas as pd

history = pd.read_csv('history.csv')
history_rows = len(history)

# accuracy
plt.plot(range(1, history_rows + 1), history['acc']) # training
plt.plot(range(1, history_rows + 1), history['val_acc']) # validation
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'validation'], loc='best')
plt.show()

# loss
plt.plot(range(1, history_rows + 1), history['loss'])
plt.plot(range(1, history_rows + 1), history['val_loss'])
plt.title('model accuracy')
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'validation'], loc='best')
plt.show()

う~ん。少しギザギザしているけど、どうなんだろ??

上のコード以外にもいろいろ試行錯誤したんだけど、学習がうまく進まない(><)、もっと酷いのも一杯見てきたから...いいほうかも。

モデルが完成したから、訓練に全く利用していないテストデータで評価してみよう。うまく犬猫が分類できるかな?画像は少量だけど30枚準備したよ。

テストデータを使って評価

In [0]:
# モデル読み込み(@保存ファイルより再読み込み用)
from keras.models import load_model
model = load_model("./model.h5")
In [0]:
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.applications.vgg16 import VGG16
from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization
from keras.models import Model, Sequential, load_model
import pandas as pd
import numpy as np
import os

# ****************************
# テストデータで予測実行 *****
# ****************************

test_data_dir = "data/test/" # テスト用データdir
img_width, img_height = 150, 150 # 画像サイズ(訓練同)
nb_test_samples = 30 # 画像データ数
batch_size = 1 # バッチサイズ
nb_category = 2 # カテゴリ数(cat, dog)

# 画像データのジェネレータ(テスト用)
test_datagen = ImageDataGenerator(rescale=1. / 255)
test_generator = test_datagen.flow_from_directory(
        test_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode=None,
        shuffle=False)

# 分類予測
pred = model.predict_generator(
        test_generator,
        steps=nb_test_samples,
        verbose=1)
Found 30 images belonging to 1 classes.
30/30 [==============================] - 1s 36ms/step
In [0]:
# ****************************
# テストデータの予測結果 *****
# ****************************

labels = ['cat', 'dog']
# データ0~14 -> Cat画像
# データ15~29 -> Dog画像

print("*** test data [cat] *****")
for i in pred[0:15]:
    cls = np.argmax(i)
    score = np.max(i)
    print("pred: {}  score = {:.3f}".format(labels[cls], score))

print("-" * 30)

print("*** test data [dog] *****")
for i in pred[15:30]:
    cls = np.argmax(i)
    score = np.max(i)
    print("pred: {}  score = {:.3f}".format(labels[cls], score))
*** test data [cat] *****
pred: cat  score = 0.897
pred: cat  score = 0.924
pred: cat  score = 1.000
pred: cat  score = 1.000
pred: cat  score = 1.000
pred: cat  score = 0.989
pred: cat  score = 0.993
pred: cat  score = 0.982
pred: dog  score = 0.695
pred: cat  score = 0.996
pred: cat  score = 1.000
pred: cat  score = 0.920
pred: cat  score = 0.999
pred: cat  score = 1.000
pred: cat  score = 0.999
------------------------------
*** test data [dog] *****
pred: dog  score = 0.999
pred: dog  score = 1.000
pred: dog  score = 0.953
pred: dog  score = 0.780
pred: dog  score = 1.000
pred: dog  score = 0.987
pred: dog  score = 0.981
pred: dog  score = 0.997
pred: dog  score = 0.998
pred: dog  score = 0.991
pred: dog  score = 0.999
pred: dog  score = 0.903
pred: dog  score = 1.000
pred: dog  score = 1.000
pred: dog  score = 0.999

猫画像で1枚誤認したようだけど、結構うまく分類できているかも。

間違えちゃった画像はスコア(識別の自信)も低くなっているよね。自信を持って誤認するときもあるけど...。

ところで、CNNモデルは画像のどの辺の特徴から、犬と猫を識別しているんだろね??モモノキ、モデル中身って見えないものかなぁ...。

ナノネ、可視化するよさげな手法を見つけたので一度試してみよう。Grad Cam(Gradient-weighted Class Activation Mapping)という手法で、画像のどの辺りの特徴が分類に大きく影響しているか、カラーマッピングできるみたいだよ。

Grad Camの実装は、以下の記事を元にさせて頂きました。(やりたかった特徴箇所への色付けができて大変感謝です)

CNNは画像のどこに注目しているの?(Grad Camでカラーマッピング)

カラーマッピングする関数を定義して、

In [0]:
import pandas as pd
import numpy as np
import cv2
from keras import backend as K
from keras.preprocessing.image import array_to_img, img_to_array, load_img
from keras.models import load_model

K.set_learning_phase(1) # set learning phase

# *************************************************
# Gradient-weighted Class Activation Mapping  *****
#**************************************************

# 呼び出し用関数
def Grad_Cam(input_model, x, layer_name):

    # 前処理
    X = np.expand_dims(x, axis=0)
    X = X.astype('float32')
    preprocessed_input = X / 255.0

    # 予測クラス算出
    predictions = model.predict(preprocessed_input)
    class_idx = np.argmax(predictions[0])
    class_output = model.output[:, class_idx]

    #  勾配取得
    conv_output = model.get_layer(layer_name).output
    grads = K.gradients(class_output, conv_output)[0]
    gradient_function = K.function([model.input], [conv_output, grads])
    output, grads_val = gradient_function([preprocessed_input])
    output, grads_val = output[0], grads_val[0]

    # 重み平均化、cam算出
    weights = np.mean(grads_val, axis=(0, 1))
    cam = np.dot(output, weights)

    # ヒートマップ合成
    w = x.shape[0]
    h = x.shape[1]
    cam = cv2.resize(cam, (w, h), cv2.INTER_LINEAR)
    
    cam = np.maximum(cam, 0)
    if cam.max() == 0: # 色付け不可(ブルー画像になる)
      return None
    
    cam = cam / cam.max()

    jetcam = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET)
    jetcam = cv2.cvtColor(jetcam, cv2.COLOR_BGR2RGB)
    jetcam = (np.float32(jetcam) + x / 2)

    return jetcam

色付け実行!

In [0]:
import os
import glob
import matplotlib.pyplot as plt

# *****************************************************
# Grad Camで色付けして可視化(テストデータで実行) ******
# *****************************************************

labels = ['cat', 'dog']
test_dir = 'data/test' # テスト画像dir
# (正解ラベルなしを仮定してunknowディレクトに保存した)

test_files = sorted(glob.glob(os.path.join(test_dir, '*', '*.jpg')))

test_data_count = len(test_files)

for idx in range(test_data_count):
  
    file = test_files[idx] # file path (試しで30データ)
    file_name = os.path.basename(file)
    img_original = load_img(file, target_size=(150,150))

    # grad cam
    arr = img_to_array(img_original)
    layer_name = 'block5_conv3' # 最後の畳み込み層
    grad_cam = Grad_Cam(model, arr, layer_name) # grad_cam呼び出し
    
    if grad_cam is None:
        layer_name = 'block5_conv2' # 最後のひとつ前の畳み込み層(ラストがダメな場合)
        grad_cam = Grad_Cam(model, arr, layer_name)   
    img_grad_cam = array_to_img(grad_cam)

    # 画像表示
    fig = plt.figure(figsize=(12, 4))

    # Image Original 
    fig.add_subplot(1, 3, 1)
    plt.imshow(img_original)
    plt.title(file_name)
    plt.axis('off')

    # Image Grad-Cam
    fig.add_subplot(1, 3, 2)
    plt.imshow(img_grad_cam)
    plt.title(layer_name)
    plt.axis('off')

    # Pie Graph prediction score
    data_pred = pred[idx]

    colors = ["orange", "green"] # pred dog

    fig.add_subplot(1, 3, 3)
    plt.pie(data_pred,
            labels=labels,
            colors=colors,
            counterclock=False,
            startangle=90,
            labeldistance=0.2,
            autopct="%.1f%%",
            pctdistance=0.7,
            textprops={'color': 'white', 'horizontalalignment':'center'})

    plt.show()
    

代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト

代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト 代替テキスト

画像によっても、特徴として捕えている箇所がまちまちだけど。ここを見て識別してるのかと、なんとなくイメージね。

ワンちゃんは、顔の鼻回りと胴体がくっくりしているかも。首輪を1つあるね。

ネコちゃんは、全体的にもや~ん?とした感じかも。

でも、なんとか犬猫の分類ができたみたいで、よかったよ。

続いて、今回の実装説明~っと行きたいところだけど...説明を書くにはまだまだ未熟なので、今回は動かしたよ~でおしまいね。

やっぱり、そうなね~、苦戦してたもんね。

犬猫以外の画像で試したり、カテゴリ数を増やしたりしても練習になりそうだね。

あとで、自力で収集した画像でも分類してみようかなぁ。画像を集めるのが大変そうだけど。

またね!

お疲れ様でした。またね!







スポンサーリンク

0 件のコメント :

コメントを投稿