転移学習
田中VPoE:「NetShop の商品画像は数千枚しかない。これだけのデータで ResNet をゼロから学習しても、まともな精度は出ない。そこで使うのが転移学習だ。」
あなた:「ImageNet で学習済みのモデルを流用するんですよね。100万枚以上の画像で学んだ知識を借りてくる。」
田中VPoE:「その通り。少ないデータでも高精度が出せるのが最大のメリットだ。実務ではゼロからの学習のほうが珍しいくらいだよ。」
転移学習とは
転移学習(Transfer Learning)は、あるタスクで学習した知識を別のタスクに転用する手法です。ImageNet のような大規模データセットで事前学習されたモデルの特徴抽出能力を活用します。
事前学習(ImageNet 120万枚) 転移学習(NetShop 数千枚)
┌────────────────────┐ ┌────────────────────┐
│ Conv層(低レベル特徴) │ 凍結 → │ Conv層(そのまま利用) │
│ Conv層(中レベル特徴) │ 凍結 → │ Conv層(そのまま利用) │
│ Conv層(高レベル特徴) │ 微調整 → │ Conv層(微調整) │
│ 全結合層(1000クラス) │ 置換 → │ 全結合層(10クラス) │
└────────────────────┘ └────────────────────┘
転移学習の2つのアプローチ
1. 特徴抽出(Feature Extraction)
事前学習済みモデルの畳み込み層を凍結し、分類層のみを学習します。
import torch
import torch.nn as nn
import torchvision.models as models
# 事前学習済み ResNet18 を読み込み
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
# すべてのパラメータを凍結
for param in model.parameters():
param.requires_grad = False
# 分類層だけを置き換え(この部分のみ学習される)
num_features = model.fc.in_features
model.fc = nn.Sequential(
nn.Linear(num_features, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 10) # NetShop の10カテゴリ
)
# 学習可能なパラメータを確認
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print(f"学習対象: {trainable:,} / {total:,} パラメータ ({trainable/total*100:.1f}%)")
2. ファインチューニング(Fine-Tuning)
事前学習済みモデルの一部または全体を小さな学習率で再学習します。
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
# 分類層を置き換え
model.fc = nn.Sequential(
nn.Linear(model.fc.in_features, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 10)
)
# 層ごとに異なる学習率を設定
optimizer = torch.optim.Adam([
{'params': model.conv1.parameters(), 'lr': 1e-5}, # 浅い層: 極小
{'params': model.layer1.parameters(), 'lr': 1e-5},
{'params': model.layer2.parameters(), 'lr': 5e-5},
{'params': model.layer3.parameters(), 'lr': 1e-4},
{'params': model.layer4.parameters(), 'lr': 5e-4}, # 深い層: やや大きい
{'params': model.fc.parameters(), 'lr': 1e-3}, # 分類層: 通常
])
アプローチの選択基準
| 条件 | 推奨アプローチ | 理由 |
|---|---|---|
| データが少ない(< 1000枚) | 特徴抽出 | 過学習を防ぐ |
| データが中程度(1000〜10000枚) | 段階的ファインチューニング | バランスが良い |
| データが多い(> 10000枚) | 全体ファインチューニング | タスク固有の特徴を学習 |
| 元タスクと似ている | 特徴抽出で十分 | 低レベル特徴が共通 |
| 元タスクと異なる | ファインチューニング必須 | 高レベル特徴の調整が必要 |
段階的ファインチューニング
実務でよく使われるテクニックです。最初は分類層のみ学習し、段階的に深い層を解凍していきます。
def gradual_unfreeze(model, epoch):
"""エポックに応じて段階的に層を解凍"""
if epoch == 0:
# 最初は分類層のみ
for param in model.parameters():
param.requires_grad = False
for param in model.fc.parameters():
param.requires_grad = True
elif epoch == 5:
# 5エポック後に layer4 を解凍
for param in model.layer4.parameters():
param.requires_grad = True
elif epoch == 10:
# 10エポック後に layer3 も解凍
for param in model.layer3.parameters():
param.requires_grad = True
torchvision の事前学習済みモデル
import torchvision.models as models
# 主なモデルの読み込み
resnet50 = models.resnet50(weights=models.ResNet50_Weights.DEFAULT)
efficientnet = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.DEFAULT)
mobilenet = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights.DEFAULT)
# 入力の前処理も取得可能
weights = models.ResNet50_Weights.DEFAULT
preprocess = weights.transforms()
| モデル | パラメータ数 | 推論速度 | 用途 |
|---|---|---|---|
| ResNet18 | 11.7M | 高速 | プロトタイプ |
| ResNet50 | 25.6M | 中程度 | 本番(精度重視) |
| EfficientNet-B0 | 5.3M | 中程度 | 精度と効率のバランス |
| MobileNetV3 | 2.5M | 非常に高速 | モバイル/エッジ |
まとめ
- 転移学習は事前学習済みモデルの知識を新しいタスクに転用する手法
- 特徴抽出は分類層のみ学習、ファインチューニングはモデル全体を微調整
- データ量とタスクの類似性に応じてアプローチを選択する
- 段階的ファインチューニングで安定した学習が可能
- 実務では転移学習がデフォルトの選択肢
チェックリスト
- 転移学習の概念と利点を説明できる
- 特徴抽出とファインチューニングの違いを理解した
- PyTorch で事前学習済みモデルの分類層を置き換えられる
- データ量に応じたアプローチの選択基準を理解した
推定読了時間: 30分