トップページデータベース研究CNN による画像分類 (image classification)転移学習での特徴抽出器(ImageNet で学習済みの ResNet-50 による転移学習)(Windows あるいは Ubuntu 上)

転移学習での特徴抽出器(ImageNet で学習済みの ResNet-50 による転移学習)(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 で学習済みのモデルResNet-50,Inception-ResNet, DenseNet, MobileNetV2 など)がある. (Keras で利用可能なモデルは,https://keras.io/api/applications/ で説明されている.)

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

目次:

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

参考 Web ページ:

前準備

Google Colab を使うか,パソコンを使う.それぞれの場合の前準備を説明する.

(1) Google Colab を使う場合

  1. Google Colab のWebページを開く

    https://colab.research.google.com

    Google Colab はオンラインの Python 開発環境. 使用するには Google アカウントが必要

  2. ファイル」で、「ノートブックを新規作成」を選ぶ

  3. Google アカウントでのログインが求められたときはログインする

(2) パソコンを使う場合

(NVIDIA GPU を使うとき)TensorFlow のバージョンを確認の上,NIDIA CUDA ツールキットとNIDIA cuDNN のバージョンを確認

TensorFlow を使う場合は,必要となる NVIDIA CUDA ツールキット,NVIDIA cuDNN のバージョン確認

TensorFlow は,そのバージョンによって,必要となるNVIDIA CUDA ツールキット,NVIDIA cuDNN のバージョンが違う(最新の NVIDIA CUDA ツールキット,NVIDIA cuDNN で動くというわけでない). そのことは,https://www.tensorflow.org/install/gpu で確認できる.

そこで, まずは,使用したい TensorFlow のバージョンを確認し,それにより, NVIDIA CUDA ツールキット,NVIDIA cuDNN を確認する.

NVIDIA CUDA ツールキットのバージョン:

指定されているバージョンより高いものは使わない. その根拠は次のページ. URL: https://www.tensorflow.org/install/source#common_installation_problems

NVIDIA cuDNN のバージョン:

その根拠は次のページ. URL: https://www.tensorflow.org/install/source#common_installation_problems

(NVIDIA GPU を使うとき)NVIDIA グラフィックスドライバ,NVIDIA CUDA ツールキット 11.0 ,NVIDIA cuDNN 8.0.5 のインストール

GPU とは,グラフィックス・プロセッシング・ユニットの略で、コンピュータグラフィックス関連の機能,乗算や加算の並列処理の機能などがある.

NVIDIA CUDA は,NVIDIA社が提供している GPU 用のプラットフォームである.

インストール手順の説明

関連 Web ページ

Python のインストール,pip と setuptools の更新,Python 開発環境(JupyterLab, spyder, nteract)のインストール,TensorFlow などのインストール

インストール手順の説明

Python プログラムを動かすために, pythonpython3などのコマンドを使う. あるいは, 開発環境や Python コンソール(Jupyter Qt ConsolespyderPyCharmPyScripter など)の利用も便利である.

GraphViz のインストール

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

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

train_dataset, validation_dataset, test_dataset を準備する.

import os
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 で学習済みの ResNet-50 をベースモデルとして,特徴抽出器を作成

参考 Web ページ: 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.preprocessing import image
    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline
    import warnings
    warnings.filterwarnings('ignore')   # Suppress Matplotlib warnings
    tf.enable_v2_behavior()
    from tensorflow.keras import backend as K 
    K.clear_session()
    from tensorflow.keras.applications.resnet50 import ResNet50
    from tensorflow.keras.applications.resnet50 import preprocess_input, decode_predictions
    from tensorflow.keras.models import Model
    from tensorflow.keras.layers import Dense, Dropout, GlobalAveragePooling2D
    # 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
    label_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()
            label_batch_all = label_batch.numpy()
        else:
            feature_batch_all = np.vstack((feature_batch_all, m(image_batch).numpy()))
            label_batch_all = np.append(label_batch_all, label_batch.numpy())
    print(feature_batch_all.shape)
    print(label_batch_all.shape)
    

  5. データのプロット

    主成分分析(PCA)による

    import pandas as pd
    features = [str(i) for i in range(feature_batch_all.shape[1])]
    df = pd.DataFrame(feature_batch_all, columns=features)
    df['label'] = label_batch_all
    df.shape
    # 主成分分析
    import sklearn
    pca = sklearn.decomposition.PCA(n_components=2)
    pca_result = pca.fit_transform(df[features].to_numpy())
    df['pca1'] = pca_result[:,0]
    df['pca2'] = pca_result[:,1] 
    # プロット
    import matplotlib.pyplot as plt
    %matplotlib inline
    import warnings
    warnings.filterwarnings('ignore')   # Suppress Matplotlib warnings
    import seaborn as sns
    plt.figure(figsize=(10,10))
    # 2クラスなので,パレット数は2
    sns.scatterplot(
        x="pca1", y="pca2",
        hue="label",
        palette=sns.color_palette("hls", 2),
        data=df,
        legend="full",
        alpha=0.4
    )
    

  6. データのプロット

    6次元に次元削減ののち,SOM を作り,SOM をプロット.前準備として「pip install minisom」を実行しておくこと.

    import pandas as pd
    features = [str(i) for i in range(feature_batch_all.shape[1])]
    df = pd.DataFrame(feature_batch_all, columns=features)
    df['label'] = label_batch_all
    df.shape
    # まず,主成分分析により,次元削減する.結果は X へ.
    import sklearn
    DIM = 6
    pca = sklearn.decomposition.PCA(n_components=DIM)
    pca_result = pca.fit_transform(df[features].values)
    df['pca1'] = pca_result[:,0]
    df['pca2'] = pca_result[:,1] 
    df['pca3'] = pca_result[:,2] 
    df['pca4'] = pca_result[:,3] 
    df['pca5'] = pca_result[:,4] 
    df['pca6'] = pca_result[:,5] 
    X = df[['pca1', 'pca2', 'pca3', 'pca4', 'pca5', 'pca6']].to_numpy()
    # see https://github.com/JustGlowing/minisom/blob/master/examples/BasicUsage.ipynb
    # マーカーと色は2種類を設定(2クラスなので),label_batch_all に入っっている 0, 1 の値に応じて選択.
    markers = ['o', 's']
    colors = ['C0', 'C1']
    from minisom import MiniSom    
    som = MiniSom(20, 20, DIM, sigma=0.3, learning_rate=0.5) # initialization of 20x20 SOM
    som.train(X, 100000) # trains the SOM with 50000 iterations
    plt.figure(figsize=(10, 10))
    plt.pcolor(som.distance_map().T, cmap='bone_r')
    plt.colorbar()
    for cnt, xx in enumerate(X):
        w = som.winner(xx)
        print(w, cnt, xx)
        plt.plot(w[0]+.5, w[1]+.5, markers[label_batch_all[cnt]], markersize=12, markeredgewidth=2, markerfacecolor='None', markeredgecolor=colors[label_batch_all[cnt]])
    plt.show()