📋 このステップで学ぶこと
- タスク別のアーキテクチャ選択(画像分類、物体検出、セグメンテーション)
- 精度 vs 速度 vs サイズのトレードオフ分析
- 転移学習の2つのアプローチ(Feature Extraction、Fine-tuning)
- データ量別の戦略(少量データ、中規模データ、大規模データ)
- 学習率の調整とLayer Freezing
- timm(PyTorch Image Models)ライブラリの活用
- 実践的な転移学習の完全なコード
🎯 1. タスク別のアーキテクチャ選択
これまでSTEP 5〜7で様々なCNNアーキテクチャを学んできました。ここでは、実際のプロジェクトでどのモデルを選ぶべきかを体系的に整理します。
1-1. 画像分類(Image Classification)のモデル選択
画像分類は最も基本的なCVタスクです。モデル選択は主にデータ量とデプロイ環境によって決まります。
【画像分類のモデル選択フローチャート】
質問1: データ量は?
├─ 少量(5,000枚未満)
│ └─ 質問2: 速度要件は?
│ ├─ リアルタイム必要 → MobileNet v2 + Feature Extraction
│ └─ 速度不要 → EfficientNet-B0 + Feature Extraction
│
├─ 中規模(5,000〜50,000枚)
│ └─ 質問2: デプロイ先は?
│ ├─ モバイル → MobileNet v2 + Fine-tuning
│ ├─ サーバー → ResNet-50 or EfficientNet-B3 + Fine-tuning
│ └─ 精度最優先 → EfficientNet-B4 + Fine-tuning
│
└─ 大規模(50,000枚以上)
└─ 質問2: 計算リソースは?
├─ 制限あり → EfficientNet-B3〜B4
└─ 潤沢 → EfficientNet-B7 or ViT-Large
1-2. 画像分類モデルの比較表
| モデル |
精度 |
速度 |
サイズ |
パラメータ |
推奨用途 |
| ResNet-18 |
⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
11.7M |
プロトタイピング、教育用 |
| ResNet-50 |
⭐⭐⭐⭐ |
⭐⭐⭐ |
⭐⭐⭐ |
25.6M |
標準的な選択、バックボーン |
| MobileNet v2 |
⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
3.5M |
モバイル、エッジデバイス |
| EfficientNet-B0 |
⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
5.3M |
バランス重視、万能型 |
| EfficientNet-B3 |
⭐⭐⭐⭐⭐ |
⭐⭐⭐ |
⭐⭐⭐ |
12M |
精度重視、コンペティション |
| DenseNet-121 |
⭐⭐⭐⭐ |
⭐⭐⭐ |
⭐⭐⭐⭐ |
8.0M |
医療画像、細かい特徴 |
1-3. 物体検出(Object Detection)のモデル選択
物体検出では、バックボーン(特徴抽出器)と検出ヘッドの組み合わせを選びます。
【物体検出のモデル選択】
■ リアルタイム重視(>30fps)
├─ YOLOv8-nano:最速、精度は控えめ
├─ YOLOv8-small:速度と精度のバランス
└─ SSD + MobileNet v2:モバイル向け
■ 精度重視(<20fps許容)
├─ Faster R-CNN + ResNet-50:標準的な高精度
├─ Faster R-CNN + ResNeXt-101:より高精度
└─ Cascade R-CNN:最高精度
■ バランス型
├─ YOLOv8-medium:実用的なバランス
└─ EfficientDet-D3:精度と効率の両立
【バックボーンの影響】
バックボーン mAP 推論速度
─────────────────────────────────
MobileNet v2 30% 50fps
ResNet-50 37% 20fps
ResNet-101 40% 15fps
ResNeXt-101 42% 10fps
1-4. セグメンテーションのモデル選択
【セグメンテーションのモデル選択】
■ セマンティックセグメンテーション
├─ DeepLab v3+ + ResNet-50:標準的な選択
├─ U-Net + ResNet:医療画像向け
└─ SegFormer:最新のTransformerベース
■ インスタンスセグメンテーション
├─ Mask R-CNN + ResNet-50:標準的
└─ YOLACT:リアルタイム向け
■ パノプティックセグメンテーション
└─ Panoptic FPN:Things + Stuffの統合
⚖️ 2. 精度・速度・サイズのトレードオフ
モデル選択では、精度、推論速度、モデルサイズのトレードオフを理解することが重要です。
2-1. トレードオフの可視化
【精度 vs パラメータ数】
精度(%)
85 | ● EfficientNet-B7
84 | ● EfficientNet-B5
83 | ● EfficientNet-B4
82 | ● EfficientNet-B3
81 | ● EfficientNet-B2
80 | ● EfficientNet-B1
79 |
78 | ● ResNet-50
77 | ● EfficientNet-B0
76 |
75 | ● ResNet-34
74 | ● DenseNet-121
73 |
72 | ● MobileNet v2
|–+—-+—-+—-+—-+—-+—-+—-+–→ パラメータ数(M)
5 10 20 30 40 50 60 70
→ EfficientNetが最もパラメータ効率が良い
2-2. 要件別の最適モデル
🎯 要件別のモデル推奨
① 精度が最優先
→ EfficientNet-B5〜B7、ViT-Large、アンサンブル
用途:Kaggleコンペ、医療診断、品質検査
② 速度が最優先(リアルタイム)
→ MobileNet v2、EfficientNet-B0 + 量子化
用途:モバイルアプリ、AR/VR、自動運転
③ サイズが最優先(組み込み)
→ MobileNet v1 + Int8量子化、SqueezeNet
用途:IoTデバイス、マイコン、ドローン
④ バランス重視(実務の多くはここ)
→ EfficientNet-B0〜B3、ResNet-50
用途:Webサービス、一般的なプロダクト
🔄 3. 転移学習の2つのアプローチ
転移学習は、大規模データセット(ImageNetなど)で事前学習したモデルを、新しいタスクに適応させる技術です。ゼロから学習するより、はるかに少ないデータと時間で高精度を達成できます。
3-1. Feature Extraction(特徴抽出)
Feature Extractionは、事前学習済みの畳み込み層を固定(フリーズ)し、最後の分類層のみを訓練するアプローチです。
💡 Feature Extractionの仕組み
考え方:事前学習済みの畳み込み層は「汎用的な特徴抽出器」として機能する。新しいタスクでは、その特徴を使って分類するだけ。
【Feature Extractionの構造】
事前学習済みResNet-50
┌─────────────────────────────────────────────┐
│ Conv層群(ImageNetで学習済み) │
│ ┌──────────────────────────────────────┐ │
│ │ conv1 → layer1 → layer2 → layer3 → layer4 │ │ ← 固定(requires_grad=False)
│ └──────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────┐ │
│ │ Global Average Pooling │ │
│ └──────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────┐ │
│ │ FC (2048 → num_classes) │ │ ← 新しく訓練
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
利点:
・訓練が高速(パラメータが少ない)
・少量データでも効果的(過学習しにくい)
・計算リソースが少なくて済む
欠点:
・最高精度は出にくい
・タスク特化の特徴は学習できない
Feature Extractionの実装
※ コードが横に長い場合は横スクロールできます
import torch
import torch.nn as nn
import torchvision.models as models
from torchvision.models import ResNet50_Weights
# ===================================================
# Feature Extraction の実装
# ===================================================
# 1. 事前学習済みモデルを読み込む
model = models.resnet50(weights=ResNet50_Weights.IMAGENET1K_V2)
# 2. 全てのパラメータを固定(学習させない)
# requires_grad = False にすると、その層は訓練時に更新されない
for param in model.parameters():
param.requires_grad = False
# 3. 最後の全結合層を新しいタスク用に置き換える
# 元のfc層は1000クラス(ImageNet)用
# 新しいタスクのクラス数に合わせて置き換え
num_classes = 2 # 例:犬 vs 猫
# model.fc.in_features で元の入力次元を取得
num_features = model.fc.in_features
print(f”FC層の入力次元: {num_features}”)
# 新しいFC層を作成
# 新しく作成した層は自動的に requires_grad=True
model.fc = nn.Sequential(
nn.Dropout(0.5), # 過学習防止のためのDropout
nn.Linear(num_features, num_classes)
)
# 4. 学習可能なパラメータ数を確認
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in model.parameters())
print(f”学習可能なパラメータ: {trainable_params:,}”)
print(f”全パラメータ: {total_params:,}”)
print(f”学習する割合: {trainable_params / total_params * 100:.2f}%”)
実行結果:
FC層の入力次元: 2048
学習可能なパラメータ: 4,098
全パラメータ: 23,512,130
学習する割合: 0.02%
3-2. Fine-tuning(ファインチューニング)
Fine-tuningは、事前学習済みモデルの全層(または一部)を訓練するアプローチです。より高い精度を目指せますが、過学習のリスクもあります。
💡 Fine-tuningの仕組み
考え方:事前学習済みの重みを「良い初期値」として使い、新しいタスクに最適化する。ただし、事前学習で獲得した有用な特徴を壊さないよう、小さい学習率を使う。
【Fine-tuningの戦略】
■ 学習率の設定(重要!)
・初期層(conv1, layer1, layer2): 非常に小さい学習率(1e-6)
・中間層(layer3): 小さい学習率(1e-5)
・後半層(layer4): やや大きい学習率(1e-4)
・新しい層(fc): 大きい学習率(1e-3)
理由:
・初期層はエッジやテクスチャなど汎用的な特徴を学習済み
・後半層はより抽象的でタスク依存の特徴
・新しい層は一から学習が必要
■ Fine-tuningの種類
① Full Fine-tuning: 全層を訓練
② Partial Fine-tuning: 後半層のみ訓練
③ Progressive Fine-tuning: 段階的に訓練する層を増やす
Full Fine-tuningの実装
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.models as models
from torchvision.models import ResNet50_Weights
# ===================================================
# Full Fine-tuning の実装
# ===================================================
# 1. 事前学習済みモデルを読み込む
model = models.resnet50(weights=ResNet50_Weights.IMAGENET1K_V2)
# 2. 最後の層を置き換える(全層は訓練可能のまま)
num_classes = 2
model.fc = nn.Sequential(
nn.Dropout(0.5),
nn.Linear(model.fc.in_features, num_classes)
)
# 3. 層ごとに異なる学習率を設定
# これがFine-tuningの重要なポイント
optimizer = optim.Adam([
# 初期層: 非常に小さい学習率(汎用特徴を保持)
{‘params’: model.conv1.parameters(), ‘lr’: 1e-6},
{‘params’: model.bn1.parameters(), ‘lr’: 1e-6},
{‘params’: model.layer1.parameters(), ‘lr’: 1e-6},
# 中間層: 小さい学習率
{‘params’: model.layer2.parameters(), ‘lr’: 1e-5},
{‘params’: model.layer3.parameters(), ‘lr’: 1e-5},
# 後半層: やや大きい学習率
{‘params’: model.layer4.parameters(), ‘lr’: 1e-4},
# 新しい層: 大きい学習率
{‘params’: model.fc.parameters(), ‘lr’: 1e-3}
])
# 学習率の確認
print(“層ごとの学習率:”)
for i, param_group in enumerate(optimizer.param_groups):
print(f” Group {i}: lr = {param_group[‘lr’]}”)
実行結果:
層ごとの学習率:
Group 0: lr = 1e-06
Group 1: lr = 1e-06
Group 2: lr = 1e-06
Group 3: lr = 1e-05
Group 4: lr = 1e-05
Group 5: lr = 0.0001
Group 6: lr = 0.001
3-3. Feature Extraction vs Fine-tuning の使い分け
| 観点 |
Feature Extraction |
Fine-tuning |
| データ量 |
少量(1,000〜5,000枚) |
中〜大量(5,000枚以上) |
| 訓練時間 |
短い(数分〜数時間) |
長い(数時間〜数日) |
| 計算リソース |
少ない |
多い |
| 過学習リスク |
低い |
高い |
| 達成精度 |
良好 |
最高 |
| 推奨場面 |
プロトタイプ、ImageNetに近いタスク |
本番環境、精度最大化 |
📊 4. データ量別の戦略
データ量によって、最適な転移学習の戦略は大きく変わります。
4-1. 少量データ(5,000枚未満)
【少量データでの戦略】
■ モデル選択
・小〜中規模モデル(ResNet-18, MobileNet v2, EfficientNet-B0)
・大きいモデルは過学習しやすい
■ 転移学習アプローチ
・Feature Extraction が基本
・Fine-tuningは避けるか、後半層のみ
■ データ拡張(非常に重要)
・RandomHorizontalFlip
・RandomRotation
・ColorJitter
・RandomResizedCrop
・Mixup / CutMix(高度な手法)
■ 正則化
・Dropout(0.5〜0.7)
・Weight Decay(1e-4〜1e-3)
・Early Stopping
4-2. 中規模データ(5,000〜50,000枚)
【中規模データでの戦略】
■ モデル選択
・中規模モデル(ResNet-50, EfficientNet-B1〜B3)
■ 転移学習アプローチ
・段階的Fine-tuning(Progressive Fine-tuning)
Phase 1: FC層のみ(5〜10エポック)
Phase 2: layer4 + FC(10エポック)
Phase 3: 全層(10〜20エポック)
■ データ拡張
・標準的な拡張で十分
■ 学習率スケジューリング
・Cosine Annealing
・ReduceLROnPlateau
4-3. 大規模データ(50,000枚以上)
【大規模データでの戦略】
■ モデル選択
・大規模モデル(EfficientNet-B5〜B7, ViT-Large)
・アンサンブル学習
■ 転移学習アプローチ
・Full Fine-tuning
・場合によってはスクラッチ学習も検討
■ データ拡張
・AutoAugment
・RandAugment
■ 高度なテクニック
・Label Smoothing
・Mixup / CutMix
・Knowledge Distillation
4-4. 段階的Fine-tuningの完全な実装
※ コードが横に長い場合は横スクロールできます
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.models as models
from torchvision.models import ResNet50_Weights
# ===================================================
# 段階的Fine-tuning(Progressive Fine-tuning)の実装
# ===================================================
def progressive_finetuning(model, train_loader, val_loader, device):
“””
3段階でFine-tuningを行う関数
Phase 1: FC層のみ訓練
Phase 2: layer4 + FC を訓練
Phase 3: 全層を訓練
“””
criterion = nn.CrossEntropyLoss()
# ===============================
# Phase 1: FC層のみ訓練
# ===============================
print(“=” * 50)
print(“Phase 1: FC層のみ訓練”)
print(“=” * 50)
# 全層を固定
for param in model.parameters():
param.requires_grad = False
# FC層のみ学習可能に
for param in model.fc.parameters():
param.requires_grad = True
# オプティマイザ(FC層のみ)
optimizer = optim.Adam(model.fc.parameters(), lr=1e-3)
# 5エポック訓練
for epoch in range(5):
train_loss = train_one_epoch(model, train_loader, criterion, optimizer, device)
val_acc = evaluate(model, val_loader, device)
print(f”Epoch {epoch+1}/5 – Loss: {train_loss:.4f}, Val Acc: {val_acc:.2f}%”)
# ===============================
# Phase 2: layer4 + FC を訓練
# ===============================
print(“\n” + “=” * 50)
print(“Phase 2: layer4 + FC を訓練”)
print(“=” * 50)
# layer4を学習可能に
for param in model.layer4.parameters():
param.requires_grad = True
# 異なる学習率
optimizer = optim.Adam([
{‘params’: model.layer4.parameters(), ‘lr’: 1e-5},
{‘params’: model.fc.parameters(), ‘lr’: 1e-4}
])
# 10エポック訓練
for epoch in range(10):
train_loss = train_one_epoch(model, train_loader, criterion, optimizer, device)
val_acc = evaluate(model, val_loader, device)
print(f”Epoch {epoch+1}/10 – Loss: {train_loss:.4f}, Val Acc: {val_acc:.2f}%”)
# ===============================
# Phase 3: 全層を訓練
# ===============================
print(“\n” + “=” * 50)
print(“Phase 3: 全層を訓練”)
print(“=” * 50)
# 全層を学習可能に
for param in model.parameters():
param.requires_grad = True
# 層ごとに異なる学習率
optimizer = optim.Adam([
{‘params’: model.conv1.parameters(), ‘lr’: 1e-6},
{‘params’: model.bn1.parameters(), ‘lr’: 1e-6},
{‘params’: model.layer1.parameters(), ‘lr’: 1e-6},
{‘params’: model.layer2.parameters(), ‘lr’: 1e-6},
{‘params’: model.layer3.parameters(), ‘lr’: 1e-5},
{‘params’: model.layer4.parameters(), ‘lr’: 1e-5},
{‘params’: model.fc.parameters(), ‘lr’: 1e-4}
])
# 15エポック訓練
for epoch in range(15):
train_loss = train_one_epoch(model, train_loader, criterion, optimizer, device)
val_acc = evaluate(model, val_loader, device)
print(f”Epoch {epoch+1}/15 – Loss: {train_loss:.4f}, Val Acc: {val_acc:.2f}%”)
return model
def train_one_epoch(model, loader, criterion, optimizer, device):
“””1エポックの訓練”””
model.train()
total_loss = 0
for images, labels in loader:
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
return total_loss / len(loader)
def evaluate(model, loader, device):
“””評価”””
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
return 100. * correct / total
# 使用例
# model = models.resnet50(weights=ResNet50_Weights.IMAGENET1K_V2)
# model.fc = nn.Linear(model.fc.in_features, num_classes)
# model = model.to(device)
# model = progressive_finetuning(model, train_loader, val_loader, device)
📚 5. timm(PyTorch Image Models)ライブラリ
timmは、700種類以上の事前学習済みモデルを統一されたAPIで提供するライブラリです。最新のモデルも含まれており、研究・実務の両方で非常に便利です。
5-1. timmのインストールと基本操作
# timmのインストール
# !pip install timm
import timm
# 利用可能なモデル一覧を取得
all_models = timm.list_models()
print(f”全モデル数: {len(all_models)}”)
# 事前学習済みモデルのみ
pretrained_models = timm.list_models(pretrained=True)
print(f”事前学習済みモデル数: {len(pretrained_models)}”)
# 特定のキーワードで検索
efficientnet_models = timm.list_models(‘*efficientnet*’)
print(f”\nEfficientNet系モデル: {len(efficientnet_models)}”)
for m in efficientnet_models[:5]:
print(f” – {m}”)
実行結果:
全モデル数: 934
事前学習済みモデル数: 723
EfficientNet系モデル: 52
– efficientnet_b0
– efficientnet_b1
– efficientnet_b2
– efficientnet_b3
– efficientnet_b4
5-2. timmでモデルを作成
import timm
import torch
# ===================================================
# timmでモデルを作成する方法
# ===================================================
# 方法1: 事前学習済み + クラス数指定(最も一般的)
model = timm.create_model(
‘efficientnet_b0’, # モデル名
pretrained=True, # 事前学習済み重みを使用
num_classes=10 # 出力クラス数を変更
)
# モデル情報を確認
print(f”モデル: {model.default_cfg[‘architecture’]}”)
print(f”入力サイズ: {model.default_cfg[‘input_size’]}”)
print(f”パラメータ数: {sum(p.numel() for p in model.parameters()):,}”)
# 方法2: 分類層なしで作成(特徴抽出器として使用)
feature_extractor = timm.create_model(
‘resnet50’,
pretrained=True,
num_classes=0 # 分類層なし
)
# 特徴次元を確認
dummy_input = torch.randn(1, 3, 224, 224)
with torch.no_grad():
features = feature_extractor(dummy_input)
print(f”\n特徴次元: {features.shape}”)
実行結果:
モデル: efficientnet_b0
入力サイズ: (3, 224, 224)
パラメータ数: 4,010,000
特徴次元: torch.Size([1, 2048])
5-3. timmで転移学習
import timm
import torch
import torch.nn as nn
import torch.optim as optim
# ===================================================
# timmを使った転移学習の完全なコード
# ===================================================
# 1. モデル作成
model = timm.create_model(
‘efficientnet_b0’,
pretrained=True,
num_classes=2 # 2クラス分類
)
# 2. Feature Extractionの設定
# timmのモデルは classifier 属性で分類層にアクセス
# (モデルによって属性名が異なる場合がある)
# 全層を固定
for param in model.parameters():
param.requires_grad = False
# 分類層のみ学習可能に
# EfficientNetの場合は classifier 属性
for param in model.classifier.parameters():
param.requires_grad = True
# 3. オプティマイザ
optimizer = optim.Adam(model.classifier.parameters(), lr=1e-3)
# 4. データ変換(timmの推奨設定を使用)
from timm.data import resolve_data_config
from timm.data.transforms_factory import create_transform
# モデルに最適な変換を自動生成
config = resolve_data_config({}, model=model)
transform = create_transform(**config)
print(“推奨データ変換:”)
print(transform)
# 5. 学習可能なパラメータを確認
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print(f”\n学習可能パラメータ: {trainable:,} / {total:,} ({100*trainable/total:.2f}%)”)
実行結果:
推奨データ変換:
Compose(
Resize(size=256, interpolation=bilinear, max_size=None, antialias=warn)
CenterCrop(size=(224, 224))
ToTensor()
Normalize(mean=tensor([0.4850, 0.4560, 0.4060]), std=tensor([0.2290, 0.2240, 0.2250]))
)
学習可能パラメータ: 2,562 / 4,010,000 (0.06%)
5-4. timmのモデル比較
import timm
import torch
import time
# ===================================================
# 複数モデルの比較
# ===================================================
models_to_compare = [
(‘efficientnet_b0’, 224),
(‘resnet50’, 224),
(‘mobilenetv2_100’, 224),
(‘convnext_tiny’, 224),
(‘swin_tiny_patch4_window7_224’, 224)
]
print(“モデル比較:”)
print(“-” * 70)
print(f”{‘モデル’:<35} {'パラメータ':<15} {'推論時間':<15}")
print("-" * 70)
for model_name, size in models_to_compare:
# モデル作成
model = timm.create_model(model_name, pretrained=False, num_classes=10)
model.eval()
# パラメータ数
params = sum(p.numel() for p in model.parameters()) / 1e6
# 推論速度測定
x = torch.randn(1, 3, size, size)
# ウォームアップ
with torch.no_grad():
_ = model(x)
# 計測
start = time.time()
with torch.no_grad():
for _ in range(50):
_ = model(x)
elapsed = (time.time() - start) / 50 * 1000 # ms
print(f"{model_name:<35} {params:>10.1f}M {elapsed:>10.2f}ms”)
print(“-” * 70)
実行結果:
モデル比較:
———————————————————————-
モデル パラメータ 推論時間
———————————————————————-
efficientnet_b0 4.0M 8.52ms
resnet50 25.6M 12.34ms
mobilenetv2_100 3.5M 5.21ms
convnext_tiny 28.6M 15.67ms
swin_tiny_patch4_window7_224 28.3M 23.45ms
———————————————————————-
📝 練習問題
問題1:モデル選択のシナリオ(基礎)
以下のシナリオで、どのモデルとどのアプローチを選ぶべきですか?理由とともに答えてください。
- データ量3,000枚、サーバーで実行、高精度優先
- データ量30,000枚、スマートフォンで動作、30fps必要
- データ量100,000枚、クラウドサーバー、Kaggleコンペ
解答:
1. データ3,000枚、サーバー、高精度優先
モデル: EfficientNet-B0
アプローチ: Feature Extraction
理由:
・データが少ないので過学習を防ぐためFeature Extraction
・EfficientNet-B0は少ないパラメータで高精度
・サーバーなので速度制約なし
・強力なデータ拡張(Mixup、CutMix)も併用
2. データ30,000枚、スマートフォン、30fps
モデル: MobileNet v2
アプローチ: Fine-tuning + Int8量子化
理由:
・スマートフォンではMobileNetが最適
・30fps = 33ms/frameなのでMobileNetで十分
・データ量があるのでFine-tuning可能
・量子化でさらに高速化
3. データ100,000枚、クラウド、Kaggleコンペ
モデル: EfficientNet-B5〜B7 のアンサンブル
アプローチ: Full Fine-tuning
理由:
・大規模データなので大きいモデルも使える
・Kaggleでは精度が全てなのでアンサンブル必須
・複数の異なるアーキテクチャを組み合わせる
例:EfficientNet-B5 + ResNeXt-101 + ViT-Base
・AutoAugment、Mixup、CutMixを使用
問題2:段階的Fine-tuningの実装(中級)
EfficientNet-B0を使って、3段階でFine-tuningを実装してください。
- Phase 1: 分類層のみ訓練(5エポック)
- Phase 2: 最後の2ブロック + 分類層(10エポック)
- Phase 3: 全層(15エポック)
解答:
import timm
import torch.nn as nn
import torch.optim as optim
# モデル作成
model = timm.create_model(‘efficientnet_b0’, pretrained=True, num_classes=10)
# Phase 1: 分類層のみ
print(“Phase 1: 分類層のみ”)
for param in model.parameters():
param.requires_grad = False
for param in model.classifier.parameters():
param.requires_grad = True
optimizer = optim.Adam(model.classifier.parameters(), lr=1e-3)
# 5エポック訓練…
# Phase 2: 最後の2ブロック + 分類層
print(“\nPhase 2: 最後の2ブロック + 分類層”)
# EfficientNetのブロック構造を確認して解凍
# blocks[-1] と blocks[-2] を解凍
for param in model.blocks[-1].parameters():
param.requires_grad = True
for param in model.blocks[-2].parameters():
param.requires_grad = True
optimizer = optim.Adam([
{‘params’: model.blocks[-2].parameters(), ‘lr’: 1e-5},
{‘params’: model.blocks[-1].parameters(), ‘lr’: 1e-5},
{‘params’: model.classifier.parameters(), ‘lr’: 1e-4}
])
# 10エポック訓練…
# Phase 3: 全層
print(“\nPhase 3: 全層”)
for param in model.parameters():
param.requires_grad = True
# 層グループを作成
param_groups = [
{‘params’: model.conv_stem.parameters(), ‘lr’: 1e-6},
{‘params’: model.bn1.parameters(), ‘lr’: 1e-6},
]
for i, block in enumerate(model.blocks):
lr = 1e-6 if i < 3 else 1e-5 if i < 5 else 1e-4
param_groups.append({'params': block.parameters(), 'lr': lr})
param_groups.append({'params': model.classifier.parameters(), 'lr': 1e-3})
optimizer = optim.Adam(param_groups)
# 15エポック訓練...
問題3:timmを使ったモデル比較(応用)
timmを使って、以下の3モデルでCIFAR-10の転移学習を行い、精度と推論速度を比較するコードを書いてください。
- EfficientNet-B0
- ResNet-50
- MobileNet v2
解答:
import timm
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import time
device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’)
# データ準備
transform = transforms.Compose([
transforms.Resize(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
# CIFAR-10をダウンロード(実行時)
# train_dataset = datasets.CIFAR10(root=’./data’, train=True, download=True, transform=transform)
# test_dataset = datasets.CIFAR10(root=’./data’, train=False, download=True, transform=transform)
# train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
# test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
models_to_compare = [‘efficientnet_b0’, ‘resnet50’, ‘mobilenetv2_100’]
results = []
for model_name in models_to_compare:
print(f”\n{‘=’*50}”)
print(f”モデル: {model_name}”)
print(f”{‘=’*50}”)
# モデル作成
model = timm.create_model(model_name, pretrained=True, num_classes=10)
model = model.to(device)
# パラメータ数
params = sum(p.numel() for p in model.parameters())
# 推論速度測定
model.eval()
x = torch.randn(1, 3, 224, 224).to(device)
start = time.time()
with torch.no_grad():
for _ in range(100):
_ = model(x)
inference_time = (time.time() – start) / 100 * 1000
print(f”パラメータ数: {params:,}”)
print(f”推論時間: {inference_time:.2f} ms”)
results.append({
‘model’: model_name,
‘params’: params,
‘inference_time’: inference_time
})
# 結果サマリ
print(“\n” + “=”*60)
print(“結果サマリ”)
print(“=”*60)
for r in results:
print(f”{r[‘model’]:<20} {r['params']/1e6:>8.1f}M {r[‘inference_time’]:>8.2f}ms”)
問題4:実践的な転移学習プロジェクト(総合)
犬vs猫の画像分類(各クラス1,000枚、計2,000枚)で、目標精度95%以上を達成するための完全な訓練コードを書いてください。
解答:
import timm
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets
from torch.utils.data import DataLoader
# ===================================================
# 犬vs猫分類 – 転移学習完全コード
# ===================================================
device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’)
print(f”使用デバイス: {device}”)
# 1. 強力なデータ拡張(少量データなので重要)
train_transform = transforms.Compose([
transforms.RandomResizedCrop(224, scale=(0.8, 1.0)),
transforms.RandomHorizontalFlip(),
transforms.RandomRotation(15),
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
transforms.RandomAffine(degrees=0, translate=(0.1, 0.1)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
test_transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
# 2. データセット読み込み(ImageFolderを使用)
# train_dataset = datasets.ImageFolder(‘data/train’, transform=train_transform)
# test_dataset = datasets.ImageFolder(‘data/test’, transform=test_transform)
# train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)
# test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)
# 3. モデル作成(EfficientNet-B0、少量データに最適)
model = timm.create_model(‘efficientnet_b0’, pretrained=True, num_classes=2)
# 4. Phase 1: Feature Extraction(過学習を防ぐ)
print(“Phase 1: Feature Extraction (10 epochs)”)
for param in model.parameters():
param.requires_grad = False
# 分類層を置き換え(Dropoutを追加)
model.classifier = nn.Sequential(
nn.Dropout(0.5),
nn.Linear(model.classifier.in_features, 2)
)
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.classifier.parameters(), lr=1e-3)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=3)
# Phase 1 訓練ループ(実際の訓練時にはコメントを外す)
# for epoch in range(10):
# model.train()
# for images, labels in train_loader:
# images, labels = images.to(device), labels.to(device)
# optimizer.zero_grad()
# outputs = model(images)
# loss = criterion(outputs, labels)
# loss.backward()
# optimizer.step()
# # 検証…
# 5. Phase 2: Partial Fine-tuning
print(“\nPhase 2: Partial Fine-tuning (20 epochs)”)
# 最後の2ブロックを解凍
for param in model.blocks[-1].parameters():
param.requires_grad = True
for param in model.blocks[-2].parameters():
param.requires_grad = True
optimizer = optim.Adam([
{‘params’: model.blocks[-2].parameters(), ‘lr’: 1e-5},
{‘params’: model.blocks[-1].parameters(), ‘lr’: 1e-5},
{‘params’: model.classifier.parameters(), ‘lr’: 1e-4}
], weight_decay=1e-4) # L2正則化
# Phase 2 訓練ループ…
# 6. 評価
def evaluate(model, loader, device):
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
return 100. * correct / total
# acc = evaluate(model, test_loader, device)
# print(f”最終精度: {acc:.2f}%”)
print(“\n訓練設定完了!”)
print(“実際のデータセットを用意して実行してください。”)
print(“目標: 95%以上の精度”)
📝 STEP 8 のまとめ
✅ このステップで学んだこと
1. タスク別のアーキテクチャ選択
・画像分類:データ量とデプロイ環境で決定
・物体検出:速度要件で YOLO vs Faster R-CNN
・セグメンテーション:U-Net(医療)、DeepLab(一般)
2. 精度・速度・サイズのトレードオフ
・EfficientNetが最もパラメータ効率が良い
・用途に応じて最適なバランスを選択
3. 転移学習の2つのアプローチ
・Feature Extraction:少量データ、高速訓練
・Fine-tuning:最高精度、層ごとの学習率が重要
4. データ量別の戦略
・少量:Feature Extraction + 強力なデータ拡張
・中規模:段階的Fine-tuning
・大規模:Full Fine-tuning + アンサンブル
5. timmライブラリ
・700+の事前学習済みモデル
・統一されたAPIで簡単に利用可能
💡 重要ポイント
転移学習はコンピュータビジョンで最も重要な技術の一つです。ゼロからモデルを訓練することは稀で、ほとんどの実務プロジェクトでは事前学習済みモデルを活用します。
次のSTEP 9からはPart 3: 物体検出に入ります。画像分類の知識をベースに、物体の位置特定という新しいタスクに挑戦します。