ResNet50実装記録 Vol.3:W&Bで実験管理のコード改善
はじめに
こんにちは、DL(ディープラーニング)を勉強している大学1年生です。
2025年の4月からプログラミングを本格的に勉強し始め、GCI(東大松尾研が提供するデータサイエンス入門講座)を修了し、現在DL基礎講座を受講しています。
今回は、DL基礎講座の最終課題に向けた学習のアウトプットとして、ResNet50を用いた画像分類に挑戦します。
この記事は、自分自身のポートフォリオとして ResNet50の実装と、その精度改善施策 を行うプロセスを記録し、共有することを目的としています。
※この記事は実装と改善のプロセスに焦点を当てており、ResNetの理論的な詳細には深く立ち入りません。理論的背景については、適切な参考文献をご参照ください。
前回の記事ではW&B (Weights & Biases) を導入しましたが、初期実装では以下の問題点がありました。
- 問題点1 (管理の二重化): ハイパーパラメータの更新とW&B記録用の辞書更新が二度手間になる。
- 問題点2 (ログの不足): 1エポックごとの学習時の詳細なメトリクスがW&Bに送信されない。
- 問題点3 (可視化の不足): モデルが誤分類した画像をW&Bに送信できていない。
今回は、これらの問題点を解決し、実験管理環境を完成させます。
実装
Google Colab環境での実装手順です。
変更点①:hyperamatersというディクショナリーを作成
ハイパーパラメータをディクショナリーhyperparameters として一元管理し、学習コードとW&B初期化コードの両方から参照するようにしました。これにより、パラメータ変更時の手間を削減できます。
hyperparameters = {
"project_name": "clasification of cifar-10 by ResNet50",
"experiment_name": "baseline_resnet50_fixed_seed", # 実験名
"note": "Baseline implementation with fixed seed and basic transforms", # 施策メモ
"architecture": "ResNet50",
"dataset": "CIFAR-10",
"epochs": 5, # 動作確認のため少なめに設定しています。
"batch_size": 128,
"learning_rate": 0.01,
"weight_decay": 1e-4, # 一般的な設定値を追加
"momentum": 0.9,
"optimizer": "SGD",
"scheduler": "CosineAnnealingLR", # 学習率スケジューラを追加
"seed": 42,
"resize": 32, # CIFAR-10のデフォルト
}
W&B初期化のコードでは、このディクショナリーを config に渡します。
run = wandb.init(
project=hyperparameters["project_name"],
name=hyperparameters["experiment_name"],
notes=hyperparameters["note"],
config=hyperparameters,
tags=["baseline", "resnet50"] # 検索用のタグ
)
変更点②:学習関数を作成し、1epochごとにログ送信
train_one_epoch 関数の末尾に wandb.log() を組み込み、1エポックの学習が完了するたびに 以下の指標をW&Bに送信するようにしました。
# 学習率の取得
current_lr = optimizer.param_groups[0]['lr']
print(f"[Train] Epoch {epoch}: Loss={avg_loss:.4f}, Acc={acc:.4f}, LR={current_lr:.6f}")
# W&Bへのログ送信
wandb.log({
"epoch": epoch,
"train/loss": avg_loss,
"train/accuracy": acc,
"train/learning_rate": current_lr
})
変更点③:評価関数を作成し、誤分類画像を送信
# 誤分類画像を保存するためのリスト
misclassified_images = []
misclassified_preds = []
misclassified_labels = []
推論結果 predicted と正解ラベル labels_devを比較し、maskを作成します。画像データ とマスクが同じGPUデバイス上にあることを利用し、最大32枚の誤分類画像を効率的に収集します。
# --- 誤分類サンプルの収集 ---
if len(misclassified_images) < 32:
mask = predicted != labels_dev
if mask.any():
# images(C PU)ではなく images_dev(GPU)を使う
# GPU同士で計算してから .cpu() で戻すことでエラーを回避
wrong_imgs = images_dev[mask].cpu()
wrong_preds = predicted[mask].cpu()
wrong_labels = labels_dev[mask].cpu()
for img, p, l in zip(wrong_imgs, wrong_preds, wrong_labels):
if len(misclassified_images) < 32:
misclassified_images.append(img)
misclassified_preds.append(p.item())
misclassified_labels.append(l.item())
収集した画像に対してキャプション(予測/正解ラベル)を付与し、最終エポックで一度にW&Bにアップロードします。
Python
wandb_images = []
for img, p, l in zip(misclassified_images, misclassified_preds, misclassified_labels):
img = torch.clamp(img, 0, 1)
caption = f"True: {classes[l]} / Pred: {classes[p]}"
wandb_images.append(wandb.Image(img, caption=caption))
log_dict["val/misclassified_examples"] = wandb_images
wandb.log(log_dict)
おわりに
今回は、前回の反省点を踏まえ、W&Bを最大限に活用するための実験トラッキング環境を完成させました。これにより、今後の精度改善実験(データ拡張、正規化、転移学習など)の成果を、客観的かつ効率的に比較・分析できるようになりました。
次回は、このベースラインモデルを起点とし、さらなる精度向上のための具体的な改善施策を順次適用していきます。
最後まで読んでいただきありがとうございました!