今回は前回同様CNNを活用して、画像認識のやり方についてまとめていきます。
今回も題材にしたコンペはこちらです。
全体の流れとして
①データの読み込み
②OpenCVを使ったデータ加工(マスク処理等)
③Kerasによるデータ複製
④KerasでCNN構築
⑤モデル評価・推論等
のような流れです。
以下コードになります。
#必要なライブラリのインポート import cv2 from glob import glob import numpy as np from matplotlib import pyplot as plt import math import pandas as pd #画像のサイズ指定 ScaleTo = 70 seed = 7 #トレーニングデータの読み込み path = "./train/*/*.png" files = glob(path) trainImg = [] trainLabel = [] j = 1 num = len(files) for img in files: print(str(j) + "/" + str(num) , end="\r") trainImg.append(cv2.resize(cv2.imread(img) ,(ScaleTo,ScaleTo))) trainLabel.append(img.split("/")[-2]) j += 1 trainImg = np.asarray(trainImg) trainLabel = pd.DataFrame(trainLabel) #いくつか画像を確認してみる for i in range(8): plt.subplot(2,4,i+1) plt.imshow(trainImg[i]) #----------------------------------------------------------------------- #データを整形する #今回は目的物(植物)が全て緑であるということを生かし #緑の部分だけを残して他の部分を削除するマスクを作成 #手順は①ノイズの除去②RGB→HSVに変換③マスクを作成④ブールマスクを作成⑤マスクの適用 clearTrainImg = [] examples = [];getEx = True for img in trainImg: #ぼかしを入れてノイズを除去 blurImg = cv2.GaussianBlur(img ,(5,5),0) #RGBからHSVに変換 hsvImg = cv2.cvtColor(blurImg , cv2.COLOR_BGR2HSV) #マスクを作成 lower_green = (25,40,50) upper_green = (75,255,255) mask = cv2.inRange(hsvImg , lower_green ,upper_green) kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11)) mask = cv2.morphologyEx(mask , cv2.MORPH_CLOSE,kernel) #ブールマスクの作成 bMask = mask > 0 #マスクの適用 #空のイメージの作成 clear = np.zeros_like(img , np.uint8) #オリジナル画像にブールマスクを適用 clear[bMask] = img[bMask] clearTrainImg.append(clear) if getEx: plt.subplot(2, 3, 1); plt.imshow(img) # Show the original image plt.subplot(2, 3, 2); plt.imshow(blurImg) # Blur image plt.subplot(2, 3, 3); plt.imshow(hsvImg) # HSV image plt.subplot(2, 3, 4); plt.imshow(mask) # Mask plt.subplot(2, 3, 5); plt.imshow(bMask) # Boolean mask plt.subplot(2, 3, 6); plt.imshow(clear) # Image without background getEx = False clearTrainImg = np.asarray(clearTrainImg) for i in range(8): plt.subplot(2, 4, i + 1) plt.imshow(clearTrainImg[i]) #----------------------------------------------------------------------- #データを正則化する clearTrainImg = clearTrainImg / 255 #ラベルデータを数値化、ワンホットエンコーディングする #必要なライブラリのインポート from keras.utils import np_utils from sklearn import preprocessing import matplotlib.pyplot as plt #ラベルのエンコードとクラスの作成 le = preprocessing.LabelEncoder() le.fit(trainLabel[0]) print("Classes:" + str(le.classes_)) encodeTrainLabels = le.transform(trainLabel[0]) #カテゴリカルラベルの作成 clearTrainLabel = np_utils.to_categorical(encodeTrainLabels) num_clases = clearTrainLabel.shape[1] print("Number of classes:" + str(num_clases)) #ラベルごとの数の表示 trainLabel[0].value_counts().plot(kind = "bar") #----------------------------------------------------------------------- #モデルの作成 #データセットの分割 from sklearn.model_selection import train_test_split trainX , testX ,trainY ,testY = train_test_split(clearTrainImg , clearTrainLabel, test_size = 0.1 ,random_state = seed , stratify = clearTrainLabel) #データの複製(ズーム、回転等) from keras.preprocessing.image import ImageDataGenerator datagen = ImageDataGenerator( rotation_range=180, # randomly rotate images in the range zoom_range = 0.1, # Randomly zoom image width_shift_range=0.1, # randomly shift images horizontally height_shift_range=0.1, # randomly shift images vertically horizontal_flip=True, # randomly flip images horizontally vertical_flip=True # randomly flip images vertically ) datagen.fit(trainX) #モデル作成 #必要なライブラリのインポート import numpy from keras.models import Sequential from keras.layers import Dense from keras.models import Dropout from keras.layers import Flatten from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.layers import BatchNormalization numpy.random.seed(seed) model = Sequential() model.add(Conv2D(filters=64, kernel_size=(5, 5), input_shape=(ScaleTo, ScaleTo, 3), activation='relu')) model.add(BatchNormalization(axis=3)) model.add(Conv2D(filters=64, kernel_size=(5, 5), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(BatchNormalization(axis=3)) model.add(Dropout(0.1)) model.add(Conv2D(filters=128, kernel_size=(5, 5), activation='relu')) model.add(BatchNormalization(axis=3)) model.add(Conv2D(filters=128, kernel_size=(5, 5), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(BatchNormalization(axis=3)) model.add(Dropout(0.1)) model.add(Conv2D(filters=256, kernel_size=(5, 5), activation='relu')) model.add(BatchNormalization(axis=3)) model.add(Conv2D(filters=256, kernel_size=(5, 5), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(BatchNormalization(axis=3)) model.add(Dropout(0.1)) model.add(Flatten()) model.add(Dense(256, activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.5)) model.add(Dense(256, activation='relu')) model.add(BatchNormalization()) model.add(Dropout(0.5)) model.add(Dense(num_clases, activation='softmax')) model.summary() # compile model model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) #----------------------------------------------------------------------- #学習の実行 from keras.callbacks import ModelCheckpoint,ReduceLROnPlateau,CSVLogger #学習率を下げるコールバックの設定 learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', patience3, verbose=0, factor=0.4, min_lr=0.00001) # チェックポイント filepath="drive/DataScience/PlantReco/weights.best_{epoch:02d}-{val_acc:.2f}.hdf5" checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max') filepath="drive/DataScience/PlantReco/weights.last_auto4.hdf5" checkpoint_all = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=False, mode='max') callbacks_list = [checkpoint, learning_rate_reduction, checkpoint_all] #学習の実行 hist = model.fit_generator(datagen.flow(trainX, trainY, batch_size=75), epochs=35, validation_data=(testX, testY), steps_per_epoch=trainX.shape[0], callbacks=callbacks_list) #----------------------------------------------------------------------- #モデル(精度)の評価 model.load_weights("../input/plantrecomodels/weights.best_17-0.96.hdf5") data = np.load("../input/plantrecomodels/Data.npz") d = dict(zip(("trainX","testX","trainY", "testY"), (data[k] for k in data))) trainX = d['trainX'] testX = d['testX'] trainY = d['trainY'] testY = d['testY'] print(model.evaluate(trainX, trainY)) #トレーニングの精度 print(model.evaluate(testX, testY)) #テスト精度 #コンフュージョンマトリックスの作成 from sklearn.metrics import confusion_matrix import itertools def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap=plt.cm.Blues): fig = plt.figure(figsize=(10,10)) plt.imshow(cm, interpolation='nearest', cmap=cmap) plt.title(title) plt.colorbar() tick_marks = np.arange(len(classes)) plt.xticks(tick_marks, classes, rotation=90) plt.yticks(tick_marks, classes) if normalize: cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] thresh = cm.max() / 2. for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): plt.text(j, i, cm[i, j], horizontalalignment="center", color="white" if cm[i, j] > thresh else "black") plt.tight_layout() plt.ylabel('True label') plt.xlabel('Predicted label') predY = model.predict(testX) predYClasses = np.argmax(predY, axis = 1) trueY = np.argmax(testY, axis = 1) confusionMTX = confusion_matrix(trueY, predYClasses) plot_confusion_matrix(confusionMTX, classes = le.classes_) #----------------------------------------------------------------------- #テストデータの整形 clearTestImg = [] examples = []; getEx = True for img in testImg: # Use gaussian blur blurImg = cv2.GaussianBlur(img, (5, 5), 0) # Convert to HSV image hsvImg = cv2.cvtColor(blurImg, cv2.COLOR_BGR2HSV) # Create mask (parameters - green color range) lower_green = (25, 40, 50) upper_green = (75, 255, 255) mask = cv2.inRange(hsvImg, lower_green, upper_green) kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11)) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # Create bool mask bMask = mask > 0 # Apply the mask clear = np.zeros_like(img, np.uint8) # Create empty image clear[bMask] = img[bMask] # Apply boolean mask to the origin image clearTestImg.append(clear) # Append image without backgroung # Show examples if getEx: plt.subplot(2, 3, 1); plt.imshow(img) # Show the original image plt.subplot(2, 3, 2); plt.imshow(blurImg) # Blur image plt.subplot(2, 3, 3); plt.imshow(hsvImg) # HSV image plt.subplot(2, 3, 4); plt.imshow(mask) # Mask plt.subplot(2, 3, 5); plt.imshow(bMask) # Boolean mask plt.subplot(2, 3, 6); plt.imshow(clear) # Image without background getEx = False clearTestImg = np.asarray(clearTestImg) clearTestImg = clearTestImg / 255 #----------------------------------------------------------------------- #推論の実行 pred = model.predict(clearTestImg) #提出ファイルの作成 predNum = np.argmax(pred, axis=1) predStr = le.classes_[predNum] res = {'file': testId, 'species': predStr} res = pd.DataFrame(res) res.to_csv("res.csv", index=False)