| --- |
| 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. |
|
|