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.