Buckets:
Bajo licencia Apache License, versión 2.0 (la "Licencia");
no puede usar este archivo excepto en cumplimiento de la Licencia.
Puede obtener una copia de la Licencia en
http://www.apache.org/licenses/LICENSE-2.0
A menos que la ley aplicable lo exija o se haya acordado por escrito, el software
distribuido bajo la Licencia se distribuye en una base "TAL CUAL",
SIN GARANTÍAS NI CONDICIONES DE NINGÚN TIPO, ya sea expresa o implícita.
Consulte la Licencia para el lenguaje específico que rige los permisos y
limitaciones de la Licencia. -->
ChronoEdit
ChronoEdit: Hacia el razonamiento temporal para la edición de imágenes y la simulación del mundo de NVIDIA y la Universidad de Toronto, por 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.
Resumen: ChronoEdit redefine la edición de imágenes como una tarea de generación de video, utilizando las imágenes de entrada y editadas como fotogramas inicial y final para aprovechar los modelos de video preentrenados con consistencia temporal. Una etapa de razonamiento temporal introduce tokens de razonamiento para garantizar ediciones físicamente plausibles y visualizar la trayectoria de la edición.
Los avances recientes en modelos generativos de gran escala han mejorado significativamente tanto la edición de imágenes como la generación de imágenes en contexto, pero aún persiste una brecha crítica en la garantía de la consistencia física, donde los objetos editados deben mantenerse coherentes. Esta capacidad es especialmente vital para tareas relacionadas con la simulación del mundo. En este artículo, presentamos ChronoEdit, un marco que reformula la edición de imágenes como un problema de generación de video. En primer lugar, ChronoEdit trata las imágenes de entrada y editadas como los primeros y últimos fotogramas de un video, lo que le permite aprovechar grandes modelos generativos de video preentrenados que capturan no solo la apariencia del objeto, sino también la física implícita del movimiento y la interacción a través de la consistencia temporal aprendida. En segundo lugar, ChronoEdit introduce una etapa de razonamiento temporal que realiza explícitamente la edición en el momento de la inferencia. Bajo esta configuración, el fotograma objetivo se desruido conjuntamente con tokens de razonamiento para imaginar una trayectoria de edición plausible que restringe el espacio de soluciones a transformaciones físicamente viables. Los tokens de razonamiento se eliminan entonces después de unos pocos pasos para evitar el alto costo computacional de renderizar un video completo. Para validar ChronoEdit, introducimos PBench-Edit, una nueva referencia de pares de imagen-prompt para contextos que requieren consistencia física, y demostramos que ChronoEdit supera a las líneas base del estado del arte tanto en fidelidad visual como en plausibilidad física. Página del proyecto para el código y los modelos: this https URL.
El pipeline ChronoEdit es desarrollado por el equipo ChronoEdit. El código original está disponible en GitHub, y los modelos preentrenados se pueden encontrar en la colección nvidia/ChronoEdit de Hugging Face.
Modelos/LoRAs disponibles:
- nvidia/ChronoEdit-14B-Diffusers
- nvidia/ChronoEdit-14B-Diffusers-Upscaler-Lora
- nvidia/ChronoEdit-14B-Diffusers-Paint-Brush-Lora
Edición de imágenes
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")
Opcionalmente, active temporal reasoning para mejorar la consistencia física:
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")
Inferencia con Lora de destilación de 8 pasos
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")
Inferencia con múltiples 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[[diffusers.ChronoEditPipeline]]
diffusers.ChronoEditPipeline[[diffusers.ChronoEditPipeline]]
diffusers.ChronoEditPipeline(tokenizer: AutoTokenizer, text_encoder: UMT5EncoderModel, image_encoder: CLIPVisionModel, image_processor: CLIPImageProcessorPil, transformer: ChronoEditTransformer3DModel, vae: AutoencoderKLWan, scheduler: FlowMatchEulerDiscreteScheduler)
Parámetros:
tokenizer (T5Tokenizer) : Tokenizador de T5, específicamente la variante google/umt5-xxl.
text_encoder (T5EncoderModel) : T5, concretamente la variante google/umt5-xxl.
image_encoder (CLIPVisionModel) : CLIP, concretamente la variante clip-vit-huge-patch14.
transformer (WanTransformer3DModel) : Transformer condicional para desruidar los latentes de entrada.
scheduler (UniPCMultistepScheduler) : Un programador para usar en combinación con transformer para desruidar los latentes de imagen codificados.
vae (AutoencoderKLWan) : Modelo de Autoencoder Variacional (VAE) para codificar y decodificar videos hacia y desde representaciones latentes.
Pipeline para la generación de video a partir de imágenes usando Wan.
Este modelo hereda de DiffusionPipeline. Consulta la documentación de la clase superior para los métodos genéricos implementados en todas las tuberías (descarga, guardado, ejecución en un dispositivo específico, etc.).
call[[diffusers.ChronoEditPipeline.call]]
__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] = None, negative_prompt: str | list[str] = None, height: int = 480, width: int = 832, num_frames: int = 81, num_inference_steps: int = 50, guidance_scale: float = 5.0, num_videos_per_prompt: int | None = 1, generator: typing.Union[torch.Generator, list[torch.Generator], NoneType] = None, latents: typing.Optional[torch.Tensor] = None, prompt_embeds: typing.Optional[torch.Tensor] = None, negative_prompt_embeds: typing.Optional[torch.Tensor] = None, image_embeds: typing.Optional[torch.Tensor] = None, output_type: str | None = 'np', return_dict: bool = True, attention_kwargs: dict[str, typing.Any] | None = None, callback_on_step_end: typing.Optional[typing.Callable[[int, int, NoneType], diffusers.callbacks.PipelineCallback | diffusers.callbacks.MultiPipelineCallbacks]] = None, callback_on_step_end_tensor_inputs: list[str] = ['latents'], max_sequence_length: int = 512, enable_temporal_reasoning: bool = False, num_temporal_reasoning_steps: int = 0)
Parámetros:
image (PipelineImageInput) : La imagen de entrada para condicionar la generación. Debe ser una imagen, una lista de imágenes o un torch.Tensor.
prompt (str o list[str], opcional) : El prompt o los prompts para guiar la generación de la imagen. Si no se define, se debe pasar prompt_embeds en su lugar.
negative_prompt (str o list[str], opcional) : El prompt o prompts que no deben guiar la generación de la imagen. Si no se define, se debe pasar negative_prompt_embeds en su lugar. Se ignora cuando no se usa guía (es decir, se ignora si guidance_scale es menor que 1).
height (int, por defecto 480) : La altura del video generado.
width (int, por defecto 832) : El ancho del video generado.
num_frames (int, por defecto 81) : El número de fotogramas en el video generado.
num_inference_steps (int, por defecto 50) : El número de pasos de desruido. Más pasos de desruido suelen conducir a una imagen de mayor calidad a costa de una inferencia más lenta.
guidance_scale (float, por defecto 5.0) : Escala de guía definida en Classifier-Free Diffusion Guidance. guidance_scale se define como w de la ecuación 2. de Imagen Paper. La escala de guía se habilita estableciendo guidance_scale > 1. Una escala de guía más alta fomenta la generación de imágenes estrechamente vinculadas al prompt de texto, generalmente a costa de una menor calidad de imagen.
num_videos_per_prompt (int, opcional, valor predeterminado 1) : El número de imágenes a generar por indicación.
generator (torch.Generator o list[torch.Generator], opcional) : Un torch.Generator para hacer la generación determinista.
latents (torch.Tensor, opcional) : Latentes ruidosos pregenerados muestreados de una distribución gaussiana, que se utilizarán como entradas para la generación de imágenes. Se pueden usar para ajustar la misma generación con diferentes prompts. Si no se proporciona, se genera un tensor de latentes mediante muestreo usando el generator aleatorio suministrado.
prompt_embeds (torch.Tensor, opcional) : Incrustaciones de texto pregeneradas. Se pueden usar para ajustar fácilmente las entradas de texto (ponderación del prompt). Si no se proporcionan, las incrustaciones de texto se generan a partir del argumento de entrada prompt.
negative_prompt_embeds (torch.Tensor, opcional) : Embeddings de texto pregenerados. Se pueden usar para ajustar fácilmente las entradas de texto (ponderación del prompt). Si no se proporcionan, los embeddings de texto se generan a partir del argumento de entrada negative_prompt.
image_embeds (torch.Tensor, opcional) : Incrustaciones de imagen pregeneradas. Se pueden usar para ajustar fácilmente las entradas de imagen (ponderación). Si no se proporcionan, las incrustaciones de imagen se generan a partir del argumento de entrada image.
output_type (str, opcional, por defecto "np") : El formato de salida de la imagen generada. Elija entre PIL.Image o np.array.
return_dict (bool, opcional, valor predeterminado True) : Indica si se debe devolver un ChronoEditPipelineOutput en lugar de una tupla simple.
attention_kwargs (dict, opcional) : Un diccionario de kwargs que, si se especifica, se pasa al AttentionProcessor tal como se define bajo self.processor en diffusers.models.attention_processor.
callback_on_step_end (Callable, PipelineCallback, MultiPipelineCallbacks, opcional) : una función o una subclase de PipelineCallback o MultiPipelineCallbacks que se llama al final de cada paso de denoising durante la inferencia, con los siguientes argumentos: callback_on_step_end(self: DiffusionPipeline, step: int, timestep: int, callback_kwargs: Dict). callback_kwargs incluirá una lista de todos los tensores especificados por callback_on_step_end_tensor_inputs.
callback_on_step_end_tensor_inputs (List, opcional) : La lista de entradas de tensor para la función callback_on_step_end. Los tensores especificados en la lista se pasarán como argumento callback_kwargs. Solo podrá incluir variables enumeradas en el atributo ._callback_tensor_inputs de su clase de pipeline.
max_sequence_length (int, por defecto 512) : La longitud máxima de la secuencia del codificador de texto. Si el prompt es más largo que esto, se truncará. Si el prompt es más corto, se rellenará hasta esta longitud.
enable_temporal_reasoning (bool, opcional, por defecto False) : Si se habilita el razonamiento temporal.
num_temporal_reasoning_steps (int, opcional, valor predeterminado 0) : El número de pasos para habilitar el razonamiento temporal.
Devuelve: ~ChronoEditPipelineOutput o tuple
Si return_dict es True, se devuelve ChronoEditPipelineOutput; en caso contrario, se devuelve una tuple cuyo primer elemento es una lista con las imágenes generadas y cuyo segundo elemento es una lista de bool que indica si la imagen generada correspondiente contiene contenido "not-safe-for-work" (nsfw).
La función de llamada para el pipeline de generación.
Ejemplos:
>>> 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[[diffusers.ChronoEditPipeline.encode_prompt]]
encode_prompt(prompt: str | list[str], negative_prompt: str | list[str] | None = None, do_classifier_free_guidance: bool = True, num_videos_per_prompt: int = 1, prompt_embeds: typing.Optional[torch.Tensor] = None, negative_prompt_embeds: typing.Optional[torch.Tensor] = None, max_sequence_length: int = 226, device: typing.Optional[torch.device] = None, dtype: typing.Optional[torch.dtype] = None)
Parámetros:
prompt (str o list[str], opcional) : prompt a codificar
negative_prompt (str o list[str], opcional) : El prompt o prompts que no deben guiar la generación de la imagen. Si no se define, se debe pasar negative_prompt_embeds en su lugar. Se ignora cuando no se usa guía (es decir, se ignora si guidance_scale es menor que 1).
do_classifier_free_guidance (bool, opcional, por defecto True) : Si se debe usar o no la guía libre de clasificador.
num_videos_per_prompt (int, opcional, valor predeterminado 1) : Número de videos que deben generarse por indicación. Dispositivo de torch en el que colocar las incrustaciones resultantes
prompt_embeds (torch.Tensor, opcional) : Embeddings de texto pregenerados. Se pueden usar para ajustar fácilmente las entradas de texto, p. ej. ponderación de prompts. Si no se proporcionan, los embeddings de texto se generarán a partir del argumento de entrada prompt.
negative_prompt_embeds (torch.Tensor, opcional) : Embeddings de texto negativos pregenerados. Se pueden utilizar para ajustar fácilmente las entradas de texto, p. ej. el ponderado de prompts. Si no se proporcionan, negative_prompt_embeds se generará a partir del argumento de entrada negative_prompt.
device : (torch.device, opcional): dispositivo de torch
dtype : (torch.dtype, opcional): dtype de torch
Codifica el prompt en estados ocultos del codificador de texto.
ChronoEditPipelineOutput[[diffusers.pipelines.chronoedit.pipeline_output.ChronoEditPipelineOutput]]
diffusers.pipelines.chronoedit.pipeline_output.ChronoEditPipelineOutput[[diffusers.pipelines.chronoedit.pipeline_output.ChronoEditPipelineOutput]]
diffusers.pipelines.chronoedit.pipeline_output.ChronoEditPipelineOutput(frames: Tensor)
Parámetros:
frames (torch.Tensor, np.ndarray o list[list[PIL.Image.Image]]) : Lista de salidas de video - Puede ser una lista anidada de longitud batch_size, donde cada sublista contiene secuencias de imágenes PIL desruidas de longitud num_frames. También puede ser un array de NumPy o un tensor de Torch de forma (batch_size, num_frames, channels, height, width).
Clase de salida para las pipelines de ChronoEdit.
Xet Storage Details
- Size:
- 26.2 kB
- Xet hash:
- 50612252a44cc54e31a78bdedc9e43d52460e06fde95696a41ff0116a78ffa11
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.