# Anima 蒸留 — 実走で分かった知見 [← README に戻る](../README.md) > **TL;DR**: 数万円予算で Anima を自前 SOTA 蒸留(DMD2+TSCD+R3GAN)するのは > 現実的に困難。**5 回失敗で累計 $165**。実用解は **`merge_turbo_lora`** > (公式 Anima Turbo LoRA との合成、$0.5、即動く)。自前で挑む人向けに、 > 何が起きるか・なぜ難しいかを以下に集約。 > > 2026-05 以降の改善試行 (PCM / LADD / Reflow など既存実装の移植) は > [migration_log.md](migration_log.md) を参照。 --- ## 1. 概要(結論先出し) このリポジトリでは Anima(CircleStone Labs, Cosmos-Predict2 派生 2B DiT)を **Decoupled DMD2 + TSCD + R3GAN** で **step 削減蒸留** することを目指した。 B200 GPU(Modal)で 5000 枚 self-distillation データセットを使い、**計 5 回の失敗**: | 試行 | 構成 | 結果 | コスト | |---|---|---|---| | Phase A | full DiT, R3GAN gamma=50 | 完全ノイズ(D 爆発) | $70 | | Phase B v1 | Q,V LoRA, R3GAN OFF | 緑色化(AdaLN 不触) | $10 | | Phase B v2 | wide LoRA, R3GAN OFF | mean collapse | $10 | | Phase B v3a | wide LoRA, gamma=0.1 | step 30 で D 爆発 abort | $5 | | **Phase B v3b** | wide LoRA, gamma=1.0 | **mean collapse + 後で D 爆発** | $20 | **最終理解**: R3GAN は「D 爆発」と「無信号 → mean collapse」の間に **安定 zone が 極めて狭く**、Anima latent(16ch × 128²)で持続的な訓練は現状の構成では困難。 DMDR / Z-Image の公式実装が **DINOv2 reward に依存** していることからも、 adv loss 単独の R3GAN だけでは Anima 系の蒸留は厳しい可能性が高い。 ### 1.1 結局どうすればいいか | 用途 | 推奨パス | コスト | 結果 | |---|---|---|---| | **すぐ 8-12 step 推論したい** | `merge_turbo_lora`(公式 Civitai Turbo LoRA を Anima base に重ねる)| **$0.5** | ✅ 即動く、CFG=1 / 8-12 step | | **どうしても自前で蒸留したい** | 本ドキュメントの試行錯誤を踏まえ、**DINOv2 reward 切替** 等を追加実装 | +$50-100 + 開発時間数日 | △ 未検証 | | **学習目的・記録目的** | 本ドキュメントを読む | $0 | 知見だけ | > **強い推奨**: 商用要件がなければ `merge_turbo_lora` で十分。CircleStone Labs > 自身が遥かに多い計算資源と試行錯誤の上で作った Turbo LoRA が既に Civitai > にある(https://civitai.com/models/2560840)、これに勝つのは数万円では困難。 --- ## 2. 結局成功した実用パス: `merge_turbo_lora` ```bash # 1. Anima Turbo LoRA を Civitai からダウンロード modal run modal_app.py::download_civitai_lora # version_id=2877687 がデフォルト # 2. (任意) 自前 Phase 1 LoRA とマージ(なくても可) modal run modal_app.py::merge_turbo_lora # 3. ComfyUI で base + LoRA(strength=1.0)を組み、8 step CFG=1 で生成 ``` 実装: `modal_app.py::download_civitai_lora`, `merge_turbo_lora`, `stage_lora_to_models`。 ComfyUI workflow は `scripts/anima_workflow_turbo.json` 参照。 実測の Turbo LoRA 出力品質: **base 30 step CFG=4.5 と同等のキャラクター品質を 8 step CFG=1 で達成**(検証画像は `/dataset/compare/turbo_8step/` に保存)。 --- ## 3. 自前 SOTA 蒸留(本リポジトリで実装、未完成) `scripts/distill/` に Decoupled DMD2 + TSCD + R3GAN を実装。**コード自体は動く** が、 ハイパーパラメータの調整で 5 回失敗。以下「我々が試した推奨設定」だが、これでも 2000 step で失敗 — **これから挑む人は次節 §4 §5 を読んでから**。 ### 3.1 試した(が安定しなかった)設定 ```text === モデル / データ === base model: Anima preview3-base (Cosmos-Predict2 派生) text encoder: Qwen3-0.6B + LLM Adapter (T5 空間ブリッジ) VAE: WanVAE (16-channel latent, scale=[mean, 1/std]) dataset: self-distillation 5000 枚(base が 30 step CFG 4.5 で生成) 解像度 1024px 周辺の 7 種 aspect ratio をランダム === 学習 (LoRA-only) === trainable: gen + guidance ともに LoRA、base は frozen gen LoRA: **wide** (all-linear except llm_adapter), rank=32 → AdaLN modulation を含む全 Linear に attach guidance LoRA: Q,V LoRA, rank=32 (DMDR 互換、軽量) optimizer: gen / guidance: AdamW lr=2e-5 β=(0.9, 0.999) wd=0.01 D: Adam lr=2e-4 β=(0, 0.99) (StyleGAN 流) grad clip: 1.0 === Loss 構成 === L_dmd: DMDR gradient trick (p_real - p_fake) / norm L_consist: TSCD MSE vs EMA generator (decay=0.999) L_adv (gen): R3GAN relativistic RpGAN, weight=0.05 L_disc: R3GAN softplus + γ/2 · (R1 + R2) γ = 0.05〜0.5 (grid search 必須) === 更新比率 / スケジュール === guidance update: 5 回 / outer step generator update: 1 回 / outer step discriminator: 1 回 / outer step CFG Augmentation: real_score を cfg=2.0 で評価 (cold_start 100 step は cfg=0) dynamic LoRA r: real-side scale を cosine で 0 に decay (decay_steps=2000) === Phase 構成 === Phase B: base 直接 + wide LoRA, num_inference_steps=4, 2000 step Phase C: Phase B から resume または base 直接, wide LoRA, num_steps=2, 2000 step ※ Full DiT 訓練 (Phase A) は不要 — LoRA-only で十分 === Sanity / Guard === sanity test: 200 step + 中間生成 1 枚で degeneration 検出 abort guards: d_r1 > 1000 / d_r2 > 1000 / loss > 1e6 checkpoint: 500 step 毎 + 都度 volume.commit() PYTHONUNBUFFERED=1 + cwd=/workspace/diffusion-pipe === Modal infra === GPU: B200 (192GB) — LoRA-only で余裕、batch=4 image: CUDA 12.4 + Python 3.11 + diffusion-pipe + torchvision volumes: anima-models / anima-dataset / anima-outputs secrets: hf_token, civitai_api_key === ComfyUI 出力形式 === LoRA key: diffusion_model..lora_A.weight / .lora_B.weight (PEFT の base_model.model.<...>.lora_A.default.weight から変換) 基底 ckpt: anima ckpt 系は net. prefix 必須 (ComfyUI が arch 検出に使う) ``` 実装は `scripts/distill/` + `modal_app.py::train_sota_distill` を参照。 > ⚠️ **重要**: 上の設定で 2000 step training を 5 回試したが、いずれも失敗。 > Anima latent では R3GAN の安定 zone が極めて狭く、長期持続が困難だった。 > **これから挑む人は §4(全失敗の詳細)+ §5(残された改善方向)を必ず読むこと**。 ### 3.2.1 なぜ LoRA-only(full DiT 訓練ではなく) | | full DiT(Phase A) | LoRA-only(Phase B/C) | |---|---|---| | trainable params | 2B | 30-150M | | step 時間 (B200) | 14 秒 | **2.8-3.0 秒**(5x 速) | | 出力 | 4 GiB ckpt | **30-150 MiB LoRA** | | 配布性 | 他 FT と排他 | **他 LoRA とスタック可** | | optimizer state | 8 GB | ~200 MB | | failure 局所化 | base 全体破壊リスク | LoRA だけ | Anima のように既に高品質な base を蒸留する場合、LoRA-only がコスト・配布性・ 安全性のすべてで優位。Phase A 流の full DiT 訓練は不要だった。 ### 3.2.2 なぜ「wide LoRA」(Q,V LoRA ではなく) Anima/Cosmos の DiT は **AdaLN modulation で timestep 情報を処理**する架構: ``` block(x, t): t_embed = t_embedder(t) # AdaLN modulation = block_input をどう変調するかを timestep から決める scale, shift, gate = adaln_modulation(t_embed) ← ここが timestep の入り口 x = LayerNorm(x) * (1 + scale) + shift x = x + gate * attention(x, ...) ``` 蒸留とは「**timestep の解釈を変える**」こと(少ない step でも denoise しきる)。 それには adaln_modulation の Linear を学習対象に含める必要がある。Q,V LoRA だと attention pattern だけ変えられて timestep 入り口を触れない → 学習が degenerate な「色 / スタイル shift」に逃げる(Phase B v1 の緑色化はこれ)。 公式 Anima Turbo LoRA も同じ理由で adaln_modulation を target(1016 keys、 我々の wide LoRA 980 keys とほぼ同等)。 ### 3.2.3 なぜ R3GAN が必要(adv loss なしではダメ) DMD2 単体は **mean collapse** に陥る(Phase B v2 で実証)。理由: - DMD gradient `(real_score - fake_score)` は「real distribution の方向」を示す - LoRA capacity が大きいほど、「real の **mean** を出力するのが最も安全」という解に収束しやすい - TSCD(EMA self との consistency)は collapse を加速こそすれ防げない R3GAN(または同等の adv / reward 信号)があると: - D が「real は sharp、fake は blurry」と学習 - gen は「blurry な mean を出すと D に見抜かれる」と分かり、sharp な多様性を保つ - これが mean collapse の唯一の防御策 実際、DMD2 / Hyper-SD / DMDR 系の全公式実装で adv loss(or reward loss)が必須。 ### 3.2.4 なぜ R3GAN gamma の grid search が必須 R3GAN の R1+R2 gradient penalty 重み `gamma` は **入力空間のスケールに比例**: | ドメイン | 入力 channel | 解像度 | gamma | |---|---|---|---| | CIFAR-10 | 3 | 32x32 | **0.05** | | FFHQ-64 | 3 | 64x64 | 2 | | FFHQ-256 | 3 | 256x256 | 150 | | **Anima latent** | **16** | **128x128** | **~0.05-1**(grid search 必須) | Anima latent は per-sample 262k 要素で、典型 pixel 空間より gradient norm が 大きい → gamma は数値が小さくないと penalty が爆発。Phase A は gamma=50 で **500x 過大** にしたら discriminator が崩壊した(詳細は §4 Phase A 参照)。 ### 3.2.5 なぜ guard rail(`d_r1/r2 > 1000` で abort) Phase A は **loss は全部健全に推移**(`l_dmd` 0.005, `l_adv_g` 0.69 で一定)しつつ 裏で discriminator gradient が爆発し、completed ckpt が完全ノイズ出力という **ステルス失敗**。後付けの分析で「step 1500 時点 d_r1 ~700 / step 2300 で 500k」と わかったため、しきい値 1000 で abort すれば即停止できる。 しきい値 1000 の根拠: 正常上限 ~100 の 10x、致命傷 500k の 1/500 で、確実に ステルス damage が始まる前に止まる。 ### 3.2.6 なぜ Decoupled DMD2 + TSCD(LCM / Hyper-SD ではなく) | 手法 | 性質 | 我々の選択理由 | |---|---|---| | LCM | consistency 単体、シンプル | low-step 品質に限界 | | Hyper-SD | TSCD + adv、segment-wise progressive | gamma calibration 必要、参照実装 SDXL only | | **DMD2 / DMDR** | **分布マッチング + adv、Anima のような flow matching DiT に最適** | Z-Image(Cosmos 派生)で実証済、適応容易 | DMD2 系は **flow matching ベース(Anima の rectified flow と同じ)** で、math 変換不要なのが決定打。TSCD は Hyper-SD から借りた多 step 一貫性で、純粋 DMD2 の単 step 偏りを補正。 ### 3.2.7 なぜ 5000 枚 self-distillation データセット | データソース | コスト | 利点 | 欠点 | |---|---|---|---| | Anima 自己生成 | $44 (10 B200 並列 40min) | base の出力分布に最適化 / ライセンス問題なし | base の癖をそのまま継承 | | Danbooru / Pixiv | $0 + キュレーション時間 | 多様性 | ライセンス・タグ品質ばらつき | | 公開データセット(LAION 等) | $0 + DL コスト | 多様性最大 | アニメ系少ない | 蒸留の本質は「**base と同じ出力を低 step で**」なので、self-distillation で 分布を base に一致させるのが理論的に正しい(distillation の定義)。 ### 3.2.8 なぜ B200(H100 / A100 ではなく) | GPU | Modal $/h | LoRA-only step 時間 | 192GB VRAM の意味 | |---|---|---|---| | A100-80GB | $2.50 | 7-9 秒 | OOM 危険、batch=1 | | H100-80GB | $3.95 | 4-6 秒 | OOM 危険、batch=1-2 | | **B200** | **$6.25** | **2.8-3.0 秒** | **3 model 同時 + batch=4-8 余裕** | B200 の per-hour 単価は高いが、**3 model(real/fake/gen)同時+batch 増**で **実質的な per-experiment コストは最安**。R3GAN を入れても OOM 不安なし。 --- ## 4. 実際の失敗(全 5 件、詳細) | # | 試行 | 構成 | 結果 | 累計 | |---|---|---|---|---| | 1 | **Phase A** | full DiT + Q,V LoRA, R3GAN γ=**50**, 3000 step | 完全ノイズ(D 爆発) | $70 | | 2 | **Phase B v1** | Q,V LoRA, R3GAN **OFF**, 2000 step | 緑色化(AdaLN 不触) | $80 | | 3 | **Phase B v2** | wide LoRA, R3GAN **OFF**, 2000 step | mean collapse(灰緑平面)| $90 | | 4 | **Phase B v3a** | wide LoRA, R3GAN γ=**0.1**, 2000 step | step 30 で d_r1=1648 → abort | $95 | | 5 | **Phase B v3b** | wide LoRA, R3GAN γ=**1.0**, 2000 step | 早期 mean collapse → 後半 D 爆発 | $115 | 各失敗が **異なる failure mode** で起きた点が重要。「1 つ直しても他で詰まる」 直交性が、SOTA 蒸留を Anima 系で安定させる難しさの本質。 ### 4.1 Phase A の詳細 postmortem(5 層因果分析) **ステルス失敗**: 訓練ログ上は全 loss 健全(`l_dmd` 0.003-0.008, `l_adv_g` 0.69 一定) だったのに、完走 ckpt が完全ノイズ出力。原因は 5 層の連鎖: **Layer 1 — gamma calibration ミス(根本)** - Anima latent(16ch × 128x128)に対し gamma=50 は 50-500 倍過大 - Agent リサーチが「latent norm 用 grid search 必須」と明示警告していたが、 手抜きで推測値を採用したのが発端 **Layer 2 — R3GAN gradient が gen に流入(見えない damage)** ``` l_adv_g = softplus(-(d_fake - d_real)) ≈ log 2 = 0.6914 ← 中立点 ``` `l_adv_g` が一定で「adv 信号効いてない」と誤読。**しかし gradient norm は別物**: ``` ∂L_adv_g/∂gen_output = (sigmoid 微分 ~0.5) · ∂(D の全層 Jacobian) ``` D 重みが gamma penalty 最小化で異常拡大 → D の Jacobian 爆発 → gen に流れる gradient が正常時の **数百〜数千倍**。adv_weight=0.05 で抑えても scale 負け。 > 教訓: **adv_loss の絶対値だけ見て安全と判断するな**。gradient norm を別途モニタ。 **Layer 3 — D 自体の破滅スパイラル** ``` 最初: l_disc = 0.69 + 25·0 = 0.69 膨張後: l_disc = 0.69 + 25·600,000 = 15,000,000 ``` gamma が大きすぎて R1+R2 penalty 項が adv 項を支配 → D は adv 学習する余地なく、 ひたすら penalty 最小化に動く → ある瞬間 scale 崩れて d_r1/r2 が指数的に膨張。 **Layer 4 — Sanity test の見落とし** - 50 step では destabilization が緩やかすぎて d_r1/r2 が正常範囲 - 本番 step 500-1000 から急速悪化 - 後から見れば step 1000 で d_r1/r2 が 100 超え始めていた($50 救えた) > 教訓: **Sanity は 200-500 step に延長**。緩慢な発散も検出可能に。 **Layer 5 — 監視/アラート不足** - d_r1/r2 はログ出していたが **しきい値アラート未実装** - NaN/Inf check はあったが「大きすぎる値」検出なし - gen の weight L2 norm を時系列で見れば damage 早期検出可能だった - 中間 ckpt 毎の自動生成テストも未実装 修正後の guard rail(実装済): ```python # scripts/distill/dmd2_trainer.py if d_r1 > 1000.0 or d_r2 > 1000.0: raise RuntimeError(f"R3GAN penalty exploded (r1={d_r1:.1f}, r2={d_r2:.1f}). " f"Reduce r3gan_gamma. Aborting.") ``` **Phase A から学んだ悪設計のチェックリスト** | 問題 | 影響 | |---|---| | gamma を grid search せず推測 | 50-500 倍ズレ | | adv_weight=0.05 で「安全装置」になると誤解 | gradient norm は別軸、効かなかった | | sanity 50 step だけで本番投入 | 緩慢な発散見逃し | | `d_r1/r2` にアラートしない | 早期 abort 機会逸失 | | 中間 ckpt で部分検証しなかった | 完走してから初めて発覚($70 ロス) | ### 4.2 Phase B v1 — Q,V LoRA だと AdaLN を触れない R3GAN を外して安全側に振った構成。loss は 0.02-0.03 で安定したが、生成すると **緑色化した anime キャラ**。LoRA strength を 1.0 → 0.3 に下げると base に戻る (= LoRA は「均一に緑方向に押している」)。 原因: Q,V LoRA は cross-attention / self-attention の query / value だけを変更。 **timestep modulation の入り口である AdaLN modulation Linear を触れない**。 DiT が「少ない step でちゃんと denoise する」ために必要な timestep 解釈の変更が できず、勾配が attention の color / style shift に逃げて degenerate に収束。 → 解決: LoRA target を **「AdaLN + attention + MLP の全 Linear」(wide LoRA)** に拡張。 公式 Anima Turbo LoRA も同じ範囲を target にしている(検証で 1016 keys 確認)。 ### 4.3 Phase B v2 — wide LoRA + R3GAN OFF で mean collapse wide LoRA(980 keys)に拡張したら、今度は **完全に灰緑色の平面**を出力。loss は v1 より遥かに小さく(`l_dmd` 0.001-0.007)、**訓練ログ上は最も健全に見える** 失敗。LoRA strength を変えても改善せず。 原因: DMD2 単体は「real distribution の方向」を示すだけ。LoRA capacity が大きい ほど **「data distribution の mean を出力すれば DMD gradient はゼロになる」** という degenerate な解に収束しやすい。R3GAN なしでは「sharp なものを出せ」と gen に教える信号がないので、訓練が進むほど mean に潰れていく。 → 解決: **R3GAN(または同等の reward / classifier loss)を必ず投入**。DMD2 系の 全公式実装(NVIDIA DMD2, Z-Image DMDR, Hyper-SD)で adv 系 loss が必須なのは このため。 ### 4.4 Phase B v3a — gamma=0.1 で D が即爆発 grid search の 100-200 step では gamma=0.1 が安定に見えていた: ``` [step 60/100] d_r1=0.020 d_r2=0.015 l_disc=0.017 ← 健全 ``` しかし本番(2000 step)で開始 30 step 以内に爆発: ``` [step 10/2000] d_r1=67.5 d_r2=74.8 l_disc=7.1 ← 既に異常 [step 30/2000] d_r1=1648.0 d_r2=1821.6 ← guard 発火 abort ``` 原因推測: - 短時間 grid search は **ランダム初期化の運**で偶然安定 zone に居ただけ - 本番の異なる初期化 + 長時間 → 不安定境界を越えた - gamma=0.1 は Anima latent では **安定境界の崖際** ### 4.5 Phase B v3b — gamma=1.0 で長期 mean collapse + 最終 D 爆発 gamma=1.0 で training は確かに **1500 step まで全 metric 健全**: ``` [step 1000/2000] l_dmd=0.001 l_consist=0.005 d_r1=0.005 l_disc=0.004 ← 全部小さい ``` **しかし step 500/1000/1500 の中間 ckpt で生成テストすると全部 mean collapse**: - step 500: 白い平面 - step 1000: 白い平面 - step 1500: 青+白の blob しかも step 1380 から D が「目覚め」始め、step ~1600 で d_r1=2656 で abort: ``` [step 1380/2000] d_adv=3.73 d_r1=0.36 d_r2=0.22 ← D が動き始める [step 1510/2000] d_adv=0.00 d_r1=0.67 d_r2=0.45 ← じわじわ拡大 [step ~1600] d_r1=2656.0 d_r2=3043.2 ← abort ``` **核心の理解**: - gamma=1.0 は D が **静か → 突然動く → 爆発** のパターン - 静かな間(d_r1 ~ 0.005)は **D が adv 信号を gen に渡せず**、gen は mean に collapse - D が動き始めた頃には gen は既に degenerate state - ckpt が「健全に見える」のは loss だけ。実態は破綻 これが **「R3GAN の安定 zone が存在しない」** という最終診断の根拠。 ### 4.6 失敗パターンの直交性 | | Phase A | B v1 | B v2 | B v3a | B v3b | |---|---|---|---|---|---| | failure mode | gradient damage(ノイズ)| degenerate(緑) | mean collapse | D 爆発 abort | D 静止 → mean collapse → D 爆発 | | 根本原因 | R3GAN γ 過大 | LoRA target 狭 | adv なし | γ 小すぎて D 暴走 | γ 大すぎて D が adv 信号出さず | | 検出 | step 1000+ d_r1 | 生成テスト即 | 生成テスト即 | step 30 で guard | 中間 ckpt 生成テスト | | 対策 | γ grid search + guard | wide LoRA | R3GAN を入れる | γ 上げる | γ 下げる(でも v3a に戻る)| **5 つの failure mode は互いに直交かつ循環**(γ 下げると v3a、上げると v3b)。 Anima latent で R3GAN を安定させる γ は、**存在するとしても極めて狭く**、 我々の grid 解像度では発見できなかった。 ### 4.7 周辺で踏んだ Modal / diffusion-pipe / ComfyUI 罠 蒸留の本体とは別に、インフラ側で踏んだバグ: **diffusion-pipe を programmatic に使う際の 8 件** | 罠 | 症状 | 対処 | |---|---|---| | `models/`, `utils/` が namespace package(`__init__.py` なし)| site-packages 側の `utils` に shadow されて `from utils.common import` 失敗 | `importlib.util.spec_from_file_location` で強制ロード(`scripts/distill/anima_loader.py`)| | `CosmosPredict2Pipeline(cfg)` の dtype が **torch.dtype 必須** | `tensor() argument 'dtype' must be torch.dtype, not str` | `cfg["model"]["dtype"] = torch.bfloat16`(文字列禁止) | | `load_text_encoder()` / `load_vae()` メソッドが **存在しない** | AttributeError | `load_diffusion_model()` だけ呼ぶ、残りは `__init__` で完了 | | `MiniTrainDIT.forward` は `padding_mask` 必須(None 不可) | `transforms.functional.resize(None, ...)` TypeError | `torch.zeros(B, 1, H, W)` を渡す | | VAE input が bfloat16 必須 | `Input type (float) and bias type (BFloat16) should be the same` | `vae_encode` 内で auto-cast | | DiT 入力 `(noisy, t, cond)` の dtype 統一必須 | `expected mat1 and mat2 same dtype` | dit_forward helper で全部 weight dtype に揃える | | `torchvision` import するが requirements に無い | `ModuleNotFoundError` | image に明示インストール | | save の filter で integer buffer を落とすと壊れる | ロード後ノイズ | float 限定 filter は廃止、全 tensor 保存 | **ComfyUI LoRA 形式** Anima/Cosmos 用 LoRA は `lora_A.weight` / `lora_B.weight`(NOT `lora_down/up`)、 `diffusion_model.` prefix 必須。PEFT 出力からの変換は `modal_app.py::_convert_peft_to_comfy_lora`。 SDXL 流 `lora_down/up` に変換すると ComfyUI が key 認識できずランダム scaling で 適用 → 出力が緑化(これも Phase B v1 のもう 1 つの寄与因子だった可能性)。 **Modal 運用** | 罠 | 対処 | |---|---| | `modal run --detach` の local CLI が早く戻る | 完了確認は `modal app list` / `modal app logs ` | | `print()` の block buffering で logs 滞留 | `PYTHONUNBUFFERED=1` を env に追加 | | Volume commit は subprocess 終了時のみ | 訓練ループ内で `modal.Volume.from_name(...).commit()` を定期発行 | | `modal volume cp` は cross-volume 不可 | 両 volume mount した Modal function で `shutil.copy` | | `run_in_background=true` + TaskStop で app が "detached_disconnected" に残る | 必ず `--detach` を一緒に付ける(明示 detach)| | Anima ckpt は `net.` prefix 前提で ComfyUI が arch 検出 | 保存時に `{"net." + k: v for k, v in sd.items()}` | ### 4.8 コスト・時間の実測値 | タスク | 時間 | コスト | |---|---|---| | dataset 生成(B200 × 10 並列) | 40 分 | $44 | | Path A baseline 確認(Turbo LoRA DL + 10 枚生成) | 5 分 | ~$1 | | **Phase A: full DiT 訓練(失敗)** | **11.6 h** | **~$70**(全損)| | Phase B v1: Q,V LoRA(失敗) | 1.6 h | ~$10 | | Phase B v2: wide LoRA, R3GAN OFF(失敗) | 1.6 h | ~$10 | | Phase B v3a: wide LoRA, γ=0.1(早期 abort) | ~5 分 | ~$5 | | Phase B v3b: wide LoRA, γ=1.0(失敗) | 4 h | ~$20 | | R3GAN gamma grid search | 30 分 | ~$3 | | 比較生成 30 枚 + その他 | | ~$2 | | Modal volume(50 GB × 月)| 常時 | ~$7.5/月 | | **累計** | | **~$165 ≈ 25,000円** | R3GAN ON で 1 step 約 +20-30%(D forward + R1/R2 backward 追加分)。 --- ## 5. 続き §4 の 5 回失敗を受け、「自前で書き下す」を諦めて **既存の動く実装を最小改造で 移植**した試行が 2026-05 から始まる。各手法 (Z-Image traj / LADD / Reflow / DMD2 / SiD2 / Shortcut / PCM / DRaFT+) の移植ログ・コスト・結果は [migration_log.md](migration_log.md) を参照。