転移学習での特徴抽出器(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 のインストール(Windows上)

注:既にPython(バージョン3.12を推奨)がインストール済みの場合は,この手順は不要である.

winget(Windowsパッケージマネージャー)を使用してインストールを行う

  1. Windowsで,コマンドプロンプト管理者権限で起動する(例:Windowsキーを押し,「cmd」と入力し,「管理者として実行」を選択)
  2. winget(Windowsパッケージマネージャー)が利用可能か確認する:
    winget --version
    
  3. Pythonのインストール(下のコマンドにより Python 3.12 がインストールされる).
    winget install --scope machine Python.Launcher
    winget install --scope machine Python.Python.3.12
    
  4. 【関連する外部サイト】

    【サイト内の関連ページ】

    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 で,コマンドプロンプト管理者権限で起動する(例:Windowsキーを押し,「cmd」と入力し,「管理者として実行」を選択)

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

      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」のキーを押して閉じる