Diffusers documentation

ChronoEdit

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

LoRA

ChronoEdit

ChronoEdit : vers le raisonnement temporel pour l'édition d'images et la simulation du monde de NVIDIA et de l'Université de Toronto, par Jay Zhangjie Wu, Xuanchi Ren, Tianchang Shen, Tianshi Cao, Kai He, Yifan Lu, Ruiyuan Gao, Enze Xie, Shiyi Lan, Jose M. Alvarez, Jun Gao, Sanja Fidler, Zian Wang, Huan Ling.

En bref : ChronoEdit reformule l'édition d'images comme une tâche de génération de vidéo, en utilisant les images d'entrée et éditées comme images de début et de fin afin d'exploiter les modèles de vidéo préentraînés avec une cohérence temporelle. Une étape de raisonnement temporel introduit des jetons de raisonnement pour garantir des édictions physiquement plausibles et visualiser la trajectoire d'édition.

Les récentes avancées dans les grands modèles génératifs ont considérablement amélioré à la fois l'édition d'images et la génération d'images en contexte, mais un écart critique demeure en matière de cohérence physique, où les objets modifiés doivent rester cohérents. Cette capacité est particulièrement cruciale pour les tâches liées à la simulation du monde. Dans cet article, nous présentons ChronoEdit, un cadre qui reformule l'édition d'images comme un problème de génération de vidéo. D'abord, ChronoEdit traite les images d'entrée et modifiées comme les première et dernière images d'une vidéo, ce qui lui permet d'exploiter de grands modèles génératifs de vidéo pré-entraînés qui capturent non seulement l'apparence des objets, mais aussi la physique implicite du mouvement et de l'interaction grâce à une cohérence temporelle apprise. Ensuite, ChronoEdit introduit une étape de raisonnement temporel qui effectue explicitement l'édition au moment de l'inférence. Dans ce contexte, l'image cible est débruitée conjointement avec des jetons de raisonnement pour imaginer une trajectoire d'édition plausible qui contraint l'espace des solutions à des transformations physiquement viables. Les jetons de raisonnement sont ensuite abandonnés après quelques étapes afin d'éviter le coût computationnel élevé du rendu d'une vidéo complète. Pour valider ChronoEdit, nous introduisons PBench-Edit, un nouveau jeu de référence de paires image-prompt pour des contextes nécessitant une cohérence physique, et démontrons que ChronoEdit surpasse les références de l'état de l'art tant en fidélité visuelle qu'en plausibilité physique. Page du projet pour le code et les modèles : this https URL.

Le pipeline ChronoEdit est développé par l'équipe ChronoEdit. Le code d'origine est disponible sur GitHub, et les modèles pré-entraînés peuvent être trouvés dans la collection nvidia/ChronoEdit sur Hugging Face.

Modèles/LoRAs disponibles :

Édition d'images

import torch
import numpy as np
from diffusers import AutoencoderKLWan, ChronoEditTransformer3DModel, ChronoEditPipeline
from diffusers.utils import export_to_video, load_image
from transformers import CLIPVisionModel
from PIL import Image

model_id = "nvidia/ChronoEdit-14B-Diffusers"
image_encoder = CLIPVisionModel.from_pretrained(model_id, subfolder="image_encoder", dtype=torch.float32)
vae = AutoencoderKLWan.from_pretrained(model_id, subfolder="vae", dtype=torch.float32)
transformer = ChronoEditTransformer3DModel.from_pretrained(model_id, subfolder="transformer", dtype=torch.bfloat16)
pipe = ChronoEditPipeline.from_pretrained(model_id, image_encoder=image_encoder, transformer=transformer, vae=vae, dtype=torch.bfloat16)
pipe.to("cuda")  # or "mps", "xpu", "cpu"

image = load_image(
    "https://huggingface.co/spaces/nvidia/ChronoEdit/resolve/main/examples/3.png"
)
max_area = 720 * 1280
aspect_ratio = image.height / image.width
mod_value = pipe.vae_scale_factor_spatial * pipe.transformer.config.patch_size[1]
height = round(np.sqrt(max_area * aspect_ratio)) // mod_value * mod_value
width = round(np.sqrt(max_area / aspect_ratio)) // mod_value * mod_value
print("width", width, "height", height)
image = image.resize((width, height))
prompt = (
    "The user wants to transform the image by adding a small, cute mouse sitting inside the floral teacup, enjoying a spa bath. The mouse should appear relaxed and cheerful, with a tiny white bath towel draped over its head like a turban. It should be positioned comfortably in the cup’s liquid, with gentle steam rising around it to blend with the cozy atmosphere. "
    "The mouse’s pose should be natural—perhaps sitting upright with paws resting lightly on the rim or submerged in the tea. The teacup’s floral design, gold trim, and warm lighting must remain unchanged to preserve the original aesthetic. The steam should softly swirl around the mouse, enhancing the spa-like, whimsical mood."
)

output = pipe(
    image=image,
    prompt=prompt,
    height=height,
    width=width,
    num_frames=5,
    num_inference_steps=50,
    guidance_scale=5.0,
    enable_temporal_reasoning=False,
    num_temporal_reasoning_steps=0,
).frames[0]
Image.fromarray((output[-1] * 255).clip(0, 255).astype("uint8")).save("output.png")

Facultativement, activez le raisonnement temporel pour une meilleure cohérence physique :

output = pipe(
    image=image,
    prompt=prompt,
    height=height,
    width=width,
    num_frames=29,
    num_inference_steps=50,
    guidance_scale=5.0,
    enable_temporal_reasoning=True,
    num_temporal_reasoning_steps=50,
).frames[0]
export_to_video(output, "output.mp4", fps=16)
Image.fromarray((output[-1] * 255).clip(0, 255).astype("uint8")).save("output.png")

Inférence avec Lora de distillation en 8 étapes

import torch
import numpy as np
from diffusers import AutoencoderKLWan, ChronoEditTransformer3DModel, ChronoEditPipeline
from diffusers.schedulers import UniPCMultistepScheduler
from diffusers.utils import export_to_video, load_image
from transformers import CLIPVisionModel
from PIL import Image

model_id = "nvidia/ChronoEdit-14B-Diffusers"
image_encoder = CLIPVisionModel.from_pretrained(model_id, subfolder="image_encoder", dtype=torch.float32)
vae = AutoencoderKLWan.from_pretrained(model_id, subfolder="vae", dtype=torch.float32)
transformer = ChronoEditTransformer3DModel.from_pretrained(model_id, subfolder="transformer", dtype=torch.bfloat16)
pipe = ChronoEditPipeline.from_pretrained(model_id, image_encoder=image_encoder, transformer=transformer, vae=vae, dtype=torch.bfloat16)
pipe.load_lora_weights("nvidia/ChronoEdit-14B-Diffusers", weight_name="lora/chronoedit_distill_lora.safetensors", adapter_name="distill")
pipe.fuse_lora(adapter_names=["distill"], lora_scale=1.0)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config, flow_shift=2.0)
pipe.to("cuda")  # or "mps", "xpu", "cpu"

image = load_image(
    "https://huggingface.co/spaces/nvidia/ChronoEdit/resolve/main/examples/3.png"
)
max_area = 720 * 1280
aspect_ratio = image.height / image.width
mod_value = pipe.vae_scale_factor_spatial * pipe.transformer.config.patch_size[1]
height = round(np.sqrt(max_area * aspect_ratio)) // mod_value * mod_value
width = round(np.sqrt(max_area / aspect_ratio)) // mod_value * mod_value
print("width", width, "height", height)
image = image.resize((width, height))
prompt = (
    "The user wants to transform the image by adding a small, cute mouse sitting inside the floral teacup, enjoying a spa bath. The mouse should appear relaxed and cheerful, with a tiny white bath towel draped over its head like a turban. It should be positioned comfortably in the cup’s liquid, with gentle steam rising around it to blend with the cozy atmosphere. "
    "The mouse’s pose should be natural—perhaps sitting upright with paws resting lightly on the rim or submerged in the tea. The teacup’s floral design, gold trim, and warm lighting must remain unchanged to preserve the original aesthetic. The steam should softly swirl around the mouse, enhancing the spa-like, whimsical mood."
)

output = pipe(
    image=image,
    prompt=prompt,
    height=height,
    width=width,
    num_frames=5,
    num_inference_steps=8,
    guidance_scale=1.0,
    enable_temporal_reasoning=False,
    num_temporal_reasoning_steps=0,
).frames[0]
export_to_video(output, "output.mp4", fps=16)
Image.fromarray((output[-1] * 255).clip(0, 255).astype("uint8")).save("output.png")

Inférence avec plusieurs LoRAs

import torch
import numpy as np
from diffusers import AutoencoderKLWan, ChronoEditTransformer3DModel, ChronoEditPipeline
from diffusers.schedulers import UniPCMultistepScheduler
from diffusers.utils import export_to_video, load_image
from transformers import CLIPVisionModel
from PIL import Image

model_id = "nvidia/ChronoEdit-14B-Diffusers"
image_encoder = CLIPVisionModel.from_pretrained(model_id, subfolder="image_encoder", dtype=torch.float32)
vae = AutoencoderKLWan.from_pretrained(model_id, subfolder="vae", dtype=torch.float32)
transformer = ChronoEditTransformer3DModel.from_pretrained(model_id, subfolder="transformer", dtype=torch.bfloat16)
pipe = ChronoEditPipeline.from_pretrained(model_id, image_encoder=image_encoder, transformer=transformer, vae=vae, dtype=torch.bfloat16)
pipe.load_lora_weights("nvidia/ChronoEdit-14B-Diffusers-Paint-Brush-Lora", weight_name="paintbrush_lora_diffusers.safetensors", adapter_name="paintbrush")
pipe.load_lora_weights("nvidia/ChronoEdit-14B-Diffusers", weight_name="lora/chronoedit_distill_lora.safetensors", adapter_name="distill")
pipe.fuse_lora(adapter_names=["paintbrush", "distill"], lora_scale=1.0)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config, flow_shift=2.0)
pipe.to("cuda")  # or "mps", "xpu", "cpu"

image = load_image(
    "https://raw.githubusercontent.com/nv-tlabs/ChronoEdit/refs/heads/main/assets/images/input_paintbrush.png"
)
max_area = 720 * 1280
aspect_ratio = image.height / image.width
mod_value = pipe.vae_scale_factor_spatial * pipe.transformer.config.patch_size[1]
height = round(np.sqrt(max_area * aspect_ratio)) // mod_value * mod_value
width = round(np.sqrt(max_area / aspect_ratio)) // mod_value * mod_value
print("width", width, "height", height)
image = image.resize((width, height))
prompt = (
    "Turn the pencil sketch in the image into an actual object that is consistent with the image’s content. The user wants to change the sketch to a crown and a hat."
)

output = pipe(
    image=image,
    prompt=prompt,
    height=height,
    width=width,
    num_frames=5,
    num_inference_steps=8,
    guidance_scale=1.0,
    enable_temporal_reasoning=False,
    num_temporal_reasoning_steps=0,
).frames[0]
export_to_video(output, "output.mp4", fps=16)
Image.fromarray((output[-1] * 255).clip(0, 255).astype("uint8")).save("output_1.png")

ChronoEditPipeline

classe diffusers.ChronoEditPipeline

< >

( tokenizer: AutoTokenizertext_encoder: UMT5EncoderModelimage_encoder: CLIPVisionModelimage_processor: CLIPImageProcessorPiltransformer: ChronoEditTransformer3DModelvae: AutoencoderKLWanscheduler: FlowMatchEulerDiscreteScheduler )

Paramètres

  • tokenizer (T5Tokenizer) — Tokenizer issu de T5, plus précisément la variante google/umt5-xxl.
  • text_encoder (T5EncoderModel) — T5, plus précisément la variante google/umt5-xxl.
  • image_encoder (CLIPVisionModel) — CLIP, plus précisément la variante clip-vit-huge-patch14.
  • transformer (WanTransformer3DModel) — Transformer conditionnel pour débruyer les latents d’entrée.
  • scheduler (UniPCMultistepScheduler) — Un planificateur à utiliser en combinaison avec transformer pour débruyer les latents d'image encodés.
  • vae (AutoencoderKLWan) — Modèle de Variational Auto-Encoder (VAE) pour encoder et décoder des vidéos vers et depuis des représentations latentes.

Pipeline pour la génération de vidéos à partir d’images utilisant Wan.

Ce modèle hérite de DiffusionPipeline. Consultez la documentation de la classe parente pour les méthodes génériques implémentées pour tous les pipelines (téléchargement, sauvegarde, exécution sur un appareil particulier, etc.).

__call__

< >

( image: typing.Union[PIL.Image.Image, numpy.ndarray, torch.Tensor, list[PIL.Image.Image], list[numpy.ndarray], list[torch.Tensor]]prompt: str | list[str] = Nonenegative_prompt: str | list[str] = Noneheight: int = 480width: int = 832num_frames: int = 81num_inference_steps: int = 50guidance_scale: float = 5.0num_videos_per_prompt: int | None = 1generator: typing.Union[torch.Generator, list[torch.Generator], NoneType] = Nonelatents: typing.Optional[torch.Tensor] = Noneprompt_embeds: typing.Optional[torch.Tensor] = Nonenegative_prompt_embeds: typing.Optional[torch.Tensor] = Noneimage_embeds: typing.Optional[torch.Tensor] = Noneoutput_type: str | None = 'np'return_dict: bool = Trueattention_kwargs: dict[str, typing.Any] | None = Nonecallback_on_step_end: typing.Optional[typing.Callable[[int, int, NoneType], diffusers.callbacks.PipelineCallback | diffusers.callbacks.MultiPipelineCallbacks]] = Nonecallback_on_step_end_tensor_inputs: list = ['latents']max_sequence_length: int = 512enable_temporal_reasoning: bool = Falsenum_temporal_reasoning_steps: int = 0 ) → ~ChronoEditPipelineOutput or tuple

Paramètres

  • image (PipelineImageInput) — L'image d'entrée sur laquelle conditionner la génération. Doit être une image, une liste d'images ou un torch.Tensor.
  • prompt (str ou list[str], facultatif) — Le prompt ou les prompts pour guider la génération d’image. S’il n’est pas défini, il faut passer prompt_embeds à la place.
  • negative_prompt (str ou list[str], facultatif) — Le ou les prompts à ne pas utiliser pour guider la génération d’image. S’il n’est pas défini, il faut passer negative_prompt_embeds à la place. Ignoré lorsque le guidage n’est pas utilisé (c’est-à-dire ignoré si guidance_scale est inférieur à 1).
  • height (int, par défaut 480) — La hauteur de la vidéo générée.
  • width (int, par défaut 832) — La largeur de la vidéo générée.
  • num_frames (int, par défaut 81) — Le nombre de frames dans la vidéo générée.
  • num_inference_steps (int, par défaut 50) — Le nombre d'étapes de débruitage. Un plus grand nombre d'étapes de débruitage conduit généralement à une image de meilleure qualité, au prix d'une inférence plus lente.
  • guidance_scale (float, par défaut 5.0) — Échelle de guidage telle que définie dans Classifier-Free Diffusion Guidance. guidance_scale est défini comme w de l’équation 2. de Imagen Paper. L’échelle de guidage est activée en définissant guidance_scale > 1. Une échelle de guidage plus élevée encourage la génération d’images étroitement liées au prompt de texte, généralement au détriment de la qualité de l’image.
  • num_videos_per_prompt (int, facultatif, valeur par défaut 1) — Le nombre d'images à générer par invite.
  • generator (torch.Generator ou list[torch.Generator], facultatif) — Un torch.Generator pour rendre la génération déterministe.
  • latents (torch.Tensor, facultatif) — Latents bruités pré-générés, échantillonnés à partir d’une distribution gaussienne, à utiliser comme entrées pour la génération d’images. Peut servir à ajuster la même génération avec des prompts différents. S’il n’est pas fourni, un tenseur de latents est généré par échantillonnage à l’aide du generator aléatoire fourni.
  • prompt_embeds (torch.Tensor, facultatif) — Embeddings de texte pré-générés. Peut être utilisé pour ajuster facilement les entrées de texte (pondération des prompts). S'il n'est pas fourni, les embeddings de texte sont générés à partir de l'argument d'entrée prompt.
  • negative_prompt_embeds (torch.Tensor, facultatif) — Embeddings de texte pré-générés. Peut être utilisé pour ajuster facilement les entrées de texte (pondération des prompts). S'il n'est pas fourni, les embeddings de texte sont générés à partir de l'argument d'entrée negative_prompt.
  • image_embeds (torch.Tensor, facultatif) — Embeddings d’image pré-générés. Peut être utilisé pour ajuster facilement les entrées d’image (pondération). S’ils ne sont pas fournis, les embeddings d’image sont générés à partir de l’argument d’entrée image.
  • output_type (str, facultatif, par défaut "np") — Le format de sortie de l'image générée. Choisissez entre PIL.Image ou np.array.
  • return_dict (bool, facultatif, par défaut True) — Indique s'il faut retourner un ChronoEditPipelineOutput plutôt qu'un simple tuple.
  • attention_kwargs (dict, facultatif) — Un dictionnaire de kwargs qui, s'il est spécifié, est transmis à l'AttentionProcessor défini sous self.processor dans diffusers.models.attention_processor.
  • callback_on_step_end (Callable, PipelineCallback, MultiPipelineCallbacks, facultatif) — Une fonction ou une sous-classe de PipelineCallback ou MultiPipelineCallbacks qui est appelée à la fin de chaque étape de débruitage pendant l’inférence, avec les arguments suivants : callback_on_step_end(self: DiffusionPipeline, step: int, timestep: int, callback_kwargs: Dict). callback_kwargs contiendra une liste de tous les tenseurs spécifiés par callback_on_step_end_tensor_inputs.
  • callback_on_step_end_tensor_inputs (List, facultatif) — La liste des entrées tensorielles pour la fonction callback_on_step_end. Les tenseurs spécifiés dans la liste seront passés en tant qu'argument callback_kwargs. Vous ne pourrez inclure que les variables listées dans l'attribut ._callback_tensor_inputs de votre classe de pipeline.
  • max_sequence_length (int, par défaut 512) — La longueur de séquence maximale de l’encodeur de texte. Si le prompt est plus long que cela, il sera tronqué. S’il est plus court, il sera complété jusqu’à cette longueur.
  • enable_temporal_reasoning (bool, facultatif, valeur par défaut False) — Indique s'il faut activer le raisonnement temporel.
  • num_temporal_reasoning_steps (int, facultatif, valeur par défaut 0) — Le nombre d'étapes pour activer le raisonnement temporel.

Retourne

~ChronoEditPipelineOutput ou tuple

Si return_dict est True, ChronoEditPipelineOutput est retourné, sinon un tuple est retourné dont le premier élément est une liste des images générées et le deuxième élément est une liste de bool indiquant si l’image générée correspondante contient du contenu « not-safe-for-work » (nsfw).

La fonction d'appel du pipeline pour la génération.

Exemples :

>>> import torch
>>> import numpy as np
>>> from diffusers import AutoencoderKLWan, ChronoEditTransformer3DModel, ChronoEditPipeline
>>> from diffusers.utils import export_to_video, load_image
>>> from transformers import CLIPVisionModel

>>> # Available models: nvidia/ChronoEdit-14B-Diffusers
>>> model_id = "nvidia/ChronoEdit-14B-Diffusers"
>>> image_encoder = CLIPVisionModel.from_pretrained(
...     model_id, subfolder="image_encoder", torch_dtype=torch.float32
... )
>>> vae = AutoencoderKLWan.from_pretrained(model_id, subfolder="vae", torch_dtype=torch.float32)
>>> transformer = ChronoEditTransformer3DModel.from_pretrained(
...     model_id, subfolder="transformer", torch_dtype=torch.bfloat16
... )
>>> pipe = ChronoEditPipeline.from_pretrained(
...     model_id, vae=vae, image_encoder=image_encoder, transformer=transformer, torch_dtype=torch.bfloat16
... )
>>> pipe.to("cuda")

>>> image = load_image("https://huggingface.co/spaces/nvidia/ChronoEdit/resolve/main/examples/3.png")
>>> max_area = 720 * 1280
>>> aspect_ratio = image.height / image.width
>>> mod_value = pipe.vae_scale_factor_spatial * pipe.transformer.config.patch_size[1]
>>> height = round(np.sqrt(max_area * aspect_ratio)) // mod_value * mod_value
>>> width = round(np.sqrt(max_area / aspect_ratio)) // mod_value * mod_value
>>> image = image.resize((width, height))
>>> prompt = (
...     "The user wants to transform the image by adding a small, cute mouse sitting inside the floral teacup, enjoying a spa bath. The mouse should appear relaxed and cheerful, with a tiny white bath towel draped over its head like a turban. It should be positioned comfortably in the cup’s liquid, with gentle steam rising around it to blend with the cozy atmosphere. "
...     "The mouse’s pose should be natural—perhaps sitting upright with paws resting lightly on the rim or submerged in the tea. The teacup’s floral design, gold trim, and warm lighting must remain unchanged to preserve the original aesthetic. The steam should softly swirl around the mouse, enhancing the spa-like, whimsical mood."
... )

>>> output = pipe(
...     image=image,
...     prompt=prompt,
...     height=height,
...     width=width,
...     num_frames=5,
...     guidance_scale=5.0,
...     enable_temporal_reasoning=False,
...     num_temporal_reasoning_steps=0,
... ).frames[0]
>>> export_to_video(output, "output.mp4", fps=16)

encode_prompt

< >

( prompt: str | list[str]negative_prompt: str | list[str] | None = Nonedo_classifier_free_guidance: bool = Truenum_videos_per_prompt: int = 1prompt_embeds: typing.Optional[torch.Tensor] = Nonenegative_prompt_embeds: typing.Optional[torch.Tensor] = Nonemax_sequence_length: int = 226device: typing.Optional[torch.device] = Nonedtype: typing.Optional[torch.dtype] = None )

Paramètres

  • prompt (str ou list[str], facultatif) — prompt à encoder
  • negative_prompt (str ou list[str], facultatif) — Le ou les prompts à ne pas utiliser pour guider la génération d’image. S’il n’est pas défini, il faut passer negative_prompt_embeds à la place. Ignoré lorsque le guidage n’est pas utilisé (c’est-à-dire ignoré si guidance_scale est inférieur à 1).
  • do_classifier_free_guidance (bool, facultatif, valeur par défaut True) — Indique s'il faut utiliser le classifier free guidance ou non.
  • num_videos_per_prompt (int, facultatif, valeur par défaut 1) — Nombre de vidéos à générer par invite. Appareil torch sur lequel placer les embeddings résultants
  • prompt_embeds (torch.Tensor, facultatif) — Embeddings de texte pré-générés. Peut être utilisé pour ajuster facilement les entrées de texte, par ex. le pondération des prompts. S'il n'est pas fourni, les embeddings de texte seront générés à partir de l'argument d'entrée prompt.
  • negative_prompt_embeds (torch.Tensor, facultatif) — Embeddings de texte négatifs pré-générés. Peut être utilisé pour ajuster facilement les entrées de texte, par ex. le pondération des prompts. S'il n'est pas fourni, negative_prompt_embeds sera généré à partir de l'argument d'entrée negative_prompt.
  • device — (torch.device, facultatif) : torch device
  • dtype — (torch.dtype, facultatif) : dtype torch

Encode le prompt dans les états cachés de l'encodeur de texte.

ChronoEditPipelineOutput

classe diffusers.pipelines.chronoedit.pipeline_output.ChronoEditPipelineOutput

< >

( frames: Tensor )

Paramètres

  • frames (torch.Tensor, np.ndarray ou list[list[PIL.Image.Image]]) — Liste des sorties vidéo - Il peut s'agir d'une liste imbriquée de longueur batch_size, où chaque sous-liste contient des séquences d'images PIL débruitées de longueur num_frames. Il peut également s'agir d'un tableau NumPy ou d'un tenseur Torch de forme (batch_size, num_frames, channels, height, width).

Classe de sortie pour les pipelines ChronoEdit.

Update on GitHub