転移学習での特徴抽出器(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 Colaboratory へのリンク

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

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

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

2. 前準備

Python 3.12 のインストール

Pythonのインストールを行い、Pythonのプログラムを実行する環境を整える。扱う環境は、Windows搭載パソコンである。金子研究室では、Python 3.12.10を推奨する。

[Windows での Python 3.12 のインストール手順を見るには、ここをクリック]

Windows での Python 3.12 のインストール

以下のいずれかの方法でPython 3.12をインストールする。Pythonがインストール済みの場合、この手順は不要である。

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

インストールコマンドの実行方法

管理者権限コマンドプロンプトを起動する(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。そして、コマンド全体をコマンドプロンプトにコピー&ペーストする。

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

REM Python 3.12 をシステム領域にインストール
winget install --id Python.Python.3.12 -e --scope machine --silent --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 Include_test=0 Include_pip=1 Include_launcher=1 InstallLauncherAllUsers=1 TargetDir=\"C:\Program Files\Python312\""

REM Python と Scripts を PATH 先頭に追加
powershell -NoProfile -Command "$p='C:\Program Files\Python312'; $s=\"$p\Scripts\"; $c=[Environment]::GetEnvironmentVariable('Path','Machine'); if((Test-Path $p) -and (';'+$c+';' -notlike \"*;$p;*\") -and (';'+$c+';' -notlike \"*;$s;*\")){[Environment]::SetEnvironmentVariable('Path',\"$p;$s;$c\",'Machine')}"

方法 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のインストールも説明している.)

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

  1. 次のコマンドを実行する.

    管理者権限コマンドプロンプトを起動する (手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。

    python -m pip install -U --no-user numpy matplotlib seaborn scikit-learn pandas pydot
    

Graphviz のインストール

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

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)

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

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

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

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

  1. ベースモデルの作成

    次の Python プログラムを実行

    Python プログラムを動かすために, pythonpython3などのコマンドを使う. あるいは, 開発環境や Python コンソール(Jupyter Qt ConsoleSpyderPyCharmPyScripter など)も便利である.
    import tensorflow as tf
    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.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)
    
  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. 結果が表示されるので確認する
    Google Colaboratory でも,同じ手順で,同様の結果を得ることができる.
  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」のキーを押して閉じる