Instructions to use darask0/MOSS-Image_4-step_adapter_lora with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use darask0/MOSS-Image_4-step_adapter_lora with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("OpenMOSS-Team/MOSS-Image-SFT", dtype=torch.bfloat16, device_map="cuda") pipe.load_lora_weights("darask0/MOSS-Image_4-step_adapter_lora") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Draw Things
- DiffusionBee
rapid-moss: MOSS-Image-SFT 4-step adapter (data-space DMD + DMAD, it 500 EMA), code, logs, eval
Browse files- .gitattributes +7 -0
- README.md +168 -0
- code/README.md +30 -0
- code/configs/dmad.json +16 -0
- code/configs/main.json +19 -0
- code/configs/smoke.json +14 -0
- code/rapid_moss/__init__.py +0 -0
- code/rapid_moss/model.py +234 -0
- code/rapid_moss/nets.py +139 -0
- code/rapid_moss/sample.py +110 -0
- code/rapid_moss/teachergen.py +113 -0
- code/rapid_moss/textenc.py +122 -0
- code/rapid_moss/train.py +499 -0
- code/scripts/main_run.sh +23 -0
- code/scripts/pod_dmad.sh +11 -0
- code/scripts/pod_setup.sh +18 -0
- code/scripts/pod_stop_train.sh +6 -0
- code/scripts/pod_teacher2.sh +8 -0
- code/scripts/pssh.sh +9 -0
- code/scripts/runpod.py +103 -0
- code/scripts/watchdog.sh +16 -0
- code/tests/test_dmad.py +52 -0
- code/tests/test_equiv.py +93 -0
- dataspace.safetensors +3 -0
- eval/eval_prompts.jsonl +17 -0
- images/compare-1.jpg +3 -0
- images/compare-2.jpg +3 -0
- images/compare-3.jpg +3 -0
- images/training/000300.jpg +3 -0
- images/training/000500.jpg +3 -0
- images/training/000800.jpg +3 -0
- images/training/init.jpg +3 -0
- inference.py +88 -0
- logs/baseline_timings_h100.json +5 -0
- logs/dmad_config.json +124 -0
- logs/dmad_train_log.jsonl +102 -0
- logs/probe_adm_discriminator.jsonl +15 -0
- logs/probe_teacher_discriminator.jsonl +8 -0
- lora.safetensors +3 -0
- time_embedding.safetensors +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
images/compare-1.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
images/compare-2.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
images/compare-3.jpg filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
images/training/000300.jpg filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
images/training/000500.jpg filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
images/training/000800.jpg filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
images/training/init.jpg filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
base_model:
|
| 4 |
+
- OpenMOSS-Team/MOSS-Image-SFT
|
| 5 |
+
- lodestones/MOSS-Image-SFT-8-steps-dmd
|
| 6 |
+
library_name: diffusers
|
| 7 |
+
pipeline_tag: text-to-image
|
| 8 |
+
language:
|
| 9 |
+
- ja
|
| 10 |
+
- en
|
| 11 |
+
tags:
|
| 12 |
+
- moss-image
|
| 13 |
+
- lora
|
| 14 |
+
- distillation
|
| 15 |
+
- few-step
|
| 16 |
+
- dmad
|
| 17 |
+
- dmd
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
# rapid-moss: MOSS-Image-SFT 4-step adapter (data-space DMD → DMAD)
|
| 21 |
+
|
| 22 |
+
**English summary.** A 4-step, CFG-free adapter for [OpenMOSS-Team/MOSS-Image-SFT](https://huggingface.co/OpenMOSS-Team/MOSS-Image-SFT)
|
| 23 |
+
(50 steps × 2 forwards with CFG 3). It continues [lodestones/MOSS-Image-SFT-8-steps-dmd](https://huggingface.co/lodestones/MOSS-Image-SFT-8-steps-dmd)
|
| 24 |
+
(data-space DMD, arXiv 2610.12102) restricted to 4 iterations, trained with DMAD (arXiv 2610.02188): a LoRA critic on the
|
| 25 |
+
frozen teacher separates teacher samples from student samples, and the student minimises the negative critic logit.
|
| 26 |
+
DiT time per 1024² image on one H100: 16.2 s (teacher) → 0.81 s. Compared with the lodestones checkpoint run for 4 steps,
|
| 27 |
+
images have more detail and livelier composition, with some regressions (see Results). Same file format and sampler as the
|
| 28 |
+
lodestones checkpoint; `inference.py` runs it with the release pipeline. Training code is in `code/`.
|
| 29 |
+
|
| 30 |
+
---
|
| 31 |
+
|
| 32 |
+
MOSS-Image-SFT(50 ステップ・CFG 3 で 1 枚 100 回の DiT 計算)を、**4 回の計算・CFG なし**で画像を出せるようにする高速化アダプタです。
|
| 33 |
+
lodestones の 8 ステップ版(data-space DMD、update 2600)を出発点に、4 ステップに絞って DMAD で追加学習しました。
|
| 34 |
+
|
| 35 |
+
| | DiT 時間 / 1024² 1 枚(H100) | DiT の計算回数 |
|
| 36 |
+
|---|---:|---:|
|
| 37 |
+
| MOSS-Image-SFT(50 step、CFG 3、負側 block 22 skip) | 16.2 s | 100 |
|
| 38 |
+
| lodestones 8 step | 1.54 s | 8 |
|
| 39 |
+
| **このアダプタ(4 step)** | **0.81 s** | **4** |
|
| 40 |
+
|
| 41 |
+
(DiT のみの計測。テキストエンコーダと VAE は含まない。実装は `code/rapid_moss/model.py`。)
|
| 42 |
+
|
| 43 |
+
## 使い方
|
| 44 |
+
|
| 45 |
+
```bash
|
| 46 |
+
pip install "diffusers>=0.38" "transformers>=5.3" accelerate safetensors huggingface_hub pillow
|
| 47 |
+
python inference.py --prompt "an anime girl in a yellow raincoat at a rainy bus stop at night" --width 1024 --height 1024 --out out.png
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
ファイルは lodestones と同じ形式です。
|
| 51 |
+
|
| 52 |
+
| ファイル | 中身 |
|
| 53 |
+
|---|---|
|
| 54 |
+
| `lora.safetensors` | fp32 LoRA、rank 128 / alpha 128、全 42 ブロックの `proj.{q,k,v,o,ffn_up_gate,ffn_down}`。kohya 形式のキー(`diffusion_model.<module>.lora_down.weight` / `lora_up.weight` / `alpha`) |
|
| 55 |
+
| `time_embedding.safetensors` | fp32 の `time_embedding.*` と `shared_block_modulation.bias` / `video_head_modulation.bias` の置き換え |
|
| 56 |
+
| `dataspace.safetensors` | `latent_mix.Q` [128, 128] と `step_codes` [1000, 968, 926, 871] |
|
| 57 |
+
|
| 58 |
+
サンプラー(ノイズの再注入もタイムステップのスケジュールもなく、同じ z を使い続ける):
|
| 59 |
+
|
| 60 |
+
```python
|
| 61 |
+
x0 = torch.zeros_like(z) # z: fp32 noise [1, 128, H/16, W/16]
|
| 62 |
+
for r in range(4): # 1〜3 回で止めても画像になる(各段階を学習している)
|
| 63 |
+
x = z + torch.einsum("oc,bchw->bohw", Q, x0)
|
| 64 |
+
x0 = z - transformer(x, codes[r], prompt_embeds, prompt_mask).sample.float()
|
| 65 |
+
# x0 を release の VAE でデコード(BN の逆正規化 + 2x2 unpatchify)
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
- base の transformer は bf16 のまま、LoRA は**マージせずに** fp32 で足してください。差分が bf16 の丸め幅より小さく、bf16 の重みにマージすると効果がほぼ消えます。
|
| 69 |
+
- time path の 3 モジュールは fp32 のまま使います。
|
| 70 |
+
- CFG とネガティブプロンプトは使いません。プロンプトの形式(自然文・タグ列・JSON レイアウト、日本語の文字指定)は MOSS-Image と同じです。
|
| 71 |
+
|
| 72 |
+
## 結果
|
| 73 |
+
|
| 74 |
+
左から teacher(50 step)/ lodestones 8 step 版を 4 step で使ったもの / このアダプタ(4 step)。同じ seed、評価用 17 プロンプト(`eval/eval_prompts.jsonl`、学習には未使用)。
|
| 75 |
+
|
| 76 |
+

|
| 77 |
+

|
| 78 |
+

|
| 79 |
+
|
| 80 |
+
lodestones の 4 step と比べた所見(目視のみ。数値指標では評価していません):
|
| 81 |
+
|
| 82 |
+
- 良くなった点
|
| 83 |
+
- 背景や小物の描き込みが増え、構図に動きが出た(teacher の雰囲気に近づいた)
|
| 84 |
+
- 縦書きポスターで「夏」が二重になる崩れが直った
|
| 85 |
+
- 付箋の 3 行、看板、吹き出しの日本語は正確なまま
|
| 86 |
+
- 悪くなった点
|
| 87 |
+
- ライトノベル表紙に頼んでいない英字が増えた
|
| 88 |
+
- 2 コマ漫画(JSON レイアウト)の下のコマに 2 人目が出た
|
| 89 |
+
- 暖簾などの小さな文字の崩れが増えた
|
| 90 |
+
- 変わらない点
|
| 91 |
+
- 厚塗りの侍の絵に頼んでいない題字が入る(lodestones から引き継いだ癖。teacher は入れない)
|
| 92 |
+
- 白黒漫画の吹き出しが意味の通らない文字になる
|
| 93 |
+
|
| 94 |
+
結論として、細部は良くなったが一長一短です。
|
| 95 |
+
|
| 96 |
+
### 学習の経過(EMA、4 step、同じ seed)
|
| 97 |
+
|
| 98 |
+
| init(lodestones) | 300 it | 500 it(公開版) | 800 it |
|
| 99 |
+
|---|---|---|---|
|
| 100 |
+
|  |  |  |  |
|
| 101 |
+
|
| 102 |
+
- 300 it では、桜の女子高生の絵が顔の寄せ集めになる崩れが一度出ました。500 it では元に戻っています。
|
| 103 |
+
- 500 → 800 it ではプロンプトへの従い方(`1girl, solo` なのに 2 人)と文字が崩れていきました。841〜850 it で NaN になり、学習を止めました。teacher サンプルに非有限値はなく、原因は特定できていません。現在のコードは非有限の勾配で更新を飛ばします。
|
| 104 |
+
- **公開版は 500 it の EMA** です。
|
| 105 |
+
|
| 106 |
+
## 手法
|
| 107 |
+
|
| 108 |
+
### 生成器(data-space iteration、arXiv 2610.12102)
|
| 109 |
+
|
| 110 |
+
lodestones の形式そのままです。`x = z + Q·x0`, `v = net(x, code_r)`, `x0 ← z − v`。
|
| 111 |
+
|
| 112 |
+
- 学習対象は LoRA(rank 128)、time path(fp32)、Q の 3 つです。
|
| 113 |
+
- lodestones update 2600 から初期化し、step codes は先頭 4 つを使います。
|
| 114 |
+
- 反復番号 r は 0〜3 を順番に回します。r 回目までは勾配なしで進め、最後の 1 回だけ勾配を流します。
|
| 115 |
+
|
| 116 |
+
### 識別器と損失(DMAD、arXiv 2610.02188)
|
| 117 |
+
|
| 118 |
+
- **critic の構成:** 凍結した teacher(MOSS-Image-SFT の bf16)に、block 21〜41 の LoRA(rank 128)を付けます。block 41 の画像トークンにヘッドを付け、1 枚につき 1 つのロジットを出します。ヘッドは 4×4 stride-2 conv(3072→512)、GroupNorm、SiLU を 2 回重ね、空間平均を取ってから線形層に通します。
|
| 119 |
+
- **critic の損失:** `softplus(−d(teacher サンプル)) + softplus(d(生徒の出力))`。ノイズ量は σ = 5u / (1 + 4u)、u ~ U[0.02, 0.98] で、teacher と生徒の組で同じ σ を使います。
|
| 120 |
+
- **生成器の損失:** `−d(ノイズを足した生徒の x0)`。teacher の CFG 推論も fake score も、学習中は使いません。
|
| 121 |
+
- **teacher サンプル:** 3,199 枚。1 プロンプトにつき 1 枚で、50 step・CFG 3・負側 block 22 skip で作りました。解像度は約 1MP で、正方形・縦長・横長を混ぜています。学習時のプロンプトはこの 3,199 件から選びます。
|
| 122 |
+
- **本物の画像を使うヘッドは使っていません**(DMAD は 2 ヘッドですが、こちらは teacher ヘッドだけ)。
|
| 123 |
+
|
| 124 |
+
### 設定
|
| 125 |
+
|
| 126 |
+
| 項目 | 値 |
|
| 127 |
+
|---|---|
|
| 128 |
+
| バッチ | 16(8 GPU × 2、1 サンプルずつ順に処理) |
|
| 129 |
+
| 生成器 | AdamW lr 2e-5、betas (0, 0.99)、weight decay 0、EMA 0.998 |
|
| 130 |
+
| critic | AdamW lr 4e-5、betas (0, 0.99)、weight decay 0.01、生成器を更新しない 50 it のウォームアップ |
|
| 131 |
+
| 反復 | 500 it(生成器の更新 450 回)、1 it 約 5.7 秒 |
|
| 132 |
+
| 計算機 | RunPod 8×H100 SXM。teacher サンプル生成約 1.9 時間、学習 500 it 約 47 分 |
|
| 133 |
+
| 費用 | 試運転と比較実験を含めて計約 $126 |
|
| 134 |
+
|
| 135 |
+
### 学習プロンプト
|
| 136 |
+
|
| 137 |
+
24,000 件(再配布はしていません)から、teacher サンプルを作った 3,199 件を学習に使いました。
|
| 138 |
+
|
| 139 |
+
| 種類 | 出典(ライセンス) |
|
| 140 |
+
|---|---|
|
| 141 |
+
| アニメの自然文キャプション | [BootsofLagrangian/danbooru-multitier-captions-202606](https://huggingface.co/datasets/BootsofLagrangian/danbooru-multitier-captions-202606)(CC-BY-4.0、Giyeong Oh)、[CaptionEmporium/anime-caption-danbooru-2021-sfw-5m-hq](https://huggingface.co/datasets/CaptionEmporium/anime-caption-danbooru-2021-sfw-5m-hq)(CC-BY-SA-4.0) |
|
| 142 |
+
| タグ列 | 上記の Danbooru タグ、[FredZhang7/anime-prompts-180K](https://huggingface.co/datasets/FredZhang7/anime-prompts-180K)(CreativeML OpenRAIL-M)。絵師名は除去 |
|
| 143 |
+
| 一般 | [ProGamerGov/synthetic-dataset-1m-dalle3-high-quality-captions](https://huggingface.co/datasets/ProGamerGov/synthetic-dataset-1m-dalle3-high-quality-captions)(MIT)、[data-is-better-together/open-image-preferences-v1](https://huggingface.co/datasets/data-is-better-together/open-image-preferences-v1)(Apache-2.0)、[nateraw/parti-prompts](https://huggingface.co/datasets/nateraw/parti-prompts)(Apache-2.0) |
|
| 144 |
+
| 文字描画(日 60% / 英 25% / 中 15%)、JSON レイアウト、短文 | テンプレートから生成 |
|
| 145 |
+
|
| 146 |
+
## うまくいかなかったこと(DMDX)
|
| 147 |
+
|
| 148 |
+
最初は DMDX(arXiv 2507.18569)の ADM を data-space DMD に足す計画でした。ADM は、生成器の出力にノイズをかけた同じ x_τ から、teacher(CFG あり)と fake score の ODE を Δt = 1/64 だけ進め、その 2 つを識別器に見分けさせる方式です。
|
| 149 |
+
|
| 150 |
+
- **結果:** 識別器は 130 回更新しても正解率 0.500〜0.506 のままで、学習しませんでした(`logs/probe_adm_discriminator.jsonl`)。2 つの入力の差は Δt·(v_real − v_fake) だけで、1 枚ずつの判定ではほぼ見分けられません。
|
| 151 |
+
- **比較:** 同じヘッドで本物側を teacher サンプルにすると、60 回で 0.56 → 0.68 まで上がりました(`logs/probe_teacher_discriminator.jsonl`)。
|
| 152 |
+
- この結果と、その後に出た DMAD を受けて、fake score も teacher の推論もいらない DMAD に切り替えました。
|
| 153 |
+
|
| 154 |
+
## 制限
|
| 155 |
+
|
| 156 |
+
- 評価は目視だけで、プロンプトは 17 件です。FID などの数値指標は取っていません。
|
| 157 |
+
- キャラクター LoRA など、他の LoRA と重ねたときの挙動は試していません。
|
| 158 |
+
- 学習プロンプトは 3,199 件と少なく、teacher サンプルは 1 プロンプトにつき 1 枚です。
|
| 159 |
+
|
| 160 |
+
## ライセンスとクレジット
|
| 161 |
+
|
| 162 |
+
- 重みとコード: Apache-2.0
|
| 163 |
+
- 元のモデル: [OpenMOSS-Team/MOSS-Image-SFT](https://huggingface.co/OpenMOSS-Team/MOSS-Image-SFT)(Apache-2.0)、初期値: [lodestones/MOSS-Image-SFT-8-steps-dmd](https://huggingface.co/lodestones/MOSS-Image-SFT-8-steps-dmd)(Apache-2.0)
|
| 164 |
+
- 参考にした論文:
|
| 165 |
+
- Few-Step Generation via Data-Space Iteration(arXiv 2610.12102)
|
| 166 |
+
- DMAD: Distribution Matching as Adversarial Distillation(arXiv 2610.02188、[コード](https://github.com/Yzmblog/DMAD))
|
| 167 |
+
- Adversarial Distribution Matching / DMDX(arXiv 2507.18569)
|
| 168 |
+
- 前作: [Anima の DMDX・DMD2・PCM 蒸留の記録](https://note.com/darask/n/neef98f000087)
|
code/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# rapid-moss training code
|
| 2 |
+
|
| 3 |
+
Distillation of MOSS-Image-SFT into an R-step data-space generator. Python 3.10+, torch >= 2.9, diffusers >= 0.38,
|
| 4 |
+
transformers >= 5.3. The release `pipeline_moss_image.py` (shipped in the MOSS-Image-SFT repo) is imported for the
|
| 5 |
+
transformer class only; the forward pass is reimplemented in `rapid_moss/model.py` (fp32 residual + modulation,
|
| 6 |
+
bf16 matmuls, unmerged LoRA sets, per-block gradient checkpointing, feature taps).
|
| 7 |
+
|
| 8 |
+
| file | role |
|
| 9 |
+
|---|---|
|
| 10 |
+
| `rapid_moss/model.py` | MOSS DiT forward shared by teacher / generator / fake score / critic (one frozen bf16 base, per-path LoRA and time path); release sampler (`sample_teacher`) |
|
| 11 |
+
| `rapid_moss/nets.py` | `Generator` (data-space iteration, lodestones format I/O), `FakeScore`, DMDX `Discriminator`, DMAD `Critic` |
|
| 12 |
+
| `rapid_moss/textenc.py` | prompt embedding cache (release Qwen3.5 text encoder, same chat template as the pipeline) |
|
| 13 |
+
| `rapid_moss/teachergen.py` | teacher samples (50 steps, CFG 3, negative-branch block-22 skip) for the critic's real side |
|
| 14 |
+
| `rapid_moss/train.py` | training loop: `method=dmad` (used for the release) or `method=dmd` (data-space DMD + DMDX discriminator) |
|
| 15 |
+
| `rapid_moss/sample.py` | side-by-side evaluation (teacher vs lodestones-format adapters) |
|
| 16 |
+
| `tests/test_equiv.py` | CPU fp32 check: forward, skip-22 and the lodestones generator path match the release transformer exactly |
|
| 17 |
+
| `tests/test_dmad.py` | CPU check of the critic wiring (generator phase / critic phase gradients) |
|
| 18 |
+
| `scripts/` | RunPod GraphQL client, pod setup and run scripts, balance watchdog |
|
| 19 |
+
| `configs/dmad.json` | the run that produced the released adapter (best checkpoint = EMA export at iteration 500) |
|
| 20 |
+
|
| 21 |
+
```
|
| 22 |
+
torchrun --nproc-per-node 8 -m rapid_moss.textenc --model MOSS-Image-SFT --prompts train.jsonl eval.jsonl --out cache
|
| 23 |
+
torchrun --nproc-per-node 8 -m rapid_moss.teachergen --model MOSS-Image-SFT --cache cache --prompts train.jsonl --out teacher --count 2000
|
| 24 |
+
torchrun --nproc-per-node 8 -m rapid_moss.train --config configs/dmad.json --set teacher_dir=teacher
|
| 25 |
+
python -m rapid_moss.sample --model MOSS-Image-SFT --cache cache --prompts eval.jsonl --out eval \
|
| 26 |
+
--method teacher:50 --method dmd:LODESTONES_DIR:4 --method dmd:runs/dmad/export/000500:4
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
The prompt set (24,000 prompts: anime captions and tags, general captions, Japanese / English / Chinese text rendering,
|
| 30 |
+
MOSS JSON layouts, short prompts) is not redistributed; see the model card for its sources.
|
code/configs/dmad.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"method": "dmad",
|
| 3 |
+
"out_dir": "/workspace/runs/dmad",
|
| 4 |
+
"teacher_dir": ["/workspace/teacher", "/workspace/teacher2"],
|
| 5 |
+
"iterations": 2500,
|
| 6 |
+
"micro": 2,
|
| 7 |
+
"critic_warmup": 50,
|
| 8 |
+
"lr_gen": 2e-5, "lr_time": 2e-5, "lr_q": 2e-5,
|
| 9 |
+
"lr_critic": 4e-5,
|
| 10 |
+
"ema": 0.998,
|
| 11 |
+
"log_every": 10,
|
| 12 |
+
"sample_every": 100,
|
| 13 |
+
"save_every": 200,
|
| 14 |
+
"export_every": 500,
|
| 15 |
+
"eval_count": 8
|
| 16 |
+
}
|
code/configs/main.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"out_dir": "/workspace/runs/main",
|
| 3 |
+
"iterations": 2000,
|
| 4 |
+
"disc_real": "teacher",
|
| 5 |
+
"teacher_dir": "/workspace/teacher",
|
| 6 |
+
"p_gan": 0.5,
|
| 7 |
+
"micro": 2,
|
| 8 |
+
"fake_per_gen": 2,
|
| 9 |
+
"fake_warmup": 150,
|
| 10 |
+
"adv_start": 50,
|
| 11 |
+
"adv_warmup": 200,
|
| 12 |
+
"lr_gen": 1.5e-5, "lr_time": 1.5e-5, "lr_q": 1.5e-5,
|
| 13 |
+
"ema": 0.998,
|
| 14 |
+
"log_every": 10,
|
| 15 |
+
"sample_every": 100,
|
| 16 |
+
"save_every": 200,
|
| 17 |
+
"export_every": 400,
|
| 18 |
+
"eval_count": 8
|
| 19 |
+
}
|
code/configs/smoke.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"out_dir": "/workspace/runs/smoke",
|
| 3 |
+
"iterations": 24,
|
| 4 |
+
"micro": 1,
|
| 5 |
+
"fake_per_gen": 2,
|
| 6 |
+
"fake_warmup": 4,
|
| 7 |
+
"adv_start": 2,
|
| 8 |
+
"adv_warmup": 4,
|
| 9 |
+
"log_every": 2,
|
| 10 |
+
"sample_every": 12,
|
| 11 |
+
"save_every": 24,
|
| 12 |
+
"export_every": 24,
|
| 13 |
+
"eval_count": 4
|
| 14 |
+
}
|
code/rapid_moss/__init__.py
ADDED
|
File without changes
|
code/rapid_moss/model.py
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""MOSS-Image DiT for distillation.
|
| 2 |
+
|
| 3 |
+
One frozen bf16 base (the release MOSSImageTransformer) is shared by the teacher, the
|
| 4 |
+
data-space generator, the fake score and the discriminator backbone; each path only
|
| 5 |
+
differs by its LoRA, its time path and optional extras. The residual stream and the
|
| 6 |
+
modulation run in fp32 (the release trains fp32-master + autocast), matmuls in bf16.
|
| 7 |
+
"""
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
import importlib.util
|
| 11 |
+
import math
|
| 12 |
+
from dataclasses import dataclass
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
import torch
|
| 16 |
+
from torch import nn
|
| 17 |
+
from torch.nn import functional as F
|
| 18 |
+
from torch.utils.checkpoint import checkpoint
|
| 19 |
+
|
| 20 |
+
BF16 = torch.bfloat16
|
| 21 |
+
PROJ = ('q', 'k', 'v', 'o', 'ffn_up_gate', 'ffn_down')
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def load_release_module(model_dir):
|
| 25 |
+
"""Import the release pipeline_moss_image.py (read and reviewed; no side effects on import)."""
|
| 26 |
+
path = Path(model_dir) / 'pipeline_moss_image.py'
|
| 27 |
+
spec = importlib.util.spec_from_file_location('pipeline_moss_image', path)
|
| 28 |
+
module = importlib.util.module_from_spec(spec)
|
| 29 |
+
spec.loader.exec_module(module)
|
| 30 |
+
return module
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def load_base(model_dir, device):
|
| 34 |
+
release = load_release_module(model_dir)
|
| 35 |
+
tr = release.MOSSImageTransformer.from_pretrained(Path(model_dir) / 'transformer', torch_dtype=BF16,
|
| 36 |
+
local_files_only=True)
|
| 37 |
+
return Moss(tr.to(device), release)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def rms(x, weight, eps=1e-6):
|
| 41 |
+
y = x.float() * torch.rsqrt(x.float().square().mean(-1, keepdim=True) + eps)
|
| 42 |
+
return y.to(x.dtype) * weight
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def situ(hidden, gate):
|
| 46 |
+
return (4.0 * torch.tanh(gate / 4.0) * torch.sigmoid(gate)) * (25.0 * torch.tanh(hidden / 25.0))
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def proj_dims(dim, ffn_dim):
|
| 50 |
+
return {'q': (dim, dim), 'k': (dim, dim), 'v': (dim, dim), 'o': (dim, dim),
|
| 51 |
+
'ffn_up_gate': (dim, 2 * ffn_dim), 'ffn_down': (ffn_dim, dim)}
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class LoRA(nn.Module):
|
| 55 |
+
"""Stacked LoRA for the projections of blocks [start, layers): A [n, r, in], B [n, out, r]; y += (alpha/r) B A x."""
|
| 56 |
+
|
| 57 |
+
def __init__(self, dims, layers, rank, alpha, start=0):
|
| 58 |
+
super().__init__()
|
| 59 |
+
self.rank, self.alpha, self.scale, self.start = rank, alpha, alpha / rank, start
|
| 60 |
+
layers -= start
|
| 61 |
+
self.A = nn.ParameterDict()
|
| 62 |
+
self.B = nn.ParameterDict()
|
| 63 |
+
for name, (fan_in, fan_out) in dims.items():
|
| 64 |
+
bound = 1 / math.sqrt(fan_in)
|
| 65 |
+
self.A[name] = nn.Parameter(torch.empty(layers, rank, fan_in).uniform_(-bound, bound))
|
| 66 |
+
self.B[name] = nn.Parameter(torch.zeros(layers, fan_out, rank))
|
| 67 |
+
self._cache = None
|
| 68 |
+
|
| 69 |
+
def delta(self, x, layer, name):
|
| 70 |
+
layer -= self.start
|
| 71 |
+
if self._cache is not None and not torch.is_grad_enabled():
|
| 72 |
+
a, b = self._cache[name]
|
| 73 |
+
a, b = a[layer], b[layer]
|
| 74 |
+
else:
|
| 75 |
+
a, b = self.A[name][layer].to(x.dtype), self.B[name][layer].to(x.dtype)
|
| 76 |
+
return F.linear(F.linear(x, a), b) * self.scale
|
| 77 |
+
|
| 78 |
+
def freeze_cache(self):
|
| 79 |
+
"""bf16 copies used by no-grad forwards only; drop_cache() before the next optimizer step."""
|
| 80 |
+
with torch.no_grad():
|
| 81 |
+
self._cache = {n: (self.A[n].to(BF16), self.B[n].to(BF16)) for n in self.A}
|
| 82 |
+
|
| 83 |
+
def drop_cache(self):
|
| 84 |
+
self._cache = None
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class TimePath(nn.Module):
|
| 88 |
+
"""time_embedding MLP + both modulation biases (fp32); modulation weights stay the base's."""
|
| 89 |
+
|
| 90 |
+
NAMES = ('time_embedding.0.weight', 'time_embedding.0.bias', 'time_embedding.2.weight',
|
| 91 |
+
'time_embedding.2.bias', 'shared_block_modulation.bias', 'video_head_modulation.bias')
|
| 92 |
+
|
| 93 |
+
def __init__(self, tensors, trainable):
|
| 94 |
+
super().__init__()
|
| 95 |
+
self.p = nn.ParameterDict({k.replace('.', '_'): nn.Parameter(tensors[k].detach().float().clone(),
|
| 96 |
+
requires_grad=trainable)
|
| 97 |
+
for k in self.NAMES})
|
| 98 |
+
|
| 99 |
+
def __getitem__(self, name):
|
| 100 |
+
return self.p[name.replace('.', '_')]
|
| 101 |
+
|
| 102 |
+
def state(self):
|
| 103 |
+
return {k: self[k].detach() for k in self.NAMES}
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
@dataclass
|
| 107 |
+
class Context:
|
| 108 |
+
tokens: torch.Tensor # [1, L, D] text_embedder output (bf16)
|
| 109 |
+
length: int
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class Moss(nn.Module):
|
| 113 |
+
def __init__(self, tr, release):
|
| 114 |
+
super().__init__()
|
| 115 |
+
self.tr = tr.requires_grad_(False).eval()
|
| 116 |
+
self.release = release
|
| 117 |
+
cfg = tr.config
|
| 118 |
+
self.dim, self.heads, self.depth = cfg.dim, cfg.num_heads, cfg.num_layers
|
| 119 |
+
self.dims = proj_dims(cfg.dim, cfg.ffn_dim)
|
| 120 |
+
sd = dict(tr.named_parameters())
|
| 121 |
+
self.base_time = TimePath(sd, trainable=False)
|
| 122 |
+
self.register_buffer('mod_w', tr.shared_block_modulation.weight.detach().float(), persistent=False)
|
| 123 |
+
self.register_buffer('head_w', tr.video_head_modulation.weight.detach().float(), persistent=False)
|
| 124 |
+
self._rope = {}
|
| 125 |
+
|
| 126 |
+
# ---- conditioning ----
|
| 127 |
+
def rope(self, h, w, length):
|
| 128 |
+
key = (h, w, length)
|
| 129 |
+
if key not in self._rope:
|
| 130 |
+
if len(self._rope) > 64:
|
| 131 |
+
self._rope.clear()
|
| 132 |
+
with torch.no_grad():
|
| 133 |
+
self._rope[key] = self.tr.rope(h, w, length, self.mod_w.device).to(BF16)
|
| 134 |
+
return self._rope[key]
|
| 135 |
+
|
| 136 |
+
@torch.no_grad()
|
| 137 |
+
def context(self, emb):
|
| 138 |
+
"""emb [L, text_dim] text-encoder hidden states -> Context (text refinement is prompt-only)."""
|
| 139 |
+
length = emb.shape[0]
|
| 140 |
+
rope = self.tr.rope(1, 1, length, self.mod_w.device).to(BF16)[:, 1:]
|
| 141 |
+
tokens = self.tr.text_embedder(emb[None].to(device=self.mod_w.device, dtype=BF16), rope)
|
| 142 |
+
return Context(tokens, length)
|
| 143 |
+
|
| 144 |
+
def time_mod(self, t, tp, extra=None):
|
| 145 |
+
half = self.tr.config.freq_dim // 2
|
| 146 |
+
t = torch.as_tensor(t, device=self.mod_w.device, dtype=torch.float32).reshape(-1)
|
| 147 |
+
freq = 10000 ** (-torch.arange(half, device=t.device, dtype=torch.float64) / half)
|
| 148 |
+
phase = t.double()[:, None] * freq
|
| 149 |
+
emb = torch.cat((phase.cos(), phase.sin()), -1).float()
|
| 150 |
+
time = F.linear(emb, tp['time_embedding.0.weight'], tp['time_embedding.0.bias'])
|
| 151 |
+
time = F.linear(F.silu(time), tp['time_embedding.2.weight'], tp['time_embedding.2.bias'])
|
| 152 |
+
if extra is not None:
|
| 153 |
+
time = time + extra
|
| 154 |
+
mod = F.linear(time, self.mod_w, tp['shared_block_modulation.bias']).view(-1, 6, self.dim)
|
| 155 |
+
head = F.linear(time, self.head_w, tp['video_head_modulation.bias']).view(-1, 2, self.dim)
|
| 156 |
+
return mod, head
|
| 157 |
+
|
| 158 |
+
# ---- blocks ----
|
| 159 |
+
def lin(self, y, i, name, lora):
|
| 160 |
+
out = F.linear(y, self.tr.layers[i].proj[name].weight)
|
| 161 |
+
if lora is not None and i >= lora.start:
|
| 162 |
+
out = out + lora.delta(y, i, name)
|
| 163 |
+
return out
|
| 164 |
+
|
| 165 |
+
def block(self, i, x, rope, mod, lora):
|
| 166 |
+
layer = self.tr.layers[i]
|
| 167 |
+
heads = self.heads
|
| 168 |
+
shift_a, scale_a, gate_a, shift_f, scale_f, gate_f = mod.unbind(1)
|
| 169 |
+
y = (rms(x, layer.norm1.weight) * (1 + scale_a[:, None]) + shift_a[:, None]).to(BF16)
|
| 170 |
+
q = rms(self.lin(y, i, 'q', lora).unflatten(-1, (heads, -1)), layer.q_norm.weight).flatten(2)
|
| 171 |
+
k = rms(self.lin(y, i, 'k', lora).unflatten(-1, (heads, -1)), layer.k_norm.weight).flatten(2)
|
| 172 |
+
a = self.release._attention(q, k, self.lin(y, i, 'v', lora), rope, heads)
|
| 173 |
+
x = x + self.lin(a, i, 'o', lora).float() * gate_a[:, None]
|
| 174 |
+
y = (rms(x, layer.norm2.weight) * (1 + scale_f[:, None]) + shift_f[:, None]).to(BF16)
|
| 175 |
+
hidden, gate = self.lin(y, i, 'ffn_up_gate', lora).chunk(2, -1)
|
| 176 |
+
return x + self.lin(situ(hidden, gate), i, 'ffn_down', lora).float() * gate_f[:, None]
|
| 177 |
+
|
| 178 |
+
def forward(self, latent, t, ctx, *, lora=None, tp=None, time_extra=None, skip=(), taps=None, ckpt=False):
|
| 179 |
+
"""latent [1, C, h, w] fp32, t on the 0..1000 scale. Returns velocity [1, C, h, w] fp32,
|
| 180 |
+
or {block: image-token features [1, h*w, D]} when taps is given (stops after the last tap)."""
|
| 181 |
+
_, _, h, w = latent.shape
|
| 182 |
+
hw = h * w
|
| 183 |
+
mod, head = self.time_mod(t, tp if tp is not None else self.base_time, time_extra)
|
| 184 |
+
rope = self.rope(h, w, ctx.length)
|
| 185 |
+
video = self.tr.video_embedder(latent.flatten(2).transpose(1, 2).to(BF16))
|
| 186 |
+
x = torch.cat((video, ctx.tokens), 1).float()
|
| 187 |
+
last = max(taps) if taps else self.depth - 1
|
| 188 |
+
use_ckpt = ckpt and torch.is_grad_enabled()
|
| 189 |
+
feats = {}
|
| 190 |
+
for i in range(last + 1):
|
| 191 |
+
if i not in skip:
|
| 192 |
+
if use_ckpt:
|
| 193 |
+
x = checkpoint(self.block, i, x, rope, mod, lora, use_reentrant=False)
|
| 194 |
+
else:
|
| 195 |
+
x = self.block(i, x, rope, mod, lora)
|
| 196 |
+
if taps and i in taps:
|
| 197 |
+
feats[i] = x[:, :hw]
|
| 198 |
+
if taps:
|
| 199 |
+
return feats
|
| 200 |
+
x = rms(x[:, :hw], self.tr.final_norm_video.weight)
|
| 201 |
+
x = x * (1 + head[:, 1, None]) + head[:, 0, None]
|
| 202 |
+
x = F.linear(x.to(BF16), self.tr.final_linear_video.weight).float()
|
| 203 |
+
return x.transpose(1, 2).reshape(1, -1, h, w)
|
| 204 |
+
|
| 205 |
+
@torch.no_grad()
|
| 206 |
+
def teacher(self, latent, t, pos, neg, cfg, skip_neg=(22,)):
|
| 207 |
+
"""Release guidance: CFG with block 22 skipped in the negative branch only."""
|
| 208 |
+
vp = self(latent, t, pos)
|
| 209 |
+
vn = self(latent, t, neg, skip=skip_neg)
|
| 210 |
+
return vn + cfg * (vp - vn)
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def release_sigmas(steps, shift=5.0, total=1000, training_shift=1.0):
|
| 214 |
+
"""MOSSImageScheduler.set_timesteps sigmas (shifted grid snapped to the training grid)."""
|
| 215 |
+
def grid(count, s):
|
| 216 |
+
lower = s / (total + s - 1)
|
| 217 |
+
values = torch.linspace(1, lower, count)
|
| 218 |
+
return s * values / (1 + (s - 1) * values)
|
| 219 |
+
sigmas = grid(steps, shift)
|
| 220 |
+
training = grid(total, training_shift).flip(0)
|
| 221 |
+
upper = torch.searchsorted(training, sigmas).clamp(max=total - 1)
|
| 222 |
+
lower = (upper - 1).clamp(min=0)
|
| 223 |
+
nearest = torch.where((sigmas - training[lower]).abs() <= (training[upper] - sigmas).abs(), lower, upper)
|
| 224 |
+
return torch.unique_consecutive(training[nearest]).tolist() + [0.0]
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
@torch.no_grad()
|
| 228 |
+
def sample_teacher(model, noise, pos, neg, steps=50, cfg=3.0, shift=5.0):
|
| 229 |
+
x = noise.float()
|
| 230 |
+
sigmas = release_sigmas(steps, shift)
|
| 231 |
+
for s, s_next in zip(sigmas[:-1], sigmas[1:]):
|
| 232 |
+
v = model.teacher(x, s * 1000, pos, neg, cfg)
|
| 233 |
+
x = x + (s_next - s) * v
|
| 234 |
+
return x
|
code/rapid_moss/nets.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Trainable parts: data-space generator, fake score, DMDX discriminator heads; lodestones-format I/O."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
from safetensors.torch import load_file, save_file
|
| 8 |
+
from torch import nn
|
| 9 |
+
from torch.nn import functional as F
|
| 10 |
+
|
| 11 |
+
from .model import PROJ, LoRA, TimePath
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class Generator(nn.Module):
|
| 15 |
+
"""Data-space iteration (arXiv 2610.12102) in the lodestones MOSS form:
|
| 16 |
+
x = z + Q x0 (channel mix), v = net(x, code_r), x0' = z - v, x0 starts at zero."""
|
| 17 |
+
|
| 18 |
+
def __init__(self, model, rank, alpha, steps):
|
| 19 |
+
super().__init__()
|
| 20 |
+
self.lora = LoRA(model.dims, model.depth, rank, alpha)
|
| 21 |
+
self.time = TimePath(model.base_time.state(), trainable=True)
|
| 22 |
+
channels = model.tr.config.latent_channels
|
| 23 |
+
self.Q = nn.Parameter(torch.zeros(channels, channels))
|
| 24 |
+
self.register_buffer('codes', torch.full((steps,), 1000.0))
|
| 25 |
+
self.steps = steps
|
| 26 |
+
|
| 27 |
+
def step(self, model, z, x0, r, ctx, ckpt=False):
|
| 28 |
+
x = z + torch.einsum('oc,bchw->bohw', self.Q, x0)
|
| 29 |
+
return z - model(x, self.codes[r], ctx, lora=self.lora, tp=self.time, ckpt=ckpt)
|
| 30 |
+
|
| 31 |
+
@torch.no_grad()
|
| 32 |
+
def rollout(self, model, z, ctx, n):
|
| 33 |
+
"""n generator calls from x0 = 0 (no grad); returns x0 after n steps."""
|
| 34 |
+
x0 = torch.zeros_like(z)
|
| 35 |
+
for r in range(n):
|
| 36 |
+
x0 = self.step(model, z, x0, r, ctx)
|
| 37 |
+
return x0
|
| 38 |
+
|
| 39 |
+
@torch.no_grad()
|
| 40 |
+
def load_lodestones(self, path):
|
| 41 |
+
path = Path(path)
|
| 42 |
+
ds = load_file(path / 'dataspace.safetensors')
|
| 43 |
+
self.Q.copy_(ds['latent_mix.Q'])
|
| 44 |
+
self.codes.copy_(ds['step_codes'][:self.steps])
|
| 45 |
+
te = load_file(path / 'time_embedding.safetensors')
|
| 46 |
+
for k in TimePath.NAMES:
|
| 47 |
+
self.time[k].copy_(te[k])
|
| 48 |
+
lora = load_file(path / 'lora.safetensors')
|
| 49 |
+
for i in range(self.lora.A[PROJ[0]].shape[0]):
|
| 50 |
+
for name in PROJ:
|
| 51 |
+
p = f'diffusion_model.layers.{i}.proj.{name}'
|
| 52 |
+
down, up = lora[p + '.lora_down.weight'], lora[p + '.lora_up.weight']
|
| 53 |
+
alpha = float(lora[p + '.alpha'])
|
| 54 |
+
if down.shape[0] != self.lora.rank:
|
| 55 |
+
raise ValueError(f'rank mismatch: file {down.shape[0]} vs {self.lora.rank}')
|
| 56 |
+
# fold the file's alpha/rank into B so our own scale applies unchanged
|
| 57 |
+
self.lora.A[name][i].copy_(down)
|
| 58 |
+
self.lora.B[name][i].copy_(up * (alpha / down.shape[0]) / self.lora.scale)
|
| 59 |
+
|
| 60 |
+
@torch.no_grad()
|
| 61 |
+
def export(self, out_dir, meta=None):
|
| 62 |
+
"""Write lodestones-compatible files (kohya LoRA, fp32 time path, Q + step codes)."""
|
| 63 |
+
out = Path(out_dir)
|
| 64 |
+
out.mkdir(parents=True, exist_ok=True)
|
| 65 |
+
rank = self.lora.rank
|
| 66 |
+
lora = {}
|
| 67 |
+
for i in range(self.lora.A[PROJ[0]].shape[0]):
|
| 68 |
+
for name in PROJ:
|
| 69 |
+
p = f'diffusion_model.layers.{i}.proj.{name}'
|
| 70 |
+
lora[p + '.lora_down.weight'] = self.lora.A[name][i].float().contiguous()
|
| 71 |
+
lora[p + '.lora_up.weight'] = (self.lora.B[name][i].float() * self.lora.scale).contiguous()
|
| 72 |
+
lora[p + '.alpha'] = torch.tensor(float(rank))
|
| 73 |
+
info = {'rank': str(rank), 'alpha': f'{float(rank)}', 'steps': str(self.steps), **(meta or {})}
|
| 74 |
+
save_file(lora, out / 'lora.safetensors', metadata=info)
|
| 75 |
+
save_file({k: v.float().contiguous() for k, v in self.time.state().items()}, out / 'time_embedding.safetensors')
|
| 76 |
+
save_file({'latent_mix.Q': self.Q.float().contiguous(), 'step_codes': self.codes.float().contiguous()},
|
| 77 |
+
out / 'dataspace.safetensors', metadata=info)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
class FakeScore(nn.Module):
|
| 81 |
+
"""Generator-distribution velocity: base + LoRA, conditioned on the refinement index r."""
|
| 82 |
+
|
| 83 |
+
def __init__(self, model, rank, alpha, steps):
|
| 84 |
+
super().__init__()
|
| 85 |
+
self.lora = LoRA(model.dims, model.depth, rank, alpha)
|
| 86 |
+
self.r_emb = nn.Parameter(torch.zeros(steps, model.dim))
|
| 87 |
+
|
| 88 |
+
def __call__(self, model, x, t, ctx, r, ckpt=False):
|
| 89 |
+
return model(x, t, ctx, lora=self.lora, time_extra=self.r_emb[r][None], ckpt=ckpt)
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
class Head(nn.Module):
|
| 93 |
+
"""DMDX 2D head: 4x4 stride-2 conv, GroupNorm(32), SiLU, then 1x1 to patch logits."""
|
| 94 |
+
|
| 95 |
+
def __init__(self, dim, hidden):
|
| 96 |
+
super().__init__()
|
| 97 |
+
self.conv = nn.Conv2d(dim, hidden, 4, 2, 1)
|
| 98 |
+
self.norm = nn.GroupNorm(32, hidden)
|
| 99 |
+
self.out = nn.Conv2d(hidden, 1, 1)
|
| 100 |
+
|
| 101 |
+
def forward(self, f):
|
| 102 |
+
return self.out(F.silu(self.norm(self.conv(f))))
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class Discriminator(nn.Module):
|
| 106 |
+
"""Trainable heads on frozen-teacher block features (backbone = base, no LoRA)."""
|
| 107 |
+
|
| 108 |
+
def __init__(self, dim, taps, hidden):
|
| 109 |
+
super().__init__()
|
| 110 |
+
self.taps = tuple(sorted(taps))
|
| 111 |
+
self.heads = nn.ModuleList([Head(dim, hidden) for _ in self.taps])
|
| 112 |
+
|
| 113 |
+
def forward(self, feats, h, w):
|
| 114 |
+
logits = []
|
| 115 |
+
for i, head in zip(self.taps, self.heads):
|
| 116 |
+
f = feats[i].float()
|
| 117 |
+
f = f * torch.rsqrt(f.square().mean(-1, keepdim=True) + 1e-6)
|
| 118 |
+
logits.append(head(f.transpose(1, 2).reshape(1, -1, h, w)).flatten(1))
|
| 119 |
+
return torch.cat(logits, 1)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
class Critic(nn.Module):
|
| 123 |
+
"""DMAD critic (arXiv 2610.02188), teacher head only: base + LoRA on blocks [start:], a conv head on the
|
| 124 |
+
last block's image tokens giving one logit per sample (teacher sample vs generator sample)."""
|
| 125 |
+
|
| 126 |
+
def __init__(self, model, rank, alpha, start, hidden):
|
| 127 |
+
super().__init__()
|
| 128 |
+
self.lora = LoRA(model.dims, model.depth, rank, alpha, start=start)
|
| 129 |
+
self.last = model.depth - 1
|
| 130 |
+
self.head = nn.Sequential(nn.Conv2d(model.dim, hidden, 4, 2, 1), nn.GroupNorm(32, hidden), nn.SiLU(),
|
| 131 |
+
nn.Conv2d(hidden, hidden, 4, 2, 1), nn.GroupNorm(32, hidden), nn.SiLU())
|
| 132 |
+
self.out = nn.Linear(hidden, 1)
|
| 133 |
+
|
| 134 |
+
def forward(self, model, x, t, ctx, ckpt=False):
|
| 135 |
+
_, _, h, w = x.shape
|
| 136 |
+
f = model(x, t, ctx, lora=self.lora, taps=(self.last,), ckpt=ckpt)[self.last].float()
|
| 137 |
+
f = f * torch.rsqrt(f.square().mean(-1, keepdim=True) + 1e-6)
|
| 138 |
+
f = self.head(f.transpose(1, 2).reshape(1, -1, h, w))
|
| 139 |
+
return self.out(f.mean((2, 3)))[:, 0]
|
code/rapid_moss/sample.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Side-by-side evaluation: release teacher vs data-space generators (lodestones-format dirs).
|
| 2 |
+
|
| 3 |
+
python -m rapid_moss.sample --model DIR --cache CACHE --prompts eval.jsonl --out OUT \
|
| 4 |
+
--method teacher:50 --method dmd:/path/lodestones:8 --method dmd:/path/lodestones:4
|
| 5 |
+
"""
|
| 6 |
+
from __future__ import annotations
|
| 7 |
+
|
| 8 |
+
import argparse
|
| 9 |
+
import json
|
| 10 |
+
import time
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
|
| 13 |
+
import torch
|
| 14 |
+
from safetensors import safe_open
|
| 15 |
+
|
| 16 |
+
from .model import load_base, sample_teacher
|
| 17 |
+
from .nets import Generator
|
| 18 |
+
from .textenc import Cache, read_prompts
|
| 19 |
+
from .train import decode
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def load_generator(model, path, steps, device):
|
| 23 |
+
with safe_open(Path(path) / 'lora.safetensors', 'pt') as f:
|
| 24 |
+
key = next(k for k in f.keys() if k.endswith('.lora_down.weight'))
|
| 25 |
+
rank = f.get_slice(key).get_shape()[0]
|
| 26 |
+
gen = Generator(model, rank, rank, steps).to(device).requires_grad_(False)
|
| 27 |
+
gen.load_lodestones(path)
|
| 28 |
+
gen.lora.freeze_cache()
|
| 29 |
+
return gen
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def label_grid(columns, labels, ids, path, cell=512):
|
| 33 |
+
from PIL import Image, ImageDraw
|
| 34 |
+
pad = 28
|
| 35 |
+
sheet = Image.new('RGB', (len(columns) * cell, len(ids) * (cell + pad)), 'white')
|
| 36 |
+
draw = ImageDraw.Draw(sheet)
|
| 37 |
+
for c, (images, label) in enumerate(zip(columns, labels)):
|
| 38 |
+
for r, im in enumerate(images):
|
| 39 |
+
im = Image.fromarray(im)
|
| 40 |
+
im.thumbnail((cell, cell))
|
| 41 |
+
y = r * (cell + pad)
|
| 42 |
+
draw.text((c * cell + 6, y + 6), f'{label} | {ids[r]}', fill='black')
|
| 43 |
+
sheet.paste(im, (c * cell + (cell - im.width) // 2, y + pad + (cell - im.height) // 2))
|
| 44 |
+
sheet.save(path, quality=88)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
@torch.no_grad()
|
| 48 |
+
def main():
|
| 49 |
+
ap = argparse.ArgumentParser()
|
| 50 |
+
ap.add_argument('--model', required=True)
|
| 51 |
+
ap.add_argument('--cache', required=True)
|
| 52 |
+
ap.add_argument('--prompts', required=True)
|
| 53 |
+
ap.add_argument('--out', required=True)
|
| 54 |
+
ap.add_argument('--method', action='append', required=True)
|
| 55 |
+
ap.add_argument('--seed', type=int, default=1234)
|
| 56 |
+
ap.add_argument('--limit', type=int, default=0)
|
| 57 |
+
args = ap.parse_args()
|
| 58 |
+
dev = torch.device('cuda')
|
| 59 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 60 |
+
out = Path(args.out)
|
| 61 |
+
out.mkdir(parents=True, exist_ok=True)
|
| 62 |
+
model = load_base(args.model, dev)
|
| 63 |
+
from diffusers import AutoencoderKLFlux2
|
| 64 |
+
vae = AutoencoderKLFlux2.from_pretrained(Path(args.model) / 'vae', torch_dtype=torch.float32,
|
| 65 |
+
local_files_only=True).to(dev).eval()
|
| 66 |
+
cache = Cache(args.cache)
|
| 67 |
+
rows = read_prompts([args.prompts])
|
| 68 |
+
rows = rows[:args.limit] if args.limit else rows
|
| 69 |
+
neg = model.context(cache.get('').to(dev))
|
| 70 |
+
columns, labels, timings = [], [], {}
|
| 71 |
+
for spec in args.method:
|
| 72 |
+
kind, *rest = spec.split(':')
|
| 73 |
+
if kind == 'teacher':
|
| 74 |
+
steps = int(rest[0]) if rest else 50
|
| 75 |
+
cfg = float(rest[1]) if len(rest) > 1 else 3.0
|
| 76 |
+
tag, gen = f'teacher{steps}-cfg{cfg:g}', None
|
| 77 |
+
elif kind == 'dmd':
|
| 78 |
+
path, steps = rest[0], int(rest[1])
|
| 79 |
+
tag = f'{Path(path).name}-{steps}step'
|
| 80 |
+
gen = load_generator(model, path, steps, dev)
|
| 81 |
+
else:
|
| 82 |
+
raise SystemExit(f'unknown method {spec}')
|
| 83 |
+
(out / tag).mkdir(exist_ok=True)
|
| 84 |
+
images, secs = [], []
|
| 85 |
+
for row in rows:
|
| 86 |
+
ctx = model.context(cache.get(row['id']).to(dev))
|
| 87 |
+
g = torch.Generator('cpu').manual_seed(args.seed)
|
| 88 |
+
z = torch.randn(1, model.tr.config.latent_channels, row['h'] // 16, row['w'] // 16, generator=g).to(dev)
|
| 89 |
+
torch.cuda.synchronize()
|
| 90 |
+
t0 = time.time()
|
| 91 |
+
x0 = sample_teacher(model, z, ctx, neg, steps, cfg) if gen is None else gen.rollout(model, z, ctx, steps)
|
| 92 |
+
torch.cuda.synchronize()
|
| 93 |
+
secs.append(time.time() - t0)
|
| 94 |
+
images.append(decode(vae, x0))
|
| 95 |
+
from PIL import Image
|
| 96 |
+
Image.fromarray(images[-1]).save(out / tag / f"{row['id']}.png")
|
| 97 |
+
del gen
|
| 98 |
+
columns.append(images)
|
| 99 |
+
labels.append(tag)
|
| 100 |
+
timings[tag] = round(sum(secs) / len(secs), 3)
|
| 101 |
+
print(json.dumps({'method': tag, 'dit_s_per_image': timings[tag]}), flush=True)
|
| 102 |
+
(out / 'timings.json').write_text(json.dumps(timings, indent=1))
|
| 103 |
+
ids = [r['id'] for r in rows]
|
| 104 |
+
for start in range(0, len(ids), 6):
|
| 105 |
+
label_grid([c[start:start + 6] for c in columns], labels, ids[start:start + 6],
|
| 106 |
+
out / f'grid-{start // 6:02d}.jpg')
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
if __name__ == '__main__':
|
| 110 |
+
main()
|
code/rapid_moss/teachergen.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Teacher samples for the discriminator's real side (DMDX ADP-style: teacher ODE endpoints).
|
| 2 |
+
|
| 3 |
+
torchrun --nproc-per-node N -m rapid_moss.teachergen --model DIR --cache CACHE --prompts train.jsonl \
|
| 4 |
+
--out TEACHER --count 2400 [--steps 50 --cfg 3]
|
| 5 |
+
Picks `count` prompts stratified by src (fixed seed), a resolution per prompt (its own w/h for
|
| 6 |
+
layouts, else a bucket), runs the release sampler (CFG 3, negative skips block 22) and stores
|
| 7 |
+
the final latent (fp16) per prompt id with index.json {id: {file, w, h}}.
|
| 8 |
+
"""
|
| 9 |
+
from __future__ import annotations
|
| 10 |
+
|
| 11 |
+
import argparse
|
| 12 |
+
import json
|
| 13 |
+
import os
|
| 14 |
+
import random
|
| 15 |
+
import time
|
| 16 |
+
import zlib
|
| 17 |
+
from collections import defaultdict
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
|
| 20 |
+
import torch
|
| 21 |
+
import torch.distributed as dist
|
| 22 |
+
from safetensors import safe_open
|
| 23 |
+
from safetensors.torch import save_file
|
| 24 |
+
|
| 25 |
+
from .model import load_base, sample_teacher
|
| 26 |
+
from .textenc import Cache, read_prompts
|
| 27 |
+
from .train import DEFAULTS
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def pick(rows, count, seed):
|
| 31 |
+
rng = random.Random(seed)
|
| 32 |
+
by_src = defaultdict(list)
|
| 33 |
+
for r in rows:
|
| 34 |
+
by_src[r.get('src', '')].append(r)
|
| 35 |
+
total = len(rows)
|
| 36 |
+
chosen = []
|
| 37 |
+
for src, items in sorted(by_src.items()):
|
| 38 |
+
rng.shuffle(items)
|
| 39 |
+
chosen += items[:round(count * len(items) / total)]
|
| 40 |
+
rng.shuffle(chosen)
|
| 41 |
+
buckets = DEFAULTS['buckets']
|
| 42 |
+
for r in chosen:
|
| 43 |
+
if 'w' not in r or 'h' not in r:
|
| 44 |
+
r['w'], r['h'], _ = rng.choices(buckets, weights=[b[2] for b in buckets])[0]
|
| 45 |
+
return chosen[:count]
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
@torch.no_grad()
|
| 49 |
+
def main():
|
| 50 |
+
ap = argparse.ArgumentParser()
|
| 51 |
+
ap.add_argument('--model', required=True)
|
| 52 |
+
ap.add_argument('--cache', required=True)
|
| 53 |
+
ap.add_argument('--prompts', required=True)
|
| 54 |
+
ap.add_argument('--out', required=True)
|
| 55 |
+
ap.add_argument('--count', type=int, default=2400)
|
| 56 |
+
ap.add_argument('--steps', type=int, default=50)
|
| 57 |
+
ap.add_argument('--cfg', type=float, default=3.0)
|
| 58 |
+
ap.add_argument('--seed', type=int, default=7)
|
| 59 |
+
ap.add_argument('--shard-size', type=int, default=200)
|
| 60 |
+
ap.add_argument('--exclude', nargs='*', default=[], help='index.json files of earlier runs; their prompts are skipped')
|
| 61 |
+
args = ap.parse_args()
|
| 62 |
+
distributed = 'RANK' in os.environ
|
| 63 |
+
if distributed:
|
| 64 |
+
dist.init_process_group('nccl')
|
| 65 |
+
rank, world = (dist.get_rank(), dist.get_world_size()) if distributed else (0, 1)
|
| 66 |
+
dev = torch.device('cuda', int(os.environ.get('LOCAL_RANK', 0)))
|
| 67 |
+
torch.cuda.set_device(dev)
|
| 68 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 69 |
+
out = Path(args.out)
|
| 70 |
+
out.mkdir(parents=True, exist_ok=True)
|
| 71 |
+
cache = Cache(args.cache)
|
| 72 |
+
skip = set()
|
| 73 |
+
for path in args.exclude:
|
| 74 |
+
skip.update(json.loads(Path(path).read_text()))
|
| 75 |
+
rows = pick([r for r in read_prompts([args.prompts]) if r['id'] in cache and r['id'] not in skip],
|
| 76 |
+
args.count, args.seed)
|
| 77 |
+
meta = {r['id']: {'w': r['w'], 'h': r['h']} for r in rows}
|
| 78 |
+
done = set()
|
| 79 |
+
for p in out.glob(f'shard-{rank}-*.safetensors'):
|
| 80 |
+
with safe_open(p, 'pt') as f:
|
| 81 |
+
done.update(f.keys())
|
| 82 |
+
mine = [r for i, r in enumerate(rows) if i % world == rank and r['id'] not in done]
|
| 83 |
+
model = load_base(args.model, dev)
|
| 84 |
+
neg = model.context(cache.get('').to(dev))
|
| 85 |
+
shard = len(list(out.glob(f'shard-{rank}-*.safetensors')))
|
| 86 |
+
buf, t0 = {}, time.time()
|
| 87 |
+
for n, row in enumerate(mine):
|
| 88 |
+
g = torch.Generator('cpu').manual_seed(zlib.crc32(f"{args.seed}:{row['id']}".encode()))
|
| 89 |
+
z = torch.randn(1, model.tr.config.latent_channels, row['h'] // 16, row['w'] // 16, generator=g).to(dev)
|
| 90 |
+
x0 = sample_teacher(model, z, model.context(cache.get(row['id']).to(dev)), neg, args.steps, args.cfg)
|
| 91 |
+
buf[row['id']] = x0[0].to('cpu', torch.float16).contiguous()
|
| 92 |
+
if len(buf) >= args.shard_size or n == len(mine) - 1:
|
| 93 |
+
save_file(buf, out / f'shard-{rank}-{shard:05d}.safetensors')
|
| 94 |
+
shard += 1
|
| 95 |
+
buf = {}
|
| 96 |
+
if rank == 0 and n % 20 == 0:
|
| 97 |
+
print(json.dumps({'done': n, 'of': len(mine), 's': round(time.time() - t0, 1)}), flush=True)
|
| 98 |
+
if distributed:
|
| 99 |
+
dist.barrier()
|
| 100 |
+
if rank == 0:
|
| 101 |
+
index = {}
|
| 102 |
+
for p in sorted(out.glob('shard-*.safetensors')):
|
| 103 |
+
with safe_open(p, 'pt') as f:
|
| 104 |
+
for k in f.keys():
|
| 105 |
+
index[k] = {'file': p.name, **meta[k]}
|
| 106 |
+
(out / 'index.json').write_text(json.dumps(index))
|
| 107 |
+
print(json.dumps({'index': len(index), 'wanted': len(rows)}), flush=True)
|
| 108 |
+
if distributed:
|
| 109 |
+
dist.destroy_process_group()
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
if __name__ == '__main__':
|
| 113 |
+
main()
|
code/rapid_moss/textenc.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Prompt embedding cache: release text encoder (Qwen3.5) hidden states, one tensor per prompt.
|
| 2 |
+
|
| 3 |
+
torchrun --nproc-per-node N -m rapid_moss.textenc --model DIR --prompts train.jsonl eval.jsonl --out CACHE
|
| 4 |
+
Each rank writes cache/shard-<rank>-<k>.safetensors; rank 0 merges cache/index.json at the end.
|
| 5 |
+
Key "" is the empty negative prompt.
|
| 6 |
+
"""
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import argparse
|
| 10 |
+
import json
|
| 11 |
+
import os
|
| 12 |
+
import time
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
import torch
|
| 16 |
+
import torch.distributed as dist
|
| 17 |
+
from safetensors import safe_open
|
| 18 |
+
from safetensors.torch import save_file
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def read_prompts(paths):
|
| 22 |
+
rows = []
|
| 23 |
+
for p in paths:
|
| 24 |
+
with open(p, encoding='utf-8') as f:
|
| 25 |
+
rows += [json.loads(line) for line in f if line.strip()]
|
| 26 |
+
return rows
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class Encoder:
|
| 30 |
+
def __init__(self, model_dir, device):
|
| 31 |
+
from transformers import AutoModel, AutoTokenizer
|
| 32 |
+
self.tok = AutoTokenizer.from_pretrained(Path(model_dir) / 'tokenizer', local_files_only=True)
|
| 33 |
+
self.enc = AutoModel.from_pretrained(Path(model_dir) / 'text_encoder', dtype=torch.bfloat16,
|
| 34 |
+
local_files_only=True).to(device).eval()
|
| 35 |
+
self.device = device
|
| 36 |
+
|
| 37 |
+
@torch.no_grad()
|
| 38 |
+
def __call__(self, prompt, max_len=4096):
|
| 39 |
+
# Same as MOSSImagePipeline.encode_prompt for one prompt.
|
| 40 |
+
text = self.tok.apply_chat_template([{'role': 'user', 'content': prompt}], tokenize=False,
|
| 41 |
+
add_generation_prompt=True, enable_thinking=True)
|
| 42 |
+
inputs = self.tok(text, return_tensors='pt', truncation=True, max_length=max_len).to(self.device)
|
| 43 |
+
return self.enc(**inputs, use_cache=False, return_dict=True).last_hidden_state[0]
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class Cache:
|
| 47 |
+
"""Read side: id -> [L, 4096] bf16 (CPU, memory-mapped shards)."""
|
| 48 |
+
|
| 49 |
+
def __init__(self, root):
|
| 50 |
+
self.root = Path(root)
|
| 51 |
+
self.index = json.loads((self.root / 'index.json').read_text())
|
| 52 |
+
self._files = {}
|
| 53 |
+
|
| 54 |
+
def __contains__(self, key):
|
| 55 |
+
return key in self.index
|
| 56 |
+
|
| 57 |
+
def get(self, key):
|
| 58 |
+
name = self.index[key]
|
| 59 |
+
if name not in self._files:
|
| 60 |
+
self._files[name] = safe_open(self.root / name, 'pt')
|
| 61 |
+
return self._files[name].get_tensor(key)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def main():
|
| 65 |
+
ap = argparse.ArgumentParser()
|
| 66 |
+
ap.add_argument('--model', required=True)
|
| 67 |
+
ap.add_argument('--prompts', nargs='+', required=True)
|
| 68 |
+
ap.add_argument('--out', required=True)
|
| 69 |
+
ap.add_argument('--shard-size', type=int, default=500)
|
| 70 |
+
args = ap.parse_args()
|
| 71 |
+
distributed = 'RANK' in os.environ
|
| 72 |
+
if distributed:
|
| 73 |
+
dist.init_process_group('nccl')
|
| 74 |
+
rank, world = (dist.get_rank(), dist.get_world_size()) if distributed else (0, 1)
|
| 75 |
+
device = torch.device('cuda', int(os.environ.get('LOCAL_RANK', 0)))
|
| 76 |
+
torch.cuda.set_device(device)
|
| 77 |
+
out = Path(args.out)
|
| 78 |
+
out.mkdir(parents=True, exist_ok=True)
|
| 79 |
+
rows = read_prompts(args.prompts)
|
| 80 |
+
keys = [''] + [r['id'] for r in rows]
|
| 81 |
+
texts = dict([('', '')] + [(r['id'], r['prompt']) for r in rows])
|
| 82 |
+
if len(set(keys)) != len(keys):
|
| 83 |
+
raise SystemExit('duplicate prompt ids')
|
| 84 |
+
done = set()
|
| 85 |
+
for p in out.glob(f'shard-{rank}-*.safetensors'):
|
| 86 |
+
with safe_open(p, 'pt') as f:
|
| 87 |
+
done.update(f.keys())
|
| 88 |
+
mine = [k for i, k in enumerate(keys) if i % world == rank and k not in done]
|
| 89 |
+
enc = Encoder(args.model, device)
|
| 90 |
+
buf, shard, t0 = {}, len(list(out.glob(f'shard-{rank}-*.safetensors'))), time.time()
|
| 91 |
+
|
| 92 |
+
def flush():
|
| 93 |
+
nonlocal buf, shard
|
| 94 |
+
if buf:
|
| 95 |
+
save_file(buf, out / f'shard-{rank}-{shard:05d}.safetensors')
|
| 96 |
+
shard += 1
|
| 97 |
+
buf = {}
|
| 98 |
+
|
| 99 |
+
for n, key in enumerate(mine):
|
| 100 |
+
buf[key] = enc(texts[key]).to('cpu', torch.bfloat16).contiguous()
|
| 101 |
+
if len(buf) >= args.shard_size:
|
| 102 |
+
flush()
|
| 103 |
+
if rank == 0 and n % 200 == 0:
|
| 104 |
+
print(json.dumps({'encoded': n, 'of': len(mine), 's': round(time.time() - t0, 1)}), flush=True)
|
| 105 |
+
flush()
|
| 106 |
+
if distributed:
|
| 107 |
+
dist.barrier()
|
| 108 |
+
if rank == 0:
|
| 109 |
+
index = {}
|
| 110 |
+
for p in sorted(out.glob('shard-*.safetensors')):
|
| 111 |
+
with safe_open(p, 'pt') as f:
|
| 112 |
+
for k in f.keys():
|
| 113 |
+
index[k] = p.name
|
| 114 |
+
missing = [k for k in keys if k not in index]
|
| 115 |
+
(out / 'index.json').write_text(json.dumps(index))
|
| 116 |
+
print(json.dumps({'index': len(index), 'missing': len(missing)}), flush=True)
|
| 117 |
+
if distributed:
|
| 118 |
+
dist.destroy_process_group()
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
if __name__ == '__main__':
|
| 122 |
+
main()
|
code/rapid_moss/train.py
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Distillation of MOSS-Image-SFT to an R-step data-space generator (arXiv 2610.12102).
|
| 2 |
+
|
| 3 |
+
torchrun --nproc-per-node N -m rapid_moss.train --config configs/main.json [--set key=value ...]
|
| 4 |
+
|
| 5 |
+
method=dmad (arXiv 2610.02188): no fake score and no teacher evaluation during training. A critic
|
| 6 |
+
(base + LoRA on the later blocks + a head on the last block) separates noised teacher samples
|
| 7 |
+
(rapid_moss.teachergen) from noised generator samples of the same prompts with a logistic loss;
|
| 8 |
+
the generator minimises -critic(noised x0). Prompts are drawn from the teacher-sample pool.
|
| 9 |
+
|
| 10 |
+
method=dmd, per iteration: fake_per_gen fake-score updates, then (after fake_warmup) one generator update
|
| 11 |
+
with the DMD direction sg[v_real - v_fake] on x0 (arXiv 2610.12102) plus the ADM generator loss
|
| 12 |
+
-D(x_fake at tau - dt) (arXiv 2507.18569), and one discriminator hinge update on the same pair
|
| 13 |
+
(x_real = x_tau - dt * v_teacher_cfg, x_fake = x_tau - dt * v_fake). Each GPU runs `micro`
|
| 14 |
+
single-sample micro-steps per update (samples have different resolutions and text lengths).
|
| 15 |
+
"""
|
| 16 |
+
from __future__ import annotations
|
| 17 |
+
|
| 18 |
+
import argparse
|
| 19 |
+
import json
|
| 20 |
+
import math
|
| 21 |
+
import os
|
| 22 |
+
import random
|
| 23 |
+
import time
|
| 24 |
+
from pathlib import Path
|
| 25 |
+
|
| 26 |
+
import torch
|
| 27 |
+
import torch.distributed as dist
|
| 28 |
+
from torch.nn import functional as F
|
| 29 |
+
|
| 30 |
+
from .model import load_base
|
| 31 |
+
from .nets import Critic, Discriminator, FakeScore, Generator
|
| 32 |
+
from .textenc import Cache, read_prompts
|
| 33 |
+
|
| 34 |
+
DEFAULTS = {
|
| 35 |
+
'model_dir': '/workspace/models/MOSS-Image-SFT',
|
| 36 |
+
'lodestones_dir': '/workspace/models/MOSS-Image-SFT-8-steps-dmd',
|
| 37 |
+
'cache_dir': '/workspace/cache',
|
| 38 |
+
'prompts': '/workspace/prompts/train.jsonl',
|
| 39 |
+
'eval_prompts': '/workspace/prompts/eval.jsonl',
|
| 40 |
+
'out_dir': '/workspace/runs/main',
|
| 41 |
+
'steps': 4,
|
| 42 |
+
'gen_rank': 128, 'gen_alpha': 128,
|
| 43 |
+
'fake_rank': 64, 'fake_alpha': 64,
|
| 44 |
+
'disc_taps': [5, 11, 17, 23, 29, 35], 'disc_hidden': 256,
|
| 45 |
+
'iterations': 3000,
|
| 46 |
+
'micro': 2,
|
| 47 |
+
'fake_per_gen': 2,
|
| 48 |
+
'fake_warmup': 200,
|
| 49 |
+
'lr_gen': 1e-5, 'lr_time': 1e-5, 'lr_q': 1e-5, 'lr_fake': 1e-4, 'lr_disc': 5e-5,
|
| 50 |
+
'betas': [0.0, 0.99],
|
| 51 |
+
'ema': 0.999,
|
| 52 |
+
'cfg': [3.0, 3.0],
|
| 53 |
+
'skip_neg': [22],
|
| 54 |
+
'tau_beta': [2.5, 1.0], 'tau_clamp': [0.03, 0.985],
|
| 55 |
+
'dt': 1 / 64,
|
| 56 |
+
'adv_weight': 0.5, 'adv_start': 50, 'adv_warmup': 200,
|
| 57 |
+
# discriminator real side: 'adm' = teacher ODE step from the same noised generator sample
|
| 58 |
+
# (ADM, x_real/x_fake at tau - dt); 'teacher' = noised teacher samples of the same prompt
|
| 59 |
+
# (ADP-style endpoints from rapid_moss.teachergen), drawn on a p_gan share of generator steps
|
| 60 |
+
'disc_real': 'adm', 'teacher_dir': '/workspace/teacher', 'p_gan': 0.5, 'gan_t': [0.02, 0.98],
|
| 61 |
+
'clip_gen': 0.0, 'clip_critic': 0.0, # 0 = no clipping; a non-finite gradient norm always skips the step
|
| 62 |
+
'buckets': [[1024, 1024, 0.35], [896, 1152, 0.15], [832, 1216, 0.15], [1152, 896, 0.1],
|
| 63 |
+
[1216, 832, 0.1], [768, 1344, 0.075], [1344, 768, 0.075]],
|
| 64 |
+
'method': 'dmd',
|
| 65 |
+
'critic_rank': 128, 'critic_alpha': 128, 'critic_start': 21, 'critic_hidden': 512,
|
| 66 |
+
'critic_shift': 5.0, 'critic_sigma': [0.02, 0.98], 'lr_critic': 4e-5, 'wd_critic': 0.01,
|
| 67 |
+
'critic_warmup': 50,
|
| 68 |
+
'ckpt': True,
|
| 69 |
+
'seed': 0,
|
| 70 |
+
'log_every': 10, 'sample_every': 100, 'save_every': 250, 'export_every': 500,
|
| 71 |
+
'eval_count': 8, 'eval_seed': 1234,
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def parse_config():
|
| 76 |
+
ap = argparse.ArgumentParser()
|
| 77 |
+
ap.add_argument('--config')
|
| 78 |
+
ap.add_argument('--set', nargs='*', default=[])
|
| 79 |
+
args = ap.parse_args()
|
| 80 |
+
cfg = dict(DEFAULTS)
|
| 81 |
+
if args.config:
|
| 82 |
+
cfg.update(json.loads(Path(args.config).read_text()))
|
| 83 |
+
for item in args.set:
|
| 84 |
+
key, value = item.split('=', 1)
|
| 85 |
+
if key not in DEFAULTS:
|
| 86 |
+
raise SystemExit(f'unknown key {key}')
|
| 87 |
+
try:
|
| 88 |
+
cfg[key] = json.loads(value)
|
| 89 |
+
except json.JSONDecodeError:
|
| 90 |
+
cfg[key] = value
|
| 91 |
+
return cfg
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
class Dist:
|
| 95 |
+
def __init__(self):
|
| 96 |
+
self.on = 'RANK' in os.environ
|
| 97 |
+
if self.on:
|
| 98 |
+
dist.init_process_group('nccl')
|
| 99 |
+
self.rank = dist.get_rank() if self.on else 0
|
| 100 |
+
self.world = dist.get_world_size() if self.on else 1
|
| 101 |
+
self.device = torch.device('cuda', int(os.environ.get('LOCAL_RANK', 0)))
|
| 102 |
+
torch.cuda.set_device(self.device)
|
| 103 |
+
|
| 104 |
+
def mean_grads(self, params):
|
| 105 |
+
grads = [p.grad for p in params]
|
| 106 |
+
if self.world == 1:
|
| 107 |
+
return
|
| 108 |
+
flat = torch._utils._flatten_dense_tensors(grads)
|
| 109 |
+
dist.all_reduce(flat)
|
| 110 |
+
flat /= self.world
|
| 111 |
+
for g, f in zip(grads, torch._utils._unflatten_dense_tensors(flat, grads)):
|
| 112 |
+
g.copy_(f)
|
| 113 |
+
|
| 114 |
+
def mean(self, values):
|
| 115 |
+
t = torch.tensor(values, device=self.device, dtype=torch.float64)
|
| 116 |
+
if self.on:
|
| 117 |
+
dist.all_reduce(t)
|
| 118 |
+
t /= self.world
|
| 119 |
+
return t.tolist()
|
| 120 |
+
|
| 121 |
+
def barrier(self):
|
| 122 |
+
if self.on:
|
| 123 |
+
dist.barrier()
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def zero_grads(params):
|
| 127 |
+
for p in params:
|
| 128 |
+
if p.grad is None:
|
| 129 |
+
p.grad = torch.zeros_like(p)
|
| 130 |
+
else:
|
| 131 |
+
p.grad.zero_()
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def load_teacher(dirs, rows, dev):
|
| 135 |
+
"""Scan teachergen shards (any number of dirs); returns the prompt rows that have a teacher latent
|
| 136 |
+
(with w/h from the latent shape) and a getter id -> [1, C, h, w] fp32 on dev."""
|
| 137 |
+
from safetensors import safe_open
|
| 138 |
+
files, where = [], {}
|
| 139 |
+
for d in [dirs] if isinstance(dirs, str) else dirs:
|
| 140 |
+
for path in sorted(Path(d).glob('shard-*.safetensors')):
|
| 141 |
+
try:
|
| 142 |
+
f = safe_open(path, 'pt')
|
| 143 |
+
except Exception as e: # a shard cut off when its teachergen run was stopped
|
| 144 |
+
print(json.dumps({'skip_shard': str(path), 'error': str(e)[:120]}), flush=True)
|
| 145 |
+
continue
|
| 146 |
+
files.append(f)
|
| 147 |
+
for k in f.keys():
|
| 148 |
+
_, h, w = f.get_slice(k).get_shape()
|
| 149 |
+
where[k] = (len(files) - 1, w * 16, h * 16)
|
| 150 |
+
pool = [dict(r, w=where[r['id']][1], h=where[r['id']][2]) for r in rows if r['id'] in where]
|
| 151 |
+
|
| 152 |
+
def get(key):
|
| 153 |
+
return files[where[key][0]].get_tensor(key)[None].to(dev, torch.float32)
|
| 154 |
+
return pool, get
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def decode(vae, x0):
|
| 158 |
+
z = x0.to(vae.dtype)
|
| 159 |
+
bn, eps = vae.bn, vae.config.batch_norm_eps
|
| 160 |
+
z = z * (bn.running_var + eps).sqrt().view(1, -1, 1, 1) + bn.running_mean.view(1, -1, 1, 1)
|
| 161 |
+
b, c, h, w = z.shape
|
| 162 |
+
z = z.reshape(b, c // 4, 2, 2, h, w).permute(0, 1, 4, 2, 5, 3).reshape(b, c // 4, 2 * h, 2 * w)
|
| 163 |
+
img = vae.decode(z, return_dict=False)[0].clamp(-1, 1)
|
| 164 |
+
return ((img[0].float() + 1) * 127.5).round().byte().permute(1, 2, 0).cpu().numpy()
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def contact_sheet(images, path, cell=384, cols=4):
|
| 168 |
+
from PIL import Image
|
| 169 |
+
rows = math.ceil(len(images) / cols)
|
| 170 |
+
sheet = Image.new('RGB', (cols * cell, rows * cell), 'white')
|
| 171 |
+
for i, im in enumerate(images):
|
| 172 |
+
im = Image.fromarray(im)
|
| 173 |
+
im.thumbnail((cell, cell))
|
| 174 |
+
sheet.paste(im, ((i % cols) * cell + (cell - im.width) // 2, (i // cols) * cell + (cell - im.height) // 2))
|
| 175 |
+
sheet.save(path, quality=90)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def main():
|
| 179 |
+
C = parse_config()
|
| 180 |
+
D = Dist()
|
| 181 |
+
dev = D.device
|
| 182 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 183 |
+
torch.backends.cudnn.allow_tf32 = True
|
| 184 |
+
out = Path(C['out_dir'])
|
| 185 |
+
if D.rank == 0:
|
| 186 |
+
(out / 'samples').mkdir(parents=True, exist_ok=True)
|
| 187 |
+
(out / 'ckpt').mkdir(exist_ok=True)
|
| 188 |
+
(out / 'config.json').write_text(json.dumps(C, indent=1))
|
| 189 |
+
R = C['steps']
|
| 190 |
+
|
| 191 |
+
model = load_base(C['model_dir'], dev)
|
| 192 |
+
gen = Generator(model, C['gen_rank'], C['gen_alpha'], R).to(dev)
|
| 193 |
+
gen.load_lodestones(C['lodestones_dir'])
|
| 194 |
+
ema = Generator(model, C['gen_rank'], C['gen_alpha'], R).to(dev).requires_grad_(False)
|
| 195 |
+
ema.load_state_dict(gen.state_dict())
|
| 196 |
+
betas = tuple(C['betas'])
|
| 197 |
+
gen_params = list(gen.parameters())
|
| 198 |
+
opt_gen = torch.optim.AdamW([{'params': list(gen.lora.parameters()), 'lr': C['lr_gen']},
|
| 199 |
+
{'params': list(gen.time.parameters()), 'lr': C['lr_time']},
|
| 200 |
+
{'params': [gen.Q], 'lr': C['lr_q']}], betas=betas, weight_decay=0.0)
|
| 201 |
+
parts = {'gen': gen, 'ema': ema, 'opt_gen': opt_gen}
|
| 202 |
+
dmad = C['method'] == 'dmad'
|
| 203 |
+
if dmad:
|
| 204 |
+
critic = Critic(model, C['critic_rank'], C['critic_alpha'], C['critic_start'], C['critic_hidden']).to(dev)
|
| 205 |
+
opt_critic = torch.optim.AdamW(critic.parameters(), lr=C['lr_critic'], betas=betas,
|
| 206 |
+
weight_decay=C['wd_critic'])
|
| 207 |
+
parts.update(critic=critic, opt_critic=opt_critic)
|
| 208 |
+
trainables = (gen_params, list(critic.parameters()))
|
| 209 |
+
elif C['method'] == 'dmd':
|
| 210 |
+
fake = FakeScore(model, C['fake_rank'], C['fake_alpha'], R).to(dev)
|
| 211 |
+
disc = Discriminator(model.dim, C['disc_taps'], C['disc_hidden']).to(dev)
|
| 212 |
+
opt_fake = torch.optim.AdamW(fake.parameters(), lr=C['lr_fake'], betas=betas, weight_decay=0.0)
|
| 213 |
+
opt_disc = torch.optim.AdamW(disc.parameters(), lr=C['lr_disc'], betas=betas, weight_decay=0.0)
|
| 214 |
+
parts.update(fake=fake, disc=disc, opt_fake=opt_fake, opt_disc=opt_disc)
|
| 215 |
+
trainables = (gen_params, list(fake.parameters()), list(disc.parameters()))
|
| 216 |
+
else:
|
| 217 |
+
raise SystemExit(f"method must be dmd or dmad, got {C['method']}")
|
| 218 |
+
for params in trainables:
|
| 219 |
+
zero_grads(params)
|
| 220 |
+
|
| 221 |
+
cache = Cache(C['cache_dir'])
|
| 222 |
+
rows = [r for r in read_prompts([C['prompts']]) if r['id'] in cache]
|
| 223 |
+
evals = [r for r in read_prompts([C['eval_prompts']]) if r['id'] in cache][:C['eval_count']]
|
| 224 |
+
neg = model.context(cache.get('').to(dev))
|
| 225 |
+
buckets = C['buckets']
|
| 226 |
+
teacher = None
|
| 227 |
+
if dmad or C['disc_real'] == 'teacher':
|
| 228 |
+
trows, teacher = load_teacher(C['teacher_dir'], rows, dev)
|
| 229 |
+
if D.rank == 0:
|
| 230 |
+
print(json.dumps({'teacher_samples': len(trows)}), flush=True)
|
| 231 |
+
elif C['disc_real'] != 'adm':
|
| 232 |
+
raise SystemExit(f"disc_real must be adm or teacher, got {C['disc_real']}")
|
| 233 |
+
|
| 234 |
+
start, gen_updates = 0, 0
|
| 235 |
+
latest = out / 'ckpt' / 'latest.pt'
|
| 236 |
+
if latest.exists():
|
| 237 |
+
state = torch.load(latest, map_location=dev, weights_only=False)
|
| 238 |
+
for key, mod in parts.items():
|
| 239 |
+
mod.load_state_dict(state[key])
|
| 240 |
+
start, gen_updates = state['it'], state['gen_updates']
|
| 241 |
+
del state
|
| 242 |
+
if D.rank == 0:
|
| 243 |
+
print(json.dumps({'resume': start, 'gen_updates': gen_updates}), flush=True)
|
| 244 |
+
rng = random.Random(C['seed'] * 1_000_003 + D.rank * 7919 + start)
|
| 245 |
+
torch.manual_seed(C['seed'] * 1_000_003 + D.rank * 7919 + start)
|
| 246 |
+
beta = torch.distributions.Beta(*[torch.tensor(float(v)) for v in C['tau_beta']])
|
| 247 |
+
lo, hi = C['tau_clamp']
|
| 248 |
+
dt = C['dt']
|
| 249 |
+
vae = None
|
| 250 |
+
|
| 251 |
+
def draw(pool=None):
|
| 252 |
+
pool = pool or rows
|
| 253 |
+
row = pool[rng.randrange(len(pool))]
|
| 254 |
+
if 'w' in row and 'h' in row:
|
| 255 |
+
w, h = row['w'], row['h']
|
| 256 |
+
else:
|
| 257 |
+
w, h, _ = rng.choices(buckets, weights=[b[2] for b in buckets])[0]
|
| 258 |
+
ctx = model.context(cache.get(row['id']).to(dev))
|
| 259 |
+
z = torch.randn(1, model.tr.config.latent_channels, h // 16, w // 16, device=dev)
|
| 260 |
+
return ctx, z, row
|
| 261 |
+
|
| 262 |
+
def tau():
|
| 263 |
+
return float(beta.sample().clamp(lo, hi))
|
| 264 |
+
|
| 265 |
+
def r_index(phase, m):
|
| 266 |
+
return ((phase * D.world + D.rank) * C['micro'] + m) % R
|
| 267 |
+
|
| 268 |
+
def fake_step(phase):
|
| 269 |
+
losses = []
|
| 270 |
+
gen.lora.freeze_cache()
|
| 271 |
+
for m in range(C['micro']):
|
| 272 |
+
ctx, z, _ = draw()
|
| 273 |
+
r = r_index(phase, m)
|
| 274 |
+
x0 = gen.rollout(model, z, ctx, r + 1)
|
| 275 |
+
t = tau()
|
| 276 |
+
eps = torch.randn_like(z)
|
| 277 |
+
v = fake(model, (1 - t) * x0 + t * eps, t * 1000, ctx, r, ckpt=C['ckpt'])
|
| 278 |
+
loss = F.mse_loss(v, eps - x0)
|
| 279 |
+
(loss / C['micro']).backward()
|
| 280 |
+
losses.append(loss.item())
|
| 281 |
+
gen.lora.drop_cache()
|
| 282 |
+
D.mean_grads(list(fake.parameters()))
|
| 283 |
+
opt_fake.step()
|
| 284 |
+
opt_fake.zero_grad(set_to_none=False)
|
| 285 |
+
return sum(losses) / len(losses)
|
| 286 |
+
|
| 287 |
+
def gen_step(phase):
|
| 288 |
+
ramp = 0.0 if gen_updates < C['adv_start'] else min(1.0, (gen_updates - C['adv_start'] + 1) / max(1, C['adv_warmup']))
|
| 289 |
+
stats = {k: 0.0 for k in ('dmd_rms', 'adv_ratio', 'lam', 'd_loss', 'd_real', 'd_fake', 'd_acc')}
|
| 290 |
+
n_gan = 0
|
| 291 |
+
fake.lora.freeze_cache()
|
| 292 |
+
gen.lora.freeze_cache()
|
| 293 |
+
for m in range(C['micro']):
|
| 294 |
+
use_teacher = teacher is not None and rng.random() < C['p_gan']
|
| 295 |
+
ctx, z, row = draw(trows if use_teacher else None)
|
| 296 |
+
r = r_index(phase, m)
|
| 297 |
+
x_prev = gen.rollout(model, z, ctx, r)
|
| 298 |
+
x0_hat = gen.step(model, z, x_prev, r, ctx, ckpt=C['ckpt'])
|
| 299 |
+
x0d = x0_hat.detach()
|
| 300 |
+
t = tau()
|
| 301 |
+
eps = torch.randn_like(z)
|
| 302 |
+
xt = (1 - t) * x0d + t * eps
|
| 303 |
+
w = rng.uniform(*C['cfg'])
|
| 304 |
+
with torch.no_grad():
|
| 305 |
+
v_real = model.teacher(xt, t * 1000, ctx, neg, w, tuple(C['skip_neg']))
|
| 306 |
+
v_fake = fake(model, xt, t * 1000, ctx, r)
|
| 307 |
+
g_dmd = (v_real - v_fake) / x0d.numel()
|
| 308 |
+
stats['dmd_rms'] += (v_real - v_fake).square().mean().sqrt().item()
|
| 309 |
+
_, _, h, wd = z.shape
|
| 310 |
+
leaf = x0d.clone().requires_grad_(True)
|
| 311 |
+
if teacher is None:
|
| 312 |
+
# ADM: generator loss -D(x_tau - dt * v_fake) at tau - dt; gradient taken w.r.t. x0 only
|
| 313 |
+
s = t - dt
|
| 314 |
+
x_fake = (1 - t) * leaf + t * eps - dt * v_fake
|
| 315 |
+
x_real = xt - dt * v_real
|
| 316 |
+
elif use_teacher:
|
| 317 |
+
s = rng.uniform(*C['gan_t'])
|
| 318 |
+
x_fake = (1 - s) * leaf + s * torch.randn_like(z)
|
| 319 |
+
x_real = (1 - s) * teacher(row['id']) + s * torch.randn_like(z)
|
| 320 |
+
else:
|
| 321 |
+
x0_hat.backward(g_dmd / C['micro'])
|
| 322 |
+
del x0_hat
|
| 323 |
+
continue
|
| 324 |
+
n_gan += 1
|
| 325 |
+
feats = model(x_fake, s * 1000, ctx, taps=disc.taps, ckpt=C['ckpt'])
|
| 326 |
+
logits_f = disc(feats, h, wd)
|
| 327 |
+
g_adv, = torch.autograd.grad(-logits_f.mean(), leaf)
|
| 328 |
+
ratio = (g_adv.norm() / (g_dmd.norm() + 1e-30)).item()
|
| 329 |
+
lam = C['adv_weight'] * ramp / max(ratio, 1e-12)
|
| 330 |
+
stats['adv_ratio'] += ratio
|
| 331 |
+
stats['lam'] += lam
|
| 332 |
+
x0_hat.backward((g_dmd + lam * g_adv) / C['micro'])
|
| 333 |
+
# discriminator hinge on the same pair (fake features reused from the pass above)
|
| 334 |
+
f_fake = {k: v.detach() for k, v in feats.items()}
|
| 335 |
+
del x0_hat, feats, logits_f
|
| 336 |
+
with torch.no_grad():
|
| 337 |
+
f_real = model(x_real, s * 1000, ctx, taps=disc.taps)
|
| 338 |
+
d_real, d_fake = disc(f_real, h, wd), disc(f_fake, h, wd)
|
| 339 |
+
d_loss = F.relu(1 - d_real).mean() + F.relu(1 + d_fake).mean()
|
| 340 |
+
(d_loss / C['micro']).backward()
|
| 341 |
+
stats['d_loss'] += d_loss.item()
|
| 342 |
+
stats['d_real'] += d_real.mean().item()
|
| 343 |
+
stats['d_fake'] += d_fake.mean().item()
|
| 344 |
+
stats['d_acc'] += 0.5 * ((d_real > 0).float().mean() + (d_fake < 0).float().mean()).item()
|
| 345 |
+
gen.lora.drop_cache()
|
| 346 |
+
fake.lora.drop_cache()
|
| 347 |
+
D.mean_grads(gen_params)
|
| 348 |
+
D.mean_grads(list(disc.parameters()))
|
| 349 |
+
gnorm = torch.nn.utils.clip_grad_norm_(gen_params, C['clip_gen'] or 1e12)
|
| 350 |
+
if torch.isfinite(gnorm):
|
| 351 |
+
opt_gen.step()
|
| 352 |
+
opt_disc.step()
|
| 353 |
+
opt_gen.zero_grad(set_to_none=False)
|
| 354 |
+
opt_disc.zero_grad(set_to_none=False)
|
| 355 |
+
with torch.no_grad():
|
| 356 |
+
for pe, p in zip(ema.parameters(), gen.parameters()):
|
| 357 |
+
pe.lerp_(p, 1 - C['ema'])
|
| 358 |
+
stats = {k: v / (C['micro'] if k == 'dmd_rms' else max(n_gan, 1)) for k, v in stats.items()}
|
| 359 |
+
stats['gan_frac'] = n_gan / C['micro']
|
| 360 |
+
stats['gnorm'] = gnorm.item()
|
| 361 |
+
stats['ramp'] = ramp
|
| 362 |
+
return stats
|
| 363 |
+
|
| 364 |
+
def critic_sigma():
|
| 365 |
+
u, k = rng.uniform(*C['critic_sigma']), C['critic_shift']
|
| 366 |
+
return k * u / (1 + (k - 1) * u)
|
| 367 |
+
|
| 368 |
+
def dmad_step(phase, gen_on):
|
| 369 |
+
stats = {k: 0.0 for k in ('g_logit', 'c_loss', 'd_teacher', 'd_gen', 'c_acc')}
|
| 370 |
+
stash = []
|
| 371 |
+
gen.lora.freeze_cache()
|
| 372 |
+
critic.requires_grad_(False)
|
| 373 |
+
for m in range(C['micro']):
|
| 374 |
+
ctx, z, row = draw(trows)
|
| 375 |
+
r = r_index(phase, m)
|
| 376 |
+
if gen_on:
|
| 377 |
+
x0_hat = gen.step(model, z, gen.rollout(model, z, ctx, r), r, ctx, ckpt=C['ckpt'])
|
| 378 |
+
s = critic_sigma()
|
| 379 |
+
logit = critic(model, (1 - s) * x0_hat + s * torch.randn_like(z), s * 1000, ctx, ckpt=C['ckpt'])
|
| 380 |
+
(-logit.mean() / C['micro']).backward()
|
| 381 |
+
stats['g_logit'] += logit.item()
|
| 382 |
+
x0 = x0_hat.detach()
|
| 383 |
+
del x0_hat, logit
|
| 384 |
+
else:
|
| 385 |
+
x0 = gen.rollout(model, z, ctx, r + 1)
|
| 386 |
+
stash.append((ctx, row, x0))
|
| 387 |
+
gen.lora.drop_cache()
|
| 388 |
+
if gen_on:
|
| 389 |
+
D.mean_grads(gen_params)
|
| 390 |
+
gnorm = torch.nn.utils.clip_grad_norm_(gen_params, C['clip_gen'] or 1e12)
|
| 391 |
+
if torch.isfinite(gnorm):
|
| 392 |
+
opt_gen.step()
|
| 393 |
+
with torch.no_grad():
|
| 394 |
+
for pe, p in zip(ema.parameters(), gen.parameters()):
|
| 395 |
+
pe.lerp_(p, 1 - C['ema'])
|
| 396 |
+
stats['gnorm'] = gnorm.item() * C['micro']
|
| 397 |
+
else:
|
| 398 |
+
stats['skip_gen'] = C['micro']
|
| 399 |
+
opt_gen.zero_grad(set_to_none=False)
|
| 400 |
+
critic.requires_grad_(True)
|
| 401 |
+
for ctx, row, x0 in stash:
|
| 402 |
+
s = critic_sigma()
|
| 403 |
+
d_q = critic(model, (1 - s) * teacher(row['id']) + s * torch.randn_like(x0), s * 1000, ctx, ckpt=C['ckpt'])
|
| 404 |
+
d_g = critic(model, (1 - s) * x0 + s * torch.randn_like(x0), s * 1000, ctx, ckpt=C['ckpt'])
|
| 405 |
+
loss = F.softplus(-d_q).mean() + F.softplus(d_g).mean()
|
| 406 |
+
(loss / C['micro']).backward()
|
| 407 |
+
stats['c_loss'] += loss.item()
|
| 408 |
+
stats['d_teacher'] += d_q.item()
|
| 409 |
+
stats['d_gen'] += d_g.item()
|
| 410 |
+
stats['c_acc'] += 0.5 * ((d_q > 0).float() + (d_g < 0).float()).item()
|
| 411 |
+
critic_params = list(critic.parameters())
|
| 412 |
+
D.mean_grads(critic_params)
|
| 413 |
+
cnorm = torch.nn.utils.clip_grad_norm_(critic_params, C['clip_critic'] or 1e12)
|
| 414 |
+
if torch.isfinite(cnorm):
|
| 415 |
+
opt_critic.step()
|
| 416 |
+
stats['cnorm'] = cnorm.item() * C['micro']
|
| 417 |
+
else:
|
| 418 |
+
stats['skip_critic'] = C['micro']
|
| 419 |
+
opt_critic.zero_grad(set_to_none=False)
|
| 420 |
+
return {k: v / C['micro'] for k, v in stats.items()}
|
| 421 |
+
|
| 422 |
+
@torch.no_grad()
|
| 423 |
+
def sample(tag):
|
| 424 |
+
nonlocal vae
|
| 425 |
+
if D.rank == 0:
|
| 426 |
+
if vae is None:
|
| 427 |
+
from diffusers import AutoencoderKLFlux2
|
| 428 |
+
vae = AutoencoderKLFlux2.from_pretrained(Path(C['model_dir']) / 'vae', torch_dtype=torch.float32,
|
| 429 |
+
local_files_only=True).to(dev).eval()
|
| 430 |
+
d = out / 'samples' / tag
|
| 431 |
+
d.mkdir(parents=True, exist_ok=True)
|
| 432 |
+
images = []
|
| 433 |
+
for row in evals:
|
| 434 |
+
g = torch.Generator('cpu').manual_seed(C['eval_seed'])
|
| 435 |
+
z = torch.randn(1, model.tr.config.latent_channels, row['h'] // 16, row['w'] // 16, generator=g).to(dev)
|
| 436 |
+
x0 = ema.rollout(model, z, model.context(cache.get(row['id']).to(dev)), R)
|
| 437 |
+
images.append(decode(vae, x0))
|
| 438 |
+
from PIL import Image
|
| 439 |
+
Image.fromarray(images[-1]).save(d / f"{row['id']}.png")
|
| 440 |
+
contact_sheet(images, out / 'samples' / f'{tag}.jpg')
|
| 441 |
+
D.barrier()
|
| 442 |
+
|
| 443 |
+
def save(it):
|
| 444 |
+
if D.rank == 0:
|
| 445 |
+
state = {key: mod.state_dict() for key, mod in parts.items()}
|
| 446 |
+
state.update(it=it, gen_updates=gen_updates, config=C)
|
| 447 |
+
tmp = out / 'ckpt' / 'latest.tmp'
|
| 448 |
+
torch.save(state, tmp)
|
| 449 |
+
if latest.exists():
|
| 450 |
+
latest.replace(out / 'ckpt' / 'prev.pt') # one older state survives a bad save
|
| 451 |
+
tmp.replace(latest)
|
| 452 |
+
D.barrier()
|
| 453 |
+
|
| 454 |
+
if start == 0 and C['sample_every']:
|
| 455 |
+
sample('init')
|
| 456 |
+
t_last, log = time.time(), []
|
| 457 |
+
for it in range(start, C['iterations']):
|
| 458 |
+
entry = {'it': it}
|
| 459 |
+
if dmad:
|
| 460 |
+
gen_on = it >= C['critic_warmup']
|
| 461 |
+
entry.update(dmad_step(it, gen_on))
|
| 462 |
+
gen_updates += gen_on
|
| 463 |
+
else:
|
| 464 |
+
entry['fake'] = sum(fake_step(it * C['fake_per_gen'] + k) for k in range(C['fake_per_gen'])) / C['fake_per_gen']
|
| 465 |
+
if it >= C['fake_warmup']:
|
| 466 |
+
entry.update(gen_step(it))
|
| 467 |
+
gen_updates += 1
|
| 468 |
+
log.append(entry)
|
| 469 |
+
done = it + 1
|
| 470 |
+
if done % C['log_every'] == 0:
|
| 471 |
+
keys = sorted({k for e in log for k in e if k != 'it'})
|
| 472 |
+
means = D.mean([sum(e.get(k, 0.0) for e in log) / len(log) for k in keys])
|
| 473 |
+
now = time.time()
|
| 474 |
+
if D.rank == 0:
|
| 475 |
+
rec = {'it': done, 'gen_updates': gen_updates, 's_per_it': round((now - t_last) / len(log), 2),
|
| 476 |
+
'mem_gib': round(torch.cuda.max_memory_allocated() / 2**30, 1),
|
| 477 |
+
**{k: round(v, 6) for k, v in zip(keys, means)}}
|
| 478 |
+
print(json.dumps(rec), flush=True)
|
| 479 |
+
with open(out / 'log.jsonl', 'a') as f:
|
| 480 |
+
f.write(json.dumps(rec) + '\n')
|
| 481 |
+
t_last, log = now, []
|
| 482 |
+
if C['sample_every'] and done % C['sample_every'] == 0:
|
| 483 |
+
sample(f'{done:06d}')
|
| 484 |
+
if C['save_every'] and done % C['save_every'] == 0:
|
| 485 |
+
save(done)
|
| 486 |
+
if C['export_every'] and done % C['export_every'] == 0 and D.rank == 0:
|
| 487 |
+
ema.export(out / 'export' / f'{done:06d}', {'iteration': str(done)})
|
| 488 |
+
save(C['iterations'])
|
| 489 |
+
if D.rank == 0:
|
| 490 |
+
ema.export(out / 'export' / 'final', {'iteration': str(C['iterations'])})
|
| 491 |
+
gen.export(out / 'export' / 'final-raw', {'iteration': str(C['iterations'])})
|
| 492 |
+
if C['sample_every']:
|
| 493 |
+
sample('final')
|
| 494 |
+
if D.on:
|
| 495 |
+
dist.destroy_process_group()
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
if __name__ == '__main__':
|
| 499 |
+
main()
|
code/scripts/main_run.sh
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Runs on the main pod (all GPUs): setup -> text cache -> [teacher samples] -> training.
|
| 3 |
+
# DISC_REAL=adm|teacher TEACHER_COUNT=2400 bash scripts/main_run.sh [--set key=value ...]
|
| 4 |
+
# Expects code at /workspace/code and prompts at /workspace/prompts/{train,eval}.jsonl.
|
| 5 |
+
set -euo pipefail
|
| 6 |
+
cd /workspace/code
|
| 7 |
+
N=$(nvidia-smi -L | wc -l)
|
| 8 |
+
M=/workspace/models/MOSS-Image-SFT
|
| 9 |
+
echo "== setup $(date -u +%T)"
|
| 10 |
+
bash scripts/pod_setup.sh
|
| 11 |
+
echo "== text cache $(date -u +%T)"
|
| 12 |
+
torchrun --nproc-per-node "$N" -m rapid_moss.textenc --model $M \
|
| 13 |
+
--prompts /workspace/prompts/train.jsonl /workspace/prompts/eval.jsonl --out /workspace/cache
|
| 14 |
+
EXTRA=(disc_real=adm)
|
| 15 |
+
if [[ "${DISC_REAL:-teacher}" == teacher ]]; then
|
| 16 |
+
echo "== teacher samples $(date -u +%T)"
|
| 17 |
+
torchrun --nproc-per-node "$N" -m rapid_moss.teachergen --model $M --cache /workspace/cache \
|
| 18 |
+
--prompts /workspace/prompts/train.jsonl --out /workspace/teacher --count "${TEACHER_COUNT:-2000}"
|
| 19 |
+
EXTRA=()
|
| 20 |
+
fi
|
| 21 |
+
echo "== train $(date -u +%T)"
|
| 22 |
+
torchrun --nproc-per-node "$N" -m rapid_moss.train --config configs/main.json --set "${EXTRA[@]}" "$@"
|
| 23 |
+
echo "== done $(date -u +%T)"
|
code/scripts/pod_dmad.sh
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# On the pod: let the second teacher run go until DEADLINE (UTC, e.g. 21:50), stop it, then train DMAD on all GPUs.
|
| 3 |
+
DEADLINE=${1:?usage: pod_dmad.sh HH:MM}
|
| 4 |
+
until [[ "$(date -u +%H:%M)" > "$DEADLINE" || "$(date -u +%H:%M)" == "$DEADLINE" ]]; do sleep 20; done
|
| 5 |
+
pkill -f "rapid_moss.teachergen"
|
| 6 |
+
while pgrep -f "rapid_moss.teachergen" > /dev/null; do sleep 5; done
|
| 7 |
+
echo "== teacher samples: $(ls /workspace/teacher /workspace/teacher2 | grep -c safetensors) shards $(date -u +%T)"
|
| 8 |
+
cd /workspace/code
|
| 9 |
+
N=$(nvidia-smi -L | wc -l)
|
| 10 |
+
torchrun --nproc-per-node "$N" -m rapid_moss.train --config configs/dmad.json
|
| 11 |
+
echo "== done $(date -u +%T)"
|
code/scripts/pod_setup.sh
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Runs on the pod: Python deps + model downloads into /workspace (idempotent).
|
| 3 |
+
set -euo pipefail
|
| 4 |
+
cd /workspace
|
| 5 |
+
export HF_HUB_ENABLE_HF_TRANSFER=0 HF_XET_HIGH_PERFORMANCE=1 PIP_BREAK_SYSTEM_PACKAGES=1
|
| 6 |
+
pip install -q --root-user-action=ignore "diffusers==0.38.0" "transformers==5.17.0" "accelerate>=1.10" \
|
| 7 |
+
"safetensors>=0.6" "huggingface_hub[hf_xet]>=1.0" pillow flash-linear-attention 2>&1 | tail -3
|
| 8 |
+
python - <<'EOF'
|
| 9 |
+
import torch, diffusers, transformers
|
| 10 |
+
print('torch', torch.__version__, 'cuda', torch.version.cuda, 'diffusers', diffusers.__version__,
|
| 11 |
+
'transformers', transformers.__version__, [torch.cuda.get_device_name(i) for i in range(torch.cuda.device_count())])
|
| 12 |
+
EOF
|
| 13 |
+
mkdir -p models
|
| 14 |
+
hf download OpenMOSS-Team/MOSS-Image-SFT --local-dir models/MOSS-Image-SFT --exclude "assets/*" > /dev/null
|
| 15 |
+
hf download lodestones/MOSS-Image-SFT-8-steps-dmd lora.safetensors time_embedding.safetensors dataspace.safetensors README.md \
|
| 16 |
+
--local-dir models/MOSS-Image-SFT-8-steps-dmd > /dev/null
|
| 17 |
+
du -sh models/*
|
| 18 |
+
md5sum models/MOSS-Image-SFT/pipeline_moss_image.py
|
code/scripts/pod_stop_train.sh
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# On the pod: stop the training run (torchrun + workers) and its pod_dmad.sh wrapper.
|
| 3 |
+
pkill -f "scripts/pod_dmad.sh"
|
| 4 |
+
pkill -f "rapid_moss.train"
|
| 5 |
+
sleep 5
|
| 6 |
+
pgrep -fa "rapid_moss.train" | head -3 || true
|
code/scripts/pod_teacher2.sh
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# On the pod: after the first teacher run finishes, generate more teacher samples for other prompts
|
| 3 |
+
# (small shards so a stop loses little; train.py scans shards directly).
|
| 4 |
+
while pgrep -f "rapid_moss.teachergen --model" > /dev/null; do sleep 15; done
|
| 5 |
+
cd /workspace/code
|
| 6 |
+
torchrun --nproc-per-node 8 -m rapid_moss.teachergen --model /workspace/models/MOSS-Image-SFT --cache /workspace/cache \
|
| 7 |
+
--prompts /workspace/prompts/train.jsonl --out /workspace/teacher2 --count 4000 --seed 8 --shard-size 25 \
|
| 8 |
+
--exclude /workspace/teacher/index.json
|
code/scripts/pssh.sh
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# ssh/rsync helpers for the pod in scripts/pod.env: pssh.sh CMD... | pssh.sh --push SRC DST | pssh.sh --pull SRC DST
|
| 3 |
+
set -euo pipefail
|
| 4 |
+
source "$(dirname "$0")/pod.env"
|
| 5 |
+
KEY=$HOME/.runpod/ssh/runpodctl-ssh-key
|
| 6 |
+
OPTS=(-i "$KEY" -p "$POD_PORT" -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=$HOME/.runpod/ssh/known_hosts -o ConnectTimeout=20 -o ServerAliveInterval=30)
|
| 7 |
+
if [[ "${1:-}" == --push ]]; then rsync -rlptz --no-owner --no-group --exclude .git -e "ssh ${OPTS[*]}" "$2" "root@$POD_HOST:$3"
|
| 8 |
+
elif [[ "${1:-}" == --pull ]]; then rsync -rlptz --no-owner --no-group --exclude .git -e "ssh ${OPTS[*]}" "root@$POD_HOST:$2" "$3"
|
| 9 |
+
else exec ssh "${OPTS[@]}" "root@$POD_HOST" "$@"; fi
|
code/scripts/runpod.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Minimal RunPod GraphQL client (API key from ~/.runpod/config.toml).
|
| 2 |
+
|
| 3 |
+
python scripts/runpod.py balance
|
| 4 |
+
python scripts/runpod.py gpus
|
| 5 |
+
python scripts/runpod.py create NAME --gpu "NVIDIA H100 80GB HBM3" --count 1 [--cloud COMMUNITY] [--volume 300]
|
| 6 |
+
python scripts/runpod.py status POD_ID # prints ssh target when running
|
| 7 |
+
python scripts/runpod.py stop POD_ID | terminate POD_ID
|
| 8 |
+
"""
|
| 9 |
+
import argparse
|
| 10 |
+
import json
|
| 11 |
+
import re
|
| 12 |
+
import sys
|
| 13 |
+
import time
|
| 14 |
+
import urllib.request
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
|
| 17 |
+
IMAGE = 'runpod/pytorch:1.4.1-cu1281-torch2130-ubuntu2404'
|
| 18 |
+
KEY_FILE = Path.home() / '.runpod' / 'ssh' / 'runpodctl-ssh-key'
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def api_key():
|
| 22 |
+
text = (Path.home() / '.runpod' / 'config.toml').read_text()
|
| 23 |
+
return re.search(r"apikey\s*=\s*['\"]([^'\"]+)", text).group(1)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def gql(query, variables=None):
|
| 27 |
+
req = urllib.request.Request('https://api.runpod.io/graphql',
|
| 28 |
+
data=json.dumps({'query': query, 'variables': variables or {}}).encode(),
|
| 29 |
+
headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {api_key()}',
|
| 30 |
+
'User-Agent': 'rapid-moss'})
|
| 31 |
+
with urllib.request.urlopen(req, timeout=60) as r:
|
| 32 |
+
out = json.load(r)
|
| 33 |
+
if out.get('errors'):
|
| 34 |
+
raise SystemExit(json.dumps(out['errors'], indent=1))
|
| 35 |
+
return out['data']
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def pod(pod_id):
|
| 39 |
+
return gql('query($id: String!) { pod(input: {podId: $id}) { id name desiredStatus costPerHr gpuCount '
|
| 40 |
+
'machine { gpuDisplayName location } runtime { uptimeInSeconds ports { ip isIpPublic privatePort '
|
| 41 |
+
'publicPort type } } } }', {'id': pod_id})['pod']
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def ssh_target(p):
|
| 45 |
+
for port in (p.get('runtime') or {}).get('ports') or []:
|
| 46 |
+
if port['privatePort'] == 22 and port['isIpPublic']:
|
| 47 |
+
return port['ip'], port['publicPort']
|
| 48 |
+
return None
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def main():
|
| 52 |
+
ap = argparse.ArgumentParser()
|
| 53 |
+
sub = ap.add_subparsers(dest='cmd', required=True)
|
| 54 |
+
sub.add_parser('balance')
|
| 55 |
+
sub.add_parser('gpus')
|
| 56 |
+
c = sub.add_parser('create')
|
| 57 |
+
c.add_argument('name')
|
| 58 |
+
c.add_argument('--gpu', default='NVIDIA H100 80GB HBM3')
|
| 59 |
+
c.add_argument('--count', type=int, default=1)
|
| 60 |
+
c.add_argument('--cloud', default='COMMUNITY')
|
| 61 |
+
c.add_argument('--volume', type=int, default=300)
|
| 62 |
+
c.add_argument('--disk', type=int, default=60)
|
| 63 |
+
for name in ('status', 'stop', 'terminate', 'wait'):
|
| 64 |
+
sub.add_parser(name).add_argument('pod_id')
|
| 65 |
+
a = ap.parse_args()
|
| 66 |
+
if a.cmd == 'balance':
|
| 67 |
+
print(json.dumps(gql('query { myself { clientBalance currentSpendPerHr pods { id name desiredStatus costPerHr } } }')['myself'], indent=1))
|
| 68 |
+
elif a.cmd == 'gpus':
|
| 69 |
+
data = gql('query { gpuTypes { id memoryInGb securePrice communityPrice lowestPrice(input:{gpuCount:1}) { stockStatus } } }')
|
| 70 |
+
for g in sorted(data['gpuTypes'], key=lambda g: -(g['memoryInGb'] or 0)):
|
| 71 |
+
if (g['memoryInGb'] or 0) >= 80:
|
| 72 |
+
print(f"{g['id']:<60} {g['memoryInGb']:>4} GB secure {g['securePrice']} community {g['communityPrice']} stock {(g['lowestPrice'] or {}).get('stockStatus')}")
|
| 73 |
+
elif a.cmd == 'create':
|
| 74 |
+
pub = KEY_FILE.with_suffix('.pub').read_text().strip()
|
| 75 |
+
q = ('mutation($in: PodFindAndDeployOnDemandInput) { podFindAndDeployOnDemand(input: $in) '
|
| 76 |
+
'{ id costPerHr machine { gpuDisplayName location } } }')
|
| 77 |
+
inp = {'cloudType': a.cloud, 'gpuCount': a.count, 'volumeInGb': a.volume, 'containerDiskInGb': a.disk,
|
| 78 |
+
'gpuTypeId': a.gpu, 'name': a.name, 'imageName': IMAGE, 'ports': '22/tcp',
|
| 79 |
+
'volumeMountPath': '/workspace', 'startSsh': True, 'supportPublicIp': True,
|
| 80 |
+
'minCudaVersion': '12.8', 'env': [{'key': 'PUBLIC_KEY', 'value': pub}]}
|
| 81 |
+
print(json.dumps(gql(q, {'in': inp})['podFindAndDeployOnDemand'], indent=1))
|
| 82 |
+
elif a.cmd == 'status':
|
| 83 |
+
p = pod(a.pod_id)
|
| 84 |
+
print(json.dumps(p, indent=1))
|
| 85 |
+
t = ssh_target(p)
|
| 86 |
+
if t:
|
| 87 |
+
print(f'ssh -i {KEY_FILE} -p {t[1]} root@{t[0]}')
|
| 88 |
+
elif a.cmd == 'wait':
|
| 89 |
+
for _ in range(120):
|
| 90 |
+
t = ssh_target(pod(a.pod_id))
|
| 91 |
+
if t:
|
| 92 |
+
print(f'{t[0]} {t[1]}')
|
| 93 |
+
return
|
| 94 |
+
time.sleep(10)
|
| 95 |
+
sys.exit('pod did not expose ssh in 20 min')
|
| 96 |
+
elif a.cmd == 'stop':
|
| 97 |
+
print(gql('mutation($id: String!) { podStop(input: {podId: $id}) { id desiredStatus } }', {'id': a.pod_id}))
|
| 98 |
+
elif a.cmd == 'terminate':
|
| 99 |
+
print(gql('mutation($id: String!) { podTerminate(input: {podId: $id}) }', {'id': a.pod_id}))
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
if __name__ == '__main__':
|
| 103 |
+
main()
|
code/scripts/watchdog.sh
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Local: stop the pod (keeps its volume) when the RunPod balance drops below $MIN (default 6).
|
| 3 |
+
cd "$(dirname "$0")/.."
|
| 4 |
+
source scripts/pod.env
|
| 5 |
+
MIN=${MIN:-6}
|
| 6 |
+
while true; do
|
| 7 |
+
OUT=$(nix shell nixpkgs#python3 -c python3 scripts/runpod.py balance 2>/dev/null) || { sleep 120; continue; }
|
| 8 |
+
BAL=$(echo "$OUT" | grep clientBalance | grep -o '[0-9.]*')
|
| 9 |
+
RUN=$(echo "$OUT" | grep -c '"RUNNING"')
|
| 10 |
+
echo "$(date +%T) balance=$BAL running=$RUN"
|
| 11 |
+
[[ "$RUN" == 0 ]] && { echo "no running pod, exit"; exit 0; }
|
| 12 |
+
if awk "BEGIN{exit !($BAL < $MIN)}"; then
|
| 13 |
+
echo "balance below $MIN, stopping $POD_ID"; nix shell nixpkgs#python3 -c python3 scripts/runpod.py stop "$POD_ID"; exit 0
|
| 14 |
+
fi
|
| 15 |
+
sleep 300
|
| 16 |
+
done
|
code/tests/test_dmad.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""CPU check of the DMAD critic wiring (fp32, tiny latent).
|
| 2 |
+
|
| 3 |
+
python tests/test_dmad.py MODEL_DIR LODESTONES_DIR
|
| 4 |
+
Generator phase (critic frozen): gradients reach the generator and nothing reaches the critic.
|
| 5 |
+
Critic phase: gradients reach the critic head and its LoRA B on blocks >= start only.
|
| 6 |
+
"""
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
import torch
|
| 10 |
+
from torch.nn import functional as F
|
| 11 |
+
|
| 12 |
+
import rapid_moss.model as M
|
| 13 |
+
from rapid_moss.nets import Critic, Generator
|
| 14 |
+
|
| 15 |
+
torch.manual_seed(0)
|
| 16 |
+
model_dir, lode_dir = sys.argv[1], sys.argv[2]
|
| 17 |
+
M.BF16 = torch.float32
|
| 18 |
+
release = M.load_release_module(model_dir)
|
| 19 |
+
tr = release.MOSSImageTransformer.from_pretrained(f'{model_dir}/transformer', torch_dtype=torch.float32,
|
| 20 |
+
local_files_only=True)
|
| 21 |
+
model = M.Moss(tr, release)
|
| 22 |
+
ctx = model.context(torch.randn(10, 4096) * 2)
|
| 23 |
+
z = torch.randn(1, 128, 4, 6)
|
| 24 |
+
|
| 25 |
+
gen = Generator(model, 128, 128, 4)
|
| 26 |
+
gen.load_lodestones(lode_dir)
|
| 27 |
+
critic = Critic(model, 16, 16, start=30, hidden=64)
|
| 28 |
+
assert critic.lora.A['q'].shape[0] == 12
|
| 29 |
+
|
| 30 |
+
# generator phase
|
| 31 |
+
critic.requires_grad_(False)
|
| 32 |
+
x0 = gen.step(model, z, gen.rollout(model, z, ctx, 1), 1, ctx, ckpt=True)
|
| 33 |
+
logit = critic(model, 0.6 * x0 + 0.4 * torch.randn_like(z), 400.0, ctx, ckpt=True)
|
| 34 |
+
assert logit.shape == (1,)
|
| 35 |
+
(-logit.mean()).backward()
|
| 36 |
+
assert all(p.grad is not None and p.grad.abs().sum() > 0 for p in gen.parameters()), 'generator grads missing'
|
| 37 |
+
assert all(p.grad is None for p in critic.parameters()), 'critic got generator-phase grads'
|
| 38 |
+
print('generator phase OK, logit', logit.item())
|
| 39 |
+
|
| 40 |
+
# critic phase
|
| 41 |
+
critic.requires_grad_(True)
|
| 42 |
+
for p in gen.parameters():
|
| 43 |
+
p.grad = None
|
| 44 |
+
d_q = critic(model, 0.5 * torch.randn_like(z) + 0.5 * z, 300.0, ctx, ckpt=True)
|
| 45 |
+
d_g = critic(model, 0.5 * x0.detach() + 0.5 * torch.randn_like(z), 300.0, ctx, ckpt=True)
|
| 46 |
+
(F.softplus(-d_q) + F.softplus(d_g)).mean().backward()
|
| 47 |
+
assert all(p.grad is None for p in gen.parameters()), 'generator got critic-phase grads'
|
| 48 |
+
assert all(p.grad.abs().sum() > 0 for p in critic.head.parameters()) and critic.out.weight.grad.abs().sum() > 0
|
| 49 |
+
b_rows = (critic.lora.B['q'].grad.flatten(1).abs().sum(1) > 0).tolist()
|
| 50 |
+
print('critic LoRA B grad per block (30..41):', b_rows)
|
| 51 |
+
assert all(b_rows)
|
| 52 |
+
print('OK')
|
code/tests/test_equiv.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""CPU check of rapid_moss.model against the release MOSSImageTransformer.
|
| 2 |
+
|
| 3 |
+
python tests/test_equiv.py MODEL_DIR LODESTONES_DIR
|
| 4 |
+
Runs everything in fp32 (rapid_moss.model.BF16 patched) so the logic must match to ~1e-5:
|
| 5 |
+
plain forward, negative-branch skip 22, the lodestones generator path (fp32 time path +
|
| 6 |
+
unmerged LoRA hooks, as its model card describes), discriminator taps and a gradient check.
|
| 7 |
+
"""
|
| 8 |
+
import sys
|
| 9 |
+
import time
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
from safetensors.torch import load_file
|
| 13 |
+
|
| 14 |
+
import rapid_moss.model as M
|
| 15 |
+
from rapid_moss.nets import Discriminator, FakeScore, Generator
|
| 16 |
+
|
| 17 |
+
torch.manual_seed(0)
|
| 18 |
+
model_dir, lode_dir = sys.argv[1], sys.argv[2]
|
| 19 |
+
M.BF16 = torch.float32
|
| 20 |
+
release = M.load_release_module(model_dir)
|
| 21 |
+
t0 = time.time()
|
| 22 |
+
tr = release.MOSSImageTransformer.from_pretrained(f'{model_dir}/transformer', torch_dtype=torch.float32,
|
| 23 |
+
local_files_only=True)
|
| 24 |
+
model = M.Moss(tr, release)
|
| 25 |
+
print(f'load {time.time() - t0:.1f}s')
|
| 26 |
+
|
| 27 |
+
h, w, L = 6, 10, 12
|
| 28 |
+
latent = torch.randn(1, 128, h, w)
|
| 29 |
+
emb = torch.randn(L, 4096) * 2
|
| 30 |
+
ctx = model.context(emb)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def rel(a, b):
|
| 34 |
+
return ((a - b).norm() / b.norm()).item()
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
with torch.no_grad():
|
| 38 |
+
for t in (999.0, 500.0, 37.0):
|
| 39 |
+
ref = tr(latent, t, emb[None]).sample.float()
|
| 40 |
+
got = model(latent, t, ctx)
|
| 41 |
+
print(f'forward t={t}: rel {rel(got, ref):.2e}')
|
| 42 |
+
assert rel(got, ref) < 1e-4
|
| 43 |
+
ref = tr(latent, 600.0, emb[None], skip_layers=[22]).sample.float()
|
| 44 |
+
got = model(latent, 600.0, ctx, skip=(22,))
|
| 45 |
+
print(f'skip22: rel {rel(got, ref):.2e} (vs no-skip {rel(got, model(latent, 600.0, ctx)):.2e})')
|
| 46 |
+
assert rel(got, ref) < 1e-4
|
| 47 |
+
|
| 48 |
+
# lodestones generator: release model + replaced time path + LoRA hooks (model card recipe)
|
| 49 |
+
gen = Generator(model, 128, 128, 4)
|
| 50 |
+
gen.load_lodestones(lode_dir)
|
| 51 |
+
te = load_file(f'{lode_dir}/time_embedding.safetensors')
|
| 52 |
+
lora = load_file(f'{lode_dir}/lora.safetensors')
|
| 53 |
+
import copy
|
| 54 |
+
tr2 = copy.deepcopy(tr)
|
| 55 |
+
tr2.load_state_dict(te, strict=False)
|
| 56 |
+
for i, layer in enumerate(tr2.layers):
|
| 57 |
+
for name, lin in layer.proj.items():
|
| 58 |
+
p = f'diffusion_model.layers.{i}.proj.{name}'
|
| 59 |
+
down, up, alpha = lora[p + '.lora_down.weight'], lora[p + '.lora_up.weight'], lora[p + '.alpha']
|
| 60 |
+
scale = float(alpha) / down.shape[0]
|
| 61 |
+
lin.register_forward_hook(lambda m, inp, out, d=down, u=up, s=scale: out + s * (inp[0] @ d.t()) @ u.t())
|
| 62 |
+
Q = load_file(f'{lode_dir}/dataspace.safetensors')['latent_mix.Q']
|
| 63 |
+
codes = load_file(f'{lode_dir}/dataspace.safetensors')['step_codes']
|
| 64 |
+
z = torch.randn(1, 128, h, w)
|
| 65 |
+
x0_ref = torch.zeros_like(z)
|
| 66 |
+
x0_got = torch.zeros_like(z)
|
| 67 |
+
for r in range(3):
|
| 68 |
+
x = z + torch.einsum('oc,bchw->bohw', Q, x0_ref)
|
| 69 |
+
x0_ref = z - tr2(x, codes[r], emb[None]).sample.float()
|
| 70 |
+
x0_got = gen.step(model, z, x0_got, r, ctx)
|
| 71 |
+
print(f'generator r={r}: rel {rel(x0_got, x0_ref):.2e}')
|
| 72 |
+
assert rel(x0_got, x0_ref) < 1e-4
|
| 73 |
+
del tr2
|
| 74 |
+
|
| 75 |
+
disc = Discriminator(model.dim, (5, 11), 256)
|
| 76 |
+
feats = model(latent, 300.0, ctx, taps=disc.taps)
|
| 77 |
+
print('taps', {k: tuple(v.shape) for k, v in feats.items()}, 'logits', tuple(disc(feats, h, w).shape))
|
| 78 |
+
|
| 79 |
+
# gradients: generator step through checkpointed blocks, fake score, D input-gradient
|
| 80 |
+
fake = FakeScore(model, 16, 16, 4)
|
| 81 |
+
x0 = gen.step(model, z, torch.randn_like(z), 1, ctx, ckpt=True)
|
| 82 |
+
x0.backward(torch.randn_like(x0))
|
| 83 |
+
nz = {n: p.grad.abs().sum().item() > 0 for n, p in gen.named_parameters()}
|
| 84 |
+
print('gen grads nonzero:', all(nz.values()), [n for n, v in nz.items() if not v][:5])
|
| 85 |
+
assert all(nz.values())
|
| 86 |
+
v = fake(model, latent, 400.0, ctx, 2, ckpt=True)
|
| 87 |
+
v.square().mean().backward()
|
| 88 |
+
print('fake r_emb grad rows nonzero:', (fake.r_emb.grad.abs().sum(1) > 0).tolist())
|
| 89 |
+
leaf = latent.clone().requires_grad_(True)
|
| 90 |
+
g, = torch.autograd.grad(-disc(model(leaf, 300.0, ctx, taps=disc.taps, ckpt=True), h, w).mean(), leaf)
|
| 91 |
+
print('D input grad norm', g.norm().item())
|
| 92 |
+
assert g.norm() > 0
|
| 93 |
+
print('OK')
|
dataspace.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d19f0e695bb26886cfce57441fd412f358e159d6eec8555ec1a71daaf30a7968
|
| 3 |
+
size 65784
|
eval/eval_prompts.jsonl
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"id": "anime-girl", "src": "eval", "prompt": "A high-quality anime illustration of a girl with long silver hair and teal eyes, wearing a yellow raincoat, standing at a rainy bus stop at night, neon reflections on wet asphalt, detailed cel shading, Japanese anime style", "w": 1024, "h": 1024}
|
| 2 |
+
{"id": "anime-tags", "src": "eval", "prompt": "1girl, solo, school uniform, cherry blossoms, wind, smile, looking at viewer, anime style, masterpiece, best quality, detailed eyes, spring, blue sky", "w": 1024, "h": 1024}
|
| 3 |
+
{"id": "chibi", "src": "eval", "prompt": "A cute chibi anime character, a small fox girl with big round eyes holding a strawberry daifuku, pastel colors, white background, sticker style illustration", "w": 1024, "h": 1024}
|
| 4 |
+
{"id": "thick-paint", "src": "eval", "prompt": "Painterly semi-realistic anime illustration of a swordsman in a bamboo forest at dawn, dramatic lighting, thick brush strokes, Japanese fantasy key visual", "w": 1024, "h": 1024}
|
| 5 |
+
{"id": "manga-mono", "src": "eval", "prompt": "Black and white Japanese manga panel, screentone shading, a high school boy running on a rooftop with speed lines, dynamic perspective, ink lineart", "w": 1024, "h": 1024}
|
| 6 |
+
{"id": "jp-sign", "src": "eval", "prompt": "A traditional Japanese ramen shop at night, a wooden sign above the door clearly reads \"麺処 はやて\" in bold brush calligraphy, a red paper lantern with the text \"営業中\"", "w": 1024, "h": 1024}
|
| 7 |
+
{"id": "jp-bubble", "src": "eval", "prompt": "An anime illustration of a girl surprised in a classroom, with a white manga speech bubble that says \"えっ、本当に!?\" in clear Japanese text", "w": 1024, "h": 1024}
|
| 8 |
+
{"id": "jp-note", "src": "eval", "prompt": "A close-up of a handwritten sticky note on a refrigerator, written in Japanese: \"牛乳を買う\n卵は二パック\n夜七時に帰ります\"", "w": 1024, "h": 1024}
|
| 9 |
+
{"id": "jp-cover", "src": "eval", "prompt": "A light novel cover illustration, anime girl mage casting a spell, the title text \"疾風の魔導書\" in large stylized Japanese letters at the top, and \"第一巻\" in the corner", "w": 1024, "h": 1024}
|
| 10 |
+
{"id": "jp-poster", "src": "eval", "prompt": "A Japanese summer festival poster, fireworks over a river, vertical text on the right side reading \"夏祭り 花火大会\" and the date \"八月十五日\" at the bottom", "w": 1024, "h": 1024}
|
| 11 |
+
{"id": "layout-manga", "src": "eval", "prompt": "{\"summary\": {\"meta\": [\"manga\"], \"canvas\": \"single\", \"caption\": \"A two-panel anime manga page in color. Top panel: a girl with short black hair waves at a friend in front of a school gate in the morning. Bottom panel: her friend, a girl with long brown hair, smiles back. Each panel has a white speech bubble with Japanese text.\"}, \"items\": [{\"label\": \"object\", \"caption\": \"Top panel: a girl with short black hair in a sailor school uniform waving, school gate behind her.\", \"bbox\": [-512, -512, -16, 512]}, {\"label\": \"object\", \"caption\": \"Bottom panel: a girl with long brown hair in a sailor school uniform smiling.\", \"bbox\": [16, -512, 512, 512]}, {\"label\": \"text\", \"caption\": \"Black Japanese text inside a white round speech bubble at the top right of the top panel.\", \"text\": \"おはよう!\", \"bbox\": [-460, 180, -330, 460]}, {\"label\": \"text\", \"caption\": \"Black Japanese text inside a white round speech bubble at the bottom left of the bottom panel.\", \"text\": \"今日もいい天気だね\", \"bbox\": [300, -470, 440, -80]}], \"bbox_coord_space\": \"abs_centralized\", \"bbox_format\": \"yxyx\"}", "w": 1024, "h": 1024}
|
| 12 |
+
{"id": "rain-neon", "src": "eval", "prompt": "masterpiece, best quality, highres, 1girl, solo, long silver hair, glowing blue eyes, oversized black hoodie, holding a transparent umbrella, neon-lit Tokyo alley at night, heavy rain, reflections on wet ground, cinematic lighting, depth of field, light particles, detailed background, vibrant colors", "w": 832, "h": 1216}
|
| 13 |
+
{"id": "sky-flight", "src": "eval", "prompt": "A breathtaking anime key visual of a girl in a white sundress jumping off a cliff into a vast summer sky, dynamic low-angle perspective, towering cumulonimbus clouds, sunbeams, flying birds, hair and dress fluttering in the wind, ultra detailed, vivid saturated colors, sense of freedom", "w": 832, "h": 1216}
|
| 14 |
+
{"id": "duo-fantasy", "src": "eval", "prompt": "masterpiece, best quality, 2girls, fantasy, a knight girl with golden armor and a witch girl with a large hat standing back to back, magic circles glowing around them, battlefield with ruins, dramatic rim lighting, sparks, highly detailed armor and fabric, epic composition", "w": 832, "h": 1216}
|
| 15 |
+
{"id": "wafu", "src": "eval", "prompt": "Japanese-style fantasy illustration of a fox spirit shrine maiden with white hair and red eyes, nine fluffy tails, holding a paper lantern, red torii gates at night, falling maple leaves, blue will-o'-the-wisps, intricate kimono patterns, highly detailed, soft glowing light", "w": 832, "h": 1216}
|
| 16 |
+
{"id": "transparent", "src": "eval", "prompt": "A delicate anime illustration with a transparent watercolor feeling, a girl with light blue hair lying in shallow water surrounded by floating flowers and small fish, sunlight caustics, pastel colors, soft focus, dreamy atmosphere, extremely detailed eyes", "w": 832, "h": 1216}
|
| 17 |
+
{"id": "scenery", "src": "eval", "prompt": "best quality, highres, scenery, 1girl, small figure, standing on a railway platform in the countryside at sunset, an old train arriving, power lines, summer clouds, orange and purple sky, lens flare, nostalgic atmosphere, highly detailed background art", "w": 832, "h": 1216}
|
images/compare-1.jpg
ADDED
|
Git LFS Details
|
images/compare-2.jpg
ADDED
|
Git LFS Details
|
images/compare-3.jpg
ADDED
|
Git LFS Details
|
images/training/000300.jpg
ADDED
|
Git LFS Details
|
images/training/000500.jpg
ADDED
|
Git LFS Details
|
images/training/000800.jpg
ADDED
|
Git LFS Details
|
images/training/init.jpg
ADDED
|
Git LFS Details
|
inference.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""4-step MOSS-Image-SFT with the rapid-moss adapter (data-space sampler, no CFG).
|
| 2 |
+
|
| 3 |
+
pip install "diffusers>=0.38" "transformers>=5.3" accelerate safetensors huggingface_hub pillow
|
| 4 |
+
python inference.py --prompt "an anime girl in a yellow raincoat at a rainy bus stop" --out out.png
|
| 5 |
+
|
| 6 |
+
The base stays bf16; the LoRA is applied unmerged in fp32 (its delta is smaller than bf16 rounding),
|
| 7 |
+
and the step embedder + modulation biases are replaced by fp32 tensors. Sampler:
|
| 8 |
+
x0 = 0; for r in range(steps): x = z + Q x0; x0 = z - transformer(x, codes[r], text)
|
| 9 |
+
with one fixed noise z, no noise re-injection and no timestep schedule.
|
| 10 |
+
"""
|
| 11 |
+
import argparse
|
| 12 |
+
import os
|
| 13 |
+
|
| 14 |
+
import torch
|
| 15 |
+
from diffusers import DiffusionPipeline
|
| 16 |
+
from huggingface_hub import snapshot_download
|
| 17 |
+
from safetensors.torch import load_file
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def load(base, adapter, device):
|
| 21 |
+
custom = os.path.join(base, 'pipeline_moss_image.py') if os.path.isdir(base) else 'pipeline_moss_image'
|
| 22 |
+
pipe = DiffusionPipeline.from_pretrained(base, custom_pipeline=custom, trust_remote_code=True,
|
| 23 |
+
torch_dtype={'default': torch.bfloat16, 'vae': torch.float32})
|
| 24 |
+
pipe.to(device)
|
| 25 |
+
tr = pipe.transformer
|
| 26 |
+
if not os.path.isdir(adapter):
|
| 27 |
+
adapter = snapshot_download(adapter, allow_patterns=['*.safetensors'])
|
| 28 |
+
for name in ('time_embedding', 'shared_block_modulation', 'video_head_modulation'):
|
| 29 |
+
getattr(tr, name).float()
|
| 30 |
+
time_path = load_file(os.path.join(adapter, 'time_embedding.safetensors'), device=str(device))
|
| 31 |
+
result = tr.load_state_dict(time_path, strict=False)
|
| 32 |
+
assert not result.unexpected_keys, result.unexpected_keys
|
| 33 |
+
lora = load_file(os.path.join(adapter, 'lora.safetensors'), device=str(device))
|
| 34 |
+
for i, layer in enumerate(tr.layers):
|
| 35 |
+
for name, lin in layer.proj.items():
|
| 36 |
+
key = f'diffusion_model.layers.{i}.proj.{name}'
|
| 37 |
+
down, up = lora[key + '.lora_down.weight'], lora[key + '.lora_up.weight']
|
| 38 |
+
scale = float(lora[key + '.alpha']) / down.shape[0]
|
| 39 |
+
|
| 40 |
+
def hook(module, inputs, output, down=down, up=up, scale=scale):
|
| 41 |
+
return output + (scale * ((inputs[0].float() @ down.t()) @ up.t())).to(output.dtype)
|
| 42 |
+
lin.register_forward_hook(hook)
|
| 43 |
+
ds = load_file(os.path.join(adapter, 'dataspace.safetensors'), device=str(device))
|
| 44 |
+
return pipe, ds['latent_mix.Q'], ds['step_codes']
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
@torch.no_grad()
|
| 48 |
+
def generate(pipe, Q, codes, prompt, width, height, steps, seed):
|
| 49 |
+
device = pipe._execution_device
|
| 50 |
+
emb, mask = pipe.encode_prompt(prompt)
|
| 51 |
+
z = torch.randn(1, 128, height // 16, width // 16, generator=torch.Generator('cpu').manual_seed(seed)).to(device)
|
| 52 |
+
x0 = torch.zeros_like(z)
|
| 53 |
+
for r in range(steps):
|
| 54 |
+
x = z + torch.einsum('oc,bchw->bohw', Q, x0)
|
| 55 |
+
x0 = z - pipe.transformer(x, codes[r], emb, mask).sample.float()
|
| 56 |
+
vae = pipe.vae
|
| 57 |
+
lat = x0.to(vae.dtype)
|
| 58 |
+
bn, eps = vae.bn, vae.config.batch_norm_eps
|
| 59 |
+
lat = lat * (bn.running_var + eps).sqrt().view(1, -1, 1, 1) + bn.running_mean.view(1, -1, 1, 1)
|
| 60 |
+
b, c, h, w = lat.shape
|
| 61 |
+
lat = lat.reshape(b, c // 4, 2, 2, h, w).permute(0, 1, 4, 2, 5, 3).reshape(b, c // 4, 2 * h, 2 * w)
|
| 62 |
+
image = vae.decode(lat, return_dict=False)[0].clamp(-1, 1)
|
| 63 |
+
return pipe.image_processor.postprocess(image, output_type='pil')[0]
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def main():
|
| 67 |
+
ap = argparse.ArgumentParser()
|
| 68 |
+
ap.add_argument('--prompt', required=True, help='natural language, tags or a MOSS JSON layout string')
|
| 69 |
+
ap.add_argument('--width', type=int, default=1024)
|
| 70 |
+
ap.add_argument('--height', type=int, default=1024)
|
| 71 |
+
ap.add_argument('--steps', type=int, default=4, help='1-4; each prefix of the 4 steps is trained')
|
| 72 |
+
ap.add_argument('--seed', type=int, default=42)
|
| 73 |
+
ap.add_argument('--out', default='out.png')
|
| 74 |
+
ap.add_argument('--base', default='OpenMOSS-Team/MOSS-Image-SFT')
|
| 75 |
+
ap.add_argument('--adapter', default='darask0/rapid-moss')
|
| 76 |
+
ap.add_argument('--device', default='cuda')
|
| 77 |
+
args = ap.parse_args()
|
| 78 |
+
if args.width % 16 or args.height % 16:
|
| 79 |
+
raise SystemExit('width and height must be multiples of 16')
|
| 80 |
+
pipe, Q, codes = load(args.base, args.adapter, torch.device(args.device))
|
| 81 |
+
if not 1 <= args.steps <= len(codes):
|
| 82 |
+
raise SystemExit(f'steps must be 1..{len(codes)}')
|
| 83 |
+
generate(pipe, Q, codes, args.prompt, args.width, args.height, args.steps, args.seed).save(args.out)
|
| 84 |
+
print(args.out)
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
if __name__ == '__main__':
|
| 88 |
+
main()
|
logs/baseline_timings_h100.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"MOSS-Image-SFT-8-steps-dmd-4step": 0.805,
|
| 3 |
+
"MOSS-Image-SFT-8-steps-dmd-8step": 1.544,
|
| 4 |
+
"teacher50-cfg3": 16.188
|
| 5 |
+
}
|
logs/dmad_config.json
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_dir": "/workspace/models/MOSS-Image-SFT",
|
| 3 |
+
"lodestones_dir": "/workspace/models/MOSS-Image-SFT-8-steps-dmd",
|
| 4 |
+
"cache_dir": "/workspace/cache",
|
| 5 |
+
"prompts": "/workspace/prompts/train.jsonl",
|
| 6 |
+
"eval_prompts": "/workspace/prompts/eval.jsonl",
|
| 7 |
+
"out_dir": "/workspace/runs/dmad",
|
| 8 |
+
"steps": 4,
|
| 9 |
+
"gen_rank": 128,
|
| 10 |
+
"gen_alpha": 128,
|
| 11 |
+
"fake_rank": 64,
|
| 12 |
+
"fake_alpha": 64,
|
| 13 |
+
"disc_taps": [
|
| 14 |
+
5,
|
| 15 |
+
11,
|
| 16 |
+
17,
|
| 17 |
+
23,
|
| 18 |
+
29,
|
| 19 |
+
35
|
| 20 |
+
],
|
| 21 |
+
"disc_hidden": 256,
|
| 22 |
+
"iterations": 2500,
|
| 23 |
+
"micro": 2,
|
| 24 |
+
"fake_per_gen": 2,
|
| 25 |
+
"fake_warmup": 200,
|
| 26 |
+
"lr_gen": 2e-05,
|
| 27 |
+
"lr_time": 2e-05,
|
| 28 |
+
"lr_q": 2e-05,
|
| 29 |
+
"lr_fake": 0.0001,
|
| 30 |
+
"lr_disc": 5e-05,
|
| 31 |
+
"betas": [
|
| 32 |
+
0.0,
|
| 33 |
+
0.99
|
| 34 |
+
],
|
| 35 |
+
"ema": 0.998,
|
| 36 |
+
"cfg": [
|
| 37 |
+
3.0,
|
| 38 |
+
3.0
|
| 39 |
+
],
|
| 40 |
+
"skip_neg": [
|
| 41 |
+
22
|
| 42 |
+
],
|
| 43 |
+
"tau_beta": [
|
| 44 |
+
2.5,
|
| 45 |
+
1.0
|
| 46 |
+
],
|
| 47 |
+
"tau_clamp": [
|
| 48 |
+
0.03,
|
| 49 |
+
0.985
|
| 50 |
+
],
|
| 51 |
+
"dt": 0.015625,
|
| 52 |
+
"adv_weight": 0.5,
|
| 53 |
+
"adv_start": 50,
|
| 54 |
+
"adv_warmup": 200,
|
| 55 |
+
"disc_real": "adm",
|
| 56 |
+
"teacher_dir": [
|
| 57 |
+
"/workspace/teacher",
|
| 58 |
+
"/workspace/teacher2"
|
| 59 |
+
],
|
| 60 |
+
"p_gan": 0.5,
|
| 61 |
+
"gan_t": [
|
| 62 |
+
0.02,
|
| 63 |
+
0.98
|
| 64 |
+
],
|
| 65 |
+
"clip_gen": 0.0,
|
| 66 |
+
"buckets": [
|
| 67 |
+
[
|
| 68 |
+
1024,
|
| 69 |
+
1024,
|
| 70 |
+
0.35
|
| 71 |
+
],
|
| 72 |
+
[
|
| 73 |
+
896,
|
| 74 |
+
1152,
|
| 75 |
+
0.15
|
| 76 |
+
],
|
| 77 |
+
[
|
| 78 |
+
832,
|
| 79 |
+
1216,
|
| 80 |
+
0.15
|
| 81 |
+
],
|
| 82 |
+
[
|
| 83 |
+
1152,
|
| 84 |
+
896,
|
| 85 |
+
0.1
|
| 86 |
+
],
|
| 87 |
+
[
|
| 88 |
+
1216,
|
| 89 |
+
832,
|
| 90 |
+
0.1
|
| 91 |
+
],
|
| 92 |
+
[
|
| 93 |
+
768,
|
| 94 |
+
1344,
|
| 95 |
+
0.075
|
| 96 |
+
],
|
| 97 |
+
[
|
| 98 |
+
1344,
|
| 99 |
+
768,
|
| 100 |
+
0.075
|
| 101 |
+
]
|
| 102 |
+
],
|
| 103 |
+
"method": "dmad",
|
| 104 |
+
"critic_rank": 128,
|
| 105 |
+
"critic_alpha": 128,
|
| 106 |
+
"critic_start": 21,
|
| 107 |
+
"critic_hidden": 512,
|
| 108 |
+
"critic_shift": 5.0,
|
| 109 |
+
"critic_sigma": [
|
| 110 |
+
0.02,
|
| 111 |
+
0.98
|
| 112 |
+
],
|
| 113 |
+
"lr_critic": 4e-05,
|
| 114 |
+
"wd_critic": 0.01,
|
| 115 |
+
"critic_warmup": 50,
|
| 116 |
+
"ckpt": true,
|
| 117 |
+
"seed": 0,
|
| 118 |
+
"log_every": 10,
|
| 119 |
+
"sample_every": 100,
|
| 120 |
+
"save_every": 200,
|
| 121 |
+
"export_every": 500,
|
| 122 |
+
"eval_count": 8,
|
| 123 |
+
"eval_seed": 1234
|
| 124 |
+
}
|
logs/dmad_train_log.jsonl
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"it": 10, "gen_updates": 0, "s_per_it": 3.51, "mem_gib": 20.4, "c_acc": 0.503125, "c_loss": 1.472324, "d_gen": -0.026185, "d_teacher": 0.02548, "g_logit": 0.0}
|
| 2 |
+
{"it": 20, "gen_updates": 0, "s_per_it": 3.4, "mem_gib": 20.4, "c_acc": 0.55, "c_loss": 1.393549, "d_gen": -0.070432, "d_teacher": 0.090518, "g_logit": 0.0}
|
| 3 |
+
{"it": 30, "gen_updates": 0, "s_per_it": 3.41, "mem_gib": 20.4, "c_acc": 0.5875, "c_loss": 1.374437, "d_gen": -0.295139, "d_teacher": 0.018142, "g_logit": 0.0}
|
| 4 |
+
{"it": 40, "gen_updates": 0, "s_per_it": 3.53, "mem_gib": 20.4, "c_acc": 0.640625, "c_loss": 1.303367, "d_gen": -0.228213, "d_teacher": 0.229624, "g_logit": 0.0}
|
| 5 |
+
{"it": 50, "gen_updates": 0, "s_per_it": 3.44, "mem_gib": 20.5, "c_acc": 0.65625, "c_loss": 1.230491, "d_gen": -0.380138, "d_teacher": 0.359761, "g_logit": 0.0}
|
| 6 |
+
{"it": 60, "gen_updates": 10, "s_per_it": 5.85, "mem_gib": 24.9, "c_acc": 0.60625, "c_loss": 1.320506, "d_gen": -0.204005, "d_teacher": 0.280464, "g_logit": -0.257044, "gnorm": 344.827544}
|
| 7 |
+
{"it": 70, "gen_updates": 20, "s_per_it": 5.89, "mem_gib": 24.9, "c_acc": 0.6125, "c_loss": 1.321517, "d_gen": -0.27649, "d_teacher": 0.113134, "g_logit": -0.267412, "gnorm": 169.696696}
|
| 8 |
+
{"it": 80, "gen_updates": 30, "s_per_it": 5.89, "mem_gib": 24.9, "c_acc": 0.61875, "c_loss": 1.258887, "d_gen": -0.346907, "d_teacher": 0.261502, "g_logit": -0.35437, "gnorm": 634.010178}
|
| 9 |
+
{"it": 90, "gen_updates": 40, "s_per_it": 5.76, "mem_gib": 24.9, "c_acc": 0.678125, "c_loss": 1.195195, "d_gen": -0.554969, "d_teacher": 0.365944, "g_logit": -0.459122, "gnorm": 157.662113}
|
| 10 |
+
{"it": 100, "gen_updates": 50, "s_per_it": 5.86, "mem_gib": 24.9, "c_acc": 0.65, "c_loss": 1.271955, "d_gen": -0.339471, "d_teacher": 0.444618, "g_logit": -0.380601, "gnorm": 398.204028}
|
| 11 |
+
{"it": 110, "gen_updates": 60, "s_per_it": 6.82, "mem_gib": 24.9, "c_acc": 0.703125, "c_loss": 1.135317, "d_gen": -0.523898, "d_teacher": 0.40571, "g_logit": -0.523776, "gnorm": 515.074624}
|
| 12 |
+
{"it": 120, "gen_updates": 70, "s_per_it": 5.75, "mem_gib": 24.9, "c_acc": 0.7, "c_loss": 1.107486, "d_gen": -0.584106, "d_teacher": 0.698363, "g_logit": -0.60042, "gnorm": 555.140576}
|
| 13 |
+
{"it": 130, "gen_updates": 80, "s_per_it": 5.81, "mem_gib": 24.9, "c_acc": 0.70625, "c_loss": 1.103744, "d_gen": -0.60869, "d_teacher": 0.821214, "g_logit": -0.620043, "gnorm": 425.754166}
|
| 14 |
+
{"it": 140, "gen_updates": 90, "s_per_it": 5.71, "mem_gib": 24.9, "c_acc": 0.784375, "c_loss": 0.8933, "d_gen": -1.041128, "d_teacher": 0.990952, "g_logit": -0.890582, "gnorm": 666.534967}
|
| 15 |
+
{"it": 150, "gen_updates": 100, "s_per_it": 5.76, "mem_gib": 24.9, "c_acc": 0.78125, "c_loss": 0.887413, "d_gen": -1.197625, "d_teacher": 0.985895, "g_logit": -1.082821, "gnorm": 379.410664}
|
| 16 |
+
{"it": 160, "gen_updates": 110, "s_per_it": 5.72, "mem_gib": 24.9, "c_acc": 0.790625, "c_loss": 0.856912, "d_gen": -1.541816, "d_teacher": 1.098191, "g_logit": -1.66994, "gnorm": 449.519646}
|
| 17 |
+
{"it": 170, "gen_updates": 120, "s_per_it": 5.7, "mem_gib": 24.9, "c_acc": 0.790625, "c_loss": 0.91846, "d_gen": -1.285428, "d_teacher": 1.172357, "g_logit": -1.261887, "gnorm": 269.401883}
|
| 18 |
+
{"it": 180, "gen_updates": 130, "s_per_it": 5.77, "mem_gib": 24.9, "c_acc": 0.84375, "c_loss": 0.797819, "d_gen": -1.637835, "d_teacher": 1.326887, "g_logit": -1.754513, "gnorm": 2882.158878}
|
| 19 |
+
{"it": 190, "gen_updates": 140, "s_per_it": 5.77, "mem_gib": 24.9, "c_acc": 0.825, "c_loss": 0.761074, "d_gen": -1.504383, "d_teacher": 1.440473, "g_logit": -1.562236, "gnorm": 861.8714}
|
| 20 |
+
{"it": 200, "gen_updates": 150, "s_per_it": 5.74, "mem_gib": 24.9, "c_acc": 0.91875, "c_loss": 0.463252, "d_gen": -2.063986, "d_teacher": 1.998507, "g_logit": -1.98676, "gnorm": 318.910345}
|
| 21 |
+
{"it": 210, "gen_updates": 160, "s_per_it": 7.69, "mem_gib": 24.9, "c_acc": 0.8375, "c_loss": 0.818473, "d_gen": -1.431804, "d_teacher": 1.621684, "g_logit": -1.605268, "gnorm": 399.719297}
|
| 22 |
+
{"it": 220, "gen_updates": 170, "s_per_it": 5.71, "mem_gib": 24.9, "c_acc": 0.85, "c_loss": 0.717284, "d_gen": -1.603106, "d_teacher": 1.577599, "g_logit": -1.603056, "gnorm": 452.001189}
|
| 23 |
+
{"it": 230, "gen_updates": 180, "s_per_it": 5.69, "mem_gib": 24.9, "c_acc": 0.875, "c_loss": 0.64667, "d_gen": -1.80143, "d_teacher": 1.676809, "g_logit": -1.889914, "gnorm": 366.318943}
|
| 24 |
+
{"it": 240, "gen_updates": 190, "s_per_it": 5.66, "mem_gib": 24.9, "c_acc": 0.8625, "c_loss": 0.639551, "d_gen": -1.8087, "d_teacher": 1.857835, "g_logit": -1.802448, "gnorm": 605.091997}
|
| 25 |
+
{"it": 250, "gen_updates": 200, "s_per_it": 5.71, "mem_gib": 24.9, "c_acc": 0.90625, "c_loss": 0.545975, "d_gen": -2.125394, "d_teacher": 1.798105, "g_logit": -2.117861, "gnorm": 649.524585}
|
| 26 |
+
{"it": 260, "gen_updates": 210, "s_per_it": 5.74, "mem_gib": 24.9, "c_acc": 0.9125, "c_loss": 0.484202, "d_gen": -2.16631, "d_teacher": 2.169687, "g_logit": -2.021578, "gnorm": 499.114932}
|
| 27 |
+
{"it": 270, "gen_updates": 220, "s_per_it": 5.7, "mem_gib": 24.9, "c_acc": 0.959375, "c_loss": 0.270355, "d_gen": -2.670422, "d_teacher": 2.456078, "g_logit": -2.582783, "gnorm": 495.963659}
|
| 28 |
+
{"it": 280, "gen_updates": 230, "s_per_it": 5.67, "mem_gib": 24.9, "c_acc": 0.925, "c_loss": 0.35589, "d_gen": -2.598104, "d_teacher": 2.468642, "g_logit": -2.570019, "gnorm": 357.345479}
|
| 29 |
+
{"it": 290, "gen_updates": 240, "s_per_it": 5.72, "mem_gib": 24.9, "c_acc": 0.978125, "c_loss": 0.224288, "d_gen": -3.003006, "d_teacher": 2.784076, "g_logit": -2.92619, "gnorm": 74.857542}
|
| 30 |
+
{"it": 300, "gen_updates": 250, "s_per_it": 5.69, "mem_gib": 24.9, "c_acc": 0.9875, "c_loss": 0.142997, "d_gen": -3.190769, "d_teacher": 3.069393, "g_logit": -3.20608, "gnorm": 69.31735}
|
| 31 |
+
{"it": 310, "gen_updates": 260, "s_per_it": 6.64, "mem_gib": 24.9, "c_acc": 0.9, "c_loss": 0.551212, "d_gen": -2.347602, "d_teacher": 2.404747, "g_logit": -2.188123, "gnorm": 342.295467}
|
| 32 |
+
{"it": 320, "gen_updates": 270, "s_per_it": 5.68, "mem_gib": 24.9, "c_acc": 0.91875, "c_loss": 0.433934, "d_gen": -2.529411, "d_teacher": 2.414225, "g_logit": -2.553354, "gnorm": 206.773278}
|
| 33 |
+
{"it": 330, "gen_updates": 280, "s_per_it": 5.7, "mem_gib": 24.9, "c_acc": 0.84375, "c_loss": 0.779442, "d_gen": -1.927769, "d_teacher": 1.969032, "g_logit": -2.008004, "gnorm": 551.766666}
|
| 34 |
+
{"it": 340, "gen_updates": 290, "s_per_it": 5.64, "mem_gib": 24.9, "c_acc": 0.85625, "c_loss": 0.71635, "d_gen": -1.580061, "d_teacher": 1.732232, "g_logit": -1.535344, "gnorm": 572.014401}
|
| 35 |
+
{"it": 350, "gen_updates": 300, "s_per_it": 5.7, "mem_gib": 24.9, "c_acc": 0.784375, "c_loss": 0.976114, "d_gen": -1.113697, "d_teacher": 0.95776, "g_logit": -1.236905, "gnorm": 1454.895154}
|
| 36 |
+
{"it": 360, "gen_updates": 310, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.765625, "c_loss": 0.824124, "d_gen": -1.330074, "d_teacher": 1.316943, "g_logit": -1.403452, "gnorm": 1251.758484}
|
| 37 |
+
{"it": 370, "gen_updates": 320, "s_per_it": 5.64, "mem_gib": 24.9, "c_acc": 0.696875, "c_loss": 1.100472, "d_gen": -0.896046, "d_teacher": 0.928468, "g_logit": -0.96601, "gnorm": 605.353458}
|
| 38 |
+
{"it": 380, "gen_updates": 330, "s_per_it": 5.68, "mem_gib": 24.9, "c_acc": 0.778125, "c_loss": 0.887347, "d_gen": -1.422161, "d_teacher": 1.172825, "g_logit": -1.269689, "gnorm": 1429.191895}
|
| 39 |
+
{"it": 390, "gen_updates": 340, "s_per_it": 5.67, "mem_gib": 24.9, "c_acc": 0.8625, "c_loss": 0.707317, "d_gen": -1.915341, "d_teacher": 1.878058, "g_logit": -1.860343, "gnorm": 797.769325}
|
| 40 |
+
{"it": 400, "gen_updates": 350, "s_per_it": 5.67, "mem_gib": 24.9, "c_acc": 0.734375, "c_loss": 0.974438, "d_gen": -1.03391, "d_teacher": 1.058606, "g_logit": -0.970323, "gnorm": 591.646497}
|
| 41 |
+
{"it": 410, "gen_updates": 360, "s_per_it": 7.69, "mem_gib": 24.9, "c_acc": 0.79375, "c_loss": 0.89193, "d_gen": -1.427567, "d_teacher": 1.424491, "g_logit": -1.53325, "gnorm": 596.328967}
|
| 42 |
+
{"it": 420, "gen_updates": 370, "s_per_it": 5.71, "mem_gib": 24.9, "c_acc": 0.778125, "c_loss": 0.843672, "d_gen": -1.146293, "d_teacher": 1.200306, "g_logit": -1.091098, "gnorm": 491.311426}
|
| 43 |
+
{"it": 430, "gen_updates": 380, "s_per_it": 5.63, "mem_gib": 24.9, "c_acc": 0.80625, "c_loss": 0.798015, "d_gen": -1.562343, "d_teacher": 1.305641, "g_logit": -1.485226, "gnorm": 969.241519}
|
| 44 |
+
{"it": 440, "gen_updates": 390, "s_per_it": 5.67, "mem_gib": 24.9, "c_acc": 0.80625, "c_loss": 0.867097, "d_gen": -1.602022, "d_teacher": 1.307751, "g_logit": -1.710642, "gnorm": 1851.946349}
|
| 45 |
+
{"it": 450, "gen_updates": 400, "s_per_it": 5.66, "mem_gib": 24.9, "c_acc": 0.84375, "c_loss": 0.640278, "d_gen": -1.727461, "d_teacher": 1.752258, "g_logit": -1.790782, "gnorm": 1126.413405}
|
| 46 |
+
{"it": 460, "gen_updates": 410, "s_per_it": 5.63, "mem_gib": 24.9, "c_acc": 0.859375, "c_loss": 0.608079, "d_gen": -1.933124, "d_teacher": 1.953212, "g_logit": -2.132834, "gnorm": 316.285908}
|
| 47 |
+
{"it": 470, "gen_updates": 420, "s_per_it": 5.66, "mem_gib": 24.9, "c_acc": 0.915625, "c_loss": 0.396266, "d_gen": -2.375104, "d_teacher": 2.246049, "g_logit": -2.372623, "gnorm": 426.73709}
|
| 48 |
+
{"it": 480, "gen_updates": 430, "s_per_it": 5.71, "mem_gib": 24.9, "c_acc": 0.909375, "c_loss": 0.394121, "d_gen": -2.525033, "d_teacher": 2.411426, "g_logit": -2.550583, "gnorm": 580.174043}
|
| 49 |
+
{"it": 490, "gen_updates": 440, "s_per_it": 5.6, "mem_gib": 24.9, "c_acc": 0.865625, "c_loss": 0.593566, "d_gen": -2.148674, "d_teacher": 2.374551, "g_logit": -2.169901, "gnorm": 716.07439}
|
| 50 |
+
{"it": 500, "gen_updates": 450, "s_per_it": 5.6, "mem_gib": 24.9, "c_acc": 0.846875, "c_loss": 0.729606, "d_gen": -2.290267, "d_teacher": 1.572728, "g_logit": -2.285638, "gnorm": 392.940741}
|
| 51 |
+
{"it": 510, "gen_updates": 460, "s_per_it": 6.78, "mem_gib": 24.9, "c_acc": 0.921875, "c_loss": 0.370543, "d_gen": -2.736271, "d_teacher": 2.455694, "g_logit": -2.707942, "gnorm": 537.985992}
|
| 52 |
+
{"it": 520, "gen_updates": 470, "s_per_it": 5.67, "mem_gib": 24.9, "c_acc": 0.965625, "c_loss": 0.252394, "d_gen": -2.877263, "d_teacher": 2.850073, "g_logit": -2.739951, "gnorm": 515.508899}
|
| 53 |
+
{"it": 530, "gen_updates": 480, "s_per_it": 5.64, "mem_gib": 24.9, "c_acc": 0.890625, "c_loss": 0.563771, "d_gen": -2.414951, "d_teacher": 2.277598, "g_logit": -2.654116, "gnorm": 709.700902}
|
| 54 |
+
{"it": 540, "gen_updates": 490, "s_per_it": 5.7, "mem_gib": 24.9, "c_acc": 0.94375, "c_loss": 0.285931, "d_gen": -2.918549, "d_teacher": 2.788963, "g_logit": -2.851511, "gnorm": 271.158658}
|
| 55 |
+
{"it": 550, "gen_updates": 500, "s_per_it": 5.64, "mem_gib": 24.9, "c_acc": 0.93125, "c_loss": 0.386427, "d_gen": -3.007278, "d_teacher": 2.665188, "g_logit": -2.941659, "gnorm": 374.554742}
|
| 56 |
+
{"it": 560, "gen_updates": 510, "s_per_it": 5.59, "mem_gib": 24.9, "c_acc": 0.953125, "c_loss": 0.253991, "d_gen": -2.992537, "d_teacher": 2.871128, "g_logit": -2.8083, "gnorm": 421.902652}
|
| 57 |
+
{"it": 570, "gen_updates": 520, "s_per_it": 5.74, "mem_gib": 24.9, "c_acc": 0.94375, "c_loss": 0.296528, "d_gen": -3.032215, "d_teacher": 2.960297, "g_logit": -2.982546, "gnorm": 367.955676}
|
| 58 |
+
{"it": 580, "gen_updates": 530, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.9, "c_loss": 0.493329, "d_gen": -2.62191, "d_teacher": 2.719897, "g_logit": -2.698434, "gnorm": 780.508957}
|
| 59 |
+
{"it": 590, "gen_updates": 540, "s_per_it": 5.69, "mem_gib": 24.9, "c_acc": 0.946875, "c_loss": 0.312489, "d_gen": -3.124627, "d_teacher": 2.567042, "g_logit": -3.063663, "gnorm": 672.813906}
|
| 60 |
+
{"it": 600, "gen_updates": 550, "s_per_it": 5.71, "mem_gib": 24.9, "c_acc": 0.9625, "c_loss": 0.203462, "d_gen": -3.358016, "d_teacher": 3.01446, "g_logit": -3.541651, "gnorm": 244.839248}
|
| 61 |
+
{"it": 610, "gen_updates": 560, "s_per_it": 7.86, "mem_gib": 24.9, "c_acc": 0.959375, "c_loss": 0.246468, "d_gen": -3.294766, "d_teacher": 2.899352, "g_logit": -3.391545, "gnorm": 274.389373}
|
| 62 |
+
{"it": 620, "gen_updates": 570, "s_per_it": 5.6, "mem_gib": 24.9, "c_acc": 0.9375, "c_loss": 0.389626, "d_gen": -3.036653, "d_teacher": 2.82729, "g_logit": -2.993505, "gnorm": 602.330268}
|
| 63 |
+
{"it": 630, "gen_updates": 580, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.953125, "c_loss": 0.236319, "d_gen": -3.326519, "d_teacher": 2.977125, "g_logit": -3.006266, "gnorm": 275.102869}
|
| 64 |
+
{"it": 640, "gen_updates": 590, "s_per_it": 5.63, "mem_gib": 24.9, "c_acc": 0.9125, "c_loss": 0.468886, "d_gen": -2.839741, "d_teacher": 2.540864, "g_logit": -2.657633, "gnorm": 181.273212}
|
| 65 |
+
{"it": 650, "gen_updates": 600, "s_per_it": 5.57, "mem_gib": 24.9, "c_acc": 0.953125, "c_loss": 0.311223, "d_gen": -3.182146, "d_teacher": 2.863069, "g_logit": -3.080172, "gnorm": 173.449964}
|
| 66 |
+
{"it": 660, "gen_updates": 610, "s_per_it": 5.72, "mem_gib": 24.9, "c_acc": 0.94375, "c_loss": 0.354878, "d_gen": -3.160589, "d_teacher": 2.84673, "g_logit": -2.883895, "gnorm": 240.966786}
|
| 67 |
+
{"it": 670, "gen_updates": 620, "s_per_it": 5.82, "mem_gib": 24.9, "c_acc": 0.90625, "c_loss": 0.406371, "d_gen": -2.754415, "d_teacher": 2.638921, "g_logit": -2.808692, "gnorm": 298.15805}
|
| 68 |
+
{"it": 680, "gen_updates": 630, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.878125, "c_loss": 0.531884, "d_gen": -2.432082, "d_teacher": 2.578791, "g_logit": -2.482742, "gnorm": 271.599031}
|
| 69 |
+
{"it": 690, "gen_updates": 640, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.9125, "c_loss": 0.4271, "d_gen": -2.860206, "d_teacher": 2.463032, "g_logit": -2.752373, "gnorm": 355.511536}
|
| 70 |
+
{"it": 700, "gen_updates": 650, "s_per_it": 5.62, "mem_gib": 24.9, "c_acc": 0.8875, "c_loss": 0.575126, "d_gen": -2.657025, "d_teacher": 2.421408, "g_logit": -2.473467, "gnorm": 229.405529}
|
| 71 |
+
{"it": 710, "gen_updates": 660, "s_per_it": 6.63, "mem_gib": 24.9, "c_acc": 0.871875, "c_loss": 0.574605, "d_gen": -2.347231, "d_teacher": 2.330401, "g_logit": -2.323787, "gnorm": 968.408723}
|
| 72 |
+
{"it": 720, "gen_updates": 670, "s_per_it": 5.6, "mem_gib": 24.9, "c_acc": 0.95, "c_loss": 0.300756, "d_gen": -3.302272, "d_teacher": 2.674137, "g_logit": -3.417291, "gnorm": 67.733886}
|
| 73 |
+
{"it": 730, "gen_updates": 680, "s_per_it": 5.64, "mem_gib": 24.9, "c_acc": 0.9375, "c_loss": 0.221562, "d_gen": -3.521256, "d_teacher": 3.014115, "g_logit": -3.507561, "gnorm": 100.00077}
|
| 74 |
+
{"it": 740, "gen_updates": 690, "s_per_it": 5.75, "mem_gib": 24.9, "c_acc": 0.971875, "c_loss": 0.138255, "d_gen": -3.753518, "d_teacher": 3.362483, "g_logit": -3.768429, "gnorm": 553.137035}
|
| 75 |
+
{"it": 750, "gen_updates": 700, "s_per_it": 5.58, "mem_gib": 24.9, "c_acc": 0.96875, "c_loss": 0.169519, "d_gen": -3.683156, "d_teacher": 3.372113, "g_logit": -3.977836, "gnorm": 65.564101}
|
| 76 |
+
{"it": 760, "gen_updates": 710, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.971875, "c_loss": 0.13752, "d_gen": -3.875997, "d_teacher": 3.534403, "g_logit": -3.927255, "gnorm": 141.72445}
|
| 77 |
+
{"it": 770, "gen_updates": 720, "s_per_it": 5.71, "mem_gib": 24.9, "c_acc": 0.95625, "c_loss": 0.233508, "d_gen": -3.549302, "d_teacher": 3.582107, "g_logit": -3.492271, "gnorm": 81.573391}
|
| 78 |
+
{"it": 780, "gen_updates": 730, "s_per_it": 5.81, "mem_gib": 24.9, "c_acc": 0.95625, "c_loss": 0.179923, "d_gen": -3.765295, "d_teacher": 3.225188, "g_logit": -3.776723, "gnorm": 31.5222}
|
| 79 |
+
{"it": 790, "gen_updates": 740, "s_per_it": 5.59, "mem_gib": 24.9, "c_acc": 0.978125, "c_loss": 0.097448, "d_gen": -4.034114, "d_teacher": 3.69661, "g_logit": -3.898952, "gnorm": 39.593995}
|
| 80 |
+
{"it": 800, "gen_updates": 750, "s_per_it": 5.68, "mem_gib": 24.9, "c_acc": 0.978125, "c_loss": 0.102428, "d_gen": -4.094866, "d_teacher": 3.774902, "g_logit": -3.896441, "gnorm": 24.271654}
|
| 81 |
+
{"it": 810, "gen_updates": 760, "s_per_it": 7.66, "mem_gib": 24.9, "c_acc": 0.9625, "c_loss": 0.202403, "d_gen": -3.854326, "d_teacher": 3.584347, "g_logit": -3.978992, "gnorm": 40.056661}
|
| 82 |
+
{"it": 820, "gen_updates": 770, "s_per_it": 5.59, "mem_gib": 24.9, "c_acc": 0.971875, "c_loss": 0.156311, "d_gen": -3.827758, "d_teacher": 3.670029, "g_logit": -3.863046, "gnorm": 44.031802}
|
| 83 |
+
{"it": 830, "gen_updates": 780, "s_per_it": 5.62, "mem_gib": 24.9, "c_acc": 0.98125, "c_loss": 0.102383, "d_gen": -4.115957, "d_teacher": 3.809848, "g_logit": -4.091031, "gnorm": 45.254895}
|
| 84 |
+
{"it": 840, "gen_updates": 790, "s_per_it": 5.73, "mem_gib": 24.9, "c_acc": 0.971875, "c_loss": 0.12304, "d_gen": -4.100542, "d_teacher": 3.828115, "g_logit": -4.164267, "gnorm": 27.769859}
|
| 85 |
+
{"it": 850, "gen_updates": 800, "s_per_it": 5.67, "mem_gib": 24.9, "c_acc": 0.778125, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 86 |
+
{"it": 860, "gen_updates": 810, "s_per_it": 5.48, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 87 |
+
{"it": 870, "gen_updates": 820, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 88 |
+
{"it": 880, "gen_updates": 830, "s_per_it": 5.58, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 89 |
+
{"it": 890, "gen_updates": 840, "s_per_it": 5.49, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 90 |
+
{"it": 900, "gen_updates": 850, "s_per_it": 5.65, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 91 |
+
{"it": 910, "gen_updates": 860, "s_per_it": 6.28, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 92 |
+
{"it": 920, "gen_updates": 870, "s_per_it": 5.56, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 93 |
+
{"it": 930, "gen_updates": 880, "s_per_it": 5.54, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 94 |
+
{"it": 940, "gen_updates": 890, "s_per_it": 5.53, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 95 |
+
{"it": 950, "gen_updates": 900, "s_per_it": 5.5, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 96 |
+
{"it": 960, "gen_updates": 910, "s_per_it": 5.52, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 97 |
+
{"it": 970, "gen_updates": 920, "s_per_it": 5.5, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 98 |
+
{"it": 980, "gen_updates": 930, "s_per_it": 5.55, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 99 |
+
{"it": 990, "gen_updates": 940, "s_per_it": 5.57, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 100 |
+
{"it": 1000, "gen_updates": 950, "s_per_it": 5.5, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 101 |
+
{"it": 1010, "gen_updates": 960, "s_per_it": 7.44, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
| 102 |
+
{"it": 1020, "gen_updates": 970, "s_per_it": 5.56, "mem_gib": 24.9, "c_acc": 0.0, "c_loss": NaN, "d_gen": NaN, "d_teacher": NaN, "g_logit": NaN, "gnorm": NaN}
|
logs/probe_adm_discriminator.jsonl
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"it": 10, "gen_updates": 0, "s_per_it": 2.75, "mem_gib": 20.7, "fake": 0.27561}
|
| 2 |
+
{"it": 20, "gen_updates": 0, "s_per_it": 2.64, "mem_gib": 20.7, "fake": 0.375196}
|
| 3 |
+
{"it": 30, "gen_updates": 10, "s_per_it": 4.93, "mem_gib": 25.1, "adv_ratio": 35.733486, "d_acc": 0.500449, "d_fake": -0.10222, "d_loss": 2.126553, "d_real": -0.101114, "dmd_rms": 0.221341, "fake": 0.353202, "gnorm": 1.763772, "lam": 0.0, "ramp": 0.0}
|
| 4 |
+
{"it": 40, "gen_updates": 20, "s_per_it": 9.97, "mem_gib": 25.3, "adv_ratio": 48.805241, "d_acc": 0.499809, "d_fake": 0.092451, "d_loss": 2.002986, "d_real": 0.095818, "dmd_rms": 0.325674, "fake": 0.416026, "gnorm": 1.199596, "lam": 0.0, "ramp": 0.0}
|
| 5 |
+
{"it": 50, "gen_updates": 30, "s_per_it": 10.45, "mem_gib": 25.4, "adv_ratio": 9.468557, "d_acc": 0.503584, "d_fake": -0.081498, "d_loss": 2.012508, "d_real": -0.073537, "dmd_rms": 0.32834, "fake": 0.505973, "gnorm": 1.627691, "lam": 0.0, "ramp": 0.0}
|
| 6 |
+
{"it": 60, "gen_updates": 40, "s_per_it": 10.57, "mem_gib": 25.4, "adv_ratio": 16.740142, "d_acc": 0.501583, "d_fake": 0.143709, "d_loss": 1.987252, "d_real": 0.157508, "dmd_rms": 0.274366, "fake": 0.463597, "gnorm": 1.094926, "lam": 0.0, "ramp": 0.0}
|
| 7 |
+
{"it": 70, "gen_updates": 50, "s_per_it": 10.33, "mem_gib": 25.4, "adv_ratio": 17.995773, "d_acc": 0.502987, "d_fake": 0.218125, "d_loss": 1.988724, "d_real": 0.229557, "dmd_rms": 0.260837, "fake": 0.4254, "gnorm": 1.340356, "lam": 0.0, "ramp": 0.0}
|
| 8 |
+
{"it": 80, "gen_updates": 60, "s_per_it": 10.4, "mem_gib": 25.4, "adv_ratio": 21.950003, "d_acc": 0.502617, "d_fake": 0.195303, "d_loss": 1.999953, "d_real": 0.200418, "dmd_rms": 0.2464, "fake": 0.405491, "gnorm": 2.077201, "lam": 0.0, "ramp": 0.0}
|
| 9 |
+
{"it": 90, "gen_updates": 70, "s_per_it": 10.41, "mem_gib": 25.4, "adv_ratio": 4.992844, "d_acc": 0.512019, "d_fake": 0.056383, "d_loss": 2.005259, "d_real": 0.089869, "dmd_rms": 0.353305, "fake": 0.438201, "gnorm": 1.893705, "lam": 0.0, "ramp": 0.0}
|
| 10 |
+
{"it": 100, "gen_updates": 80, "s_per_it": 10.52, "mem_gib": 25.4, "adv_ratio": 22.842478, "d_acc": 0.500302, "d_fake": 0.098687, "d_loss": 1.999297, "d_real": 0.099608, "dmd_rms": 0.232808, "fake": 0.345837, "gnorm": 1.049859, "lam": 0.0, "ramp": 0.0}
|
| 11 |
+
{"it": 110, "gen_updates": 90, "s_per_it": 10.42, "mem_gib": 25.4, "adv_ratio": 14.325914, "d_acc": 0.504625, "d_fake": 0.015475, "d_loss": 1.990486, "d_real": 0.027477, "dmd_rms": 0.245574, "fake": 0.39951, "gnorm": 1.243515, "lam": 0.0, "ramp": 0.0}
|
| 12 |
+
{"it": 120, "gen_updates": 100, "s_per_it": 10.54, "mem_gib": 25.4, "adv_ratio": 14.00046, "d_acc": 0.50106, "d_fake": 0.017234, "d_loss": 1.999404, "d_real": 0.018786, "dmd_rms": 0.253277, "fake": 0.425688, "gnorm": 1.833253, "lam": 0.0, "ramp": 0.0}
|
| 13 |
+
{"it": 130, "gen_updates": 110, "s_per_it": 10.33, "mem_gib": 25.4, "adv_ratio": 8.808989, "d_acc": 0.506074, "d_fake": -0.007883, "d_loss": 1.982148, "d_real": 0.010178, "dmd_rms": 0.319683, "fake": 0.470164, "gnorm": 1.987517, "lam": 0.0, "ramp": 0.0}
|
| 14 |
+
{"it": 140, "gen_updates": 120, "s_per_it": 10.55, "mem_gib": 25.4, "adv_ratio": 30.816719, "d_acc": 0.500643, "d_fake": 0.018101, "d_loss": 1.999332, "d_real": 0.018775, "dmd_rms": 0.23059, "fake": 0.44002, "gnorm": 1.406316, "lam": 0.0, "ramp": 0.0}
|
| 15 |
+
{"it": 150, "gen_updates": 130, "s_per_it": 10.44, "mem_gib": 25.4, "adv_ratio": 21.776939, "d_acc": 0.50403, "d_fake": 0.049467, "d_loss": 2.006303, "d_real": 0.067547, "dmd_rms": 0.255741, "fake": 0.51779, "gnorm": 1.035783, "lam": 0.0, "ramp": 0.0}
|
logs/probe_teacher_discriminator.jsonl
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"it": 10, "gen_updates": 0, "s_per_it": 2.76, "mem_gib": 20.7, "fake": 0.2758}
|
| 2 |
+
{"it": 20, "gen_updates": 0, "s_per_it": 2.67, "mem_gib": 20.7, "fake": 0.374674}
|
| 3 |
+
{"it": 30, "gen_updates": 10, "s_per_it": 4.96, "mem_gib": 25.5, "adv_ratio": 30.275976, "d_acc": 0.555563, "d_fake": -0.104033, "d_loss": 2.012383, "d_real": 0.087962, "dmd_rms": 0.205062, "fake": 0.32308, "gan_frac": 1.0, "gnorm": 0.77355, "lam": 0.0, "ramp": 0.0}
|
| 4 |
+
{"it": 40, "gen_updates": 20, "s_per_it": 4.96, "mem_gib": 25.5, "adv_ratio": 99.557544, "d_acc": 0.58669, "d_fake": -0.229194, "d_loss": 1.836997, "d_real": 0.012343, "dmd_rms": 0.305676, "fake": 0.440187, "gan_frac": 1.0, "gnorm": 1.42406, "lam": 0.0, "ramp": 0.0}
|
| 5 |
+
{"it": 50, "gen_updates": 30, "s_per_it": 4.8, "mem_gib": 25.5, "adv_ratio": 39.060537, "d_acc": 0.646695, "d_fake": -0.243651, "d_loss": 1.674095, "d_real": 0.232983, "dmd_rms": 0.284247, "fake": 0.443884, "gan_frac": 1.0, "gnorm": 3.348034, "lam": 0.0, "ramp": 0.0}
|
| 6 |
+
{"it": 60, "gen_updates": 40, "s_per_it": 4.85, "mem_gib": 25.5, "adv_ratio": 48.76557, "d_acc": 0.583147, "d_fake": -0.154269, "d_loss": 1.790229, "d_real": 0.145679, "dmd_rms": 0.281149, "fake": 0.425242, "gan_frac": 1.0, "gnorm": 2.247003, "lam": 0.0, "ramp": 0.0}
|
| 7 |
+
{"it": 70, "gen_updates": 50, "s_per_it": 4.77, "mem_gib": 25.5, "adv_ratio": 59.619794, "d_acc": 0.581655, "d_fake": -0.218971, "d_loss": 1.795289, "d_real": 0.126522, "dmd_rms": 0.310085, "fake": 0.388189, "gan_frac": 1.0, "gnorm": 1.043796, "lam": 0.0, "ramp": 0.0}
|
| 8 |
+
{"it": 80, "gen_updates": 60, "s_per_it": 4.86, "mem_gib": 25.5, "adv_ratio": 68.792467, "d_acc": 0.682936, "d_fake": -0.367275, "d_loss": 1.531309, "d_real": 0.305816, "dmd_rms": 0.224524, "fake": 0.357255, "gan_frac": 1.0, "gnorm": 1.901103, "lam": 0.0, "ramp": 0.0}
|
lora.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4a4c8e2d6244a0fcdc2822b87b3435226ae57c289aef99fc2ac54edeab9e09bb
|
| 3 |
+
size 1189176832
|
time_embedding.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2ebabc91e2a9e68c00e948dd80b05235a826e808817b5b2600b441457570d244
|
| 3 |
+
size 41017896
|