Files
LTX-2/docs/plan.md
T
indigo e03cc62548 Add SCAIL-2 training integration (Phase 3, ltx-trainer FlexibleStrategy)
Wire SCAIL-2 driving + in-context mask conditioning into the trainer via the
unified FlexibleStrategy, so the widened patchify_proj (Phase 2) can be trained.

- flexible.py: new DrivingConditionConfig (driving-latent concat with a RoPE
  width offset ΔW) and MaskChannelsConditionConfig (semantic masks -> per-token
  channels), added to the condition union and get_data_sources. Driving is
  prepended (cond-first, target stays at the tail for loss slicing); mask
  channels are written onto the driving tokens via Modality.cond_channels,
  reusing ltx-core encode_mask_channels. The noisy target keeps a zero mask.
- model_loader.load_transformer gains mask_conditioning_channels, widening the
  video patchify_proj with zero-init columns via a new live-module helper
  (widen_module_patchify_proj_for_mask_channels). ModelConfig exposes the field.
- trainer unfreezes patchify_proj in LoRA mode when mask channels are active
  (the new input columns are new base params LoRA cannot reach).
- configs/scail_animation_lora.yaml plus README / training-modes table rows.

Verified on CPU (verify_phase3_trainer.py): config round-trips, prepare_training
_inputs builds cond_channels [B,T,56] with the mask on the driving tokens, a tiny
widened model forwards and compute_loss returns a finite [B] loss, and the widen
helper is output-preserving at zero init. Real training needs Linux+GPU+checkpoint;
dataset preprocessing (driving latents + semantic masks) and validation-runner
wiring are left for later.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 10:09:40 +08:00

67 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SCAIL-2 → LTX-2 移植計畫
將 SCAIL-2arXiv:2606.10804`zai-org/SCAIL-2`)的端到端角色動畫手法移植到 LTX-2。
> **注意**SCAIL-2 原始實作建構於 **Wan 2.1**,非 LTX-2。座標慣例與架構需翻譯到 LTX 的資料流。
## 三個核心機制
1. **Driving latent 直接串接** — 把驅動影片 latent 直接接進 DiT token 序列(不經骨架/pose 中介),用 width 軸座標偏移 ΔW 讓 driving 座標跟主 video 座標分開。
2. **In-context mask channel** — 疊加額外輸入 channel(1 個環境開關 + K=6 個角色綁定槽,展開為 `4(K+1)=28` channel)到模型輸入,讓模型知道背景/角色對應。
3. **Mode-specific RoPE** — Animation Mode 與 Replacement Mode 用不同的座標指派規則。
## LTX-2 對應落點
| 機制 | LTX-2 落點 | 改權重? |
|---|---|---|
| 1. Driving 串接 + ΔW | 新 `ConditioningItem`clone `reference_video_cond.py`),改 `positions` 偏移 | 否 |
| 3. Mode-specific RoPE | 上述 item 加 `DrivingMode` enum | 否 |
| 2. In-context mask channel | 加寬 `patchify_proj` 輸入 channel + `LatentState` 帶額外 channel + 投影前 concat | **是**(需微調) |
**關鍵洞察**LTX 的 `ConditioningItem.apply_to(latent_state, latent_tools) -> LatentState` 就是「串接進序列」的天然注入點,機制 1+3 **完全不用動 transformer / rope.py**。RoPE 由 `LatentState.positions` `[B,3,T,2]`pixel 座標,axis1=(time,h,w))驅動;ΔW = 對 `positions[:,2]`width)加常數。width 正規化上界 `max_pos[2]=2048`,超過會 wrap。
## SCAIL-2 座標規則(論文)
序列 `[z_ref; z_t; z_driv]`driving 永遠在 width 軸帶固定偏移 ΔW:
| | Animation | Replacement |
|---|---|---|
| z_ref | T=0, H=[0,Hv), W=[0,Wv) | T=0, **H=[ΔH_ref, ΔH_ref+Hv)**, W=[0,Wv) |
| z_t | T=[1,Tv], H=[0,Hv), W=[0,Wv) | T=[0,Tv1], H=[0,Hv), W=[0,Wv) |
| z_driv | T=[1,Tv], H=[0,Hv), **W=[ΔW, ΔW+Wv)** | T=[0,Tv1], H=[0,Hv), **W=[ΔW, ΔW+Wv)** |
## 分階段計畫
### Phase 1 — Driving 串接 item(機制 1+3,推論期 PoC)✅ 已完成
- 純推論、不改權重、不動 `patchify_proj`、不碰 ltx-trainer。
- 用現有 checkpoint 驗證資料流正確性(序列長度、座標偏移、attention mask、denoise_mask、不 wrap)。
- **PoC 僅驗證 plumbing**LTX-2 未經此訓練,畫面不會是正確動畫。
### Phase 2 — In-context mask channel(機制 2checkpoint 手術)✅ 已完成(plumbing
- **決策**:時間編碼採忠實堆疊,`8×(K+1)=56` channelLTX 時間因子 8K=6),非 Wan 的 28。
- `LTXModel(mask_conditioning_channels=0)` config-gated 加寬 `patchify_proj`;預設不變。
- `LatentState`/`Modality``cond_channels` 欄位,跟著 clone/clear/append 流動;投影前在 `_apply_patchify_proj` concatNone 補零)。
- 新輸入欄位 **zero-init**`widen_patchify_proj_for_mask_channels` 轉換舊 checkpoint,行為不變、待微調才生效。
- `VideoConditionByMaskChannels`(K+1) 語意 mask → 空間下採樣 + 時間 8× 堆疊 → 寫入尾端 driving tokentarget 保持零,符合論文)。
- 驗證通過(`verify_mask_channels.py`):向後相容、zero-init 加寬 forward == baseline、mask pipeline 不 crash。**僅驗證 plumbing,畫質需 Phase 3 微調。**
### Phase 3 — 訓練整合(ltx-trainer)✅ 已完成(程式碼路徑;實訓需 GPU)
- **決策**:完整整合到 `FlexibleStrategy`;訓練 = LoRA + 解凍 `patchify_proj`(新 mask 欄位無法純 LoRA 訓練)。
-`DrivingConditionConfig` + `MaskChannelsConditionConfig``flexible.py`);`_apply_driving_condition`(cond-first concat + ΔW) + `_build_mask_channels`(重用 `encode_mask_channels`) → `Modality.cond_channels`
- `load_transformer(mask_conditioning_channels=)``widen_module_patchify_proj_for_mask_channels` 加寬;`ModelConfig.mask_conditioning_channels`trainer 在 LoRA 模式解凍 patchify_proj。
- `configs/scail_animation_lora.yaml` + docs。CPU 單元驗證通過(`verify_phase3_trainer.py`)。
- **本機無 GPU/Linux/checkpoint → 未跑實機訓練**dataset 前處理(driving latents + 語意 mask)與 validation runner 接線未做。
### Phase 4 — Pipeline + CLI 包裝 ⬜ 未開始
- 仿 `lipdub.py``scail_animation.py` pipeline + arg parser。
## Phase 1 簡化取捨(記錄,Phase 2 需回頭處理)
- (a) driving 時間座標直接複製 target 的(token-wise),故 driving 需與 target 同 F/H/W。
- (b) 單一 frozen driving group 的 `attention_mask` 維持 None(= 全連接,target 完全看得到 driving),與 reference cond 一致。
- (c) **ANIMATION 與 REPLACEMENT 在 Phase 1 產生相同 driving 座標** — mode 差異(z_ref 的 ΔH_ref 高度位移、target 時間原點、mask channel)屬 Phase 2enum 先保留佔位。
## 參考
- 論文:arXiv:2606.10804 — *SCAIL-2: Unifying Controlled Character Animation with End-to-end In-Context Conditioning*
- 官方實作:`zai-org/SCAIL-2`GitHub / HuggingFace),建構於 Wan 2.1
- 藍本檔案:`packages/ltx-core/src/ltx_core/conditioning/types/reference_video_cond.py`