Diffusers documentation

SANA-WM

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.42.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

SANA-WM

SANA-WM é um modelo de mundo de imagem para vídeo controlado por câmera, construído sobre o SANA. Dada uma imagem do primeiro quadro, um prompt de texto e uma trajetória de câmera (seja poses c2w explícitas ou uma string de ações WASD/IJKL), ele gera um vídeo cujo movimento segue o caminho de câmera solicitado.

A inferência é executada em duas etapas:

  1. Etapa 1 — SANA-WM DiT. Um DiT bidirecional com 1,6 bilhão de parâmetros, com atenção linear GDN-Triton e um ramo de controle de câmera UCPE. A amostragem usa um agendador Euler de correspondência de fluxo no estilo LTX com tempos por token; o primeiro frame latente é a âncora de condicionamento.
  2. Etapa 2 — refinador LTX-2 (opcional). Um pipeline de refinamento Euler bidirecional com sink separado (SanaWMLTX2Refiner) que encapsula SanaWMLTX2RefinerTransformer3DModel + LTX2TextConnectors e um codificador de texto Gemma-3, executado por 3 passos de sigma destilados.

Ambas as etapas decodificam por meio do VAE AutoencoderKLLTX2Video.

Modelos disponíveis:

Modeldtype recomendado
Efficient-Large-Model/SANA-WM_bidirectional-diffuserstorch.bfloat16
Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refinertorch.bfloat16

SANA-WM é treinado em uma resolução fixa de 704×1280. O dtype recomendado é para os pesos do transformer — mantenha o text encoder em torch.bfloat16 e o VAE em torch.float32 para a melhor numérica. O pipeline espera intrínsecas da câmera [fx, fy, cx, cy] em coordenadas de pixels da imagem original; a transformação de redimensionamento e recorte centralizado é aplicada internamente.

Inferência

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
)

Pass action=None e forneça suas próprias poses c2w (array numpy (F, 4, 4)) para controlar explicitamente a trajetória da câmera. Remova output_type="latent" para obter o vídeo diretamente da etapa 1 e pular o refinador.

Etapa 2 — o refinador LTX-2

SanaWMLTX2Refiner é distribuído como um repositório próprio, da mesma forma que o SDXL separa o modelo base do refiner. Passe o VAE do pipeline base para que os pesos sejam compartilhados em vez de serem carregados duas vezes:

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)

Sem um vae, o refiner retorna latentes refinados em vez de vídeo, o que é útil se você quiser decodificar por conta própria.

Ative o offloading nos dois pipelines, ou libere a etapa 1 antes da etapa 2 (pipe.transformer.to("cpu")). As duas etapas juntas ocupam cerca de 45 GB em torch.bfloat16, e manter ambas residentes em uma única GPU de 80 GB deixa pouco espaço para ativações. Observe também que a etapa 2 respeita torch_dtype: carregar o refiner em torch.float32 praticamente dobra seu uso de memória e altera levemente a saída.

Se você não tiver as intrínsecas da câmera, um bloco modular hospedado pode estimá-las a partir de um único quadro. Ele fica fora do diffusers porque ele traz o Pi3X — uma dependência extra e um segundo checkpoint —, então nada é baixado até que você solicite:

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")

Convertendo o checkpoint liberado

Se você tiver a liberação original do SANA-WM (não o snapshot pré-convertido do diffusers), execute o script de conversão uma vez:

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

Isso grava dois diretórios: o pipeline base em --dst e o refinador da etapa 2 ao lado, em ./SANA-WM_bidirectional-diffusers-refiner (sobrescreva com --dst-refiner). Em seguida, carregue cada um de seu caminho local como de costume.

Componentes

O refinador da etapa 2 é um repositório separado com seu próprio transformer (SanaWMLTX2RefinerTransformer3DModel), connectors (LTX2TextConnectors), tokenizer, text_encoder Gemma-3 e scheduler. Ele não possui um vae próprio — passe o do pipeline base.

SanaWMPipeline

classe diffusers.SanaWMPipeline

< >

( tokenizer: GemmaTokenizer | GemmaTokenizerFasttext_encoder: Gemma2PreTrainedModelvae: AutoencoderKLLTX2Videotransformer: SanaWMTransformer3DModelscheduler: FlowMatchEulerDiscreteScheduler )

Parâmetros

  • tokenizer ([GemmaTokenizer] ou [GemmaTokenizerFast]) — O tokenizer do Gemma-2.
  • text_encoder ([Gemma2PreTrainedModel]) — O codificador de texto do Gemma-2.
  • vae ([AutoencoderKLLTX2Video]) — O VAE do LTX-2.
  • transformer ([SanaWMTransformer3DModel]) — O DiT bidirecional SANA-WM de 1600M.
  • scheduler ([FlowMatchEulerDiscreteScheduler]) — Agendador Euler de fluxo (timesteps por token no estilo LTX). latentes diretamente.

Pipeline de imagem para vídeo controlado por câmera do SANA-WM.

Gera um vídeo a partir de uma imagem do primeiro quadro, um prompt de texto e uma trajetória de câmera (poses c2w explícitas ou uma string de ações WASD/IJKL). Usa o SANA DiT bidirecional de 1600M para a amostragem da etapa 1 e o refinador Euler sink-bidirectional do LTX-2 para o polimento da etapa 2; ambos são decodificados pelo VAE do LTX-2.

__call__

< >

( image: PIL.Image.Image | str | Pathprompt: strc2w: np.ndarray | None = Noneaction: str | None = Noneintrinsics: np.ndarray | list[float] | None = Noneheight: int = 704width: int = 1280num_frames: int = 161fps: int = 16num_inference_steps: int = 60guidance_scale: float = 5.0negative_prompt: str = ''generator: torch.Generator | list[torch.Generator] | None = Noneprompt_embeds: torch.Tensor | None = Noneprompt_attention_mask: torch.Tensor | None = Nonenegative_prompt_embeds: torch.Tensor | None = Nonenegative_prompt_attention_mask: torch.Tensor | None = Nonemax_sequence_length: int = 300chi_prompt: list[str] | None = Noneoutput_type: Literal['np', 'pil', 'pt', 'latent'] = 'np'callback_on_step_end: Callable[[DiffusionPipeline, int, int, dict], dict] | None = Nonecallback_on_step_end_tensor_inputs: list[str] = ['latents']return_dict: bool = True )

Parâmetros

  • image (PIL.Image.Image ou str) — Imagem do primeiro quadro (PIL ou caminho).
  • prompt (str) — Prompt de texto.
  • c2w (np.ndarray, opcional) — (F, 4, 4) poses de câmera para mundo. Mutuamente exclusivo com action.
  • action (str, opcional) — String de Action-DSL, por exemplo, "w-80,jw-40,w-40". Mutuamente exclusivo com c2w.
  • intrinsics (np.ndarray ou list[float]) — [fx, fy, cx, cy] em coordenadas de pixels da imagem original. O pipeline aplica a transformação de redimensionamento + recorte internamente.
  • height (int, padrão 704) — Altura do quadro de saída (fixa para o modelo público).
  • width (int, padrão 1280) — Largura do quadro de saída (fixa para o modelo público).
  • num_frames (int, padrão 161) — Quantidade de quadros-alvo; ajustada para 8k+1 (restrição do VAE do LTX-2).
  • fps (int, padrão 16) — Taxa de quadros de saída (também fornecida ao refiner).
  • num_inference_steps (int, padrão 60) — Número de etapas de amostragem do DiT da etapa 1.
  • guidance_scale (float, padrão 5.0) — Escala de orientação sem classificador.
  • negative_prompt (str, padrão "") — Prompt negativo opcional.
  • generator (torch.Generator ou list[torch.Generator], opcional) — Um ou mais geradores torch para tornar a amostragem do ruído determinística. Se None, a amostragem é não determinística.
  • prompt_embeds (torch.Tensor, opcional) — Incorporações de texto pré-computadas, para pular o codificador de texto. Deve ser passado junto com prompt_attention_mask.
  • prompt_attention_mask (torch.Tensor, opcional) — Máscara de atenção para prompt_embeds.
  • negative_prompt_embeds (torch.Tensor, opcional) — Incorporações de texto negativas pré-computadas. Deve ser passado junto com negative_prompt_attention_mask.
  • negative_prompt_attention_mask (torch.Tensor, opcional) — Máscara de atenção para negative_prompt_embeds.
  • max_sequence_length (int, padrão 300) — Máximo de tokens do prompt.
  • chi_prompt (list[str], opcional) — Substitui o prefixo chi-prompt (o padrão espelha a versão pública).
  • output_type (“np”, “pil”, “pt” ou “latent”, padrão “np”) — Formato de saída.
  • callback_on_step_end (Callable, opcional) — Chamado no final de cada etapa de desruidamento como callback_on_step_end(self, step, timestep, callback_kwargs), onde callback_kwargs contém os tensores nomeados em callback_on_step_end_tensor_inputs. Os tensores no dicionário retornado substituem os do pipeline.
  • callback_on_step_end_tensor_inputs (list[str], padrão [“latents”]) — Quais tensores passar para callback_on_step_end; deve ser um subconjunto de ._callback_tensor_inputs.
  • return_dict (bool, padrão True) — Retorna [SanaWMPipelineOutput] ou tupla.

Gere um vídeo controlado por câmera do SANA-WM.

Exemplos:

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

< >

( c2w: np.ndarray | Noneaction: str | Noneintrinsics: np.ndarray | list[float] | Nonecallback_on_step_end_tensor_inputs: list[str] | None = None )

Valida as entradas de __call__. Lança uma exceção em caso de entrada inválida e não retorna nada.

encode_prompt

< >

( prompt: strnegative_prompt: str = ''device: torch.device | None = Nonemax_sequence_length: int = 300chi_prompt: list[str] | None = Noneprompt_embeds: torch.Tensor | None = Noneprompt_attention_mask: torch.Tensor | None = Nonenegative_prompt_embeds: torch.Tensor | None = Nonenegative_prompt_attention_mask: torch.Tensor | None = None )

Codifique o prompt + prompt negativo por meio do Gemma-2.

Espelha o truque de prefixo de prompt chi do SANA: o prompt chi é adicionado antes do prompt do usuário, e em seguida um recorte select_index = [0, -L+1, ..., -1] pega o token BOS mais os últimos max_sequence_length - 1 tokens.

prepare_camera_trajectory

< >

( c2w: np.ndarray | Noneaction: str | Noneintrinsics: np.ndarray | list[float]num_frames: int )

Normalize as entradas da câmera para (c2w_(F, 4, 4), intrinsics_(F, 4)).

Também ajusta num_frames para o formato 8k+1, compatível com o VAE, e recorta ambos os arrays para que fiquem com o mesmo tamanho. A imagem recortada e as intrínsecas redimensionadas são fornecidas posteriormente, uma vez que a resolução de destino é conhecida.

prepare_latents

< >

( first_latent: torch.Tensornum_frames: intheight: intwidth: intdtype: torch.dtypedevice: torch.devicegenerator: torch.Generator )

Amostras os latentes iniciais e fixa o primeiro quadro como âncora de condicionamento.

Retorna (latents, condition_mask), em que condition_mask possui uns nos tokens do primeiro frame (que permanecem limpos durante todo o amostramento) e zeros em todos os outros locais.

SanaWMLTX2Refiner

O refinador de estágio 2 do LTX-2 é um DiffusionPipeline independente que recebe os latentes do estágio 1. Forneça um vae (o do pipeline base, para que os pesos sejam compartilhados) para que ele decodifique para vídeo; sem um, ele retorna os latentes refinados.

classe diffusers.SanaWMLTX2Refiner

< >

( transformer: SanaWMLTX2RefinerTransformer3DModelconnectors: LTX2TextConnectorstokenizer: GemmaTokenizer | GemmaTokenizerFasttext_encoder: Gemma3ForConditionalGenerationscheduler: FlowMatchEulerDiscreteSchedulervae: AutoencoderKLLTX2Video | None = Nonetext_max_sequence_length: int = 1024 )

Parâmetros

  • transformer ([SanaWMLTX2RefinerTransformer3DModel]) — O DiT de vídeo LTX-2 com cache KV de janela deslizante causal por bloco.
  • connectors ([LTX2TextConnectors]) — Conectores de texto do LTX-2.
  • tokenizer — tokenizer do Gemma-3.
  • text_encoder — Codificador de texto do Gemma-3.
  • scheduler ([FlowMatchEulerDiscreteScheduler]) — Agendador Euler de fluxo. Construído com shift=1.0 para que os sigmas destilados passem sem modificações.
  • vae ([AutoencoderKLLTX2Video], opcional) — O mesmo VAE usado por [SanaWMPipeline]; passe vae=pipe.vae para compartilhar os pesos. Quando fornecido, o refiner decodifica para vídeo; caso contrário, retorna latentes refinados.
  • text_max_sequence_length (int, padrão 1024) — Número máximo de tokens passados ao tokenizer do Gemma-3.

LTX-2 sink-bidirectional Euler refiner — SANA-WM etapa 2, como um pipeline independente.

Envolve os componentes do LTX-2 (transformer refinador + conectores de texto + codificador de texto Gemma-3 + tokenizador) além de um [FlowMatchEulerDiscreteScheduler] que carrega o agendamento de sigma destilado e executa as etapas de Euler. Ele é registrado como um componente opcional do [SanaWMPipeline] e também pode ser usado de forma independente para refinar os latentes da etapa 1.

__call__

< >

( sana_latent: torch.Tensorprompt: strfps: floatsink_size: int = 1generator: torch.Generator | None = Noneblock_size: int = 3kv_max_frames: int = 11sigmas: tuple[float, ...] = (0.909375, 0.725, 0.421875, 0.0)output_type: str = 'np' ) → torch.Tensor

Parâmetros

  • sana_latent — latente da etapa 1, (B, C, F, H, W).
  • prompt — prompt de texto.
  • fps — taxa de quadros do vídeo (controla a escala temporal do RoPE do LTX-2).
  • sink_size — quantos quadros iniciais brutos de z_sana ancorar como o sink de atenção (canônico: 1).
  • generator — torch.Generator para o ruído do endpoint FM. O padrão é um gerador com semente 42, para que os resultados sejam reproduzíveis por padrão.
  • block_size — quadros latentes por bloco AR (canônico: 3).
  • kv_max_frames — número máximo de quadros de contexto + ativos mantidos na janela deslizante (canônico: 11 = 1 sink + 10 recentes).
  • sigmas — agenda descendente de Euler que termina em 0.0 (destilada canônica de 3 etapas: (0.909375, 0.725, 0.421875, 0.0)). Enviada para self.scheduler (sem o 0.0 final, que o scheduler adiciona por conta própria).
  • output_type — “latent” retorna os latentes refinados. Qualquer outro valor decodifica por meio de self.vae e faz o pós-processamento para esse tipo (“np”, “pt”, “pil”); sem um vae, os latentes são retornados independentemente.

Retorna

torch.Tensor

Latentes de VAE refinados de forma (B, C, F, H, W) — os primeiros sink_size quadros carregam os latentes de sink da etapa 1 brutos sem alterações, e o restante carrega a saída refinada.

Execute o refinador LTX-2 e retorne os latentes VAE refinados.

Usa a receita AR causal por blocos em que o modelo foi treinado (block_size=3, kv_max_frames=11): uma janela deslizante de [source_sink + recent_history + active_block] K/V é fornecida ao transformador um bloco de cada vez, de modo que o cálculo por bloco é limitado e o custo total de refinamento escala linearmente com o comprimento do vídeo.

SanaWMPipelineOutput

classe diffusers.SanaWMPipelineOutput

< >

( frames: typing.Union[torch.Tensor, numpy.ndarray, list[list[PIL.Image.Image]]]c2w: numpy.ndarray | None = Nonelatent: typing.Optional[torch.Tensor] = None )

Parâmetros

  • frames (torch.Tensor, np.ndarray ou list[PIL.Image.Image]) — Vídeo gerado: um np.ndarray float de forma (T, H, W, 3) em [0, 1] para output_type="np", um tensor (T, 3, H, W) para "pt", uma lista de T `PIL.Image para "pil", ou o tensor latente (B, C, T_lat, H_lat, W_lat) para "latent".
  • c2w (np.ndarray) — Poses de câmera para mundo (T, 4, 4) alinhadas com frames (o refiner remove o frame de âncora sink; este array é realinhado de acordo quando o refiner foi executado).
  • latent (torch.Tensor, optional) — Latent tensor in LTX-2 VAE space, shape (B, C, T_lat, H_lat, W_lat). Returned when `output_type=“latent”“.

Classe de saída para o pipeline de imagem para vídeo SANA-WM.

Update on GitHub