転移学習での特徴抽出器(ImageNet で学習済みの ResNet50 による転移学習)(Windows あるいは Ubuntu 上)

転移学習 (transfer learning): CNN の学習では,ImageNet などのデータを用いた前学習 (pretrain) ののち,別のデータを用いた学習に移るということがよく行われる.別のデータでの学習は,次のいずれかで行う.
  1. CNN を画像からの特徴抽出器として使う: CNN の最終層である全結合層を取り除く.残りは,画像からの特徴抽出器(最終層のユニットの数だけの数値を出力する.ImageNet で学習したときは 1000 個の数値である)と見ることができる.そして,CNN の最終層の代わりに,線形分類器 (linear classifier) を付け加える.線形分類器には,線形 SVM や,softmax 分類器がある.その後,データを用いて,学習を行う.画像からの特徴抽出器と言っている部分(最終層である全結合層を取り除いた残り)の結合の重みは変化させない
  2. CNN での Fine Tuning も行う: CNN を画像からの特徴抽出器として使うことに加えて, 画像からの特徴抽出器と言っている部分(最終層である全結合層を取り除いた残り)の結合の重みを,バックプロパゲーションにより,変化させる(このことを Fine Tuning という).Fine Tuning においては,すべての層の結合の重みを変化させることもあるし,後段の層の結合の重みのみを変化させる場合もある(過学習の防止のため). Fine Tuning でのエポック数(学習率)は,過学習の防止のため,小さな値にすることを意識する.

上の 1, 2 のどちらで行うかの目安

前学習でのデータと類似している別データで転移学習を行うとき:過学習が起きないだけの十分な量の別データがあるときは,Fine Tuning も行い,Fine Tuning においては,すべての層の結合の重みを変化させる.十分な量の別データがないときは,CNN を画像からの特徴抽出器として使うだけにとどめて,Fine Tuning を行わないことを検討する.

前学習でのデータと類似していない別データで転移学習を行うとき: 過学習が起きないだけの十分な量の別データがあるときは,Fine Tuning も行い,Fine Tuning においては,すべての層の結合の重みを変化させるのか,あるいは,転移学習を行わないのかを検討する(転移学習を行う方がよい場合があると期待できる).十分な量の別データがないときは,CNN を画像からの特徴抽出器として使うだけにとどめる(Fine Tuning を行わない),あるいは,線形分離器として線形 SVM を用いた上で,層を最終層から少しさかのぼってのFine Tuning を行うのがよい可能性がある.

Keras の機能として, ImageNet で学習済みのモデルResNet50,Inception-ResNet, DenseNet, MobileNetV2 など)がある. (Keras で利用可能なモデルは,https://keras.io/api/applications/ で説明されている.)

モデルからの最終層の除去,線形分類器 (linear classifier) の追加と別データでの学習,学習曲線の確認,Fine Tuning の実行を行う.

目次:

  1. Google Colab へのリンク
  2. 前準備
  3. 特徴抽出を行う画像データの準備
  4. ImageNet で学習済みの ResNet50 をベースモデルとして,特徴抽出器を作成

関連する外部ページ】:

Google Colab へのリンク

書きかけ

このページに掲載のソースコードは,Google Colaboratory でも実行できる.

このページに掲載のソースコードが入った Google Colaboratory のノートブック(Google ドライブ内)は,次の URL である.

https://colab.research.google.com/drive/1c0uJaZB7B6SDTnxS_5FJukKd9FbYg4-e?usp=sharing

前準備

Python 3.12 のインストール

以下のいずれかの方法で Python 3.12 をインストールする。

方法1:winget によるインストール

Python がインストール済みの場合、この手順は不要である。管理者権限コマンドプロンプトで以下を実行する。管理者権限のコマンドプロンプトを起動するには、Windows キーまたはスタートメニューから「cmd」と入力し、表示された「コマンドプロンプト」を右クリックして「管理者として実行」を選択する。

winget install -e --id Python.Python.3.12 --scope machine --silent --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 AssociateFiles=1 InstallLauncherAllUsers=1"

--scope machine を指定することで、システム全体(全ユーザー向け)にインストールされる。このオプションの実行には管理者権限が必要である。インストール完了後、コマンドプロンプトを再起動すると PATH が自動的に設定される。

方法2:インストーラーによるインストール

  1. Python 公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンから Windows 用インストーラーをダウンロードする。
  2. ダウンロードしたインストーラーを実行する。
  3. 初期画面の下部に表示される「Add python.exe to PATH」に必ずチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから python コマンドを実行できない。
  4. 「Install Python 3.xx for all users」にチェックを入れ、「Install」をクリックする。

インストールの確認

コマンドプロンプトで以下を実行する。

python --version

バージョン番号(例:Python 3.12.x)が表示されればインストール成功である。「'python' は、内部コマンドまたは外部コマンドとして認識されていません。」と表示される場合は、インストールが正常に完了していない。

TensorFlow,Keras のインストール

Windows での TensorFlowKeras のインストール: 別ページ »で説明

(このページで,Build Tools for Visual Studio 2022,NVIDIA ドライバ, NVIDIA CUDA ツールキットNVIDIA cuDNNのインストールも説明している.)

Graphviz のインストール

Windows での Graphviz のインストール: 別ページ »で説明

numpy,matplotlib, seaborn, scikit-learn, pandas, pydot のインストール

  1. 次のコマンドを管理者権限コマンドプロンプトで実行する (手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。
  2. する.
    python -m pip install -U numpy matplotlib seaborn scikit-learn pandas pydot
    

GraphViz のインストール

特徴抽出を行う画像データの準備

TensorFlow チュートリアルのページ: https://www.tensorflow.org/tutorials/images/transfer_learning?hl=jaに掲載の犬,猫のデータを使用.

train_dataset, validation_dataset, test_dataset を準備する.

import os
import tensorflow as tf
from tensorflow.keras.preprocessing import image_dataset_from_directory

# 追加データである画像の画像サイズを IMG_SIZE に設定すること
IMG_SIZE = (160, 160)
IMG_SHAPE = IMG_SIZE + (3,)
# TensorFlow の API で処理するときのバッチサイズの設定
BATCH_SIZE = 32
# URL によりダウンロード
_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')

train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')
train_dataset = image_dataset_from_directory(train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
validation_dataset = image_dataset_from_directory(validation_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
val_batches = tf.data.experimental.cardinality(validation_dataset)
# validation_dataset を test_dataset とvalidation_dataset に振り分け
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)
# プリフェッチの設定(読み込み高速化のため)
AUTOTUNE = tf.data.AUTOTUNE
train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE)
validation_dataset = validation_dataset.prefetch(buffer_size=AUTOTUNE)
test_dataset = test_dataset.prefetch(buffer_size=AUTOTUNE)

ImageNet で学習済みの ResNet50 をベースモデルとして,特徴抽出器を作成

ImageNet で学習済みの ResNet50 をベースモデルとして使用.

関連する外部ページhttps://keras.io/ja/applications/

謝辞:ここでは、https://keras.io/ja/applications に記載のプログラムを変更して使用している

  1. ベースモデルの作成

    次の Python プログラムを実行

    Python プログラムを動かすために, pythonpython3などのコマンドを使う. あるいは, 開発環境や Python コンソール(Jupyter Qt ConsoleSpyderPyCharmPyScripter など)も便利である.
    from __future__ import absolute_import, division, print_function, unicode_literals
    import tensorflow.compat.v2 as tf
    import tensorflow_datasets as tfds
    from tensorflow.keras.applications.resnet50 import ResNet50
    from tensorflow.keras.preprocessing import image
    from tensorflow.keras.applications.resnet50 import preprocess_input, decode_predictions
    from tensorflow.keras.utils import plot_model
    from tensorflow.keras.models import Model
    from tensorflow.keras.layers import Dense, Dropout, GlobalAveragePooling2D
    import numpy as np
    
    # include_top=False により分類層を含まないようにする
    base_model = ResNet50(weights='imagenet', input_shape=IMG_SHAPE, include_top=False)
    # 学習中に結合の重みが更新されないようにする
    base_model.trainable = False
    base_model.summary()
    
  2. ベースモデルと画像データの事前確認のため,ベースモデルを用いて画像データを処理してみる

    エラーメッセージが出ないことを確認.ここの結果をあとで使うことはない.

    image_batch, label_batch = iter(train_dataset).get_next()
    feature_batch = base_model(image_batch)
    print(feature_batch.shape)
    
  3. ベースモデルを用いて,特徴抽出器のモデルの作成
    inputs = tf.keras.Input(IMG_SHAPE)
    x = base_model(inputs, training=False)
    x = GlobalAveragePooling2D()(x)
    m = Model(inputs=inputs, outputs=x)
    m.summary()
    
  4. 別データを,特徴抽出器により処理し結果を得る

    結果は,feature_batch_all に得る 結果として,長さ 2048 の数値ベクトルが 2000個得られる.

    feature_batch_all = None
    it = iter(train_dataset)
    while True:
        try:
            image_batch, label_batch = it.get_next()
        except tf.errors.OutOfRangeError:
            break
        if feature_batch_all is None:
            feature_batch_all = m(image_batch).numpy()
        else:
            feature_batch_all = np.vstack((feature_batch_all, m(image_batch).numpy()))
    
    print(feature_batch_all.shape)
    
    global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
    feature_batch_average = global_average_layer(feature_batch)
    print(feature_batch_average.shape)
    
    prediction_layer = tf.keras.layers.Dense(1)
    prediction_batch = prediction_layer(feature_batch_average)
    print(prediction_batch.shape)
    
    preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
    rescale = tf.keras.layers.experimental.preprocessing.Rescaling(1./127.5, offset= -1)
    
  5. ベースモデルを用いて,画像分類のモデルの作成
    inputs = tf.keras.Input(IMG_SHAPE)
    x = base_model(inputs, training=False)
    x = GlobalAveragePooling2D()(x)
    x = Dropout(0.2)(x)
    x = Dense(1)(x)
    m = Model(inputs=inputs, outputs=x)
    
  6. 画像分類の実行
    C:/image/fruits.jpg」のところには,画像ファイル名を指定すること.
    from matplotlib import pyplot as plt
    %matplotlib inline
    import warnings
    warnings.filterwarnings('ignore')   # Suppress Matplotlib warnings
    import PIL
    
    img_path = 'C:/image/fruits.jpg'
    img = image.load_img(img_path, target_size=IMG_SIZE)
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    
    features = m.predict(x)
    print(np.shape(features))
    
  7. 結果が表示されるので確認する
    GoogleColab でも,同じ手順で,同様の結果を得ることができる.
  8. 別の画像 home.jpg画像分類の実行
    from matplotlib import pyplot as plt
    %matplotlib inline
    import warnings
    warnings.filterwarnings('ignore')   # Suppress Matplotlib warnings
    
    img_path = 'C:/image/home.jpg'
    img = image.load_img(img_path, target_size=(224, 224))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    
    # decode the results into a list of tuples (class, description, probability)
    # (one such list for each sample in the batch)
    plt.imshow(img)
    print('Predicted:', decode_predictions(m.predict(x), top=3)[0])
    
  9. 結果が表示されるので確認する

USB 接続ビデオカメラの表示例

USB接続できるビデオカメラを準備し,パソコンに接続しておく.

OpenCV による動画表示を行う.

import cv2
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')   # Suppress Matplotlib warnings

v = cv2.VideoCapture(0)
while(v.isOpened()):
    r, f = v.read()
    if ( r == False ):
        break
    img = cv2.resize(f, (224, 224))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    preds = m.predict(x)
    cv2.imshow("", img)
    print('Predicted:', decode_predictions(preds, top=3)[0])
    # Press Q to exit
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

v.release()
cv2.destroyAllWindows()

分類結果が表示されるので確認する

* 止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる