Diffusers documentation
SANA-WM
SANA-WM
SANA-WM es un modelo de mundo de imagen a video controlado por cámara, construido sobre SANA. Dada una imagen de primer fotograma, un prompt de texto y una trayectoria de cámara (ya sea una pose c2w explícita o una cadena de acciones WASD/IJKL), genera un video cuyo movimiento sigue la trayectoria de cámara solicitada.
La inferencia se ejecuta en dos etapas:
- Etapa 1 — SANA-WM DiT. Un DiT bidireccional de 1.6B parámetros con atención lineal GDN-Triton y una rama de control de cámara UCPE. El muestreo utiliza un planificador Euler de flow-matching estilo LTX con pasos de tiempo por token; el primer marco latente es la ancla de condicionamiento.
- Etapa 2 — Refinador LTX-2 (opcional). Un pipeline de refinamiento Euler bidireccional con sink independiente
(SanaWMLTX2Refiner) que envuelve SanaWMLTX2RefinerTransformer3DModel +
LTX2TextConnectorsy un codificador de texto Gemma-3, ejecutado durante 3 pasos de sigma destilados.
Ambas etapas decodifican a través del VAE AutoencoderKLLTX2Video.
Modelos disponibles:
| Modelo | dtype recomendado |
|---|---|
Efficient-Large-Model/SANA-WM_bidirectional-diffusers | torch.bfloat16 |
Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner | torch.bfloat16 |
SANA-WM se entrena a una resolución fija de 704×1280. El dtype recomendado para los pesos del transformer es
torch.bfloat16; mantenga el codificador de texto entorch.bfloat16y el VAE entorch.float32para obtener la mejor precisión numérica. El pipeline espera las intrínsecas de la cámara[fx, fy, cx, cy]en coordenadas de píxeles de la imagen original; la transformación de redimensionado y recorte centrado se aplica internamente.
Inferencia
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
)Pasa action=None y proporciona tus propias poses c2w (un array numpy de (F, 4, 4)) para controlar la trayectoria de la cámara de forma explícita. Omita output_type="latent" para obtener el video directamente de la etapa 1 y saltarse el refinador.
Etapa 2 — el refinador LTX-2
SanaWMLTX2Refiner se distribuye como su propio repositorio, de la misma manera que SDXL separa el modelo base y el refiner. Pasa el VAE del pipeline base para que los pesos se compartan en lugar de cargarse dos veces:
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)Sin un vae, el refiner devuelve latentes refinados en lugar de video, lo cual es útil si deseas decodificarlos tú mismo.
Habilite el offloading en ambos pipelines, o libere la etapa 1 antes de la etapa 2 (
pipe.transformer.to("cpu")). Las dos etapas juntas ocupan alrededor de 45 GB entorch.bfloat16, y mantener ambas residentes en una tarjeta de 80 GB deja demasiado poco espacio para las activaciones. Tenga en cuenta también que la etapa 2 respetatorch_dtype: cargar el refiner entorch.float32duplica aproximadamente su memoria y cambia ligeramente la salida.
Si no tienes las intrínsecas de la cámara, un bloque modular alojado puede estimarlas a partir de un solo fotograma. Se encuentra fuera de diffusers porque incorpora Pi3X, una dependencia adicional y un segundo punto de control, por lo que no se descarga nada hasta que lo solicites:
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")Convertir el punto de control publicado
Si tienes la versión de origen de SANA-WM (no la instantánea de diffusers preconvertida), ejecuta el script de conversión una vez:
python scripts/convert_sana_wm_to_diffusers.py \
--src Efficient-Large-Model/SANA-WM_bidirectional \
--dst ./SANA-WM_bidirectional-diffusersEsto escribe dos directorios: el pipeline base en --dst y el refiner de la etapa 2 junto a él en ./SANA-WM_bidirectional-diffusers-refiner (se puede sobrescribir con --dst-refiner). Luego, carga cada uno desde su ruta local como de costumbre.
Componentes
tokenizer—GemmaTokenizerFasttext_encoder— Gemma-2 (devuelve los estados ocultos del decodificador)vae— AutoencoderKLLTX2Video (LTX-2, espacial ×32 / temporal ×8)transformer— SanaWMTransformer3DModel, DiT bidireccional de 1.600 millones de parámetrosscheduler— FlowMatchEulerDiscreteScheduler
El refiner de la etapa 2 es un repositorio independiente con su propio transformer (SanaWMLTX2RefinerTransformer3DModel), connectors (LTX2TextConnectors), tokenizer, text_encoder Gemma-3 y scheduler. No tiene un vae propio: pase el de la pipeline base.
SanaWMPipeline
clase diffusers.SanaWMPipeline
< source >( tokenizer: GemmaTokenizer | GemmaTokenizerFasttext_encoder: Gemma2PreTrainedModelvae: AutoencoderKLLTX2Videotransformer: SanaWMTransformer3DModelscheduler: FlowMatchEulerDiscreteScheduler )
Parámetros
- tokenizer ([GemmaTokenizer] o [GemmaTokenizerFast]) — El tokenizador de Gemma-2.
- text_encoder ([Gemma2PreTrainedModel]) — El codificador de texto de Gemma-2.
- vae ([AutoencoderKLLTX2Video]) — El VAE de LTX-2.
- transformer ([SanaWMTransformer3DModel]) — El DiT bidireccional SANA-WM de 1600M.
- scheduler ([FlowMatchEulerDiscreteScheduler]) — Programador de Euler de flujo de coincidencia (pasos de tiempo por token estilo LTX). latentes directamente.
Pipeline de imagen a video controlado por cámara de SANA-WM.
Genera un video a partir de una imagen de primer fotograma, un prompt de texto y una trayectoria de cámara (poses c2w explícitas o una cadena de acciones WASD/IJKL). Utiliza el SANA DiT bidireccional de 1600M para la muestreo de la etapa 1 y el refinador Euler sink-bidireccional de LTX-2 para el pulido de la etapa 2; ambos se decodifican a través del VAE de 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 o str) — Imagen del primer fotograma (PIL o ruta).
- prompt (str) — Prompt de texto.
- c2w (np.ndarray, opcional) —
(F, 4, 4)poses de cámara al mundo. Mutuamente excluyente con action. - action (str, opcional) —
Cadena de Action-DSL, por ejemplo
"w-80,jw-40,w-40". Mutuamente excluyente con c2w. - intrinsics (np.ndarray o list[float]) —
[fx, fy, cx, cy]en coordenadas de píxeles de la imagen original. El pipeline aplica internamente la transformación de redimensionado y recorte. - height (int, por defecto 704) — Altura del cuadro de salida (fija para el modelo público).
- width (int, por defecto 1280) — Ancho del cuadro de salida (fijo para el modelo público).
- num_frames (int, por defecto 161) —
Número de fotogramas objetivo; se ajusta a
8k+1(restricción del VAE de LTX-2). - fps (int, por defecto 16) — Tasa de fotogramas de salida (también se pasa al refiner).
- num_inference_steps (int, por defecto 60) — Número de pasos de muestreo de DiT de la etapa 1.
- guidance_scale (float, por defecto 5.0) — Escala de guía libre de clasificador.
- negative_prompt (str, por defecto "") — Prompt negativo opcional.
- generator (torch.Generator o list[torch.Generator], opcional) — Uno o más generadores de torch para hacer que la muestreo de ruido sea determinista. Si es None, la muestreo es no determinista.
- prompt_embeds (torch.Tensor, opcional) — Incrustaciones de texto precalculadas, para omitir el codificador de texto. Debe pasarse junto con prompt_attention_mask.
- prompt_attention_mask (torch.Tensor, opcional) — Máscara de atención para prompt_embeds.
- negative_prompt_embeds (torch.Tensor, opcional) — Incrustaciones de texto negativo precalculadas. Debe pasarse junto con negative_prompt_attention_mask.
- negative_prompt_attention_mask (torch.Tensor, opcional) — Máscara de atención para negative_prompt_embeds.
- max_sequence_length (int, por defecto 300) — Número máximo de tokens del prompt.
- chi_prompt (list[str], opcional) — Sobrescribe el prefijo chi-prompt (el valor predeterminado replica la versión pública).
- output_type (“np”, “pil”, “pt” o “latent”, por defecto “np”) — Formato de salida.
- callback_on_step_end (Callable, opcional) — Se llama al final de cada paso de desruido como callback_on_step_end(self, step, timestep, callback_kwargs), donde callback_kwargs contiene los tensores nombrados en callback_on_step_end_tensor_inputs. Los tensores en el diccionario devuelto reemplazan los de la pipeline.
- callback_on_step_end_tensor_inputs (list[str], por defecto [“latents”]) — Qué tensores pasar a callback_on_step_end; debe ser un subconjunto de ._callback_tensor_inputs.
- return_dict (bool, por defecto True) — Devuelve [SanaWMPipelineOutput] o una tupla.
Genera un video controlado por cámara de SANA-WM.
Ejemplos:
>>> 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 las entradas de __call__. Lanza una excepción si la entrada es incorrecta y no devuelve 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 )
Codifica el prompt y el prompt negativo a través de Gemma-2.
Reproduce el truco de prefijo de chi-prompt de SANA: el prompt chi se antepone al prompt del usuario y luego una rebanada select_index = [0, -L+1, ..., -1] toma el token BOS junto con los últimos max_sequence_length - 1 tokens.
prepare_camera_trajectory
< source >( c2w: np.ndarray | Noneaction: str | Noneintrinsics: np.ndarray | list[float]num_frames: int )
Normaliza las entradas de la cámara a (c2w_(F, 4, 4), intrinsics_(F, 4)).
También ajusta num_frames al formato 8k+1 compatible con el VAE y recorta ambos arreglos para que coincidan. La imagen recortada y las intrínsecas reescaladas se proporcionan más adelante, una vez que se conoce la resolución objetivo.
prepare_latents
< source >( first_latent: torch.Tensornum_frames: intheight: intwidth: intdtype: torch.dtypedevice: torch.devicegenerator: torch.Generator )
Muestree los latentes iniciales y fije el primer fotograma como ancla de condicionamiento.
Devuelve (latents, condition_mask), donde condition_mask tiene unos en los tokens del primer fotograma (se mantienen limpios durante todo el muestreo) y ceros en el resto.
SanaWMLTX2Refiner
El refinador de la etapa 2 de LTX-2 es un DiffusionPipeline independiente que recibe los latentes de la etapa 1. Si se le proporciona un vae (el de la pipeline base, para compartir los pesos), decodifica a video; si no, devuelve los latentes refinados.
clase diffusers.SanaWMLTX2Refiner
< source >( transformer: SanaWMLTX2RefinerTransformer3DModelconnectors: LTX2TextConnectorstokenizer: GemmaTokenizer | GemmaTokenizerFasttext_encoder: Gemma3ForConditionalGenerationscheduler: FlowMatchEulerDiscreteSchedulervae: AutoencoderKLLTX2Video | None = Nonetext_max_sequence_length: int = 1024 )
Parámetros
- transformer ([SanaWMLTX2RefinerTransformer3DModel]) — El DiT de video LTX-2 con caché KV de ventana deslizante causal por bloques.
- connectors ([LTX2TextConnectors]) — Conectores de texto de LTX-2.
- tokenizer — Tokenizer de Gemma-3.
- text_encoder — Codificador de texto de Gemma-3.
- scheduler ([FlowMatchEulerDiscreteScheduler]) —
Programador de Euler para flow-matching. Se construye con
shift=1.0para que las sigmas destiladas pasen sin modificarse. - vae ([AutoencoderKLLTX2Video], opcional) — El mismo VAE utilizado por [SanaWMPipeline]; pase vae=pipe.vae para compartir los pesos. Si se proporciona, el refiner decodifica a video; de lo contrario, devuelve latentes refinados.
- text_max_sequence_length (int, por defecto 1024) — Número máximo de tokens pasados al tokenizador de Gemma-3.
LTX-2 sink-bidirectional Euler refiner — SANA-WM etapa 2, como pipeline independiente.
Envuelve los componentes de LTX-2 (transformador refinador + conectores de texto + codificador de texto Gemma-3 + tokenizador) junto con un [FlowMatchEulerDiscreteScheduler] que lleva la programación de sigma destilada y realiza los pasos de Euler. Está registrado como un componente opcional de [SanaWMPipeline] y también puede usarse de forma independiente para refinar los latentes de la 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 de la etapa 1,
(B, C, F, H, W). - prompt — prompt de texto.
- fps — tasa de fotogramas por segundo del video (controla la escalada temporal de RoPE en LTX-2).
- sink_size — número de fotogramas iniciales de
z_sanasin procesar que se fijan como sumidero de atención (canónico: 1). - generator — torch.Generator para el ruido del endpoint FM. Por defecto, se usa un generador con semilla 42 para que los resultados sean reproducibles desde el inicio.
- block_size — fotogramas latentes por bloque AR (canónico: 3).
- kv_max_frames — número máximo de cuadros de contexto + activos que se conservan en la ventana deslizante (canónico: 11 = 1 sink + 10 recientes).
- sigmas — plan de Euler descendente que termina en 0.0 (destilado canónico de 3 pasos:
(0.909375, 0.725, 0.421875, 0.0)). Se pasa aself.scheduler(sin el 0.0 final, que el scheduler añade por sí mismo). - output_type — “latent” devuelve los latentes refinados. Cualquier otro valor se decodifica a través de self.vae y se postprocesa a ese tipo (“np”, “pt”, “pil”); sin un vae, se devuelven los latentes de todos modos.
Devuelve
torch.Tensor
Latentes de VAE refinados de forma (B, C, F, H, W): los primeros sink_size cuadros conservan los latentes de sink de la etapa 1 sin cambios, y el resto contiene la salida refinada.
Ejecuta el refinador LTX-2 y devuelve los latentes VAE refinados.
Utiliza la receta AR de causalidad por bloques con la que se entrenó el modelo (block_size=3, kv_max_frames=11): una ventana deslizante de K/V de [source_sink + recent_history + active_block] se alimenta al transformer un bloque a la vez, de modo que el cómputo por bloque está acotado y el coste total de refinamiento escala linealmente con la longitud del video.
SanaWMPipelineOutput
clase 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 o list[PIL.Image.Image]) —
Video generado: un
np.ndarrayde tipo float con forma(T, H, W, 3)en[0, 1]paraoutput_type="np", un tensor(T, 3, H, W)para"pt", una lista deT`PIL.Imagepara"pil", o el tensor latente(B, C, T_lat, H_lat, W_lat)para"latent". - c2w (np.ndarray) —
Posas de cámara al mundo
(T, 4, 4)alineadas conframes(el refiner descarta el marco de ancla de sink; este array se realinea en consecuencia cuando se ejecutó el refiner). - 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”“.
Clase de salida para el pipeline de imagen a video de SANA-WM.