はじめに:人物画像生成の評価における「一貫性」と「リソース」のジレンマ

画像生成AIを用いたコンテンツ制作において、「同一人物の顔(ID)を維持したまま、別のアングルや服装の画像を生成する」というタスクは極めて重要です。これを実現する最先端の技術として注目されているのが PhotoMaker V2 です。しかし、ベースとなるモデル(RealVisXL V4.0/V5.0やJuggernaut-XLなど)の選定によって、顔の再現度(ID一貫性)や生成速度、さらには必要なGPU VRAM量などのシステムリソースが大きく変動します。

自らの環境に最適なモデルを見極めるには、同一の入力素材と条件を用いて客観的なスコアを測定し、モデルごとに比較評価を行うための「ベンチマーク環境」が不可欠です。しかし、大きなモデルのダウンロード時にネットワーク上限で処理が停止する問題や、同じモデルで何回も試行した結果が散乱して比較表が煩雑になる問題、さらには開発メンバーごとにOS(Windows CUDA / Mac MPS)やデバイス環境が異なりエラーになる問題など、実運用においては様々な障害が立ちはだかります。

本稿では、これらの課題を解決するPhotoMaker V2自動ベンチマーク実行・比較集計基盤の構築手法を、ソースコードを交えて詳しく解説します。

1. ベンチマーク測定の自動化設計

まず、個別のモデルに対して、同一ケースの生成パラメータで実行し、性能指標を測定する benchmark_photomaker.py を準備します。評価の柱となるのは以下のメトリクスです。

  • 顔類似度 (Face Similarity): InsightFaceを用いて、元画像と生成された画像の顔ベクトル間の最大コサイン類似度を算出。
  • 生成速度 (Generation Speed): モデルの初期ロード時間および画像生成完了までの秒数を記録。
  • ピークVRAM (Peak VRAM): PyTorchの最大メモリ割り当て関数を利用し、生成中の最大グラフィックメモリ使用量を算出。

実行環境の自動判別ロジック

ベンチマークを多様な環境で安全に走らせるためには、ハードウェアの構成(NVIDIA GPU、Apple Silicon、CPUのみ)を動的に判断し、適切な処理にフォールバックさせる必要があります。以下に実装した環境判定ロジックを示します。

def environment_info() -> dict[str, Any]:
    import torch

    info: dict[str, Any] = {
        "python": platform.python_version(),
        "platform": platform.platform(),
        "torch": torch.__version__,
        "cuda_available": torch.cuda.is_available(),
        "cuda_version": torch.version.cuda if torch.cuda.is_available() else None,
    }
    if torch.cuda.is_available():
        properties = torch.cuda.get_device_properties(0)
        info.update({
            "gpu": torch.cuda.get_device_name(0),
            "gpu_vram_gib": round(properties.total_memory / 1024**3, 3),
        })
    elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
        info.update({
            "gpu": "Apple Silicon MPS",
            "gpu_vram_gib": "n/a",
        })
    else:
        info.update({
            "gpu": "CPU",
            "gpu_vram_gib": 0.0,
        })
    return info

これにより、VRAM測定の可否やデバイス名を適切に environment.json に書き出し、集計システム側で非数値("n/a"など)が来てもパースエラーで落ちないようガードします。

2. 複数モデルの自動一括比較と「最新試行のみ抽出」の実装

複数の新規候補モデルを自動で切り替えてベンチマークを回し、最後に比較表を更新するPowerShellスクリプト run_model_comparison.ps1 と、結果をまとめる compare_runs.py を構築します。

ネットワーク上限と認証エラーを回避する -HfToken

Hugging Face Hubから大規模モデルをダウンロードする際、キャッシュディレクトリを変更していると(デフォルト以外のパスなど)、認証セッション切れやAPIのレートリミット上限でダウンロードが途中で停止する問題が多発します。これに対処するため、スクリプト側で HF_TOKEN を任意に受け渡せるようパラメータを追加します。

# run_model_comparison.ps1 からの抜粋
param(
    [string[]]$Models = @(
        "SG161222/RealVisXL_V5.0",
        "RunDiffusion/Juggernaut-XL-v9",
        "stabilityai/stable-diffusion-xl-base-1.0"
    ),
    [string]$HfToken,
    [switch]$LatestOnly
)

# パラメータで指定されたトークンを環境変数に引き渡す
if ($HfToken) {
    $env:HF_TOKEN = $HfToken
    Write-Host "Hugging Face Token has been set from parameters."
}

モデルごとの「最新の成功ラン」だけを抽出する --latest-only 集計ロジック

試行錯誤を繰り返す中で、同じモデルに対する測定結果ディレクトリ(例:20260623_010000_photomaker-v2 など)が複数残ることがあります。普通にすべてをテーブルに表示すると、同じモデルの古い結果が重複して表が長くなってしまいます。
そこで、ベースモデル名ごとに最もタイムスタンプが新しいランだけを抽出し、他を非表示にするロジックを compare_runs.py に組み込みました。

# compare_runs.py 内のフィルタ処理
if args.latest_only:
    latest_rows: dict[str, dict[str, Any]] = {}
    for row in rows:
        model = row["base_model"]
        # runフォルダはタイムスタンプ順でソートされているため、
        # 後から上書きされたものが「最新」になる
        latest_rows[model] = row
    rows = list(latest_rows.values())

このアプローチと、欠損データを - 記号へと整形するフォーマット処理を組み合わせることで、以下のような比較テーブルを自動的に得ることができます。

生成される比較レポート(Markdown)の例:
| Run | Base model | Success | Load (s) | Mean gen (s) | Mean face sim | Peak VRAM (GiB) |
|---|---|---:|---:|---:|---:|---:|
| 20260623_010713_photomaker-v2 | `SG161222/RealVisXL_V4.0` | 1/1 | 19.379 | 15.976 | 0.57013 | 6.28 |
このように、過去の不要なエラーランや一時的な測定データを自動的に省き、現時点の各モデルの「ベストかつ最新」の結果のみがダイレクトに表示されます。

3. 頑健性テストによる多様な環境(CPU/MPS)の動作検証

どれほど優れたベンチマークでも、集計プログラム自体が開発メンバーごとの動作環境差で例外エラーを吐いて止まってしまっては意味がありません。これを保証するため、テストフレームワークである pytest を導入し、ダミーの測定ログを用いてテストを網羅しました。

特に、VRAMが測定できない「Apple Silicon MPS」環境や、GPU非搭載の「CPUのみ」の測定結果(非数値のダッシュ表現や空白など)を擬似的に入力し、集計器がクラッシュせず正常に出力を完了することを確認するユニットテストを実行しました。

def test_summarize_run_non_numeric_vram_and_cpu(self) -> None:
    with tempfile.TemporaryDirectory() as temp_dir:
        run_path = Path(temp_dir) / "20260623_020000_photomaker-v2"
        run_path.mkdir()

        # VRAMが非数値のMPS環境データをダミー生成
        env_data = {
            "base_model": "test/model-v2",
            "low_vram": True,
            "model_load_seconds": 5.0,
            "environment": {
                "gpu": "Apple Silicon MPS",
                "gpu_vram_gib": "n/a",
            }
        }
        (run_path / "environment.json").write_text(json.dumps(env_data), encoding="utf-8")

        results = [{"case": "case1", "status": "ok", "generation_seconds": "10.0", "identity_similarity_max": "0.75", "peak_vram_gib": "n/a"}]
        # (中略:CSV書き出しと集計の呼び出し)

        summary = summarize_run(run_path)
        self.assertEqual(summary["gpu"], "Apple Silicon MPS")
        self.assertEqual(summary["max_peak_vram_gib"], "") # エラーにならず空値(-に変換用)として処理される

まとめ

PhotoMaker V2による人物ID一貫性生成を実運用へ載せるにあたり、モデルごとの特性を客観的に評価する比較基盤を構築しました。 run_model_comparison.ps1 に備わった -HfToken によるAPI制限回避、compare_runs.py--latest-only によるスマートな最新ラン抽出、そして多様な環境での安全な集計処理をテストで担保することで、非常に信頼性の高い自動検証ラインが実現しています。

今後新たなベースモデル(RealVisXL V5.0やJuggernaut-XL v9など)を実ダウンロードして回す際も、回線や環境の差異に怯えることなく、ワンコマンドで安全かつクリーンに自動評価を回せるようになりました。ローカル環境でのLLM/画像生成AIの性能評価や、CI/CDラインでのモデル品質計測にぜひ参考にしてください。