Diffusers documentation
ChronoEdit
ChronoEdit
NVIDIA와 토론토 대학교의 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이 발표한 ChronoEdit: Towards Temporal Reasoning for Image Editing and World Simulation
요약: ChronoEdit는 이미지 편집을 비디오 생성 작업으로 재정의하며, 입력 이미지와 편집된 이미지를 시작/종료 프레임으로 사용하여 시간적 일관성을 갖춘 사전 학습된 비디오 모델을 활용합니다. 시간 추론 단계에서는 물리적으로 타당한 편집을 보장하고 편집 궤적을 시각화하기 위해 추론 토큰을 도입합니다.
대형 생성 모델의 최근 발전은 이미지 편집과 컨텍스트 기반 이미지 생성을 크게 향상시켰으나, 편집된 객체가 일관성을 유지해야 하는 물리적 일관성을 보장하는 데에는 여전히 중요한 격차가 존재합니다. 이러한 기능은 월드 시뮬레이션 관련 작업에서 특히 중요합니다. 본 논문에서는 이미지 편집을 비디오 생성 문제로 재정의하는 프레임워크인 ChronoEdit를 제시합니다. 첫째, ChronoEdit는 입력 이미지와 편집된 이미지를 비디오의 첫 번째 프레임과 마지막 프레임으로 취급하여, 학습된 시간적 일관성을 통해 객체의 외형뿐만 아니라 움직임과 상호작용의 암묵적 물리 법칙까지 포착하는 대규모 사전 학습된 비디오 생성 모델을 활용할 수 있게 합니다. 둘째, ChronoEdit는 추론 시점에 명시적으로 편집을 수행하는 시간적 추론 단계를 도입합니다. 이 설정에서 대상 프레임은 추론 토큰과 함께 공동으로 디노이즈되어, 해의 공간을 물리적으로 실현 가능한 변환으로 제한하는 타당한 편집 궤적을 상상합니다. 이후 전체 비디오 렌더링의 높은 계산 비용을 피하기 위해 몇 단계 후 추론 토큰은 제거됩니다. ChronoEdit를 검증하기 위해, 물리적 일관성이 필요한 컨텍스트를 위한 이미지-프롬프트 쌍의 새로운 벤치마크인 PBench-Edit를 도입하고, ChronoEdit가 시각적 충실도와 물리적 타당성 모두에서 최첨단 베이스라인을 능가함을 입증합니다. 코드와 모델에 대한 프로젝트 페이지: this https URL.
ChronoEdit 파이프라인은 ChronoEdit 팀이 개발했습니다. 원본 코드는 GitHub에서 사용할 수 있으며, 사전 학습된 모델은 Hugging Face의 nvidia/ChronoEdit 컬렉션에서 찾을 수 있습니다.
사용 가능한 모델/LoRA:
- nvidia/ChronoEdit-14B-Diffusers
- nvidia/ChronoEdit-14B-Diffusers-Upscaler-Lora
- nvidia/ChronoEdit-14B-Diffusers-Paint-Brush-Lora
이미지 편집
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")선택적으로 temporal reasoning을 활성화하여 물리적 일관성을 향상시킬 수 있습니다:
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")8단계 증류 Lora를 사용한 추론
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")여러 LoRA를 사용한 추론
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
< source >( tokenizer: AutoTokenizertext_encoder: UMT5EncoderModelimage_encoder: CLIPVisionModelimage_processor: CLIPImageProcessorPiltransformer: ChronoEditTransformer3DModelvae: AutoencoderKLWanscheduler: FlowMatchEulerDiscreteScheduler )
매개변수
- tokenizer (
T5Tokenizer) — T5의 토크나이저로, 구체적으로 google/umt5-xxl 변형입니다. - text_encoder (
T5EncoderModel) — 구체적으로 google/umt5-xxl 변형을 사용하는 T5입니다. - image_encoder (
CLIPVisionModel) — 구체적으로 clip-vit-huge-patch14 변형인 CLIP - transformer (WanTransformer3DModel) — 입력 latents의 노이즈를 제거하기 위한 조건부 Transformer.
- scheduler (UniPCMultistepScheduler) —
transformer와 함께 사용되어 인코딩된 이미지 latents의 노이즈를 제거하는 데 사용되는 스케줄러. - vae (AutoencoderKLWan) — 잠재 표현으로 비디오를 인코딩 및 디코딩하는 Variational Auto-Encoder (VAE) 모델.
Wan을 사용하여 이미지에서 비디오로 생성하는 Pipeline
이 모델은 DiffusionPipeline에서 상속됩니다. 모든 파이프라인에 대해 구현된 일반적 메서드(다운로드, 저장, 특정 디바이스에서 실행 등)에 대해서는 상위 클래스 문서를 확인하세요.
__call__
< source >( 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
매개변수
- image (
PipelineImageInput) — 생성을 조건화할 입력 이미지입니다. 이미지, 이미지 목록 또는torch.Tensor여야 합니다. - prompt (
str또는list[str], 선택 사항) — 이미지 생성을 안내할 프롬프트입니다. 정의되지 않은 경우prompt_embeds를 대신 전달해야 합니다. - negative_prompt (
str또는list[str], 선택 사항) — 이미지 생성을 안내하지 않을 프롬프트입니다. 정의되지 않은 경우negative_prompt_embeds를 대신 전달해야 합니다. 가이던스를 사용하지 않을 때 무시됩니다(즉,guidance_scale이1보다 작으면 무시됩니다). - height (
int, 기본값480) — 생성된 비디오의 높이입니다. - width (
int, 기본값832) — 생성된 비디오의 너비입니다. - num_frames (
int, 기본값81) — 생성된 비디오의 프레임 수입니다. - num_inference_steps (
int, 기본값50) — 디노이징 단계의 수입니다. 디노이징 단계가 많을수록 일반적으로 더 높은 품질의 이미지를 생성하지만, 추론 속도는 느려집니다. - guidance_scale (
float, 기본값5.0) — Classifier-Free Diffusion Guidance에서 정의한 guidance scale입니다.guidance_scale은 Imagen Paper의 2번 식의w로 정의됩니다.guidance_scale > 1로 설정하면 guidance scale이 활성화됩니다. guidance scale이 높을수록prompt텍스트와 밀접하게 연결된 이미지를 생성하도록 유도하지만, 일반적으로 이미지 품질이 낮아지는 대가를 치릅니다. - num_videos_per_prompt (
int, 선택 사항, 기본값 1) — 프롬프트당 생성할 이미지의 수. - generator (
torch.Generator또는list[torch.Generator], 선택 사항) — 생성을 결정적으로 만들기 위한torch.Generator. - latents (
torch.Tensor, 선택 사항) — 가우시안 분포에서 샘플링된 사전 생성된 노이즈 latents로, 이미지 생성의 입력으로 사용됩니다. 동일한 생성을 다른 프롬프트로 조정하는 데 사용할 수 있습니다. 제공되지 않으면, 제공된 랜덤generator를 사용하여 샘플링하여 latents 텐서를 생성합니다. - prompt_embeds (
torch.Tensor, 선택) — 미리 생성된 텍스트 임베딩입니다. 텍스트 입력(프롬프트 가중치)을 쉽게 조정하는 데 사용할 수 있습니다. 제공되지 않으면prompt입력 인자에서 텍스트 임베딩이 생성됩니다. - negative_prompt_embeds (
torch.Tensor, 선택) — 미리 생성된 텍스트 임베딩입니다. 텍스트 입력(프롬프트 가중치)을 쉽게 조정하는 데 사용할 수 있습니다. 제공되지 않으면negative_prompt입력 인자로부터 텍스트 임베딩이 생성됩니다. - image_embeds (
torch.Tensor, 선택) — 미리 생성된 이미지 임베딩입니다. 이미지 입력(가중치)을 쉽게 조정하는 데 사용할 수 있습니다. 제공되지 않으면image입력 인자로부터 이미지 임베딩이 생성됩니다. - output_type (
str, 선택 사항, 기본값"np") — 생성된 이미지의 출력 형식입니다.PIL.Image또는np.array중 하나를 선택합니다. - return_dict (
bool, 선택 사항, 기본값True) — 일반 튜플 대신ChronoEditPipelineOutput을 반환할지 여부. - attention_kwargs (
dict, 선택 사항) — 지정된 경우 diffusers.models.attention_processor의self.processor에서 정의된AttentionProcessor로 전달되는 kwargs 사전입니다. - callback_on_step_end (
Callable,PipelineCallback,MultiPipelineCallbacks, 선택 사항) — 추론 중 각 denoising 단계의 끝에서 호출되는 함수 또는PipelineCallback또는MultiPipelineCallbacks의 하위 클래스입니다. 다음 인수를 가집니다:callback_on_step_end(self: DiffusionPipeline, step: int, timestep: int, callback_kwargs: Dict).callback_kwargs에는callback_on_step_end_tensor_inputs로 지정된 모든 텐서 목록이 포함됩니다. - callback_on_step_end_tensor_inputs (
List, 선택 사항) —callback_on_step_end함수의 텐서 입력 목록입니다. 목록에 지정된 텐서는callback_kwargs인수로 전달됩니다. 파이프라인 클래스의._callback_tensor_inputs속성에 나열된 변수만 포함할 수 있습니다. - max_sequence_length (
int, 기본값512) — 텍스트 인코더의 최대 시퀀스 길이입니다. 프롬프트가 이 길이보다 길면 잘리고, 짧으면 이 길이까지 패딩됩니다. - enable_temporal_reasoning (
bool, 선택 사항, 기본값False) — 시간 추론을 활성화할지 여부. - num_temporal_reasoning_steps (
int, 선택 사항, 기본값0) — 시간 추론을 활성화할 단계 수입니다.
반환값
~ChronoEditPipelineOutput 또는 tuple
return_dict가 True인 경우 ChronoEditPipelineOutput가 반환되고, 그렇지 않으면 tuple이 반환됩니다. 이 튜플의 첫 번째 요소는 생성된 이미지 목록이고, 두 번째 요소는 각 생성된 이미지에 “not-safe-for-work”(nsfw) 콘텐츠가 포함되어 있는지 여부를 나타내는 bool 목록입니다.
생성을 위한 pipeline의 호출 함수.
예:
>>> 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
< source >( 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 )
매개변수
- prompt (
str또는list[str], 선택 사항) — 인코딩할 프롬프트 - negative_prompt (
str또는list[str], 선택 사항) — 이미지 생성을 안내하지 않을 프롬프트입니다. 정의되지 않은 경우negative_prompt_embeds를 대신 전달해야 합니다. 가이던스를 사용하지 않을 때 무시됩니다(즉,guidance_scale이1보다 작으면 무시됩니다). - do_classifier_free_guidance (
bool, 선택 사항, 기본값True) — classifier free guidance를 사용할지 여부. - num_videos_per_prompt (
int, 선택 사항, 기본값 1) — 프롬프트당 생성할 비디오의 수. 결과 임베딩을 배치할 torch device - prompt_embeds (
torch.Tensor, 선택) — 미리 생성된 텍스트 임베딩입니다. 텍스트 입력을 쉽게 조정하는 데 사용할 수 있으며, 예를 들어 프롬프트 가중치 설정에 활용할 수 있습니다. 제공되지 않으면prompt입력 인자로부터 텍스트 임베딩이 생성됩니다. - negative_prompt_embeds (
torch.Tensor, 선택 사항) — 미리 생성된 negative text embeddings입니다. 텍스트 입력을 쉽게 조정하는 데 사용할 수 있으며, 예를 들어 프롬프트 가중치 설정에 활용할 수 있습니다. 제공되지 않으면negative_prompt입력 인자로부터 negative_prompt_embeds가 생성됩니다. - device — (
torch.device, 선택 사항): torch device - dtype — (
torch.dtype, 선택 사항): torch dtype
프롬프트를 텍스트 인코더의 히든 상태로 인코딩합니다.
ChronoEditPipelineOutput
클래스 diffusers.pipelines.chronoedit.pipeline_output.ChronoEditPipelineOutput
< source >( frames: Tensor )
ChronoEdit 파이프라인의 출력 클래스입니다.