File size: 15,709 Bytes
78e6693 | 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 | # smoothloopv3 — diário de bordo (LoRA MiniMax H3)
Início: 2026-09-19. GPU: RTX 5090 32 GB (driver 595.91.07, CUDA 13.2).
Disco: overlay 350 GB, **NÃO é volume persistente** (`df` mostra overlay em /workspace).
→ Tudo que importa precisa ir para o HF. Recycle/destroy apaga tudo.
## Decisões fixadas
- Trainer: fork AkaneTendo25/musubi-tuner, branch minimax-h3, pin `ede9ed9f...` (relatório 18/09).
- Receita base: v3 (rank/alpha 32, LR 5e-5, AdamW8bit, sem preservation, guidance 4/sigma/normalized,
jitter 0.2, swap 32, SDPA, convrot int8, AdaLN rank 16, fused qk/rope).
- HF: conta AdwolfCzar, padrão `minih33`, público + gated manual, sem "minimax" no nome.
## Descobertas
| # | Quando | Achado |
|---|---|---|
| 1 | 02:5x | `captionkreator` é repo privado; acesso via `$GITHUB_TOKEN` (ghp_...) do ambiente. |
| 2 | 02:5x | Tokens HF no ambiente: `HF_TOKEN`→AdwolfCzar, `HF_TOKEN_USER`→adbrasi. hf-xet 1.6.0 presente. |
| 3 | 02:5x | Mega: `megatools` (apt) baixa link público de pasta sem login. rclone não tinha config. |
| 4 | 02:5x | Dataset traz `.txt` com **tags danbooru** (não captions). O perfil smoothloop NÃO as usa como |
| | | entrada (user.md só manda `Animation type: {{folder}}` + vídeo) e o `run` **sobrescreve** o .txt. |
| | | → Backup das tags antes de rodar o captioner. |
| 5 | 02:5x | Amostra inicial: 512x384, **10 fps**, 16 frames (1,6 s), sem áudio, tag `looping_animation`. |
| | | `captioner convert` (smoothloop) resolve: fps 24 + `loop:true`/`min_duration:5` (tiling de ciclos |
| | | inteiros) + `max_edge 1280` + CFR. Substitui o `extend_loops.py` histórico. |
| 6 | 02:5x | `OPENROUTER_API_KEY` presente no ambiente (perfil smoothloop usa openrouter). |
| 7 | 03:1x | Venv estava **sem torch** (ambiente novo, nao o de agosto). Instalado torch 2.10.0+cu130 |
| | | (combo validado no historico); `torch.cuda` ok, cc (12,0) = Blackwell. |
| | | `/venv/main` exigiu `sudo chown -R claude:claude` antes de instalar (armadilha ja no NOTES). |
| 8 | 03:1x | Mega a 0,57 MB/s com `megadl` (sequencial) = 3,6 h. Escrevi downloader paralelo |
| | | (`/workspace/scripts/mega_folder_dl.py`, API do Mega + AES-CTR, 16 conexoes) -> **4,1 MB/s**, |
| | | ETA ~30 min. Retoma o que o megadl ja tinha baixado (compara tamanho). |
| 9 | 03:1x | Dataset real: **7,82 GB, 1749 mp4 + 1752 txt**, raiz `smoothlooper_v3_datasetCRU` com |
| | | subpastas `1`..`6` (mp4 por pasta: 1=180, 2=521, 3=~471, 4=76, 5=39, 6=463). |
| | | A estrutura 1..6 e exatamente o que o perfil smoothloop espera (`Animation type: {{folder}}`). |
| 10| 03:2x | **BUG no template do handoff**: `--save_last_n_steps_state` NAO existe no pin ede9ed9f. |
| | | So existe `--save_last_n_checkpoints N`, que apaga LoRAs antigos junto com os states. |
| | | Decisao: NAO passar retencao nenhuma (guarda todos os LoRAs p/ checkpoint picking) e deixar |
| | | o meu uploader apagar states antigos localmente depois de confirmados no HF. |
| 11| 03:2x | O trainer tem upload HF embutido (`--huggingface_repo_id`, `--async_upload`), mas nao cobre |
| | | os samples mp4. Vou usar uploader proprio (watcher) como no historico. |
| 12| 03:1x | `captioner convert` (smoothloop) validado em 3 clipes reais: 604x504@14,6fps/2,19s -> 24fps/6,58s/158f; |
| | | 512x384@10fps/1,6s -> 24fps/6,29s/151f; 1080x1920@60fps -> **720x1280** (max_edge 1280)/24fps/160f. |
| | | Dataset e heterogeneo (retrato/paisagem/quadrado, 10-60 fps). Tiling entrega ~150-160f > 124f. |
| 13| 03:2x | **`OPENROUTER_API_KEY` do ambiente estava EXPIRADA** ("API key expired"). Usuario forneceu chave nova, |
| | | gravada em `/workspace/.env` (chmod 600). Sem limite, sem expiracao. |
| 14| 03:3x | `captioner run` NAO pula arquivos que ja tem .txt (Skipped 0) -> as tags danbooru SAO sobrescritas. |
| | | Backup obrigatorio antes. Custo medido: **$0,0024 / 3 videos** => ~$1,40 para os 1749. |
| 15| 03:3x | Decisao do usuario: samples usam o **primeiro frame** (casa com o contrato "<Picture 1> em 0.00s"). |
| 16| 03:4x | Meu downloader tinha bug: o campo `k` do Mega traz varias entradas `handle:chave` separadas |
| | | por `/` (pasta compartilhada). `split(":")[1]` pegava lixo -> **147 arquivos indecifraveis**. |
| | | Corrigido testando todas as entradas. Dataset integro: 3501 = 1749 txt + 1651 mp4 + 101 webm. |
| 17| 03:4x | Inventario do bruto: fps caotico (30/16/60/24/10/29,97/25/33,33/6,67/12,5/5/20/4...), |
| | | resolucoes de 486x1080 a 3840x2160, **480 clipes COM audio** (historico tinha zero), |
| | | duracao mediana 5,53 s / p90 20 s / max 85,9 s. 51,3% ja >=124f a 24fps. |
| 18| 03:5x | **BUG no captionkreator (corrigido)**: fontes de fps baixo (4-12) falhavam a conversao com |
| | | "duration changed from 6.000s to 5.750s" -> ~11% do dataset. Duas causas: `-stream_loop` |
| | | com uma copia a menos do que o `-t` precisa, e tolerancia usando o fps ALVO em vez do da FONTE. |
| | | Branch `fix/low-fps-duration`, commit 6baca90 (local, sem push). Suite: os mesmos 10 testes |
| | | falham com e sem o patch (pre-existentes, versao do ffmpeg do container). |
| 19| 03:5x | Armadilha do NOTES confirmada 2x na pratica: `pgrep/pkill -f <padrao>` casa com o proprio |
| | | shell e mata a sessao. Passei a gravar PID em arquivo (`/workspace/logs/*.pid`). |
| 20| 04:0x | Projecao de disco: dataset convertido fica **menor** que o bruto (fator 0,45x; max_edge 1280 |
| | | reduz fontes 4K/1440p, max_duration 10s corta as longas). ~4 GB convertido + ~4 GB zip + |
| | | ~18 GB cache + ~1,1 GB por checkpoint. Total ~35 GB contra 239 GB livres. |
| | | ComfyUI do usuario: 9,3 GB (8,1 GB so o venv dele) - irrelevante, mantido a pedido. |
| | | Gargalo real e VRAM (treino ~18-24 GB dos 32 GB), nao disco: nao rodar ComfyUI junto. |
| 21| 04:1x | Segunda iteracao do fix de fps baixo: tolerancia `1,05/source_fps` errava por 0,5 ms num |
| | | clipe 888x888 a 6,67 fps (deficit 0,158 s vs limite 0,1575 s). Corrigida para |
| | | `1/source_fps + 2/target_fps`. Commit 8c6f813. 1 unico arquivo do dataset era afetado. |
| 22| 04:3x | Dataset convertido: **100% a 24 fps**, lado maior <=1280, 1752 mp4 / 0 webm, 4,3 GB. |
| | | Mediana 183f (7,6 s), p75 239f, max 240f (teto de 10 s). 96% >=124f. |
| 23| 04:4x | **Captions: 1752/1752, zero falhas, $0,65** (17,9 M tokens in / 1,28 M out). |
| | | Validacao pasta->gatilho: 180 static / 522 slow / 472 smooth / 76 intense / 39 turntable / |
| | | 463 chroma-key = **100% corretos**, zero contaminacao cruzada. |
| 24| 04:4x | **Decisao do usuario: respeitar o minimo do H3 de 5 s.** No grid 17k+5 o valor acima de 5 s |
| | | e 124f (5,17 s) -> NENHUMA view abaixo disso. Descartados os esquemas com f107/f90/f73 |
| | | (inclusive a receita do smoothloop historico). Esquema final: 3 areas (512x288/640x384/ |
| | | 832x480, quotas 55/28/17) **todas em f124**, estratificadas por resolucao de origem. |
| | | Tokens medios de video ~7870; ancora historica mais proxima = quick (124f multi-res) 12,8 s/it, |
| | | mas este pin tem fused_qk_norm_rope + fixes de recompilacao/sync, entao esperar menos. |
| 25| 04:4x | 70 clipes (4%) sairam com 117-123f. Reconvertidos com perfil derivado `smoothloop_min124` |
| | | (min_duration 5.3, max_duration 12) para ganhar um ciclo inteiro a mais. |
| 26| 04:4x | Armadilha nova: `captioner` consome stdin; dentro de `while read -r f` ele come caracteres |
| | | do caminho lido (paths viravam "orkspace/..."). Fix: `</dev/null` no comando interno. |
| 27| 04:4x | Armadilha nova: `:` sem aspas em `description:` do profile.yaml quebra o parse YAML |
| | | ("mapping values are not allowed here") e o convert falha sem dizer qual arquivo. |
| 28| 05:0x | Dataset FINAL: 1752 clipes, 100% 24 fps, **100% >=124f** (min exatamente 124 = 5,17 s), |
| | | 1752/1752 com caption H3. Mediana 191f, max 246f. 4,3 GB. |
| 29| 05:0x | Views (estratificadas por px da fonte, seed 42): v288 963 / v384 491 / v480 298 = 1752. |
| | | So 6 clipes (0,3%) tem fonte abaixo da area de 512x288; com bucket_no_upscale eles treinam |
| | | no bucket nativo menor, que e o comportamento correto. |
| 30| 05:0x | Dataset publicado: huggingface.co/datasets/AdwolfCzar/smoothloopv3_dataset (zip -0 + backup |
| | | das tags danbooru). Upload via xet a ~76 MB/s. |
| 31| 05:0x | Samples: 3 previews cobrindo paisagem/quadrado/retrato E tipos smooth/slow/static. |
| | | 832x480 seed42 / 576x704 seed43 / 480x832 seed44, todos 124f, 20 passos. |
| | | Troquei o 2o sorteio: o clipe tinha a moldura inteira girando (cunhas pretas), ruim como |
| | | referencia de monitoramento. Substituido por um com fundo liso, que isola o movimento. |
| 32| 05:0x | **SMOKE LEG 1 PASSOU**: 10 steps (loss 0,074), samples nos steps 0/5/10 (9 mp4 + json |
| | | validos: 832x480 / 576x704 / 480x832, todos 124f a 24 fps), checkpoints 5 e 10 + states. |
| | | **~10 s/it** nos itens MAIS PESADOS (melhor que a ancora historica de 12,8 s/it). |
| | | VRAM: pico 15,1 GiB reservado no sampling; 15,3 GiB em uso durante os steps. Folga grande |
| | | nos 32 GB com swap 32. |
| | | Custo de sampling medido: ~113 s por preview (101,6 s denoising + 11,7 s decode) => ~6 min |
| | | por evento de 3 previews. A cada 500 steps (~83 min) isso e ~7% de overhead. |
| 33| 05:0x | Conversao ComfyUI validada: 600 tensores do trainer -> 400 com chaves `diffusion_model.*`, |
| | | 569 MB. O uploader gera essa versao automaticamente a cada checkpoint. |
| 34| 06:0x | Smoke leg 2 (resume) PASSOU: retomou de global_step=10, pulou 10 batches, foi a 15. |
| | | Loss 0,074 -> 0,046. Gatilho de parada confirmado no codigo (trainer_base.py:2462, |
| | | poll_checkpoint_request_files a cada optimizer step). |
| 35| 08:2x | **CACHE COMPLETO**: 21,5 GB (v288 9,6 / v384 6,5 / v480 5,4), 3504 arquivos = |
| | | 1752 latentes + 1752 TE. Preflight de captions passou com 1752 itens. |
| | | Latentes ~2,5 h (GPU 100%, VAE-bound), TE ~20 min. Serial, como manda o historico. |
| 36| 08:4x | **TREINO LANCADO** (`minih33_smoothloopv3`), 6000 steps de teto, save+sample a cada 500. |
| | | Medido: **12,07 s/it**, loss 0,0996 -> 0,0952 nos primeiros 33 steps. |
| | | **VRAM 25,1 GB / 32 GB** - bem acima dos 15,3 GB do smoke (dataset real tem mais variedade |
| | | de bucket). Folga ~7 GB. Historico teve OOM no step ~4502 com swap 24; aqui swap 32. |
| | | MONITORAR: se passar de ~29 GB, reiniciar com BLOCKS_TO_SWAP=40 e RESUME=1. |
| 37| 08:4x | Uploader em tempo real ativo: sobe checkpoint + versao _comfy + samples mp4/json + tb, |
| | | e apaga states locais antigos (mantem 2). Samples do step 0 ja no HF. |
| 38| 20/09 | **`convert_lora.py --target other` QUEBRA o LoRA de H3 — nao usar.** O ComfyUI |
| | 02:3x | relatou "lora key not loaded" em 200 dos 400 tensores do `_comfy`. Causa: o conversor |
| | | so sabe trocar todo `_` por `.` e depois aplicar correcoes hardcoded por arquitetura |
| | | (Wan `self_attn`, Z-Image `to_q`, Hunyuan `double_blocks`, tabela Qwen-Image). **Nao ha |
| | | regra para H3**, entao `blocks.N.attn.qkv_proj` virava `attn.qkv.proj` e |
| | | `attn.out_proj` virava `attn.out.proj` (50 blocos x 2 modulos x 2 tensores = 200). |
| | | `mlp.fc1`/`fc2` escapavam por nao terem underscore. O fork adicionou H3 no lado do |
| | | TREINO e nunca tocou no script de exportacao — ponto cego, nao regressao. |
| 39| 20/09 | **O checkpoint NATIVO carrega 100% no ComfyUI — a conversao e desnecessaria.** |
| | 02:4x | `comfy/lora.py::model_lora_keys_unet` monta o mapa a partir das chaves do MODELO |
| | | carregado: `k[len("diffusion_model."):-len(".weight")].replace(".", "_")` -> |
| | | `lora_unet_blocks_0_attn_qkv_proj`, que e exatamente o nome que o musubi grava. |
| | | O ComfyUI resolve o mapeamento com o modelo em maos; o `convert_lora.py` tenta |
| | | adivinhar o inverso as cegas. **DECISAO DO USUARIO: `--no-comfy` e o padrao a partir |
| | | de agora** (hf_uploader.py: virou `--comfy` opt-in; `--no-comfy` aceito como no-op). |
| | | Usar sempre `minih33_*-stepNNNNNNNN.safetensors`, sem sufixo. |
| 40| 20/09 | **Os LoRAs de agosto tem o mesmo bug.** Verificado por range request no header dos |
| | 02:4x | safetensors no HF (sem baixar 596 MB): `minih33-jiggle/checkpoints/comfy/` |
| | | `minih33_jiggle-step00002500_comfy.safetensors` tem `attn.out.proj`/`attn.qkv.proj`. |
| | | Vale para minih33-jiggle, minih33-smoothloop e minih33_quick (NOTES (4).md l.164 |
| | | confirma o mesmo comando). Quem usou o `_comfy` de agosto rodou com METADE do LoRA |
| | | (so MLP, zero atencao). Os nativos desses repos estao corretos. |
## Bugs / incidentes
| Quando | O que | Resolucao |
|---|---|---|
| 20/09 02:3x | ComfyUI ignorava 200/400 tensores do `_comfy` (descoberta 38) | Patch no `convert_to_diffusers` com ramo H3 (ida e volta) + os 7 `_comfy` locais regerados e validados. **Mas a decisao final foi abandonar o `_comfy`** (descoberta 39): o nativo e o arquivo bom. |
| 20/09 02:1x | `nohup ... &` dentro do Bash tool morre junto com a chamada (nem o log foi criado) | Usar `run_in_background: true` do proprio tool, nao `nohup &`. |
| 20/09 02:2x | `/workspace/.env` NAO existe nesta maquina (existia na 51502554) | Tokens vivem no environ dos processos: `tr '\0' '\n' < /proc/$(cat /workspace/logs/uploader.pid)/environ`. |
## Progresso
- [x] Ler relatório + NOTES + handoff
- [x] Acesso Mega, GitHub, HF validados
- [x] Download dataset Mega (7,3 GB, 1752 midias em 6 pastas de tipo de animacao)
- [x] Backup tags + convert + captions (1752/1752, $0,65, gatilhos 100% corretos)
- [x] Upload dataset (zip + xet) para HF
- [x] Download pesos H3 (82 GB, Comfy-Org/MiniMax-H3: DiT fl2va bf16, TE nvfp4_awq, 2 VAEs)
- [x] Views/buckets + TOMLs (3 areas, todas f124)
- [ ] Samples (3 vídeos aleatórios, first frame + caption)
- [x] Smoke test + resume (leg1 10 steps + leg2 resume ate 15, ambos exit 0)
- [x] Cache completo (21,5 GB)
- [x] Treino lancado + uploader em tempo real ativo
## Validar um checkpoint sem ter ComfyUI a mao
Duas checagens contra o state dict de `minimax_h3_fl2va_bf16.safetensors`. Pegam
exatamente o bug das descobertas 38-40 e sao baratas (so leem headers):
1. **Nomes** — toda chave do LoRA tem que apontar para um modulo que existe no base:
`mod = key[len("diffusion_model."):].rsplit(".lora_",1)[0]` e entao `mod+".weight" in base_keys`.
Esperado: 400/400, zero orfaos. O arquivo quebrado dava 200 orfaos.
2. **Shapes** — `B @ A` tem que ter o shape do peso base: `B[1]==A[0]` e `[B[0],A[1]]==W`.
Ex.: `blocks.0.attn.out_proj` -> W `[5376, 7168]`, B `[5376, 32]`, A `[32, 7168]`.
Para o formato nativo o nome e `lora_unet_<modulo com _ no lugar de .>`, entao a
checagem 1 vira: trocar `lora_unet_` por nada, `_` por `.`, e conferir — lembrando
que `qkv_proj`/`out_proj` sao os unicos com underscore interno.
Header remoto sem baixar o arquivo (usado na descoberta 40): ler 8 bytes
little-endian = tamanho do header JSON, depois os proximos N bytes, via
`Range: bytes=0-7` / `Range: bytes=8-N+7`.
|