転移学習での特徴抽出器(ImageNet で学習済みの ResNet50 による転移学習)(Windows あるいは Ubuntu 上)
【概要】
転移学習 (transfer learning): CNN の学習では,ImageNet などのデータを用いた前学習 (pretrain) ののち,別のデータを用いた学習に移るということがよく行われる.別のデータでの学習は,次のいずれかで行う.
- CNN を画像からの特徴抽出器として使う: CNN の最終層である全結合層を取り除く.残りは,画像からの特徴抽出器(決まった個数の数値を出力する)と見ることができる.そして,CNN の最終層の代わりに,線形分類器 (linear classifier) を付け加える.線形分類器には,線形 SVM や,softmax 分類器がある.その後,データを用いて,学習を行う.画像からの特徴抽出器と言っている部分(最終層である全結合層を取り除いた残り)の結合の重みは変化させない.
- 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 など)がある.
このページでは,モデルからの最終層の除去,特徴抽出器の作成,特徴抽出の実行,抽出した特徴のプロットを行う.
【目次】
- 1. Google Colaboratory での実行
- 2. Windows での実行
- 3. 特徴抽出を行う画像データの準備
- 4. ImageNet で学習済みの ResNet50 をベースモデルとして,特徴抽出器を作成
【関連する外部ページ】
- https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html
- https://www.tensorflow.org/guide/keras/transfer_learning?hl=ja
- TensorFlow チュートリアルのページ: https://www.tensorflow.org/tutorials/images/transfer_learning?hl=ja
- Keras で利用できる学習済みモデルのページ: https://keras.io/api/applications/
【サイト内の関連情報】
1. Google Colaboratory での実行
Google Colaboratory のノートブックを新規作成して実行する場合の手順を説明する.
パソコンを使う場合は,下の「2. Windows での実行」で説明している.
- Google Colaboratory の Web ページを開く
- 「ファイル」で,「ノートブックを新規作成」を選ぶ
- Google アカウントでのログインが求められたときはログインする
2. Windows での実行
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:インストーラーによるインストール
- Python公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンからWindows用インストーラーをダウンロードする。
- ダウンロードしたインストーラーを実行する。
- 初期画面の下部に表示される「Add python.exe to PATH」にチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから
pythonコマンドを実行できない。 - 「Install Python 3.xx for all users」にチェックを入れ、「Install」をクリックする。
インストールの確認
コマンドプロンプトで以下を実行する。
python --version
バージョン番号(例:Python 3.12.x)が表示されればインストール成功である。「'python' は、内部コマンドまたは外部コマンドとして認識されていません。」と表示される場合は、インストールが正常に完了していない。
Python の開発環境 Visual Studio Code のインストールと Python 用の設定
Python の開発環境Visual Studio Code(プログラムを編集するソフトウェア。以下、VS Code)を整える。
[Windows での Visual Studio Code のインストールと Python 用の設定手順を見るには、ここをクリック]
Windows での Visual Studio Code のインストールと Python 用の設定手順
1. VS Code と拡張機能のインストール
以下のコマンドにより,既存の VS Code を削除し,全ユーザー共有の設定で再インストールしたうえで,拡張機能(VS Code に機能を追加するソフトウェア)をまとめて導入する.
【インストールコマンドの実行方法】
管理者権限でコマンドプロンプトを起動する(手順:Windows キーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。そして,コマンド全体をコマンドプロンプトにコピー&ペーストする。
インストールコマンド
REM ============================================================
REM Microsoft Visual Studio Code
REM ============================================================
winget uninstall -e --id Microsoft.VisualStudioCode --silent --disable-interactivity --accept-source-agreements
rmdir /s /q C:\ProgramData\vscode-extensions 2>nul
rmdir /s /q "%APPDATA%\Code" 2>nul
rmdir /s /q "%USERPROFILE%\.vscode" 2>nul
rmdir /s /q "%LOCALAPPDATA%\Microsoft\vscode-update" 2>nul
REM VS Code をシステム領域に新規インストール
winget install --scope machine --id Microsoft.VisualStudioCode -e --silent --accept-source-agreements --accept-package-agreements
REM 全ユーザー共有の拡張機能フォルダ
mkdir C:\ProgramData\vscode-extensions 2>nul
icacls "C:\ProgramData\vscode-extensions" /grant "Everyone:(OI)(CI)M" /T
REM スタートメニューのショートカットを --extensions-dir 付きで再作成
rmdir /s /q "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code" 2>nul
del "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk" 2>nul
powershell -NoProfile -Command "$s=New-Object -ComObject WScript.Shell; $lnk=$s.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk'); $lnk.TargetPath='C:\Program Files\Microsoft VS Code\Code.exe'; $lnk.Arguments='--extensions-dir \"C:\ProgramData\vscode-extensions\"'; $lnk.Save()"
REM ショートカットの検証
powershell -NoProfile -Command "$s=New-Object -ComObject WScript.Shell; $lnk=$s.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code.lnk'); Write-Host 'TargetPath:' $lnk.TargetPath; Write-Host 'Arguments:' $lnk.Arguments"
REM ファイル / フォルダ右クリックの「Code で開く」を登録
reg add "HKLM\SOFTWARE\Classes\*\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%1\"" /f
reg add "HKLM\SOFTWARE\Classes\Directory\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%1\"" /f
reg add "HKLM\SOFTWARE\Classes\Directory\Background\shell\VSCode\command" /ve /d "\"C:\Program Files\Microsoft VS Code\Code.exe\" --extensions-dir \"C:\ProgramData\vscode-extensions\" \"%V\"" /f
REM --extensions-dir 付きで起動する code.cmd ラッパを作成
REM (%* を echo で書くと対話的 cmd で失われるため、PowerShell で [char]37+'*' を書き出す)
powershell -NoProfile -Command "$pct=[char]37; $q=[char]34; $c='@echo off'+[char]13+[char]10+$q+'C:\Program Files\Microsoft VS Code\bin\code.cmd'+$q+' --extensions-dir '+$q+'C:\ProgramData\vscode-extensions'+$q+' '+$pct+'*'+[char]13+[char]10; [IO.File]::WriteAllText('C:\ProgramData\vscode-extensions\vscode.cmd',$c,[Text.Encoding]::ASCII)"
REM 拡張機能のインストール
set "CODE=C:\Program Files\Microsoft VS Code\bin\code.cmd"
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --uninstall-extension GitHub.copilot
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --uninstall-extension GitHub.copilot-chat
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.python
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.vscode-pylance
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension ms-python.debugpy
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension MS-CEINTL.vscode-language-pack-ja
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension saoudrizwan.claude-dev
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension rust-lang.rust-analyzer
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension tamasfe.even-better-toml
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension anthropic.claude-code
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --install-extension almenon.arepl
"%CODE%" --extensions-dir "C:\ProgramData\vscode-extensions" --list-extensions --show-versions
echo === セットアップ完了 ===
2. Python インタプリタの選択
同一マシンに複数の Python がインストールされている場合,VS Code で使用する Python 本体(インタプリタ:Python プログラムを解釈・実行するソフトウェア)を選択する必要がある.
- コマンドパレット(コマンド名で機能を呼び出す VS Code の入力欄)を開く(
Ctrl+Shift+P) Python: Select Interpreterと入力する
- 表示される一覧から,使用する Python(例:
C:\Program Files\Python312\python.exe)を選択する.
TensorFlow,Keras のインストール
管理者権限でコマンドプロンプトを起動する
(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。
次のコマンドを実行することにより,TensorFlow(Keras を含む)と tensorflow_datasets がインストール(インストール済みのときは最新版に更新)される. 1行目は,以前の版が残っているときに競合しないように取り除くためのものである.
python -m pip uninstall -y tensorflow tensorflow-cpu tensorflow-gpu tensorflow-intel tensorflow-text tf-models-official tf_slim tensorflow_datasets tensorflow-hub keras keras-tuner keras-visualizer
python -m pip install -U --no-user tensorflow tensorflow_datasets
TensorFlow 2.11 以降は,Windows のネイティブ環境では GPU に対応していない(Windows で GPU を使う場合は WSL2 上で動かす). Windows のネイティブ環境では CPU で動作する. 出典: https://www.tensorflow.org/install/pip
Graphviz のインストール
Windows での Graphviz のインストール: 別ページ »で説明
numpy,matplotlib,seaborn,scikit-learn,pandas,pydot のインストール
管理者権限でコマンドプロンプトを起動する
(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。
次のコマンドを実行する.
python -m pip install -U --no-user numpy matplotlib seaborn scikit-learn pandas pydot
3. 特徴抽出を行う画像データの準備
train_dataset, validation_dataset, test_dataset を準備する.
import os
import tensorflow as tf
# 追加データである画像の画像サイズを 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(path_to_zip, 'cats_and_dogs_filtered')
train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')
train_dataset = tf.keras.utils.image_dataset_from_directory(train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
validation_dataset = tf.keras.utils.image_dataset_from_directory(validation_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
val_batches = validation_dataset.cardinality()
# 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/ に記載のプログラムを変更して使用している.
- ベースモデルの作成
次の Python プログラムを実行する.
import tensorflow as tf import numpy as np tf.keras.backend.clear_session() %matplotlib inline import matplotlib.pyplot as plt import warnings warnings.filterwarnings('ignore') # Matplotlib の警告メッセージを表示しない from tensorflow.keras.applications.resnet50 import ResNet50 from tensorflow.keras.models import Model from tensorflow.keras.layers import GlobalAveragePooling2D # include_top=False により分類層を含まないようにする base_model = ResNet50(weights='imagenet', input_shape=IMG_SHAPE, include_top=False) # 学習中に結合の重みが更新されないようにする base_model.trainable = False base_model.summary()
- ベースモデルと画像データの事前確認のため,ベースモデルを用いて画像データを処理してみる
エラーメッセージが出ないことを確認する.ここの結果をあとで使うことはない.
image_batch, label_batch = next(iter(train_dataset)) feature_batch = base_model(image_batch) print(feature_batch.shape)
- ベースモデルを用いて,特徴抽出器のモデルの作成
inputs = tf.keras.Input(IMG_SHAPE) x = base_model(inputs, training=False) x = GlobalAveragePooling2D()(x) m = Model(inputs=inputs, outputs=x) m.summary()
- 別データを,特徴抽出器により処理し結果を得る
特徴抽出器による処理結果は,feature_batch_all に格納する. それは,長さ 2048 の数値ベクトル,2000個になる.
feature_batch_all = None label_batch_all = None for image_batch, label_batch in train_dataset: 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)
- データのプロット
主成分分析(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 # 主成分分析 import sklearn.decomposition 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] # プロット %matplotlib inline import matplotlib.pyplot as plt import warnings warnings.filterwarnings('ignore') # Matplotlib の警告メッセージを表示しない import seaborn as sns plt.style.use('default') 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次元に次元削減ののち,SOM(自己組織化マップ。高次元のデータを 2次元の平面上に配置して可視化する方法)を作り,SOM をプロットする.
前準備として,次のコマンドを実行しておく.
管理者権限でコマンドプロンプトを起動する (手順:Windowsキーまたはスタートメニュー →
cmdと入力 → 右クリック → 「管理者として実行」)。python -m pip install -U --no-user minisomimport 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 # まず,主成分分析により,次元削減する.結果は X へ. import sklearn.decomposition 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) # 20x20 の SOM を初期化 som.train(X, 100000) # 100000 回の繰り返しで SOM を学習 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) 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()