本文へスキップ
BecomeCoder

PyTorchコース · 第5章 ファインチューニング ― 学習済みモデルを自分用に · レッスン19

画像モデルのファインチューニング(torchvision / ResNet)

ローカル実施

導入

具体例として、画像認識の定番モデル ResNet を使い、「犬 vs 猫」の2クラス分類器を作ってみましょう。ゼロから作れば数百万枚の画像と数日かかる学習が、ファインチューニングなら数百枚・数分で済みます。

説明

torchvision は、学習済みの画像モデルを配布しているライブラリです。ResNet18 を読み込み、レッスン18の手順(凍結 → ヘッド付け替え)を適用します。

import torch
import torch.nn as nn
from torchvision import models

# ① ImageNet(140万枚)で事前学習済みの ResNet18 を読み込む
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)

# ② 特徴抽出部を全凍結(勾配を計算しない=更新しない)
for param in model.parameters():
    param.requires_grad = False

# ③ 出力層(fc)を、2クラス分類の新しい層に付け替える
#    (新しい層は requires_grad=True がデフォルト → ここだけ学習される)
model.fc = nn.Linear(model.fc.in_features, 2)

あとは第4章の訓練ループがそのまま使えます。ポイントは、optimizer に学習対象のパラメータだけを渡すことです。

# 凍結していない(=付け替えたヘッドの)パラメータだけ最適化
optimizer = torch.optim.Adam(model.fc.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()          # 分類の定番損失

for epoch in range(5):
    for images, labels in train_loader:    # DataLoaderでバッチ供給
        optimizer.zero_grad()
        loss = criterion(model(images), labels)
        loss.backward()
        optimizer.step()
flowchart LR
  pre["ResNet18<br/>ImageNetで事前学習"] --> frz["前半を凍結"]
  frz --> rep["fc層を<br/>1000→2クラスに付替"]
  rep --> tr["犬猫の画像数百枚で<br/>ヘッドだけ数エポック学習"]
  tr --> done["犬猫分類器の完成"]

損失に CrossEntropyLoss を使っている点に注目。回帰(第2章)では MSE でしたが、分類ではクロスエントロピーを使うのが定番です。タスクに応じて損失関数を選ぶ、というのも大事な勘所です。

前処理をそろえる

もう1つ実務で重要なのが、入力画像を事前学習時と同じ形に前処理すること(サイズ・正規化)。weights.transforms() で当時と同じ前処理を取り出せます。ここがずれると精度が出ません。

まとめ

  • torchvision.models で学習済み画像モデル(ResNet等)を読み込める。
  • 「全凍結 → model.fc を付け替え → ヘッドだけ学習」で少数データでも高精度。
  • 分類の損失は CrossEntropyLoss。入力の前処理は事前学習時と揃えるのが必須。