EfficientNetを用いた画像分類モデルを学習させるまで。

概要

EfficientNetを用いた画像分類を行っていきます。この記事で実際に紹介するものは以下の通りです。

  • EfficientNetのインストール
  • 学習済みモデルを用いた画像分類
  • ファインチューニングによる再学習

EfficientNetのインストール

Requirements

  • Keras >= 2.2.0 / TensorFlow >= 1.12.0
  • keras_applications >= 1.0.7
  • scikit-image

インストール

$ pip install -U git+https://github.com/qubvel/efficientnet

学習済みモデルを用いた画像分類

学習済みモデル一覧

以下利用できる学習済みモデルです。今回はこの中のEfficientNetB0(Imagenet)を利用していきます。

Architecture @top1* Imagenet @top1* Noisy-Student
EfficientNetB0 0.772 0.788
EfficientNetB1 0.791 0.815
EfficientNetB2 0.802 0.824
EfficientNetB3 0.816 0.841
EfficientNetB4 0.830 0.853
EfficientNetB5 0.837 0.861
EfficientNetB6 0.841 0.864
EfficientNetB7 0.844 0.869

学習済みモデルで画像分類してみる。

githubでも使われている以下のパンダの画像をテスト画像に使います。

efficientnet

コードは以下の通り。シンプル。

import os
import sys
import numpy as np
from skimage.io import imread
import matplotlib.pyplot as plt

from keras.applications.imagenet_utils import decode_predictions

from efficientnet.keras import EfficientNetB0
from efficientnet.keras import center_crop_and_resize, preprocess_input


# テスト画像
image = imread('./panda.jpg')


# 学習済みモデルのロード
model = EfficientNetB0(weights='imagenet')


# 画像の前処理
image_size = model.input_shape[1]
x = center_crop_and_resize(image, image_size=image_size)
x = preprocess_input(x)
x = np.expand_dims(x, 0)


# 分類
y = model.predict(x)
print(decode_predictions(y))

"""出力
[[('n02510455', 'giant_panda', 0.75878674), 
('n02134084', 'ice_bear', 0.008354761), 
('n02132136', 'brown_bear', 0.007207236), 
('n02509815', 'lesser_panda', 0.004130227), 
('n02120079', 'Arctic_fox', 0.004021081)]]
"""

パンダと予測されていますね。

ファインチューニングによる再学習

画像変換関数

今回はmnistを用いて再学習を行います。mnistなら簡単に試せるやろ、という気持ちです。しかし以下の2点で学習させる際に引っかかってしまうことが判明。

  • 最低でも32x32の画像な!
  • チャンネル数は3やで!

mnistは28x28な上に、チャンネル数は1という。。。なので関数を作り前処理をさせます。冗長なコードですがお許しください。ちなみに上記の2点に当てはまらない場合はこれは無視して大丈夫です!

def mnist_preprocessing(X):
    import cv2
    X_list = []
    for x_i in X:
        resize_X = cv2.resize(x_i, (32, 32))
        img = cv2.cvtColor(resize_X, cv2.COLOR_GRAY2BGR)
        X_list.append(img)
    X_list = np.array(X_list)

    return X_list

学習

import keras
from efficientnet.keras import EfficientNetB0
from efficientnet.keras import center_crop_and_resize, preprocess_input
from keras.datasets import mnist
import numpy as np


def mnist_preprocessing(X):
    import cv2
    X_list = []
    for x_i in X:
        resize_X = cv2.resize(x_i, (32, 32))
        img = cv2.cvtColor(resize_X, cv2.COLOR_GRAY2BGR)
        X_list.append(img)
    X_list = np.array(X_list)

    return X_list

# データの準備。今回はmnist。
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train_processed = mnist_preprocessing(X_train)
X_test_processed = mnist_preprocessing(X_test)
y_train_categorical = keras.utils.to_categorical(y_train)
y_test_categorical = keras.utils.to_categorical(y_test)

# efficientnetに必要なところ。
X_train = preprocess_input(X_train)
X_test_processed = preprocess_input(X_test_processed)

n_classes = 10

# モデルの構築
INPUT_SHAPE = (32, 32, 3)
base_model = EfficientNetB0(input_shape=INPUT_SHAPE, weights='imagenet', include_top=False)
x = keras.layers.GlobalAveragePooling2D()(base_model.output)
output = keras.layers.Dense(n_classes, activation='softmax')(x)
model = keras.models.Model(inputs=[base_model.input], outputs=[output])

# 学習
model.compile(optimizer='SGD', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(X_train_processed, y_train_categorical) #epoch数とか諸々のものは一般のkerasと同様ここでオプション追加する
model.save('my_model.h5')

モデル評価

model = keras.models.load_model("my_model.h5")
score = model.evaluate(X_test_processed, y_test_categorical, verbose=0)

print("loss:", score[0])
print("accuracy:", score[1])

"""出力
loss: 0.08207062631845474
accuracy: 0.9783999919891357
"""

まとめ

efficientnetの使い方を紹介した。

参考文献