Diffusers documentation
SANA-WM
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:
- 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.
- Etapa 2 — refinador LTX-2 (opcional). Um pipeline de refinamento Euler bidirecional com sink separado
(SanaWMLTX2Refiner) que encapsula SanaWMLTX2RefinerTransformer3DModel +
LTX2TextConnectorse 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:
| Model | dtype recomendado |
|---|---|
Efficient-Large-Model/SANA-WM_bidirectional-diffusers | torch.bfloat16 |
Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner | torch.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.bfloat16e o VAE emtorch.float32para 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 emtorch.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 respeitatorch_dtype: carregar o refiner emtorch.float32praticamente 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-diffusersIsso 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
tokenizer—GemmaTokenizerFasttext_encoder— Gemma-2 (retorna os estados ocultos do decodificador)vae— AutoencoderKLLTX2Video (LTX-2, espacial ×32 / temporal ×8)transformer— SanaWMTransformer3DModel, DiT bidirecional com 1,6 bilhão de parâmetrosscheduler— FlowMatchEulerDiscreteScheduler
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
< source >( 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__
< source >( 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
< source >( 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
< source >( 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
< source >( 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
< source >( 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
< source >( 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.0para 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__
< source >( 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_sanaancorar 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 paraself.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
< source >( 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.ndarrayfloat de forma(T, H, W, 3)em[0, 1]paraoutput_type="np", um tensor(T, 3, H, W)para"pt", uma lista deT`PIL.Imagepara"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 comframes(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.