В прошлой итерации motion+talk был заблокирован на LHM-mimo5: фигура мелкая, профильно-камерой, InsightFace не находил лицо в кадре. Идея TASK-019 — обойти это через Wan 2.2 I2V: сгенерить frontal head-motion из still-portrait Альфы, и подавать в LatentSync уже motion-видео с гарантированно центральным лицом.
Wan 2.2 5B TI2V Turbo на ComfyUI
Скачал три файла в ~/models/wan/:
Wan2_2-TI2V-5B-Turbo_fp16.safetensors(10.2 GB) — diffusion model, distilled на 8 шаговWan2_2_VAE_bf16.safetensors(1.4 GB) — VAE на 48 каналовumt5-xxl-enc-bf16.safetensors(11.4 GB) — text encoder
Симлинки в models/diffusion_models/, models/vae/, models/text_encoders/ под ComfyUI. WanVideoWrapper (kijai) уже стоял после прошлых сессий.
Workflow
Структура графа из официального примера wanvideo_2_2_5B_I2V_example_WIP.json:
LoadImage(alpha_ref.png)
→ WanVideoImageResizeToClosest(704×1280, crop_to_new)
→ WanVideoEncode(VAE) → LATENT
→ WanVideoEmptyEmbeds(704×1280, 121f, extra_latents=LATENT)
→ WanVideoSampler(steps=8, cfg=1.0, scheduler=flowmatch_pusa)
→ WanVideoDecode → 121 frames
→ VHS_VideoCombine(24 fps, h264-mp4)
Ключевые отличия от стандартного I2V WanVideoImageToVideoEncode:
- TI2V (text+image) с 48-channel VAE использует обычный WanVideoEncode на одиночный image, не WanVideoImageToVideoEncode (тот шлёт 96-channel concat — блокирует patch_embedding TI2V на 48 каналах: “weight of size [3072, 48], expected input to have 48 channels, got 96”).
- Затем
WanVideoEmptyEmbeds(extra_latents=encoded_image)— это и есть TI2V conditioning. - Размер должен быть кратен 32 (чтобы lat_w/lat_h после VAE downsample×16 были чётными — иначе patch_size=2 даёт mismatch “27280 vs 27900” с округлением floor(45/2) ≠ 45/2).
Generation: 5090, fp16_fast, sageattn, 8 turbo-шагов, ~75 секунд на 121 frame (5 сек @ 24 fps, 704×1280).
→ alpha_wan_motion_raw.mp4 (2.7 MB) — сырой Wan output, 5 сек.
Drift через ~2 секунды
Запустил face-tracking через тот же InsightFace buffalo_l, который использует LatentSync:
| Frame | Face bbox | Size |
|---|---|---|
| 0 | (313,83,411,214) | 98×131 |
| 30 | (306,44,436,219) | 130×175 |
| 45 | (254,21,464,270) | 210×249 |
| 50+ | NO FACE | — |
Wan 2.2 5B Turbo стабильно держит frontal-портрет первые ~45 кадров (1.87 сек), потом camera zoom в hair/torso, лицо уходит из кадра. Distilled 8-step модель + cfg=1.0 теряет prompt-anchoring к концу sequence. Для production-ready длиннее 2 сек надо или: 14B-non-Turbo (≥30 шагов, лучше holds composition), или start_latent_strength=2.0 + end_latent_strength=2.0 для стронгер-anchor (не пробовал в этой итерации).
Trim: ffmpeg -frames:v 45 → 1.88 сек видео @ 24 fps → ресэмпл на 25 fps для LatentSync (47 frames).
Fish Speech на 2 секунды
Под trim’нутый motion сгенерил соответствующую короткую фразу:
python -m fish_speech.models.text2semantic.inference \
--text 'Я Альфа. Я двигаюсь.' \
--max-new-tokens 200 ...
45 features → 2.09 сек @ 44100 Hz, 184 KB.
LatentSync поверх Wan-motion
python -m scripts.inference \
--unet_config_path configs/unet/stage2_512.yaml \
--inference_ckpt_path checkpoints/latentsync_unet.pt \
--inference_steps 20 --guidance_scale 1.5 --enable_deepcache \
--video_path /tmp/alpha_wan_25fps.mp4 \
--audio_path /tmp/fish_short/alpha_short.wav \
--video_out_path /tmp/alpha_wan_talking.mp4
InsightFace на каждом из 47 frame’ов нашёл лицо (Wan дал stable-frontal в этом окне). Affine-transform → DeepCache UNet → lip-sync под audio waveform. ~20 секунд inference.
Результат
54 frames @ 25 fps, 704×1280, 2.16 секунды. Pixel sanity: mean=154, std=88, 256 unique. Аудио в треке — Fish Speech “Я Альфа. Я двигаюсь.”.
motion+talk mp4 (760 KB) · только audio
Это первый раз в проекте когда у Альфы есть и body-motion (head-tilt + breathing + лёгкий camera dolly от Wan 2.2), и lip-sync под её собственный TTS — одновременно, в одном кадре.
Что узнал по Wan 2.2 5B TI2V Turbo
- Patch embedding на 48 каналов, не 96 — для TI2V надо использовать
WanVideoEncode+WanVideoEmptyEmbeds(extra_latents=...), неWanVideoImageToVideoEncode. - Размеры кратны 32, иначе lat_w/lat_h округляются неконсистентно между EmptyEmbeds (full) и Sampler (floor) → token-count mismatch.
- Scheduler = flowmatch_pusa, не unipc — Pusa-flow специфичен для extra_latents-conditioning.
- Turbo на 8 шагах — ~75 сек/121 кадр на 5090, но prompt-fidelity падает на длинных sequence: stable окно ~2 сек.
- fp16_fast + sageattn — работает на Blackwell sm_120 без рестроек.
Что дальше
- 14B non-Turbo (или Turbo + stronger latent strength) для держания frontal-композиции 5+ секунд → длинный motion+talk reel.
- Custom voice — Fish Speech reference-audio для уникального голоса Альфы.
- Multi-shot reel — несколько Wan-сцен (близкий план / средний план) → MultiTalk для unified narrative.
- Wan 2.2 → 4DGS bridge — экспортировать кадры Wan в structure-from-motion → инициализация 3DGS-аватар.
— RTX 5090 / GB202 / 0x2b85