File size: 6,533 Bytes
9a24cbd | 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 | ---
license: apache-2.0
tags:
- lora
- reference-conditioning
- anima
- krea-2
- diffusion-pipe
---
# Reference adapters — Anima e Krea 2 (bateria de 2026-07-25/26)
Adapters de referência treinados no fork
[adbrasi/diffusion-pipe-easycontrol](https://github.com/adbrasi/diffusion-pipe-easycontrol),
branch `ic-lora`. Documentação completa em `docs/` daquele repo — em especial
`ANIMA_FUTURO_TREINO.md` e `KREA2_MULTIREF_RECEITA.md`.
Dois projetos separados aqui:
| pasta | modelo | tarefa |
|---|---|---|
| `anima/` | Anima (2B, DiT de vídeo derivado do Cosmos-Predict2) | uma referência, "próxima cena" |
| `krea2/` | Krea 2 (22B... na prática 12,8B de DiT) | **N referências separadas**, endereçadas por texto |
---
## `krea2/` — multi-referência (o resultado novo)
**Método `krea2_multiref_grounded`.** Krea 2 recebendo N referências
**separadas** (não coladas numa imagem só), endereçadas por texto no caption:
`"Generate an image of the woman from image 1 holding the bag from image 2."`
Treinado no [Azily/Macro-Dataset](https://huggingface.co/datasets/Azily/Macro-Dataset)
(bracket 1-3, filtrado pelas notas do juiz do próprio dataset), 512px,
`max_refs = 2`.
- `multiref_step500` — 2.200 amostras, 500 steps
- `multiref_step250` — mesmo run, checkpoint anterior
### O achado que fez funcionar
O `width_shift` do Krea 2 soma uma **constante** ao deslocar a referência no
RoPE. Um laço sobre N reusando aquilo daria a todos os spans posições
**idênticas** — e aí a saída do DiT fica *exatamente invariante* à troca de
duas referências: a atenção é permutation-invariant sobre keys, o `tvec` e as
máscaras são uniformes, MLP e norm são pointwise.
**Não é "difícil de aprender", é impossível em princípio.** A correção é
offset **cumulativo**: slot *i* em `w += (i+1) * W`.
### Formato de caption
`image 1` / `image 2`, **sem** os sinais `<` `>`. Treinar com `<image 1>` fez
o modelo *renderizar o marcador como texto dentro da imagem*. Os blocos de
visão do Qwen3-VL são rotulados com o mesmo vocabulário (`image 1:`), então
não há ponte entre dois vocabulários para o modelo aprender.
### Resultados
Avaliação held-out em **anime** (domínio totalmente fora da distribuição — o
Macro é quase todo fotográfico): **6/6 corretos a 1024px**, 4/6 a 512px. As
duas falhas de 512 eram limitação de resolução, não de capacidade: a
referência é codificada na resolução do alvo, então em 1024 ela carrega 4×
mais tokens.
Num exemplo com posição explícita (*"os dois personagens de image 1 na
esquerda e o homem de image 2 na direita"*), a saída obedece — e **trocar a
ordem das referências troca quem está de cada lado**. Isso é endereçamento,
não mistura.
### Uso
Requer o fork (o runner constrói o modelo a partir do `to_layers()` do
pipeline, então treino e inferência compartilham o packing exato):
```bash
python tools/infer_reference_adapter.py \
--config examples/macro_multiref/run2_multiref.toml \
--adapter multiref_step500/ \
--reference ref1.jpg --reference ref2.jpg \
--prompt "Generate an image of the woman from image 1 holding the bag from image 2." \
--width 1024 --height 1024 \
--turbo-lora krea2_turbo_lora_rank_64_bf16.safetensors
```
A **ordem das flags `--reference` é a ordem dos slots**. `--turbo-lora` usa a
LoRA turbo oficial (8 steps, CFG 1.0, mu 1.15).
---
## `anima/` — bateria de métodos de adapter de referência
Sete braços de uma bateria controlada, todos com o mesmo dataset, seed e
protocolo de avaliação (10 exemplos held-out × 4 colunas: sem referência /
força 1.0 / ref_cfg 1.75 / referência embaralhada).
| adapter | método | veredito |
|---|---|---|
| **`M1_armD_dropout_step2000_VENCEDOR`** | `ic_lora_v3` target-first, `llm_adapter` congelado, adaln fora, `condition_dropout 0.1`, 2000 steps | 🏆 **vencedor** (visual, do usuário) |
| `M1_arm1_llm_frozen_step500` / `step1000` | mesma receita, sem dropout | empata em qualidade, caráter diferente |
| `M1_armB_dropout_step1000` | mesma receita com dropout, só 1000 steps | perde — não convergiu ainda |
| `M2_arm3_llm_trainable_step1000` | `llm_adapter` treinável | ❌ perde ("praticamente não pega a referência") |
| `M3_armA_adaln_in_step1000` | LoRA também no adaln | ❌ perde (artefato de instabilidade) |
| `M4_armC_routing_step1000` | routing condition-only | ❌ perde |
### Os dois achados
**1. O `condition_dropout` não remove a referência — ele a ZERA.** O frame
continua concatenado, com o mesmo timestep e as mesmas posições de RoPE; só
fica em branco. Consequência: o modelo ganha um *nulo calibrado* e passa a
tratar a referência como entrada **separável que consulta** (atribui), em vez
de fundir referência e alvo (acopla). Para um contrato do tipo *"o que não
está escrito é herdado"*, atribuição é exatamente o que se precisa.
**2. Dropout sem aumentar os steps é estritamente PIOR que não usar dropout.**
Sensibilidade medida: armB (dropout, 1000 steps) 0.589 < arm1 (sem, 1000)
0.657 < armD (dropout, 2000) 0.921. O dropout bloqueia a rota fácil, então o
modelo aprende mais devagar — as duas mudanças andam juntas ou nenhuma delas.
### Receita vencedora
```toml
[model]
type = 'ic_lora_v3'
llm_adapter_lr = 0 # CONGELADO — bate com a recomendação oficial do Anima
[ic_lora_full]
ref_first = false # target-first
condition_dropout = 0.1
include_adaln = false
[adapter]
rank = 32
[optimizer]
type = 'adamw_optimi'
lr = 1e-4 # batch efetivo 8
# 2000 steps, não 500
```
Inferência: `--mode ominicontrol_subject --lora_strength 1.0 --ref_cfg 1.0`.
⚠️ **`M4_armC_routing` precisa de `--mode ic_lora_dual`** — o modo padrão funde
a LoRA em todos os pesos e destrói o adapter routado, produzindo ruído puro
que *parece* "o método falhou".
---
## Ressalvas honestas
- Nenhum ranking fino entre `arm1`, `armB` e `armD` sobrevive à estatística
(Welch t=1.74 com 6 seeds, crítico 2.23). O que sobrevive são os efeitos
grandes: `llm_adapter` congelado vence, adaln fora, routing perde.
- Os adapters do Anima foram treinados num dataset com **captions
exaustivas**, que causam "atalho de caption" — a caption descreve o alvo por
completo e a referência vira supérflua. É plausível que o ranking mude com
delta-captions.
- O `krea2/multiref` é de um treino de 500 steps sobre 2.200 amostras. A
capacidade está demonstrada; não é um modelo de produção.
|