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 est un modèle de monde image-vers-vidéo contrôlé par caméra, construit sur la base de SANA. À partir d'une image de première image, d'un prompt texte et d'une trajectoire de caméra (soit des poses c2w explicites, soit une chaîne d'actions WASD/IJKL), il génère une vidéo dont le mouvement suit le chemin de caméra demandé.

L'inférence s'exécute en deux étapes :

  1. Étape 1 — SANA-WM DiT. Un DiT bidirectionnel de 1,6 milliard de paramètres avec une attention linéaire GDN-Triton et une branche de contrôle caméra UCPE. L'échantillonnage utilise un planificateur Euler de correspondance de flux de type LTX avec des pas de temps par jeton ; le premier cadre latent est l'ancrage de conditionnement.
  2. Étape 2 — Rafineur LTX-2 (facultatif). Un pipeline de raffinement Euler bidirectionnel distinct (SanaWMLTX2Refiner) qui encapsule SanaWMLTX2RefinerTransformer3DModel + LTX2TextConnectors et un encodeur de texte Gemma-3, exécuté sur 3 étapes de sigma distillées.

Les deux étapes décodent via le VAE AutoencoderKLLTX2Video.

Modèles disponibles :

Modèledtype recommandé
Efficient-Large-Model/SANA-WM_bidirectional-diffuserstorch.bfloat16
Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refinertorch.bfloat16

SANA-WM est entraîné à une résolution fixe de 704×1280. Le dtype recommandé pour les poids du transformer est torch.bfloat16 — conservez l'encodeur de texte en torch.bfloat16 et le VAE en torch.float32 pour une meilleure précision numérique. Le pipeline s'attend à des intrinsèques de caméra [fx, fy, cx, cy] dans les coordonnées de pixels de l'image d'origine ; la transformation de redimensionnement et de recadrage centré est appliquée en interne.

Inférence

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
)

Passez action=None et fournissez vos propres poses c2w (tableau numpy (F, 4, 4)) pour piloter explicitement la trajectoire de la caméra. Supprimez output_type="latent" pour obtenir la vidéo directement depuis l'étape 1 et ignorer le raffineur.

Étape 2 — le raffineur LTX-2

SanaWMLTX2Refiner est fourni sous forme de dépôt distinct, à la manière dont SDXL sépare le modèle de base et le raffineur. Transmettez le VAE du pipeline de base afin que les poids soient partagés plutôt que chargés deux fois :

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)

Sans vae, le refiner renvoie des latents affinés au lieu de la vidéo, ce qui est utile si vous souhaitez effectuer le décodage vous-même.

Activez le déchargement sur les deux pipelines, ou libérez l’étape 1 avant l’étape 2 (pipe.transformer.to("cpu")). Les deux étapes représentent environ 45 Go en torch.bfloat16, et les maintenir toutes deux sur une seule carte de 80 Go laisse trop peu de place pour les activations. Notez également que l’étape 2 respecte torch_dtype : charger le raffineur en torch.float32 double approximativement sa mémoire et modifie légèrement la sortie.

Si vous ne disposez pas des intrinsèques de la caméra, un bloc modulaire hébergé peut les estimer à partir d’une seule image. Il se trouve en dehors de diffusers car il intègre Pi3X — une dépendance supplémentaire et un second point de contrôle — de sorte que rien n’est téléchargé tant que vous ne le demandez pas :

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

Conversion du point de contrôle publié

Si vous disposez de la version source SANA-WM (et non du instantané diffusers pré-converti), exécutez le script de conversion une seule fois :

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

Cela écrit deux répertoires : le pipeline de base dans --dst, et le raffineur de l’étape 2 à côté, dans ./SANA-WM_bidirectional-diffusers-refiner (à remplacer par --dst-refiner). Chargez ensuite chacun depuis son chemin local, comme d’habitude.

Composants

Le raffineur de l’étape 2 est un dépôt distinct disposant de son propre transformer (SanaWMLTX2RefinerTransformer3DModel), de ses connectors (LTX2TextConnectors), de son tokenizer, de son text_encoder Gemma-3 et de son scheduler. Il ne possède pas de vae propre — transmettez celui du pipeline de base.

SanaWMPipeline

classe diffusers.SanaWMPipeline

< >

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

Paramètres

  • tokenizer ([GemmaTokenizer] ou [GemmaTokenizerFast]) — Le tokenizer Gemma-2.
  • text_encoder ([Gemma2PreTrainedModel]) — L’encodeur de texte Gemma-2.
  • vae ([AutoencoderKLLTX2Video]) — Le VAE de LTX-2.
  • transformer ([SanaWMTransformer3DModel]) — Le DiT bidirectionnel SANA-WM de 1600M.
  • scheduler ([FlowMatchEulerDiscreteScheduler]) — Planificateur Euler de flow-matching (pas de temps par jeton de type LTX). latents directement.

Pipeline d'image vers vidéo contrôlé par caméra SANA-WM.

Génère une vidéo à partir d’une image de première image, d’un prompt texte et d’une trajectoire de caméra (poses c2w explicites ou une chaîne d’actions WASD/IJKL). Utilise le SANA DiT bidirectionnel 1600M pour l’échantillonnage de l’étape 1 et le refineur Euler bidirectionnel à sink de LTX-2 pour la finition de l’étape 2 ; les deux sont décodés via le VAE de 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 )

Paramètres

  • image (PIL.Image.Image ou str) — Image de la première image (PIL ou chemin).
  • prompt (str) — Prompt texte.
  • c2w (np.ndarray, facultatif) — (F, 4, 4) poses caméra-monde. Mutuellement exclusif avec action.
  • action (str, facultatif) — Chaîne Action-DSL, par exemple "w-80,jw-40,w-40". Mutuellement exclusif avec c2w.
  • intrinsics (np.ndarray ou list[float]) — [fx, fy, cx, cy] dans les coordonnées de pixels de l'image d'origine. Le pipeline applique la transformation de redimensionnement et de recadrage en interne.
  • height (int, par défaut 704) — Hauteur du cadre de sortie (fixe pour le modèle public).
  • width (int, par défaut 1280) — Largeur du cadre de sortie (fixe pour le modèle public).
  • num_frames (int, par défaut 161) — Nombre de cibles ; arrondi à 8k+1 (contrainte du VAE LTX-2).
  • fps (int, par défaut 16) — Taux de sortie des images (également transmis au refiner).
  • num_inference_steps (int, par défaut 60) — Nombre d'étapes d'échantillonnage DiT de l'étape 1.
  • guidance_scale (float, par défaut 5.0) — Échelle de guidage sans classifieur.
  • negative_prompt (str, par défaut "") — Prompt négatif facultatif.
  • generator (torch.Generator ou list[torch.Generator], facultatif) — Un ou plusieurs générateurs torch pour rendre l'échantillonnage du bruit déterministe. Si None, l'échantillonnage est non déterministe.
  • prompt_embeds (torch.Tensor, facultatif) — Embeddings de texte précalculés, pour ignorer l’encodeur de texte. Doit être passé avec prompt_attention_mask.
  • prompt_attention_mask (torch.Tensor, facultatif) — Masque d'attention pour prompt_embeds.
  • negative_prompt_embeds (torch.Tensor, facultatif) — Embeddings de texte négatifs précalculés. Doit être passé avec negative_prompt_attention_mask.
  • negative_prompt_attention_mask (torch.Tensor, facultatif) — Masque d'attention pour negative_prompt_embeds.
  • max_sequence_length (int, par défaut 300) — Nombre maximal de jetons du prompt.
  • chi_prompt (list[str], facultatif) — Remplace le préfixe chi-prompt (par défaut, il reflète la version publique).
  • output_type (“np”, “pil”, “pt” ou “latent”, par défaut “np”) — Format de sortie.
  • callback_on_step_end (Callable, facultatif) — Appelé à la fin de chaque étape de débruitage sous la forme callback_on_step_end(self, step, timestep, callback_kwargs), où callback_kwargs contient les tenseurs nommés dans callback_on_step_end_tensor_inputs. Les tenseurs du dictionnaire retourné remplacent ceux du pipeline.
  • callback_on_step_end_tensor_inputs (list[str], par défaut [“latents”]) — Tenseurs à passer à callback_on_step_end ; doit être un sous-ensemble de ._callback_tensor_inputs.
  • return_dict (bool, par défaut True) — Retourne [SanaWMPipelineOutput] ou un tuple.

Générer une vidéo contrôlée par caméra SANA-WM.

Exemples :

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

Valide les entrées de __call__. Lève une exception en cas d'entrée invalide et ne renvoie rien.

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 )

Encoder le prompt et le prompt négatif via Gemma-2.

Reprend l’astuce du préfixe chi-prompt de SANA : le prompt chi est préfixé au prompt de l’utilisateur, puis une tranche select_index = [0, -L+1, ..., -1] extrait le jeton BOS ainsi que les max_sequence_length - 1 derniers jetons.

prepare_camera_trajectory

< >

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

Normaliser les entrées de la caméra en (c2w_(F, 4, 4), intrinsics_(F, 4)).

Également arrondit num_frames à la valeur 8k+1 compatible avec le VAE et ajuste les deux tableaux en conséquence. L’image recadrée et les intrinsèques remises à l’échelle sont fournies plus tard, une fois la résolution cible connue.

prepare_latents

< >

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

Échantillonnez les latents initiaux et fixez le premier plan comme ancre de conditionnement.

Retourne (latents, condition_mask) où condition_mask contient des uns sur les jetons de la première image (ils restent propres tout au long de l’échantillonnage) et des zéros ailleurs.

SanaWMLTX2Refiner

Le raffineur de l’étape 2 de LTX-2 est un DiffusionPipeline autonome qui reçoit les latents de l’étape 1. Fournissez-lui un vae (celui du pipeline de base, afin que les poids soient partagés) pour qu’il décode en vidéo ; sans celui-ci, il renvoie des latents raffinés.

classe diffusers.SanaWMLTX2Refiner

< >

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

Paramètres

  • transformer ([SanaWMLTX2RefinerTransformer3DModel]) — Le DiT vidéo LTX-2 avec cache KV glissant causal par blocs.
  • connectors ([LTX2TextConnectors]) — Connecteurs texte de LTX-2.
  • tokenizer — Tokenizer Gemma-3.
  • text_encoder — encodeur de texte Gemma-3.
  • scheduler ([FlowMatchEulerDiscreteScheduler]) — Planificateur Euler de flow-matching. Construit avec shift=1.0 afin que les sigmas distillés passent sans modification.
  • vae ([AutoencoderKLLTX2Video], facultatif) — Le même VAE utilisé par [SanaWMPipeline] ; passez vae=pipe.vae pour partager les poids. S’il est fourni, le refiner décode en vidéo, sinon il renvoie des latents affinés.
  • text_max_sequence_length (int, par défaut 1024) — Nombre maximal de jetons transmis au tokenizer Gemma-3.

LTX-2 sink-bidirectionnel Euler refiner — SANA-WM étape 2, en tant que pipeline autonome.

Encapsule les composants de LTX-2 (transformer de raffinement + connecteurs de texte + encodeur de texte Gemma-3 + tokenizer) ainsi qu'un [FlowMatchEulerDiscreteScheduler] qui porte l'agenda sigma distillé et exécute les étapes d'Euler. Il est enregistré en tant que composant optionnel de [SanaWMPipeline] et peut également être utilisé de manière autonome pour raffiner les latents de l'étape 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

Paramètres

  • sana_latent — latent de l'étape 1, (B, C, F, H, W).
  • prompt — invite textuelle.
  • fps — fréquence des images de la vidéo (pilote le redimensionnement temporel de RoPE pour LTX-2).
  • sink_size — nombre de trames brutes z_sana initiales à ancrer comme puits d'attention (valeur canonique : 1).
  • generator — torch.Generator pour le bruit du point de terminaison FM. Par défaut, un générateur initialisé avec la graine 42 est utilisé, afin que les résultats soient reproductibles dès l’installation.
  • block_size — nombre de trames latentes par bloc AR (valeur canonique : 3).
  • kv_max_frames — nombre maximal de frames de contexte + actives conservées dans la fenêtre glissante (valeur canonique : 11 = 1 sink + 10 récentes).
  • sigmas — plan d’Euler descendant se terminant à 0.0 (distillation canonique en 3 étapes : (0.909375, 0.725, 0.421875, 0.0)). Transmis à self.scheduler (sans le 0.0 final, que le planificateur ajoute lui-même).
  • output_type — “latent” renvoie les latents affinés. Toute autre valeur décode via self.vae et post-traite vers ce type (“np”, “pt”, “pil”) ; en l’absence de vae, les latents sont renvoyés indépendamment.

Retourne

torch.Tensor

Latents VAE affinés de forme (B, C, F, H, W) — les sink_size premières images portent les latents bruts du sink de l'étape 1 sans modification, le reste porte la sortie affinée.

Exécutez le raffineur LTX-2 et renvoyez les latents VAE raffinés.

Utilise la recette AR causale par blocs sur laquelle le modèle a été entraîné (block_size=3, kv_max_frames=11) : une fenêtre glissante de [source_sink + recent_history + active_block] K/V est transmise au transformer un bloc à la fois, de sorte que le calcul par bloc est borné et que le coût total de raffinement évolue linéairement avec la longueur de la vidéo.

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 )

Paramètres

  • frames (torch.Tensor, np.ndarray ou list[PIL.Image.Image]) — Vidéo générée : un tableau np.ndarray flottant de forme (T, H, W, 3) dans [0, 1] pour output_type="np", un tenseur (T, 3, H, W) pour "pt", une liste de T `PIL.Image pour "pil", ou le tenseur latent (B, C, T_lat, H_lat, W_lat) pour "latent".
  • c2w (np.ndarray) — Poses caméra-monde (T, 4, 4) alignées avec frames (le refiner supprime le cadre d’ancrage sink ; ce tableau est réaligné en conséquence si le refiner a été exécuté).
  • 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 sortie pour le pipeline image-vers-vidéo SANA-WM.

Update on GitHub