これまでfastaiを使った転移学習は行ってきましたが、学習した結果を使って
アプリを作成したりする場合にはKeras(Tensorflow)の方が便利そうだったので
今回はkerasを使った転移学習を行っていきます。
学習に使用するデータセットは例によってKaggleのいつものやつを使います。
(書いていませんでしたが、データセットをダウンロードするためにはKaggleへの登録が必要です)
Kerasにも事前学習済モデルが用意されており、以下のモデルが使えるみたいです。
Xception
VGG16
VGG19
ResNet50
InceptionV3
InceptionResNetV2
MobileNet
DenseNet121
DenseNet169
DenseNet201
今回はVGG16を使用して作成していきます。
ちなみにモデルを呼び出すときは
from keras.applications.vgg16 import VGG16
こんな感じで書けは使用することができます。
①画像・ラベルの読み込み・前加工・Keras形式のデータセット作成
#必要なライブラリのインポート from sklearn.model_selection import train_test_split import numpy as np from PIL import Image import os from glob import glob from sklearn.preprocessing import LabelEncoder import cv2 from keras.utils import np_utils from matplotlib import pyplot as plt import pandas as pd #画像のサイズ指定・カテゴリ数等指定 ScaleTo = 70 seed = 7 num_clases = 12 #トレーニングデータの読み込み #画像データをフォルダ毎に分けて入れておけば、ラベルデータも生成してくれる data_dir = "~/train" 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))) j += 1 #ラベルデータの読み込み for dir in os.listdir(data_dir): if dir == ".DS_Store": continue dir1 = data_dir + "/" + dir label = dir for file in os.listdir(dir1): if file != "Thumbs.db": trainLabel.append(label) # kerasに渡すために画像をnumpy配列・ラベルをpd.Daraframeに変換。 image_list = np.asarray(trainImg) label_list = pd.DataFrame(trainLabel) 画像の前加工 clearTrainImg = [] examples = [];getEx = True for img in image_list: #ぼかしを入れてノイズを除去 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) #8枚ほど表示してみる for i in range(8): plt.subplot(2, 4, i + 1) plt.imshow(clearTrainImg[i]) #加工後の画像もnp配列に変換 clearTrainImg = np.asarray(clearTrainImg) clearTrainImg.shape #画像の正則化 clearTrainImg = clearTrainImg / 255 # ラベルをワンホットエンコーディング le = LabelEncoder() le = le.fit(label_list) label_list = le.transform(label_list) label_list label_list = np_utils.to_categorical(label_list) label_list #トレーニングデータとバリデーションデータの分割 X_train, X_test, y_train, y_test = train_test_split(clearTrainImg, label_list, test_size=0.33, random_state=0) #kerasのImageDataGeneratorを使いオーグメンテーションを指定 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(X_train)
②モデルの構築
#必要なライブラリの読み込み from keras.applications.vgg16 import VGG16 from keras.models import Model import tensorflow as tf import keras from tensorflow import keras from keras.layers import Conv2D, MaxPooling2D,Input from keras.layers import Dense, Dropout, Flatten, Activation,GlobalAveragePooling2D,Input from keras.models import Sequential from keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint from keras.optimizers import Adam from keras import optimizers # VGG16のロード。FC層は不要なので include_top=False input_tensor = Input(shape=(ScaleTo, ScaleTo, 3)) vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor) # 最下層の出力層等オリジナルモデル部分をSequentialモデルで作成 top_model = Sequential() top_model.add(Flatten(input_shape=vgg16.output_shape[1:])) top_model.add(Dense(256, activation='relu')) top_model.add(Dropout(0.5)) top_model.add(Dense(nb_classes, activation='softmax')) # VGG16とオリジナルモデル部分を結合してモデルを作成 vgg_model = Model(input=vgg16.input, output=top_model(vgg16.output)) #一旦モデル全体を表示してみる vgg_model.summary() # input層を含めた15層目までは重みを固定 #最初の方の層は、汎用的な特徴検出に使われるため #個々の部分の学習を省略することで効率よく学習を進めることができる for layer in vgg_model.layers[:15]: layer.trainable = False #モデルをコンパイル、多クラス分類を指定 vgg_model.compile(loss='categorical_crossentropy', optimizer=optimizers.SGD(lr=1e-3, momentum=0.9), metrics=['accuracy']) vgg_model.summary()
③学習の実行
#学習の実行 hist = vgg_model.fit_generator(datagen.flow(X_train, y_train, batch_size=75), epochs=35, validation_data=(X_test, y_test), steps_per_epoch=X_train.shape[0])
④パラメータの保存と精度の評価
#パラメータの保存 vgg_model.save_weights('mnist_mlp_weights.h5') print(vgg_model.evaluate(X_train, y_train)) #トレーニングの精度 print(vgg_model.evaluate(X_test, y_test)) #テスト精度
④テストデータの成型と推論、提出用データの作成
path = "~/test/*.png" files = glob(path) testImg = [] testId = [] j = 1 num = len(files) for img in files: print("Obtain images: " + str(j) + "/" + str(num), end='\r') testId.append(img.split('/')[-1]) # Images id's testImg.append(cv2.resize(cv2.imread(img), (ScaleTo, ScaleTo))) j += 1 testImg = np.asarray(testImg) # Train images set for i in range(8): plt.subplot(2, 4, i + 1) plt.imshow(testImg[i]) #テストデータの成型 clearTestImg = [] examples = []; getEx = True for img in testImg: # Use gaussian blur blurImg = cv2.GaussianBlur(img, (5, 5), 0) 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) # Create empty image clear[bMask] = img[bMask] # Apply boolean mask to the origin image clearTestImg.append(clear) # Append image without backgroung 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 = vgg_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)