# SANA-WM

SANA-WM — это модель мира для генерации видео по изображению с управлением камерой, построенная на базе SANA. По первому кадру, текстовому запросу и траектории камеры (явные позы `c2w` или строка действий WASD/IJKL) модель генерирует видео, движение в котором следует заданному пути камеры.

Вывод выполняется в два этапа:

1. **Этап 1 — SANA-WM DiT.** Двусторонний DiT с 1,6 млрд параметров, использующий линейное внимание GDN-Triton и ветвь управления камерой UCPE. Для выборки применяется планировщик Эйлера с потоковым согласованием в стиле LTX с временными шагами для каждого токена; первый латентный кадр служит якорем для условного контекста.
2. **Этап 2 — LTX-2 refiner (необязательно).** Отдельный sink-bidirectional Euler refiner pipeline ([SanaWMLTX2Refiner](/docs/diffusers/main/ru/api/pipelines/sana_wm#diffusers.SanaWMLTX2Refiner)), который оборачивает [SanaWMLTX2RefinerTransformer3DModel](/docs/diffusers/main/ru/api/models/sana_wm_refiner_transformer3d#diffusers.SanaWMLTX2RefinerTransformer3DModel) + `LTX2TextConnectors` и текстовый энкодер Gemma-3, выполняется за 3 дистиллированных шага sigma.

Оба этапа декодируются через VAE [AutoencoderKLLTX2Video](/docs/diffusers/main/ru/api/models/autoencoderkl_ltx_2#diffusers.AutoencoderKLLTX2Video).

Доступные модели:

| Модель | Рекомендуемый dtype |
|:-----:|:-----------------:|
| [`Efficient-Large-Model/SANA-WM_bidirectional-diffusers`](https://huggingface.co/Efficient-Large-Model/SANA-WM_bidirectional-diffusers) | `torch.bfloat16` |
| [`Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner`](https://huggingface.co/Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner) | `torch.bfloat16` |

> [!TIP]
> SANA-WM обучается при фиксированном разрешении 704×1280. Рекомендуемый dtype для весов трансформера — `torch.bfloat16`; для наилучшей численной точности текстовый энкодер следует держать в `torch.float32`, а VAE — в `torch.float32`. Пайплайн ожидает внутренние параметры камеры `[fx, fy, cx, cy]` в пиксельных координатах *исходного изображения*; трансформация с масштабированием и центрированным кадрированием применяется внутри.

## Вывод

```python
import torch
from PIL import Image

from diffusers import SanaWMPipeline
from diffusers.utils import export_to_video

pipe = SanaWMPipeline.from_pretrained(
    "Efficient-Large-Model/SANA-WM_bidirectional-diffusers",
    torch_dtype=torch.bfloat16,
)
pipe.enable_model_cpu_offload()  # ~45 GB of weights — offload between stages

# SANA-WM was trained on the LTX-2 VAE in framewise mode with tiling enabled. Without these
# settings the VAE encodes the whole (B, C, T, H, W) clip in one shot, which gives subtly
# different numerics from the released checkpoint.
pipe.vae.enable_tiling()
pipe.vae.use_framewise_encoding = True
pipe.vae.use_framewise_decoding = True
pipe.vae.tile_sample_stride_num_frames = 64
pipe.vae.tile_sample_min_num_frames = 96

prompt = "A car driving across a vast desert plain at golden hour."
output = pipe(
    image=Image.open("input.png").convert("RGB"),
    prompt=prompt,
    action="w-80,jw-40,w-40",        # WASD-style action DSL: forward 80f, jump+forward 40f, forward 40f
    intrinsics=[800.0, 800.0, 845.0, 464.0],  # fx, fy, cx, cy in original-image pixels
    num_frames=161,
    num_inference_steps=60,
    guidance_scale=5.0,
    generator=torch.Generator(device="cuda").manual_seed(42),
    output_type="latent",            # hand the latents to the refiner below
)
```

Передайте `action=None` и укажите собственные позы `c2w` (`(F, 4, 4)` массив numpy), чтобы явно задавать траекторию камеры. Уберите `output_type="latent"`, чтобы получить видео сразу из первого этапа и пропустить этап уточнения.

### Этап 2 — рефинер LTX-2

[SanaWMLTX2Refiner](/docs/diffusers/main/ru/api/pipelines/sana_wm#diffusers.SanaWMLTX2Refiner) поставляется в виде отдельного репозитория, как SDXL разделяет базовую модель и refiner. Передайте VAE из базового пайплайна, чтобы веса разделялись, а не загружались дважды:

```python
from diffusers import SanaWMLTX2Refiner

refiner = SanaWMLTX2Refiner.from_pretrained(
    "Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner",
    vae=pipe.vae,
    torch_dtype=torch.bfloat16,
)
refiner.enable_model_cpu_offload()

frames = refiner(output.latent, prompt, fps=16)
export_to_video(list(frames), "sana_wm.mp4", fps=16)
```

Без `vae` refiner возвращает уточненные латенты вместо видео, что полезно, если вы хотите декодировать их самостоятельно.

> [!TIP]
> Включите offloading для **обоих** пайплайнов или освободите stage 1 перед stage 2 (`pipe.transformer.to("cpu")`). Оба этапа вместе занимают около 45 ГБ в `torch.bfloat16`, и удержание обоих на одной карте на 80 ГБ оставляет слишком мало места для активаций. Обратите также внимание, что stage 2 учитывает `torch_dtype`: загрузка refiner в `torch.float32` примерно вдвое увеличивает потребление памяти и слегка меняет результат.

Если у вас нет внутренних параметров камеры, размещённый [модульный блок](../../modular_diffusers/overview) может оценить их по одному кадру. Он находится вне `diffusers`, поскольку подключает Pi3X — это дополнительная зависимость и вторая контрольная точка, поэтому ничего не скачивается, пока вы явно не запросите это:

```python
from diffusers import ModularPipeline

# One-time per image. Requires `pip install pi3-vision`.
estimator = ModularPipeline.from_pretrained(
    "Efficient-Large-Model/pi3x-intrinsics-estimator", trust_remote_code=True
)
estimator.load_components(dtype=torch.bfloat16)
intrinsics = estimator(image=Image.open("input.png").convert("RGB"), output="intrinsics")
```

## Конвертация выпущенного контрольного пункта

Если у вас исходный релиз SANA-WM (а не преобразованный снимок diffusers), выполните скрипт преобразования один раз:

```bash
python scripts/convert_sana_wm_to_diffusers.py \
    --src Efficient-Large-Model/SANA-WM_bidirectional \
    --dst ./SANA-WM_bidirectional-diffusers
```

Это создаёт два каталога: базовый пайплайн в `--dst`, а рефинер второго этапа рядом с ним в `./SANA-WM_bidirectional-diffusers-refiner` (можно переопределить с помощью `--dst-refiner`). Затем загрузите каждый из них из локального пути как обычно.

## Компоненты

- `tokenizer` — `GemmaTokenizerFast`
- `text_encoder` — Gemma-2 (возвращает скрытые состояния декодера)
- `vae` — [AutoencoderKLLTX2Video](/docs/diffusers/main/ru/api/models/autoencoderkl_ltx_2#diffusers.AutoencoderKLLTX2Video) (LTX-2, пространственное ×32 / временное ×8)
- `transformer` — [SanaWMTransformer3DModel](/docs/diffusers/main/ru/api/models/sana_wm_transformer3d#diffusers.SanaWMTransformer3DModel), двунаправленный DiT с 1,6 млрд параметров
- `scheduler` — [FlowMatchEulerDiscreteScheduler](/docs/diffusers/main/ru/api/schedulers/flow_match_euler_discrete#diffusers.FlowMatchEulerDiscreteScheduler)

Рефинер второго этапа — это отдельный репозиторий со своим `transformer` ([SanaWMLTX2RefinerTransformer3DModel](/docs/diffusers/main/ru/api/models/sana_wm_refiner_transformer3d#diffusers.SanaWMLTX2RefinerTransformer3DModel)), `connectors` (`LTX2TextConnectors`), `tokenizer`, текстовым энкодером Gemma-3 `text_encoder` и `scheduler`. У него нет собственного `vae` — передайте его из базового пайплайна.

## SanaWMPipeline[[diffusers.SanaWMPipeline]]

#### diffusers.SanaWMPipeline[[diffusers.SanaWMPipeline]]

```python
diffusers.SanaWMPipeline(tokenizer: GemmaTokenizer | GemmaTokenizerFast, text_encoder: Gemma2PreTrainedModel, vae: AutoencoderKLLTX2Video, transformer: SanaWMTransformer3DModel, scheduler: FlowMatchEulerDiscreteScheduler)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L143)

**Параметры:**

tokenizer ([*GemmaTokenizer*] или [*GemmaTokenizerFast*]) : токенизатор Gemma-2.

text_encoder ([*Gemma2PreTrainedModel*]) : Текстовый энкодер Gemma-2.

vae ([*AutoencoderKLLTX2Video*]) : VAE для LTX-2.

transformer ([*SanaWMTransformer3DModel*]) : Двусторонний DiT SANA-WM с 1,6 млрд параметров.

scheduler ([*FlowMatchEulerDiscreteScheduler*]) : планировщик Euler для flow-matching (timesteps на уровне токенов в стиле LTX). latents напрямую.

Конвейер SANA-WM для управления камерой при преобразовании изображения в видео.

Генерирует видео на основе изображения первого кадра, текстового промпта и траектории камеры (явные позы `c2w` или строка действий WASD/IJKL). Использует 1600M bidirectional SANA DiT для сэмплирования на первом этапе и LTX-2 sink-bidirectional Euler refiner для доработки на втором этапе; оба этапа декодируются через LTX-2 VAE.

#### __call__[[diffusers.SanaWMPipeline.__call__]]

```python
__call__(image: PIL.Image.Image | str | Path, prompt: str, c2w: np.ndarray | None = None, action: str | None = None, intrinsics: np.ndarray | list[float] | None = None, height: int = 704, width: int = 1280, num_frames: int = 161, fps: int = 16, num_inference_steps: int = 60, guidance_scale: float = 5.0, negative_prompt: str = '', generator: torch.Generator | list[torch.Generator] | None = None, prompt_embeds: torch.Tensor | None = None, prompt_attention_mask: torch.Tensor | None = None, negative_prompt_embeds: torch.Tensor | None = None, negative_prompt_attention_mask: torch.Tensor | None = None, max_sequence_length: int = 300, chi_prompt: list[str] | None = None, output_type: Literal['np', 'pil', 'pt', 'latent'] = 'np', callback_on_step_end: Callable[[DiffusionPipeline, int, int, dict], dict] | None = None, callback_on_step_end_tensor_inputs: list[str] = ['latents'], return_dict: bool = True)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L457)

**Параметры:**

image (*PIL.Image.Image* или *str*) : Изображение первого кадра (PIL или путь).

prompt (*str*) : Текстовый промпт.

c2w (*np.ndarray*, *optional*) : позы камеры относительно мира `(F, 4, 4)`. Взаимоисключается с *action*.

action (*str*, *optional*) : строка Action-DSL, например `"w-80,jw-40,w-40"`. Взаимоисключается с *c2w*.

intrinsics (*np.ndarray* или *list[float]*) : `[fx, fy, cx, cy]` в пиксельных координатах **исходного изображения**. Конвейер внутренне применяет преобразование resize+crop.

height (*int*, по умолчанию 704) : Высота выходного кадра (фиксирована для публичной модели).

width (*int*, по умолчанию 1280) : Ширина выходного кадра (фиксирована для публичной модели).

num_frames (*int*, по умолчанию 161) : Целевое количество кадров; округляется до `8k+1` (ограничение VAE LTX-2).

fps (*int*, по умолчанию 16) : Частота кадров на выходе (также передаётся в refiner).

num_inference_steps (*int*, по умолчанию 60) : Количество шагов сэмплирования DiT первого этапа.

guidance_scale (*float*, по умолчанию 5.0) : Масштаб направляющей без классификатора (classifier-free guidance).

negative_prompt (*str*, по умолчанию "") : Необязательный отрицательный промпт.

generator (*torch.Generator* или *list[torch.Generator]*, *optional*) : Один или несколько генераторов torch для детерминированной выборки шума. Если *None*, выборка недетерминирована.

prompt_embeds (*torch.Tensor*, *optional*) : Предварительно вычисленные текстовые эмбеддинги для пропуска текстового энкодера. Должны передаваться вместе с *prompt_attention_mask*.

prompt_attention_mask (*torch.Tensor*, *optional*) : Маска внимания для *prompt_embeds*.

negative_prompt_embeds (*torch.Tensor*, *optional*) : Предварительно вычисленные эмбеддинги отрицательных текстов. Должен передаваться вместе с *negative_prompt_attention_mask*.

negative_prompt_attention_mask (*torch.Tensor*, *optional*) : Маска внимания для *negative_prompt_embeds*.

max_sequence_length (*int*, по умолчанию 300) : Максимальное количество токенов в запросе.

chi_prompt (*list[str]*, *optional*) : Переопределяет префикс chi-prompt (по умолчанию совпадает с публичным релизом).

output_type (*"np"*, *"pil"*, *"pt"* или *"latent"*, по умолчанию *"np"*) : Формат вывода.

callback_on_step_end (*Callable*, *необязательный*) : Вызывается в конце каждого шага денойзинга как *callback_on_step_end(self, step, timestep, callback_kwargs)*, где *callback_kwargs* содержит тензоры, указанные в *callback_on_step_end_tensor_inputs*. Тензоры в возвращаемом словаре заменяют тензоры пайплайна.

callback_on_step_end_tensor_inputs (*list[str]*, по умолчанию *["latents"]*) : какие тензоры передавать в *callback_on_step_end*; должно быть подмножеством *._callback_tensor_inputs*.

return_dict (*bool*, по умолчанию True) : возвращает [*SanaWMPipelineOutput*] вместо кортежа.

**Возвращает:**

[*SanaWMPipelineOutput*] с *.frames* формы `(T, H, W, 3)`, float `np.ndarray` в диапазоне `[0, 1]` для *output_type="np"*, список `PIL.Image.Image` длины `T` для *"pil"*, тензор `(T, 3, H, W)` для *"pt"* или исходный тензор латентов для *"latent"*.

Сгенерируйте видео с управлением камерой в SANA-WM.

Примеры:
```py
>>> import torch
>>> from PIL import Image
>>> from diffusers import SanaWMPipeline

>>> pipe = SanaWMPipeline.from_pretrained(
...     "Efficient-Large-Model/SANA-WM_bidirectional-diffusers", torch_dtype=torch.bfloat16
... ).to("cuda")

>>> output = pipe(
...     image=Image.open("input.png").convert("RGB"),
...     prompt="A car driving across a vast desert plain at golden hour.",
...     action="w-80,jw-40,w-40",
...     intrinsics=[800.0, 800.0, 845.0, 464.0],  # fx, fy, cx, cy in original-image pixels
...     num_inference_steps=60,
... )
>>> # output.frames is (T, H, W, 3) float np.ndarray in [0, 1] (diffusers convention).
```

#### check_inputs[[diffusers.SanaWMPipeline.check_inputs]]

```python
check_inputs(c2w: np.ndarray | None, action: str | None, intrinsics: np.ndarray | list[float] | None, callback_on_step_end_tensor_inputs: list[str] | None = None)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L335)

Проверяет входные данные `__call__`. Вызывает исключение при некорректном вводе и ничего не возвращает.

#### encode_prompt[[diffusers.SanaWMPipeline.encode_prompt]]

```python
encode_prompt(prompt: str, negative_prompt: str = '', device: torch.device | None = None, max_sequence_length: int = 300, chi_prompt: list[str] | None = None, prompt_embeds: torch.Tensor | None = None, prompt_attention_mask: torch.Tensor | None = None, negative_prompt_embeds: torch.Tensor | None = None, negative_prompt_attention_mask: torch.Tensor | None = None)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L204)

**Возвращает:**

`(cond, cond_mask, neg, neg_mask)`, где `cond` и `neg` — скрытые состояния Gemma формы `(1, 1, L, D)`, а маски имеют форму `(1, L)`.

Кодируйте промпт и негативный промпт через Gemma-2.

Повторяет трюк SANA с префиксом chi-промпта: chi-промпт добавляется в начало пользовательского промпта, затем срез `select_index = [0, -L+1, ..., -1]` извлекает токен BOS и последние `max_sequence_length - 1` токенов.

#### prepare_camera_trajectory[[diffusers.SanaWMPipeline.prepare_camera_trajectory]]

```python
prepare_camera_trajectory(c2w: np.ndarray | None, action: str | None, intrinsics: np.ndarray | list[float], num_frames: int)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L365)

Нормализуйте входные данные камеры до `(c2w_(F, 4, 4), intrinsics_(F, 4))`.

Также округляет `num_frames` до значения, удобного для VAE, `8k+1`, и обрезает оба массива до соответствующей длины. Обрезанное изображение и пересчитанные внутренние параметры появятся позже, когда будет известна целевое разрешение.

#### prepare_latents[[diffusers.SanaWMPipeline.prepare_latents]]

```python
prepare_latents(first_latent: torch.Tensor, num_frames: int, height: int, width: int, dtype: torch.dtype, device: torch.device, generator: torch.Generator)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L403)

Сгенерируйте начальные латенты и зафиксируйте первый кадр в качестве опорного для условного контекста.

Возвращает `(latents, condition_mask)`, где `condition_mask` содержит единицы на токенах первого кадра (они остаются чистыми на протяжении всего процесса сэмплирования) и нули в остальных местах.

## SanaWMLTX2Refiner[[diffusers.SanaWMLTX2Refiner]]

Рефинер LTX-2 stage-2 представляет собой автономный [DiffusionPipeline](/docs/diffusers/main/ru/api/pipelines/overview#diffusers.DiffusionPipeline), который принимает латенты stage-1. Передайте ему `vae` (из базового пайплайна, чтобы веса были общими), чтобы декодировать результат в видео; без него он вернет уточненные латенты.

#### diffusers.SanaWMLTX2Refiner[[diffusers.SanaWMLTX2Refiner]]

```python
diffusers.SanaWMLTX2Refiner(transformer: SanaWMLTX2RefinerTransformer3DModel, connectors: LTX2TextConnectors, tokenizer: GemmaTokenizer | GemmaTokenizerFast, text_encoder: Gemma3ForConditionalGeneration, scheduler: FlowMatchEulerDiscreteScheduler, vae: AutoencoderKLLTX2Video | None = None, text_max_sequence_length: int = 1024)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/refiner.py#L47)

**Параметры:**

transformer ([*SanaWMLTX2RefinerTransformer3DModel*]) : видео-DiT LTX-2 с чанково-каузальным скользящим окном KV-кэша.

connectors ([*LTX2TextConnectors*]) : текстовые коннекторы LTX-2.

tokenizer : токенизатор Gemma-3.

text_encoder : текстовый энкодер Gemma-3.

scheduler ([*FlowMatchEulerDiscreteScheduler*]) : планировщик Euler для flow-matching. Создан с параметром `shift=1.0`, чтобы дистиллированные сигмы проходили без изменений.

vae ([*AutoencoderKLLTX2Video*], *необязательный*) : тот же VAE, что используется в [*SanaWMPipeline*]; передайте *vae=pipe.vae*, чтобы использовать общие веса. Если параметр указан, рефинер декодирует в видео, в противном случае возвращает уточненные латенты.

text_max_sequence_length (*int*, по умолчанию 1024) : Максимальное количество токенов, передаваемых токенизатору Gemma-3.

LTX-2 sink-bidirectional Euler refiner — SANA-WM stage 2, как самостоятельный конвейер.

Обёртка для компонентов LTX-2 (трансформер-рефинер + текстовые коннекторы + текстовый энкодер Gemma-3 + токенизатор), а также [*FlowMatchEulerDiscreteScheduler*], который содержит дистиллированный сигма-расписание и выполняет шаги метода Эйлера. Зарегистрирован как необязательный компонент [*SanaWMPipeline*] и может использоваться самостоятельно для уточнения латентов первого этапа.

#### __call__[[diffusers.SanaWMLTX2Refiner.__call__]]

```python
__call__(sana_latent: torch.Tensor, prompt: str, fps: float, sink_size: int = 1, generator: torch.Generator | None = None, block_size: int = 3, kv_max_frames: int = 11, sigmas: tuple[float, ...] = (0.909375, 0.725, 0.421875, 0.0), output_type: str = 'np')
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/refiner.py#L107)

**Параметры:**

sana_latent : `(B, C, F, H, W)` латентный тензор первого этапа.

prompt : текстовый промпт.

fps : частота кадров видео (определяет временное масштабирование RoPE в LTX-2).

sink_size : сколько начальных необработанных кадров `z_sana` использовать в качестве якоря для attention sink (каноническое значение: 1).

generator : torch.Generator для шума на конечной точке FM. По умолчанию используется генератор с начальным значением 42, что обеспечивает воспроизводимость результатов без дополнительной настройки.

block_size : количество латентных кадров на блок AR (каноническое значение: 3).

kv_max_frames : максимальное количество контекста и активных кадров, удерживаемых в скользящем окне (каноническое значение: 11 = 1 sink + 10 недавних).

sigmas : нисходящее расписание Эйлера, завершающееся в 0.0 (канонический 3-шаговый дистиллированный вариант: `(0.909375, 0.725, 0.421875, 0.0)`). Передаётся в `self.scheduler` (без завершающего 0.0, которое планировщик добавляет самостоятельно).

output_type : *"latent"* возвращает уточненные латенты. Любое другое значение декодируется через *self.vae* и постобработка приводит результат к указанному типу (*"np"*, *"pt"*, *"pil"*); если *vae* отсутствует, возвращаются латенты в любом случае.

**Возвращает:** `*torch.Tensor*`

Усовершенствованные VAE-латенты формы `(B, C, F, H, W)` — первые `sink_size` кадров содержат исходные sink-латенты первого этапа без изменений, остальные — усовершенствованный вывод.

Запустите LTX-2 refiner и верните уточненные VAE-латенты.

Использует рецепт chunk-causal AR, на котором обучалась модель (`block_size=3`, `kv_max_frames=11`): скользящее окно K/V вида `[source_sink + recent_history + active_block]` подаётся в трансформер по одному блоку за раз, поэтому вычисления на блок ограничены, а общая стоимость уточнения линейно масштабируется с длиной видео.

## SanaWMPipelineOutput[[diffusers.SanaWMPipelineOutput]]

#### diffusers.SanaWMPipelineOutput[[diffusers.SanaWMPipelineOutput]]

```python
diffusers.SanaWMPipelineOutput(frames: typing.Union[torch.Tensor, numpy.ndarray, list[list[PIL.Image.Image]]], c2w: numpy.ndarray | None = None, latent: typing.Optional[torch.Tensor] = None)
```

[Источник](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_output.py#L25)

**Параметры:**

frames (*torch.Tensor*, *np.ndarray* или *list[PIL.Image.Image]*) : Сгенерированное видео: float `np.ndarray` формы `(T, H, W, 3)` в диапазоне `[0, 1]` для `output_type="np"`, тензор `(T, 3, H, W)` для `"pt"`, список из `T` объектов ``PIL.Image` для `"pil"` или тензор латентов `(B, C, T_lat, H_lat, W_lat)` для `"latent"`.

c2w (*np.ndarray*) : Позиции камеры относительно мира `(T, 4, 4)`, выровненные с `frames` (refiner удаляет якорную кадр sink; этот массив выравнивается соответственно, если refiner был запущен).

latent (*torch.Tensor*, optional) : Латентный тензор в пространстве VAE LTX-2, форма `(B, C, T_lat, H_lat, W_lat)`. Возвращается, когда `output_type="latent"``.

Класс вывода для пайплайна image-to-video SANA-WM.

