darask0's picture
Anima In-Context Character LoRA v1 + ComfyUI nodes + workflow
e545366 verified
|
Raw
History Blame Contribute Delete
7.13 kB

comfyui-anima-incontext

Anima (circlestone-labs, Cosmos-Predict2 2B DiT) 向けの 参照画像条件付けカスタムノード集。2 つの独立したストリームを持つ:

  • キャラストリーム (in-context) — 参照画像のVAE latentをDiTの 時間軸(T軸)に「クリーンフレーム」として連結し、shared self-attentionでキャラの見た目を参照させる。CLIP埋め込み型 IP-Adapterと違い、参照はモデル自身のVAE latentのまま自己注意に 入るため、髪飾り・服の柄・瞳などの細部が原理的に落ちない (OminiControl / IC-LoRA / UNO 系のアプローチ)。
  • 絵柄ストリーム (decoupled cross-attn) — SigLIP パッチトークンを 各ブロックのテキスト cross-attn に decoupled attention で注入する 統計的転写(AnimeAdapter 系)。細部をコピーしないことが目的なので、 あえて埋め込み注入型。要学習済みアダプタ

2 つは別モジュール(self-attn / cross-attn)をパッチするので併用可能。 charstyle の強度は独立に制御できる。

なぜT軸連結か

ComfyUI本体の実装(comfy/ldm/cosmos/predict2.py, comfy/ldm/anima/model.py) を読んだ結果:

  • AnimaのDiTはvideoアーキテクチャで、latentは (B, C, T, H, W)、 自己注意は (t h w) を平坦化した列に 3D RoPE 付きで計算される。 Animaのconfigは max_frames=128, patch_temporal=1 なので、 T=2(生成1 + 参照1)はRoPE的に完全に正当。参照トークンは時間座標が ずれるため、生成フレームと空間位置が衝突しない。
  • timesteps(B, T) のフレーム毎形式を受け付ける (ndim==1 のときだけ unsqueeze)。よって 参照フレームだけ timestep=0(クリーン画像)としてAdaLN変調 できる。
  • forwardWrappersMP.DIFFUSION_MODEL のWrapperExecutor経由 なので、ModelPatcherのwrapper登録だけで非侵襲にフックできる。
  • 各Blockの self_attn.attn_op は属性(torch_attention_op)なので、 add_object_patch で差し替えて参照トークンへの attention bias(log(strength))による強度制御ができる。

ノード

Anima Reference Encode (in-context)

IMAGE (+ 任意で MASK) + VAE → LATENT。 マスクを与えるとキャラを白背景に合成してからエンコードする (背景バイアス除去。アニメ被写体では効果が確認されている定石)。 target_width / target_height を生成解像度に合わせると、 アスペクト保持の白パディングでリサイズしてからエンコードする (サンプリング時のlatent空間リサンプルを回避できるので推奨)。 複数枚バッチ入力可 — 各画像が独立した参照フレームになる。

Anima Reference Latent Batch

解像度の異なる参照LATENT同士を1つの複数フレーム参照に結合する (2つ目を1つ目のサイズにfit)。チェーン可能。

Anima In-Context Reference Apply

MODEL + 参照LATENT → MODEL。

  • strength — 参照トークンへのattention bias。1.0=中立、0=無効
  • start_percent / end_percent — 参照を有効にするステップ範囲
  • cond_only(既定 ON)— CFGのuncond側では参照キーをマスクする。 学習契約(uncond=参照なし分布)と一致するので推奨
  • fit_mode — 参照latentが生成解像度と違う場合のfit方法 (pad=アスペクト保持+エッジ複製パディング(既定)/ stretch / crop
  • ref_timestep — 参照フレームのtimestep(既定0=クリーン。 noise augmentation学習をした場合のみ変更)

Anima Style Adapter Loader / Anima Style Encode (SigLIP) / Anima Style Apply

絵柄ストリーム。models/anima_style_adapters/ に学習済みアダプタを置く。 SigLIP系の CLIP_VISION モデルでエンコードし、style_weight で強度制御。 cond_only(既定 ON)。未学習アダプタは gate=0 で完全no-op。

ワークフロー例

LoadImage ─┐
           ├→ AnimaRefEncode ─┐
VAELoader ─┘                  │
                              ▼
UNETLoader → LoraLoader → AnimaInContextApply → (AnimaStyleApply) → KSampler → ...
             (in-context LoRA)      ▲
                                    │ (絵柄も使う場合)
CLIPVisionLoader → AnimaStyleEncode ┘ + AnimaStyleAdapterLoader

重要: 学習との契約 (training contract)

Anima本体は単フレームT2Iとして学習されているため、このノード単体 (zero-shot)での参照効果は弱い/不安定。専用のin-context LoRAを 学習して初めて本来の精度が出る。学習コード (リポジトリの training/anima_incontext_train_network.py)は 以下の推論時仕様をバイト単位で再現する:

  1. 参照latentは生成フレームの 後ろ にT軸連結(生成frames→参照frames)
  2. 参照フレームのtimestepは 0(生成フレームはサンプラーのt)
  3. 参照latentは latent_format 正規化済み(process_latent_in 相当、 Wan21のper-channel mean/std)
  4. 損失は生成フレームのみに適用(参照フレームの出力は破棄)
  5. テキスト条件(LLMAdapter経由)は変更なし
  6. 学習ペア: 同一キャラ・異なる出典の2枚(参照≠ターゲット)。 同一画像ペアはコピー機化するため禁止
  7. CFG dropout: 参照を確率~10%でドロップ(フレーム連結自体を外す) → 推論側 cond_only=True のuncondがこの分布に対応

実機検証結果(2026-07-04, RTX PRO 6000 / anima-base-v1.0)

  • strength=0 ⇔ 通常生成: bit単位で完全一致(strength≤0 は連結自体を スキップする実装。連結+全マスクでも数学的には同値だが、bf16 では attention kernel差がステップ毎に複利で増幅する — fp32 では1ステップ差 mean 0.05/255 と確認済み)
  • 全バリアント完走: strength=1.0(cond_only 両方)/ 解像度違い参照 (512x768→1024x1024, fit=pad) / 複数参照 (RefLatentBatch) / sigma窓
  • zero-shot(LoRA なし, strength=1.0)の挙動: 参照キャラを ポーズ・衣装込みでほぼ完全にコピーし、背景が崩壊する。 video プライアが参照を「隣接フレーム」として扱うため。 経路が機能している証拠だが、実用には in-context LoRA が必須 (参照≠ターゲットのペア学習がこのコピー機挙動を 「同一キャラ・別ポーズ/シーン」に矯正する)。 strength を下げても中間にはならず画質が劣化するだけ

既知の制約

  • 参照フレームのK/Vは全ステップ不変だがキャッシュしていない (2Bモデルなので実害は小さい。最適化はTODO)
  • tests/ にモックComfyUIでの契約テストあり