File size: 20,743 Bytes
df76dc7
 
 
 
 
 
 
 
89b4d83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df76dc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d235fdc
df76dc7
 
 
 
35689fc
 
b5b5d4c
 
 
 
 
df76dc7
 
 
 
 
 
 
 
d235fdc
8ea062a
 
d235fdc
 
 
 
 
8ea062a
 
 
 
 
0d2112e
 
 
 
 
 
 
 
 
 
 
dfe17d7
 
 
 
 
89b4d83
dfe17d7
 
9b38ce5
 
 
 
 
 
 
 
cbe34ec
 
 
 
 
 
5603c9c
 
 
 
 
 
c91589e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85865ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5981656
 
 
 
 
85865ba
b544077
 
 
 
 
 
 
 
 
 
 
 
 
9e9e9e4
 
 
 
 
 
 
 
 
 
 
 
 
896283d
 
 
 
 
 
 
 
acce2fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d235fdc
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# MiniMax H3 LoRA — anime loop i2v (projeto h3_loop)

## Objetivo
LoRA de MiniMax H3 (FL2VA) no dataset `AdwolfCzar/anime_loop_2d_dataset_captioned_29-07`.
Fase 1 ("quick"): 2 épocas nos ~3.9k clipes do `mega_curated` para validar o pipeline completo.
Fase 2: treino com o dataset completo (`loopcut_000..005`, ~49 GB) ou o que couber.
Foco de uso: image2video (primeiro frame → vídeo). Task de treino: `i2va`.

## RUNBOOK — caminho das pedras (para o próximo agente/treino)

Sequência exata que funcionou, com os custos medidos. Scripts em `scripts/`, configs em `configs/`.

1. **Ambiente**: usar /venv/main (torch 2.10.0+cu130 — NÃO troque torch; nightly quebra CUBLAS).
   `uv pip install -e .` no fork Akane commit c4b84fa. `uv pip install tensorboard` (não vem).
   Se o venv der Permission denied: `sudo chown -R claude:claude /venv/main`.
2. **Downloads** (hf CLI com xet, muito rápido): pesos Comfy-Org/MiniMax-H3 (DiT bf16 66 GB +
   TE nvfp4 15 GB + 2 VAEs) e dataset. TE bf16 (48 GB) é desnecessário — nvfp4 funciona em
   Blackwell para cache E sampling do trainer.
3. **Análise quantitativa do dataset ANTES de tudo** (ffprobe em paralelo): fps real, SAR/DAR
   (DVDs 720×480 são anamórficos!), nb_frames, áudio. Sem isso o treino sai distorcido/errado.
4. **Normalização** (`normalize_videos.py`, ~30 jobs, ~15 min/4k clipes): 24 fps CFR + setsar=1
   + scale por SAR. Nunca treinar fonte com fps misto (uncanny motion) ou pixel anamórfico.
5. **Extensão de loops** (`extend_loops.py`): tiling do ciclo até escada 124/90/73/56
   (canvas do H3 começa em ~124f; treinar 22f não é validado por ninguém). Loops = tiling limpo.
6. **Buckets multi-res** (`assign_buckets.py`): 3 áreas (512×288 / 640×384 / 832×480, 55/28/17),
   symlinks, sem upscale. Multi-res é OBRIGATÓRIA no H3 (RoPE por área) + jitter 0.2 no treino.
7. **Smoke test** (`smoke_train.sh`): 10 steps + sampling + checkpoint + resume (leg 2 com
   --max_train_steps 15 valida autoresume de verdade). Incluir os itens MAIS PESADOS por bucket.
8. **Cache** (`cache_quick.sh`): batch 24 + workers 16, SERIAL (latents → TE). Medido na 5090:
   latents ~4,5 h + TE ~1,5 h para 3.885 itens ≈ 31,7 GB. NUNCA rodar TE em paralelo com latents
   na mesma GPU (medido: piora ambos). Batch >24 não ajuda (VAE é o gargalo, GPU 100%).
9. **Treino** (`train_quick.sh` via tmux + tee log): receita anti-destilação completa (ver seção
   Receita). ~13 s/it na 5090 no regime 124f multi-res. Sampling+checkpoint a cada 500 steps.
10. **Uploader HF** (`hf_uploader.py`) ativo DESDE o smoke; repo gated manual, nunca "minimax" no nome.
11. **Monitorar**: loss média SOBE com preservation ligada — é normal, olhar val/loss de vídeo;
    watchdog de stall (freeze silencioso near-OOM = step 10x mais lento, não crasha).

**Armadilhas que já custaram tempo aqui:**
- ffmpeg pesado em paralelo durante CARGA do DiT → 6× mais lento (carga é CPU-bound); durante
  steps de treino, ok.
- Jupyter cria `.ipynb_checkpoints` root-owned dentro de output/ quando o usuário navega —
  `rm -rf` falha; usar `sudo rm` ou ignorar.
- Nunca `pkill -f` com padrão que casa com o próprio comando composto; matar por PID exato.
- Nunca apagar cache com processo de treino/cache vivo apontando para ele.
- Cache TOML separado do train TOML (batch alto só no cache; treino EXIGE batch_size=1).
- `--save_last_n_steps_state 1500` limita states em disco (cada state = 859 MB).

## Ambiente (medido em 2026-08-10)
- Vast.ai, RTX 5090 32 GB (sm_120), 124 GB RAM, 32 vCPU, disco 600 GB (overlay, **não persistente**)
- Python 3.12.13 em `/venv/main`, torch 2.10.0+cu130 (combinação validada pela comunidade)
- Trainer: fork `AkaneTendo25/musubi-tuner`, branch `minimax-h3`, commit **c4b84fa** (pin do relatório 2026-08-10)
- Instalação: `uv pip install -e .` (torch não é tocado — extras cu130 não instalados)
- ffmpeg 6.1.1 do sistema

## Pesos
`Comfy-Org/MiniMax-H3``/workspace/models/MiniMax-H3/`
- `diffusion_models/minimax_h3_fl2va_bf16.safetensors` (~66 GB; int8 convrot na carga)
- `text_encoders/qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors` (~15 GB; Blackwell OK)
- `vae/minimax_h3_video_vae_fp16.safetensors`, `vae/minimax_h3_audio_vae_fp32.safetensors`

## Dataset — fatos medidos (mega_curated)
- 3.889 mp4 + 3.889 .txt (captions sidecar dentro do zip; jsonl tem 6.855 linhas, 2.966 com caption nula — os .txt do zip estão completos)
- **Áudio: nenhum clipe tem trilha** → `h3_target_mode = "video"` (sem audio VAE no cache, sequência menor)
- fps caótico: ~24 (2239), 25 (341), ~30 (182), centenas de variantes 22–29 (VFR/telecine)
- Resoluções: 720×480 anamórfico (SAR 853:720 e 186:157, ambos DAR ~16:9) ×1852; 1920×1080 ×1093; 1280×720 ×354; 704×396 ×245; 1270×720 ×104; 960×720 ×35; 640×480 ×7
- Frames pós-conversão 24fps, snap 17n+5: 22×1706, 39×875, 56×480, 73×199, 90×173, 107×114, 124×139; 4 itens < 22 frames (descartados)

## Normalização (não-destrutiva)
`scripts/normalize_videos.py`: fonte `/workspace/datasets/mega_curated` (intocada) →
`/workspace/datasets/mega_24`: 24 fps CFR (`fps=24`), pixels quadrados (scale por SAR + `setsar=1`),
libx264 crf 15 preset fast, sem áudio. Clipes com <22 frames pós-conversão são pulados.

## Buckets multi-resolução (obrigatório no H3 — RoPE normalizado por área)
Diretiva do usuário (10/08): resolução pequena/média, 1024×576 é alto demais.
`scripts/assign_buckets.py` (seed 42, sem upscale, estratificado por resolução de origem):
- `v288` [512×288] ×2138 (~55%) — movimento barato
- `v384` [640×384] ×1087 (~28%) — bucket principal
- `v480` [832×480] ×660 (~17%) — âncora de densidade média
(v576 descartado; caches v384/v480 de smoke reaproveitados, cache v576 removido)
Views por symlink em `/workspace/datasets/train_quick/`; manifest em `configs/bucket_manifest_quick.csv`.

## Receita de treino (relatórios info/ de 09-10/08 + docs do fork)
- guidance 4 + schedule sigma + form normalized; preservation 0.02; spatial density jitter 0.2
- SEM adapter do Ostris; SDPA (flash_attn quebra int8 convrot); int8 convrot fwd bf16; AdaLN rank 16
- rank/alpha 32 (estilo amplo), LR 1e-4 AdamW8bit (recomendação do trainer), warmup 50
- batch físico 1 (obrigatório no H3), **gradient_accumulation = 1**
- 5090 32 GB: blocks_to_swap 24 h2d_only ring 2 pinned; PYTORCH_ALLOC_CONF=expandable_segments:True
- Sampling i2v durante treino: 3 primeiros-frames do próprio dataset + captions como estão (`--i`), TE nvfp4
- max_frames 124 (regime de extensão de loops — ver seção Extensão de loops)

## Fase 2 — dimensionamento (medido)
- loopcut_000..005: **19.747 mp4** (~50 GB descomprimido), zero overlap de nomes com mega_curated
- Dataset completo fase 2 = loopcut (19.7k) + mega_curated (3.9k) ≈ 23,6k clipes
- Normalização 24fps concluída 10/08 06:5x: 19.746 ok (1 duplicata), zero falhas, 43 GB em loopcut_24
- Extensão de loops (mesma escada 124/90/73/56) → loopcut_24_ext, iniciada em seguida
- Extensão loopcut concluída: 4.592 tiled + 15.154 linked (clipes naturalmente longos), só 8,3 GB.
  Histograma: 124f×16490 (84%!), 107×1774, 90×1100, 73×269, 56×113
- Config fase 2 deve reintroduzir diversidade de duração: sub-datasets por bucket com max_frames
  124/90/73 via symlinks (per-dataset max_frames no TOML, sem re-encode)
- Disco p/ fase 2: caches ~100-140 GB estimados, 341 GB livres — cabe; recalcular antes do caching

## Log de execução
- 2026-08-10 04:1x: downloads iniciados (modelos ~86 GB, dataset completo ~52 GB) — xet, muito rápido
- 2026-08-10 04:2x: normalização 3.889 clipes lançada (30 jobs paralelos)

## Incidentes
- 2026-08-10 04:47: smoke #1 (buckets antigos c/ v576) caiu no step 1 com FileNotFoundError — causa: remoção do cache v576 com o processo ainda vivo (erro operacional meu, não bug do trainer). Antes de cair validou: carga DiT bf16→int8 convrot (~2 min), sampling i2v 3/3 (pico 14,8 GiB), 1 step com loss 0.546 a 4,8 s/it. Smoke #2 relançado com buckets novos.

## Extensão de loops (decisão técnica minha após pergunta do usuário, 2026-08-10 ~05:30)
Faixa publicada do H3 começa em ~124 frames (5,17s); mediana do dataset era 42f. Como os clipes são
loops seamless, cada clipe é estendido por tiling do ciclo até um alvo sorteado (seed determinística):
124f 55% / 90f 20% / 73f 15% / 56f 10%. Justificativa: canvas publicado do H3 comeca em ~124f;
44% do dataset natural estava em 22f (nunca validado por ninguem no canal); caso worldx documenta
acao esticada ao gerar mais longo que o treinado. Contra: custo ~2,4x/step; canal treina 39-73f sem
quebra especifica de duracao. Decisao: casar treino com regime de geracao (~5s) vence o custo.
Clipes ja maiores que o alvo ficam no comprimento natural
(cap 124, symlink sem re-encode). Ensina movimento cíclico no regime real de geração (~5s).
`scripts/extend_loops.py``/workspace/datasets/mega_24_ext`; max_frames=124; sampling --f 124.
Custo: step médio ~2x vs regime 73f. Block swap mantido em 24 (teste com 16 não mostrou ganho;
folga de VRAM protege contra freeze near-OOM, e o custo do swap no H3 é ~5% — compute-bound).

## Smoke test (2026-08-10 ~05:10)
- Leg 1 (buckets novos 288/384/480): PASSOU exit 0 — 10 steps, loss 0.895→0.156, ~5-7 s/it
  (inclui overhead de saves), VRAM pico 23,5 GiB c/ swap 24, RAM 26 GB
- Sampling i2v 3/3 nas 3 resoluções: denoising 13,5s (512×288), 21s (640×384), 33s (832×480) a 20 steps;
  pico sampling 14-15 GiB; mp4+json escritos
- Checkpoint validado: 600 tensores LoRA, dim/alpha 32/32, 569 MB (fp32); state 859 MB
- Carga DiT bf16→int8: ~2 min sem contenção de CPU (com 24 ffmpeg paralelos: 6× mais lento — lição:
  pausar normalização pesada durante fases de carga)
- Leg 2 (resume + swap 16) em execução: valida autoresume e mede ganho de velocidade com menos swap
- Uploader HF verificado durante smoke (NOTES/configs subiram para AdwolfCzar/minih33-loop-i2v, gated manual)

## Probe 124f + lançamento (2026-08-10 05:36-05:42)
- Probe 5 steps no regime estendido: PASSOU exit 0, ~12-13 s/it, loss 0.167→0.101, VRAM ~18 GiB
  no início dos steps (dimensionado pelos itens mais pesados nos smoke buckets)
- Sampling 124f: 35s (512×288) / 62s (640×384) / 108s (832×480) de denoising por vídeo;
  pico 16,7 GiB; ~3,5 min por evento de sampling (a cada 500 steps → overhead ~1%)
- 05:42 lançado tmux `h3quick`: cache completo (3.885 itens; batch final 24) → treino 2 épocas encadeado
- Log: /workspace/logs/quick_pipeline.log

## Medições de cache (10/08 06:00-06:40)
- Latents batch 4: ~7 s/item; batch 12: ~5 s/item; batch 24: ~1,7-6,5 s/item conforme grupo de
  frames (124f domina). GPU 100% — VAE encode é o gargalo real; batch >24 não deve ajudar.
- TE em paralelo com latents na mesma GPU: FRACASSO (TE 11-12 s/item vs ~1,6 solo; latents +14%).
  GPU time-slicing serializa com overhead. Regra: estágios de cache SEMPRE seriais em single-GPU.
- Checkpoints do treino ajustados a pedido do usuário: a cada 500 steps (sampling idem);
  states retidos: últimos 1500 steps.

## Fase 2 — config pronta (10/08 ~12:20)
- `assign_buckets_phase2.py`: loopcut 19.746 → v288 10.862 / v384 5.528 / v480 3.356;
  views de duração (≥124f: 70% f124 / 20% f90 / 10% f73): 9 sub-datasets em train_full/
- `dataset_full_train.toml`: 12 datasets (3 mega reutilizando cache/quick + 9 loopcut → cache/full)
- `train_full.sh` (minih33_full, 1 época default — revisar com resultados do quick), `cache_full.sh`

## Treino quick — lançado (2026-08-10 12:12 UTC)
- Cache final: v288 13 GB + v384 9,7 GB + v480 9,0 GB = 31,7 GB (3.885 itens, latents+TE i2va+guidance)
- Duração total do caching (batch 24, serial): ~6h (latents ~4,5h + TE ~1,5h)
- Treino: 2 épocas = 7.770 steps; checkpoint+sampling a cada 500; disco a 49% no início
- Monitores: watchdog stall 15min, checkpoints/samples/erros, marcos do pipeline

## Treino quick — ENCERRADO pelo usuário no step 2.500 (10/08 ~21:20 UTC)
- Rodou 2.564 steps a 12,8 s/it; loss 0.129→0.088; 5 checkpoints (500..2500) + samples no HF
- Usuário avaliou samples: "está aprendendo bem"; decidiu parar e ir para fase 2 maior
- Checkpoint 2500 convertido p/ ComfyUI (convert_lora.py --target other, chaves diffusion_model.*)
  → checkpoints/comfy/minih33_quick-step00002500_comfy.safetensors no repo

## BUG da base preservation em c4b84fa (descoberto pelo canal em 10/08)
- Ada: preservation comparava contra o modelo COM a LoRA ativa → efeito nulo/parcial
- Fix: 5d06e34 "disable training LoRA for base preservation" (verificado no diff: toggle
  enabled no LoRAModule + teste); head atualizado para f175417
- Implicação: o quick run rodou na prática como "guidance 4 + jitter" — checkpoint VÁLIDO
  (guidance segura runs curtos), mas diz pouco sobre preservation em run longo
- Caches NÃO afetados (fix é na loss; chancelor retomou sem recache; diff não toca fingerprint)
- Validação externa: mamad8 24h+ em 8x4090 com a receita guidance4+prsv0.02+jitter SEM degradação

## Fase 2 — revisão pós-relatório do outro agente (10/08 ~21:30)
- Fork: f175417 (fix preservation); re-smoke em execução
- Durações rebalanceadas 35/30/35 (f124/f90/f73) — corta step médio de ~12 p/ ~8-9 s/it
- Duas etapas: STAGE A main (v288+v384, mega+loopcut, 1 época ≈ 20,2k steps) →
  STAGE B polish (v480, 3.000 steps, --network_weights do LoRA final da A)
- `--h3_fused_qk_norm_rope` habilitado (recomendação Ada; validando no smoke)
- **LR 1e-4 nas duas etapas — decisão explícita do usuário** (recusou 5e-5)
- Block swap 24 mantido (benchmark Ada: 0 vs 48 blocos = 0,03 s/it — swap é grátis)
- Pipeline: launch_full_pipeline.sh (cache 12 datasets → stage A → stage B, tmux)

## FASE 3 (composição nova definida pelo usuário, 10/08 ~21:30)
Substitui o plano "fase 2 completa". Dataset: mega_curated 3.889 (caches quick reutilizados) +
loopcut 2.000 (seleção seeded estratificada por bucket/duração; não-selecionados deletados p/
liberar ~38 GB) + looper_v4 10.000 → ~15,9k itens, ~2 épocas (~31,8k steps), LR 1e-4 (usuário).
- looper_v4 (AdwolfCzar/looper_v4_dataset_captioned): 3 zips ~50 GB, 26,5k mp4, TUDO ~30fps
  SAR 1:1, resoluções web modernas (1080p/720p/4K + retrato/quadrado), 79% vira 107f em 24fps;
  25.724 com captions; 1.222 curtos demais excluídos
- Prep looper: seleção seeded 10k → normalize 24fps + DOWNSCALE cap 0,61 MP (fonte 4K não serve
  p/ buckets ≤0,4MP) → SEM extensão de loop (107f natural já no regime; diversidade via views)
- Views compartilhadas train_p3/{bucket}_{dur} (loopcut2k + looper10k juntos), caches cache/p3/*
- Smoke f175417 completo: leg1 10 steps + resume leg (loss 0.185→0.066) com fused_qk_norm_rope
- Limpezas autorizadas executadas: extract_tmp, zips (todos), mega_curated raw, loopcut
  não-selecionado, states antigos — pico de 443 GB livres
- Entregas ao repo: guia_comfyui.md (resoluções/durações/uso), exemplo_de_captions.txt (100
  aleatórias), checkpoint 2500 convertido p/ ComfyUI (convert_lora.py --target other)
- Armadilha nova p/ o runbook: NUNCA usar `until pgrep -f <padrão>` em background quando o
  próprio comando contém o padrão — o wrapper se auto-detecta e trava para sempre
- Armadilha (11/08, CAUSA REAL corrigida): vídeos com metadata não-UTF8 (tags latin-1) quebram
  o PyAV do musubi (av.open → avdict_to_dict → UnicodeDecodeError) — o ffprobe tolera, o PyAV não,
  e o ffmpeg PRESERVA metadata da fonte por default. Fix: remux lossless `-c copy -map_metadata -1`
  nos 10k do looper (validação PyAV 10000/10000 ok) + `-map_metadata -1` adicionado aos scripts de
  normalização. (Primeira hipótese "race de symlinks" estava errada.)

## FASE 3 — treino LANÇADO e saudável (2026-08-11 16:48 UTC)
- Cache p3 completo: 100 GB (12k itens novos: loopcut-2k + looper-10k; mega reutilizou cache/quick)
  Latents ~14h + TE ~5h no total (incluindo os reruns dos incidentes de metadata)
- Treino minih33_v2: 2 épocas × 15.885 itens = 31.770 steps
  Medido no step 500: **10,15 s/it** (rebalance de durações 35/30/35 + fused_qk_norm_rope
  entregaram: era 12,8 no quick), loss 0.116 caindo, VRAM 17,4 GB
- Config: f175417 (preservation FUNCIONAL), guidance 4/sigma/normalized, prsv 0.02, jitter 0.2,
  LR 1e-4 (decisão do usuário), rank 32, swap 24, checkpoint+sampling a cada 500 + upload HF
- Samples step 0 e step 500 (3/3 cada) no repo; primeiro checkpoint 500 salvo
- Projeção aritmética (não promessa): ~3,7 dias para as 2 épocas; checkpoints utilizáveis
  desde já (quick mostrou sinal bom em ~2,5k steps)
- Disco: 333 GB livres após tudo | Watchdog stall + monitores de erro ativos

## RUN v3 (12/08 ~04:1x UTC) — decisões do usuário após avaliação dos samples v2
Contexto: samples do v2 a 3,5k steps considerados fracos pelo usuário. Diagnóstico: (1) f175417
NÃO tem o fix 365d980 (amostragem da preservation + propagação do jitter + alinhamento
sigma-guidance) — receita parcialmente torta pela 3ª vez; (2) doutrina do canal virou em 11/08:
LR 1e-4 é alto para H3 destilado (rank 32 → 2-5e-5); (3) preservation freia ~2x por design.
Decisões (usuário): fork f8561f6c; LR 5e-5; SEM preservation (vai parar cedo por checkpoint-
picking, prioriza aprendizado rápido; guidance 4 + jitter 0.2 ficam); max 2 épocas (~31,8k steps)
mas parada manual a qualquer momento; restart DO ZERO (10h de GPU descartadas por baseline limpo);
output_v3/ + repo novo AdwolfCzar/minih33-loop-i2v-v3 (gated manual) com uploader próprio.
v2 encerrado no step ~3.5k (checkpoints 500-3500 + samples preservados no repo original).
Novidade do f8561f6c: checkpoint sob demanda por arquivo-gatilho (parada graciosa a qualquer
momento — casa exatamente com o plano de parada manual do usuário).

## Incidente v3: OOM no step ~4.502 (12/08 15:1x UTC) — RECUPERADO
- CUDA OOM (alocação de 1,12 GiB com 30,08 GiB já alocados) após 11h de run — batch pesado
  no pior bucket; expandable_segments estava ativo (fragmentação não era a causa; VRAM cheia real)
- Fix: blocks_to_swap 24→32 (~3 GiB a mais de folga; custo ~zero, H3 é compute-bound) +
  autoresume do state 4500. Checkpoints 500-4500 + samples intactos no repo v3
- Lição p/ runbook: em runs >10h na 5090, swap 32 desde o início; monitores com `tail -n 0`
  (log em append guarda Tracebacks antigos → falso alarme no relançamento)

## FASE 4 — dois treinos separados (decisão do usuário, 14/08)
v3 encerrado no step 17.500 (usuário: "já tá bom o suficiente"). Caches antigos apagados
(449 GB livres). Agora: **um treino por dataset, um de cada vez** — smoothloop primeiro,
jiggle depois; 10 épocas cada (parada manual quando estiver bom).

### SMOOTHLOOP (966 clipes)
- Fontes: 2 pastas mega.nz + 1 arquivo mega (zip 5 GB) + zip do HF smoothloop_dataset_base_v2
- **Dedup real (o palpite do usuário estava certo)**: 1.863 mp4 → 966 únicos
  444 duplicatas exatas (md5 do conteúdo) + 444 mesmo-ID re-encodado em outra fonte
- Captions casadas por **stem entre fontes** (o zip do mega3 tinha 1.580 captions p/ 505 vídeos —
  as fontes se complementam; matching por sibling .txt teria perdido a maioria)
- Normalização p4: 24fps CFR + SAR + cap 0,61 MP + `-map_metadata -1`; 966/966 ok, mediana 236f
  (78% já ≥124f → sem tiling de loop)
- Views: v288 532 / v384 270 / v480 164 × f124/f90/f73; cache 11 GB (966 latents + 966 TE)
- Config: **idêntica ao minih33_v3** (verificado por diff), só muda dataset/output/samples/épocas
- Repo: AdwolfCzar/minih33-smoothloop (gated) + uploader + conversor ComfyUI automático

### JIGGLE (1.232 clipes) — preparado, aguardando o fim do smoothloop
- bouncing_body_jiggle_captioned_30-07; cap **800 por nível** (medium 866→800, low 225, intense 272)
- **Triggers por nível aplicados na caption** conforme README do dataset:
  "bouncing body, " → "bouncing body with {low,medium,intense} jiggle and bouncing, "
- Normalizado: 1.232 ok, 65 curtos demais descartados

### Armadilha nova (14/08)
`--max_train_steps N` NÃO limita quando o script já passa `--max_train_epochs M` — o smoke de
8 steps virou treino real de 230 steps antes de eu notar. Para smoke com esses scripts,
sobrescreva TAMBÉM as épocas (ou use um script dedicado).

## Publicação HF (resolvido 10/08)
Repo `AdwolfCzar/minih33-loop-i2v` — público (sem custo de cota privada) + gated manual
(arquivos só baixáveis com aprovação do dono). Regra do usuário: nunca mencionar "minimax" no
nome/card público; identificador: minih33. Uploader: `scripts/hf_uploader.py` (watch em output/).