Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 80dfbb99b8 | |||
| 6976cab7ca | |||
| fcbed3fa79 | |||
| b98b314b7a | |||
| 74558ff65b | |||
| 49644babd3 | |||
| 56b3b21693 | |||
| 9cef07da5a | |||
| 2d94c7838e | |||
| a81334e3f0 | |||
| d704a730cd | |||
| 49db233b35 | |||
| 93ea26f272 | |||
| f5dfe2a8b0 | |||
| 4836cfad98 | |||
| 1ccbfbb663 | |||
| 29dfe22a8e | |||
| 56806cdbfd | |||
| 8ccc76ab37 |
@@ -162,6 +162,25 @@ class LCMLoRATextToImageBenchmark(TextToImageBenchmark):
|
|||||||
guidance_scale=1.0,
|
guidance_scale=1.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def benchmark(self, args):
|
||||||
|
flush()
|
||||||
|
|
||||||
|
print(f"[INFO] {self.pipe.__class__.__name__}: Running benchmark with: {vars(args)}\n")
|
||||||
|
|
||||||
|
time = benchmark_fn(self.run_inference, self.pipe, args) # in seconds.
|
||||||
|
memory = bytes_to_giga_bytes(torch.cuda.max_memory_allocated()) # in GBs.
|
||||||
|
benchmark_info = BenchmarkInfo(time=time, memory=memory)
|
||||||
|
|
||||||
|
pipeline_class_name = str(self.pipe.__class__.__name__)
|
||||||
|
flush()
|
||||||
|
csv_dict = generate_csv_dict(
|
||||||
|
pipeline_cls=pipeline_class_name, ckpt=self.lora_id, args=args, benchmark_info=benchmark_info
|
||||||
|
)
|
||||||
|
filepath = self.get_result_filepath(args)
|
||||||
|
write_to_csv(filepath, csv_dict)
|
||||||
|
print(f"Logs written to: {filepath}")
|
||||||
|
flush()
|
||||||
|
|
||||||
|
|
||||||
class ImageToImageBenchmark(TextToImageBenchmark):
|
class ImageToImageBenchmark(TextToImageBenchmark):
|
||||||
pipeline_class = AutoPipelineForImage2Image
|
pipeline_class = AutoPipelineForImage2Image
|
||||||
|
|||||||
@@ -198,6 +198,8 @@
|
|||||||
title: Outputs
|
title: Outputs
|
||||||
title: Main Classes
|
title: Main Classes
|
||||||
- sections:
|
- sections:
|
||||||
|
- local: api/loaders/ip_adapter
|
||||||
|
title: IP-Adapter
|
||||||
- local: api/loaders/lora
|
- local: api/loaders/lora
|
||||||
title: LoRA
|
title: LoRA
|
||||||
- local: api/loaders/single_file
|
- local: api/loaders/single_file
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||||
|
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
# IP-Adapter
|
||||||
|
|
||||||
|
[IP-Adapter](https://hf.co/papers/2308.06721) is a lightweight adapter that enables prompting a diffusion model with an image. This method decouples the cross-attention layers of the image and text features. The image features are generated from an image encoder. Files generated from IP-Adapter are only ~100MBs.
|
||||||
|
|
||||||
|
<Tip>
|
||||||
|
|
||||||
|
Learn how to load an IP-Adapter checkpoint and image in the [IP-Adapter](../../using-diffusers/loading_adapters#ip-adapter) loading guide.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
## IPAdapterMixin
|
||||||
|
|
||||||
|
[[autodoc]] loaders.ip_adapter.IPAdapterMixin
|
||||||
@@ -49,12 +49,12 @@ make_image_grid([original_image, mask_image, image], rows=1, cols=3)
|
|||||||
|
|
||||||
## AsymmetricAutoencoderKL
|
## AsymmetricAutoencoderKL
|
||||||
|
|
||||||
[[autodoc]] models.autoencoder_asym_kl.AsymmetricAutoencoderKL
|
[[autodoc]] models.autoencoders.autoencoder_asym_kl.AsymmetricAutoencoderKL
|
||||||
|
|
||||||
## AutoencoderKLOutput
|
## AutoencoderKLOutput
|
||||||
|
|
||||||
[[autodoc]] models.autoencoder_kl.AutoencoderKLOutput
|
[[autodoc]] models.autoencoders.autoencoder_kl.AutoencoderKLOutput
|
||||||
|
|
||||||
## DecoderOutput
|
## DecoderOutput
|
||||||
|
|
||||||
[[autodoc]] models.vae.DecoderOutput
|
[[autodoc]] models.autoencoders.vae.DecoderOutput
|
||||||
|
|||||||
@@ -54,4 +54,4 @@ image
|
|||||||
|
|
||||||
## AutoencoderTinyOutput
|
## AutoencoderTinyOutput
|
||||||
|
|
||||||
[[autodoc]] models.autoencoder_tiny.AutoencoderTinyOutput
|
[[autodoc]] models.autoencoders.autoencoder_tiny.AutoencoderTinyOutput
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ model = AutoencoderKL.from_single_file(url)
|
|||||||
|
|
||||||
## AutoencoderKLOutput
|
## AutoencoderKLOutput
|
||||||
|
|
||||||
[[autodoc]] models.autoencoder_kl.AutoencoderKLOutput
|
[[autodoc]] models.autoencoders.autoencoder_kl.AutoencoderKLOutput
|
||||||
|
|
||||||
## DecoderOutput
|
## DecoderOutput
|
||||||
|
|
||||||
[[autodoc]] models.vae.DecoderOutput
|
[[autodoc]] models.autoencoders.vae.DecoderOutput
|
||||||
|
|
||||||
## FlaxAutoencoderKL
|
## FlaxAutoencoderKL
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ accelerate launch --mixed_precision="fp16" train_text_to_image_lora.py \
|
|||||||
--pretrained_model_name_or_path=$MODEL_NAME \
|
--pretrained_model_name_or_path=$MODEL_NAME \
|
||||||
--dataset_name=$DATASET_NAME \
|
--dataset_name=$DATASET_NAME \
|
||||||
--dataloader_num_workers=8 \
|
--dataloader_num_workers=8 \
|
||||||
--resolution=512
|
--resolution=512 \
|
||||||
--center_crop \
|
--center_crop \
|
||||||
--random_flip \
|
--random_flip \
|
||||||
--train_batch_size=1 \
|
--train_batch_size=1 \
|
||||||
@@ -214,4 +214,4 @@ image = pipeline("A pokemon with blue eyes").images[0]
|
|||||||
Congratulations on training a new model with LoRA! To learn more about how to use your new model, the following guides may be helpful:
|
Congratulations on training a new model with LoRA! To learn more about how to use your new model, the following guides may be helpful:
|
||||||
|
|
||||||
- Learn how to [load different LoRA formats](../using-diffusers/loading_adapters#LoRA) trained using community trainers like Kohya and TheLastBen.
|
- Learn how to [load different LoRA formats](../using-diffusers/loading_adapters#LoRA) trained using community trainers like Kohya and TheLastBen.
|
||||||
- Learn how to use and [combine multiple LoRA's](../tutorials/using_peft_for_inference) with PEFT for inference.
|
- Learn how to use and [combine multiple LoRA's](../tutorials/using_peft_for_inference) with PEFT for inference.
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ accelerate launch train_unconditional.py \
|
|||||||
If you're training with more than one GPU, add the `--multi_gpu` parameter to the training command:
|
If you're training with more than one GPU, add the `--multi_gpu` parameter to the training command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
accelerate launch --mixed_precision="fp16" --multi_gpu train_unconditional.py \
|
accelerate launch --multi_gpu train_unconditional.py \
|
||||||
--dataset_name="huggan/flowers-102-categories" \
|
--dataset_name="huggan/flowers-102-categories" \
|
||||||
--output_dir="ddpm-ema-flowers-64" \
|
--output_dir="ddpm-ema-flowers-64" \
|
||||||
--mixed_precision="fp16" \
|
--mixed_precision="fp16" \
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ def save_model_card(
|
|||||||
repo_folder=None,
|
repo_folder=None,
|
||||||
vae_path=None,
|
vae_path=None,
|
||||||
):
|
):
|
||||||
img_str = "widget:\n" if images else ""
|
img_str = "widget:\n"
|
||||||
for i, image in enumerate(images):
|
for i, image in enumerate(images):
|
||||||
image.save(os.path.join(repo_folder, f"image_{i}.png"))
|
image.save(os.path.join(repo_folder, f"image_{i}.png"))
|
||||||
img_str += f"""
|
img_str += f"""
|
||||||
@@ -121,6 +121,10 @@ def save_model_card(
|
|||||||
url:
|
url:
|
||||||
"image_{i}.png"
|
"image_{i}.png"
|
||||||
"""
|
"""
|
||||||
|
if not images:
|
||||||
|
img_str += f"""
|
||||||
|
- text: '{instance_prompt}'
|
||||||
|
"""
|
||||||
|
|
||||||
trigger_str = f"You should use {instance_prompt} to trigger the image generation."
|
trigger_str = f"You should use {instance_prompt} to trigger the image generation."
|
||||||
diffusers_imports_pivotal = ""
|
diffusers_imports_pivotal = ""
|
||||||
@@ -157,8 +161,6 @@ tags:
|
|||||||
base_model: {base_model}
|
base_model: {base_model}
|
||||||
instance_prompt: {instance_prompt}
|
instance_prompt: {instance_prompt}
|
||||||
license: openrail++
|
license: openrail++
|
||||||
widget:
|
|
||||||
- text: '{validation_prompt if validation_prompt else instance_prompt}'
|
|
||||||
---
|
---
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -2010,43 +2012,42 @@ def main(args):
|
|||||||
text_encoder_lora_layers=text_encoder_lora_layers,
|
text_encoder_lora_layers=text_encoder_lora_layers,
|
||||||
text_encoder_2_lora_layers=text_encoder_2_lora_layers,
|
text_encoder_2_lora_layers=text_encoder_2_lora_layers,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Final inference
|
|
||||||
# Load previous pipeline
|
|
||||||
vae = AutoencoderKL.from_pretrained(
|
|
||||||
vae_path,
|
|
||||||
subfolder="vae" if args.pretrained_vae_model_name_or_path is None else None,
|
|
||||||
revision=args.revision,
|
|
||||||
variant=args.variant,
|
|
||||||
torch_dtype=weight_dtype,
|
|
||||||
)
|
|
||||||
pipeline = StableDiffusionXLPipeline.from_pretrained(
|
|
||||||
args.pretrained_model_name_or_path,
|
|
||||||
vae=vae,
|
|
||||||
revision=args.revision,
|
|
||||||
variant=args.variant,
|
|
||||||
torch_dtype=weight_dtype,
|
|
||||||
)
|
|
||||||
|
|
||||||
# We train on the simplified learning objective. If we were previously predicting a variance, we need the scheduler to ignore it
|
|
||||||
scheduler_args = {}
|
|
||||||
|
|
||||||
if "variance_type" in pipeline.scheduler.config:
|
|
||||||
variance_type = pipeline.scheduler.config.variance_type
|
|
||||||
|
|
||||||
if variance_type in ["learned", "learned_range"]:
|
|
||||||
variance_type = "fixed_small"
|
|
||||||
|
|
||||||
scheduler_args["variance_type"] = variance_type
|
|
||||||
|
|
||||||
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config, **scheduler_args)
|
|
||||||
|
|
||||||
# load attention processors
|
|
||||||
pipeline.load_lora_weights(args.output_dir)
|
|
||||||
|
|
||||||
# run inference
|
|
||||||
images = []
|
images = []
|
||||||
if args.validation_prompt and args.num_validation_images > 0:
|
if args.validation_prompt and args.num_validation_images > 0:
|
||||||
|
# Final inference
|
||||||
|
# Load previous pipeline
|
||||||
|
vae = AutoencoderKL.from_pretrained(
|
||||||
|
vae_path,
|
||||||
|
subfolder="vae" if args.pretrained_vae_model_name_or_path is None else None,
|
||||||
|
revision=args.revision,
|
||||||
|
variant=args.variant,
|
||||||
|
torch_dtype=weight_dtype,
|
||||||
|
)
|
||||||
|
pipeline = StableDiffusionXLPipeline.from_pretrained(
|
||||||
|
args.pretrained_model_name_or_path,
|
||||||
|
vae=vae,
|
||||||
|
revision=args.revision,
|
||||||
|
variant=args.variant,
|
||||||
|
torch_dtype=weight_dtype,
|
||||||
|
)
|
||||||
|
|
||||||
|
# We train on the simplified learning objective. If we were previously predicting a variance, we need the scheduler to ignore it
|
||||||
|
scheduler_args = {}
|
||||||
|
|
||||||
|
if "variance_type" in pipeline.scheduler.config:
|
||||||
|
variance_type = pipeline.scheduler.config.variance_type
|
||||||
|
|
||||||
|
if variance_type in ["learned", "learned_range"]:
|
||||||
|
variance_type = "fixed_small"
|
||||||
|
|
||||||
|
scheduler_args["variance_type"] = variance_type
|
||||||
|
|
||||||
|
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config, **scheduler_args)
|
||||||
|
|
||||||
|
# load attention processors
|
||||||
|
pipeline.load_lora_weights(args.output_dir)
|
||||||
|
|
||||||
|
# run inference
|
||||||
pipeline = pipeline.to(accelerator.device)
|
pipeline = pipeline.to(accelerator.device)
|
||||||
generator = torch.Generator(device=accelerator.device).manual_seed(args.seed) if args.seed else None
|
generator = torch.Generator(device=accelerator.device).manual_seed(args.seed) if args.seed else None
|
||||||
images = [
|
images = [
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ class WebdatasetFilter:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Text2ImageDataset:
|
class SDText2ImageDataset:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
train_shards_path_or_url: Union[str, List[str]],
|
train_shards_path_or_url: Union[str, List[str]],
|
||||||
@@ -359,19 +359,43 @@ def scalings_for_boundary_conditions(timestep, sigma_data=0.5, timestep_scaling=
|
|||||||
|
|
||||||
|
|
||||||
# Compare LCMScheduler.step, Step 4
|
# Compare LCMScheduler.step, Step 4
|
||||||
def predicted_origin(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
def get_predicted_original_sample(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
if prediction_type == "epsilon":
|
if prediction_type == "epsilon":
|
||||||
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
|
||||||
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
|
||||||
pred_x_0 = (sample - sigmas * model_output) / alphas
|
pred_x_0 = (sample - sigmas * model_output) / alphas
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_x_0 = model_output
|
||||||
elif prediction_type == "v_prediction":
|
elif prediction_type == "v_prediction":
|
||||||
pred_x_0 = alphas[timesteps] * sample - sigmas[timesteps] * model_output
|
pred_x_0 = alphas * sample - sigmas * model_output
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Prediction type {prediction_type} currently not supported.")
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
return pred_x_0
|
return pred_x_0
|
||||||
|
|
||||||
|
|
||||||
|
# Based on step 4 in DDIMScheduler.step
|
||||||
|
def get_predicted_noise(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
|
if prediction_type == "epsilon":
|
||||||
|
pred_epsilon = model_output
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_epsilon = (sample - alphas * model_output) / sigmas
|
||||||
|
elif prediction_type == "v_prediction":
|
||||||
|
pred_epsilon = alphas * model_output + sigmas * sample
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
|
return pred_epsilon
|
||||||
|
|
||||||
|
|
||||||
def extract_into_tensor(a, t, x_shape):
|
def extract_into_tensor(a, t, x_shape):
|
||||||
b, *_ = t.shape
|
b, *_ = t.shape
|
||||||
out = a.gather(-1, t)
|
out = a.gather(-1, t)
|
||||||
@@ -835,34 +859,35 @@ def main(args):
|
|||||||
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
|
|
||||||
# The scheduler calculates the alpha and sigma schedule for us
|
# DDPMScheduler calculates the alpha and sigma noise schedules (based on the alpha bars) for us
|
||||||
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
||||||
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
||||||
|
# Initialize the DDIM ODE solver for distillation.
|
||||||
solver = DDIMSolver(
|
solver = DDIMSolver(
|
||||||
noise_scheduler.alphas_cumprod.numpy(),
|
noise_scheduler.alphas_cumprod.numpy(),
|
||||||
timesteps=noise_scheduler.config.num_train_timesteps,
|
timesteps=noise_scheduler.config.num_train_timesteps,
|
||||||
ddim_timesteps=args.num_ddim_timesteps,
|
ddim_timesteps=args.num_ddim_timesteps,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 2. Load tokenizers from SD-XL checkpoint.
|
# 2. Load tokenizers from SD 1.X/2.X checkpoint.
|
||||||
tokenizer = AutoTokenizer.from_pretrained(
|
tokenizer = AutoTokenizer.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="tokenizer", revision=args.teacher_revision, use_fast=False
|
args.pretrained_teacher_model, subfolder="tokenizer", revision=args.teacher_revision, use_fast=False
|
||||||
)
|
)
|
||||||
|
|
||||||
# 3. Load text encoders from SD-1.5 checkpoint.
|
# 3. Load text encoders from SD 1.X/2.X checkpoint.
|
||||||
# import correct text encoder classes
|
# import correct text encoder classes
|
||||||
text_encoder = CLIPTextModel.from_pretrained(
|
text_encoder = CLIPTextModel.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="text_encoder", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="text_encoder", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
|
|
||||||
# 4. Load VAE from SD-XL checkpoint (or more stable VAE)
|
# 4. Load VAE from SD 1.X/2.X checkpoint
|
||||||
vae = AutoencoderKL.from_pretrained(
|
vae = AutoencoderKL.from_pretrained(
|
||||||
args.pretrained_teacher_model,
|
args.pretrained_teacher_model,
|
||||||
subfolder="vae",
|
subfolder="vae",
|
||||||
revision=args.teacher_revision,
|
revision=args.teacher_revision,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 5. Load teacher U-Net from SD-XL checkpoint
|
# 5. Load teacher U-Net from SD 1.X/2.X checkpoint
|
||||||
teacher_unet = UNet2DConditionModel.from_pretrained(
|
teacher_unet = UNet2DConditionModel.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
@@ -872,7 +897,7 @@ def main(args):
|
|||||||
text_encoder.requires_grad_(False)
|
text_encoder.requires_grad_(False)
|
||||||
teacher_unet.requires_grad_(False)
|
teacher_unet.requires_grad_(False)
|
||||||
|
|
||||||
# 7. Create online (`unet`) student U-Nets.
|
# 7. Create online student U-Net.
|
||||||
unet = UNet2DConditionModel.from_pretrained(
|
unet = UNet2DConditionModel.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
@@ -935,6 +960,7 @@ def main(args):
|
|||||||
# Also move the alpha and sigma noise schedules to accelerator.device.
|
# Also move the alpha and sigma noise schedules to accelerator.device.
|
||||||
alpha_schedule = alpha_schedule.to(accelerator.device)
|
alpha_schedule = alpha_schedule.to(accelerator.device)
|
||||||
sigma_schedule = sigma_schedule.to(accelerator.device)
|
sigma_schedule = sigma_schedule.to(accelerator.device)
|
||||||
|
# Move the ODE solver to accelerator.device.
|
||||||
solver = solver.to(accelerator.device)
|
solver = solver.to(accelerator.device)
|
||||||
|
|
||||||
# 10. Handle saving and loading of checkpoints
|
# 10. Handle saving and loading of checkpoints
|
||||||
@@ -1011,13 +1037,14 @@ def main(args):
|
|||||||
eps=args.adam_epsilon,
|
eps=args.adam_epsilon,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 13. Dataset creation and data processing
|
||||||
# Here, we compute not just the text embeddings but also the additional embeddings
|
# Here, we compute not just the text embeddings but also the additional embeddings
|
||||||
# needed for the SD XL UNet to operate.
|
# needed for the SD XL UNet to operate.
|
||||||
def compute_embeddings(prompt_batch, proportion_empty_prompts, text_encoder, tokenizer, is_train=True):
|
def compute_embeddings(prompt_batch, proportion_empty_prompts, text_encoder, tokenizer, is_train=True):
|
||||||
prompt_embeds = encode_prompt(prompt_batch, text_encoder, tokenizer, proportion_empty_prompts, is_train)
|
prompt_embeds = encode_prompt(prompt_batch, text_encoder, tokenizer, proportion_empty_prompts, is_train)
|
||||||
return {"prompt_embeds": prompt_embeds}
|
return {"prompt_embeds": prompt_embeds}
|
||||||
|
|
||||||
dataset = Text2ImageDataset(
|
dataset = SDText2ImageDataset(
|
||||||
train_shards_path_or_url=args.train_shards_path_or_url,
|
train_shards_path_or_url=args.train_shards_path_or_url,
|
||||||
num_train_examples=args.max_train_samples,
|
num_train_examples=args.max_train_samples,
|
||||||
per_gpu_batch_size=args.train_batch_size,
|
per_gpu_batch_size=args.train_batch_size,
|
||||||
@@ -1037,6 +1064,7 @@ def main(args):
|
|||||||
tokenizer=tokenizer,
|
tokenizer=tokenizer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 14. LR Scheduler creation
|
||||||
# Scheduler and math around the number of training steps.
|
# Scheduler and math around the number of training steps.
|
||||||
overrode_max_train_steps = False
|
overrode_max_train_steps = False
|
||||||
num_update_steps_per_epoch = math.ceil(train_dataloader.num_batches / args.gradient_accumulation_steps)
|
num_update_steps_per_epoch = math.ceil(train_dataloader.num_batches / args.gradient_accumulation_steps)
|
||||||
@@ -1051,6 +1079,7 @@ def main(args):
|
|||||||
num_training_steps=args.max_train_steps,
|
num_training_steps=args.max_train_steps,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 15. Prepare for training
|
||||||
# Prepare everything with our `accelerator`.
|
# Prepare everything with our `accelerator`.
|
||||||
unet, optimizer, lr_scheduler = accelerator.prepare(unet, optimizer, lr_scheduler)
|
unet, optimizer, lr_scheduler = accelerator.prepare(unet, optimizer, lr_scheduler)
|
||||||
|
|
||||||
@@ -1072,7 +1101,7 @@ def main(args):
|
|||||||
).input_ids.to(accelerator.device)
|
).input_ids.to(accelerator.device)
|
||||||
uncond_prompt_embeds = text_encoder(uncond_input_ids)[0]
|
uncond_prompt_embeds = text_encoder(uncond_input_ids)[0]
|
||||||
|
|
||||||
# Train!
|
# 16. Train!
|
||||||
total_batch_size = args.train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps
|
total_batch_size = args.train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps
|
||||||
|
|
||||||
logger.info("***** Running training *****")
|
logger.info("***** Running training *****")
|
||||||
@@ -1123,6 +1152,7 @@ def main(args):
|
|||||||
for epoch in range(first_epoch, args.num_train_epochs):
|
for epoch in range(first_epoch, args.num_train_epochs):
|
||||||
for step, batch in enumerate(train_dataloader):
|
for step, batch in enumerate(train_dataloader):
|
||||||
with accelerator.accumulate(unet):
|
with accelerator.accumulate(unet):
|
||||||
|
# 1. Load and process the image and text conditioning
|
||||||
image, text = batch
|
image, text = batch
|
||||||
|
|
||||||
image = image.to(accelerator.device, non_blocking=True)
|
image = image.to(accelerator.device, non_blocking=True)
|
||||||
@@ -1140,37 +1170,37 @@ def main(args):
|
|||||||
|
|
||||||
latents = latents * vae.config.scaling_factor
|
latents = latents * vae.config.scaling_factor
|
||||||
latents = latents.to(weight_dtype)
|
latents = latents.to(weight_dtype)
|
||||||
|
|
||||||
# Sample noise that we'll add to the latents
|
|
||||||
noise = torch.randn_like(latents)
|
|
||||||
bsz = latents.shape[0]
|
bsz = latents.shape[0]
|
||||||
|
|
||||||
# Sample a random timestep for each image t_n ~ U[0, N - k - 1] without bias.
|
# 2. Sample a random timestep for each image t_n from the ODE solver timesteps without bias.
|
||||||
|
# For the DDIM solver, the timestep schedule is [T - 1, T - k - 1, T - 2 * k - 1, ...]
|
||||||
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
||||||
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
||||||
start_timesteps = solver.ddim_timesteps[index]
|
start_timesteps = solver.ddim_timesteps[index]
|
||||||
timesteps = start_timesteps - topk
|
timesteps = start_timesteps - topk
|
||||||
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
||||||
|
|
||||||
# 20.4.4. Get boundary scalings for start_timesteps and (end) timesteps.
|
# 3. Get boundary scalings for start_timesteps and (end) timesteps.
|
||||||
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
||||||
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
||||||
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
||||||
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
||||||
|
|
||||||
# 20.4.5. Add noise to the latents according to the noise magnitude at each timestep
|
# 4. Sample noise from the prior and add it to the latents according to the noise magnitude at each
|
||||||
# (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
# timestep (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
||||||
|
noise = torch.randn_like(latents)
|
||||||
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
||||||
|
|
||||||
# 20.4.6. Sample a random guidance scale w from U[w_min, w_max] and embed it
|
# 5. Sample a random guidance scale w from U[w_min, w_max]
|
||||||
|
# Note that for LCM-LoRA distillation it is not necessary to use a guidance scale embedding
|
||||||
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
||||||
w = w.reshape(bsz, 1, 1, 1)
|
w = w.reshape(bsz, 1, 1, 1)
|
||||||
w = w.to(device=latents.device, dtype=latents.dtype)
|
w = w.to(device=latents.device, dtype=latents.dtype)
|
||||||
|
|
||||||
# 20.4.8. Prepare prompt embeds and unet_added_conditions
|
# 6. Prepare prompt embeds and unet_added_conditions
|
||||||
prompt_embeds = encoded_text.pop("prompt_embeds")
|
prompt_embeds = encoded_text.pop("prompt_embeds")
|
||||||
|
|
||||||
# 20.4.9. Get online LCM prediction on z_{t_{n + k}}, w, c, t_{n + k}
|
# 7. Get online LCM prediction on z_{t_{n + k}} (noisy_model_input), w, c, t_{n + k} (start_timesteps)
|
||||||
noise_pred = unet(
|
noise_pred = unet(
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
@@ -1179,7 +1209,7 @@ def main(args):
|
|||||||
added_cond_kwargs=encoded_text,
|
added_cond_kwargs=encoded_text,
|
||||||
).sample
|
).sample
|
||||||
|
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
noise_pred,
|
noise_pred,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1190,17 +1220,27 @@ def main(args):
|
|||||||
|
|
||||||
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
||||||
|
|
||||||
# 20.4.10. Use the ODE solver to predict the kth step in the augmented PF-ODE trajectory after
|
# 8. Compute the conditional and unconditional teacher model predictions to get CFG estimates of the
|
||||||
# noisy_latents with both the conditioning embedding c and unconditional embedding 0
|
# predicted noise eps_0 and predicted original sample x_0, then run the ODE solver using these
|
||||||
# Get teacher model prediction on noisy_latents and conditional embedding
|
# estimates to predict the data point in the augmented PF-ODE trajectory corresponding to the next ODE
|
||||||
|
# solver timestep.
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda"):
|
with torch.autocast("cuda"):
|
||||||
|
# 1. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and conditional embedding c
|
||||||
cond_teacher_output = teacher_unet(
|
cond_teacher_output = teacher_unet(
|
||||||
noisy_model_input.to(weight_dtype),
|
noisy_model_input.to(weight_dtype),
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
||||||
).sample
|
).sample
|
||||||
cond_pred_x0 = predicted_origin(
|
cond_pred_x0 = get_predicted_original_sample(
|
||||||
|
cond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
cond_pred_noise = get_predicted_noise(
|
||||||
cond_teacher_output,
|
cond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1209,13 +1249,21 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get teacher model prediction on noisy_latents and unconditional embedding
|
# 2. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and unconditional embedding 0
|
||||||
uncond_teacher_output = teacher_unet(
|
uncond_teacher_output = teacher_unet(
|
||||||
noisy_model_input.to(weight_dtype),
|
noisy_model_input.to(weight_dtype),
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
||||||
).sample
|
).sample
|
||||||
uncond_pred_x0 = predicted_origin(
|
uncond_pred_x0 = get_predicted_original_sample(
|
||||||
|
uncond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
uncond_pred_noise = get_predicted_noise(
|
||||||
uncond_teacher_output,
|
uncond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1224,12 +1272,17 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.11. Perform "CFG" to get x_prev estimate (using the LCM paper's CFG formulation)
|
# 3. Calculate the CFG estimate of x_0 (pred_x0) and eps_0 (pred_noise)
|
||||||
|
# Note that this uses the LCM paper's CFG formulation rather than the Imagen CFG formulation
|
||||||
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
||||||
pred_noise = cond_teacher_output + w * (cond_teacher_output - uncond_teacher_output)
|
pred_noise = cond_pred_noise + w * (cond_pred_noise - uncond_pred_noise)
|
||||||
|
# 4. Run one step of the ODE solver to estimate the next point x_prev on the
|
||||||
|
# augmented PF-ODE trajectory (solving backward in time)
|
||||||
|
# Note that the DDIM step depends on both the predicted x_0 and source noise eps_0.
|
||||||
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
||||||
|
|
||||||
# 20.4.12. Get target LCM prediction on x_prev, w, c, t_n
|
# 9. Get target LCM prediction on x_prev, w, c, t_n (timesteps)
|
||||||
|
# Note that we do not use a separate target network for LCM-LoRA distillation.
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda", dtype=weight_dtype):
|
with torch.autocast("cuda", dtype=weight_dtype):
|
||||||
target_noise_pred = unet(
|
target_noise_pred = unet(
|
||||||
@@ -1238,7 +1291,7 @@ def main(args):
|
|||||||
timestep_cond=None,
|
timestep_cond=None,
|
||||||
encoder_hidden_states=prompt_embeds.float(),
|
encoder_hidden_states=prompt_embeds.float(),
|
||||||
).sample
|
).sample
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
target_noise_pred,
|
target_noise_pred,
|
||||||
timesteps,
|
timesteps,
|
||||||
x_prev,
|
x_prev,
|
||||||
@@ -1248,7 +1301,7 @@ def main(args):
|
|||||||
)
|
)
|
||||||
target = c_skip * x_prev + c_out * pred_x_0
|
target = c_skip * x_prev + c_out * pred_x_0
|
||||||
|
|
||||||
# 20.4.13. Calculate loss
|
# 10. Calculate loss
|
||||||
if args.loss_type == "l2":
|
if args.loss_type == "l2":
|
||||||
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
||||||
elif args.loss_type == "huber":
|
elif args.loss_type == "huber":
|
||||||
@@ -1256,7 +1309,7 @@ def main(args):
|
|||||||
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.14. Backpropagate on the online student model (`unet`)
|
# 11. Backpropagate on the online student model (`unet`)
|
||||||
accelerator.backward(loss)
|
accelerator.backward(loss)
|
||||||
if accelerator.sync_gradients:
|
if accelerator.sync_gradients:
|
||||||
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class WebdatasetFilter:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Text2ImageDataset:
|
class SDXLText2ImageDataset:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
train_shards_path_or_url: Union[str, List[str]],
|
train_shards_path_or_url: Union[str, List[str]],
|
||||||
@@ -346,19 +346,43 @@ def scalings_for_boundary_conditions(timestep, sigma_data=0.5, timestep_scaling=
|
|||||||
|
|
||||||
|
|
||||||
# Compare LCMScheduler.step, Step 4
|
# Compare LCMScheduler.step, Step 4
|
||||||
def predicted_origin(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
def get_predicted_original_sample(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
if prediction_type == "epsilon":
|
if prediction_type == "epsilon":
|
||||||
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
|
||||||
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
|
||||||
pred_x_0 = (sample - sigmas * model_output) / alphas
|
pred_x_0 = (sample - sigmas * model_output) / alphas
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_x_0 = model_output
|
||||||
elif prediction_type == "v_prediction":
|
elif prediction_type == "v_prediction":
|
||||||
pred_x_0 = alphas[timesteps] * sample - sigmas[timesteps] * model_output
|
pred_x_0 = alphas * sample - sigmas * model_output
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Prediction type {prediction_type} currently not supported.")
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
return pred_x_0
|
return pred_x_0
|
||||||
|
|
||||||
|
|
||||||
|
# Based on step 4 in DDIMScheduler.step
|
||||||
|
def get_predicted_noise(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
|
if prediction_type == "epsilon":
|
||||||
|
pred_epsilon = model_output
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_epsilon = (sample - alphas * model_output) / sigmas
|
||||||
|
elif prediction_type == "v_prediction":
|
||||||
|
pred_epsilon = alphas * model_output + sigmas * sample
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
|
return pred_epsilon
|
||||||
|
|
||||||
|
|
||||||
def extract_into_tensor(a, t, x_shape):
|
def extract_into_tensor(a, t, x_shape):
|
||||||
b, *_ = t.shape
|
b, *_ = t.shape
|
||||||
out = a.gather(-1, t)
|
out = a.gather(-1, t)
|
||||||
@@ -830,9 +854,10 @@ def main(args):
|
|||||||
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
|
|
||||||
# The scheduler calculates the alpha and sigma schedule for us
|
# DDPMScheduler calculates the alpha and sigma noise schedules (based on the alpha bars) for us
|
||||||
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
||||||
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
||||||
|
# Initialize the DDIM ODE solver for distillation.
|
||||||
solver = DDIMSolver(
|
solver = DDIMSolver(
|
||||||
noise_scheduler.alphas_cumprod.numpy(),
|
noise_scheduler.alphas_cumprod.numpy(),
|
||||||
timesteps=noise_scheduler.config.num_train_timesteps,
|
timesteps=noise_scheduler.config.num_train_timesteps,
|
||||||
@@ -886,7 +911,7 @@ def main(args):
|
|||||||
text_encoder_two.requires_grad_(False)
|
text_encoder_two.requires_grad_(False)
|
||||||
teacher_unet.requires_grad_(False)
|
teacher_unet.requires_grad_(False)
|
||||||
|
|
||||||
# 7. Create online (`unet`) student U-Nets.
|
# 7. Create online student U-Net.
|
||||||
unet = UNet2DConditionModel.from_pretrained(
|
unet = UNet2DConditionModel.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
@@ -950,6 +975,7 @@ def main(args):
|
|||||||
# Also move the alpha and sigma noise schedules to accelerator.device.
|
# Also move the alpha and sigma noise schedules to accelerator.device.
|
||||||
alpha_schedule = alpha_schedule.to(accelerator.device)
|
alpha_schedule = alpha_schedule.to(accelerator.device)
|
||||||
sigma_schedule = sigma_schedule.to(accelerator.device)
|
sigma_schedule = sigma_schedule.to(accelerator.device)
|
||||||
|
# Move the ODE solver to accelerator.device.
|
||||||
solver = solver.to(accelerator.device)
|
solver = solver.to(accelerator.device)
|
||||||
|
|
||||||
# 10. Handle saving and loading of checkpoints
|
# 10. Handle saving and loading of checkpoints
|
||||||
@@ -1057,7 +1083,7 @@ def main(args):
|
|||||||
|
|
||||||
return {"prompt_embeds": prompt_embeds, **unet_added_cond_kwargs}
|
return {"prompt_embeds": prompt_embeds, **unet_added_cond_kwargs}
|
||||||
|
|
||||||
dataset = Text2ImageDataset(
|
dataset = SDXLText2ImageDataset(
|
||||||
train_shards_path_or_url=args.train_shards_path_or_url,
|
train_shards_path_or_url=args.train_shards_path_or_url,
|
||||||
num_train_examples=args.max_train_samples,
|
num_train_examples=args.max_train_samples,
|
||||||
per_gpu_batch_size=args.train_batch_size,
|
per_gpu_batch_size=args.train_batch_size,
|
||||||
@@ -1175,6 +1201,7 @@ def main(args):
|
|||||||
for epoch in range(first_epoch, args.num_train_epochs):
|
for epoch in range(first_epoch, args.num_train_epochs):
|
||||||
for step, batch in enumerate(train_dataloader):
|
for step, batch in enumerate(train_dataloader):
|
||||||
with accelerator.accumulate(unet):
|
with accelerator.accumulate(unet):
|
||||||
|
# 1. Load and process the image, text, and micro-conditioning (original image size, crop coordinates)
|
||||||
image, text, orig_size, crop_coords = batch
|
image, text, orig_size, crop_coords = batch
|
||||||
|
|
||||||
image = image.to(accelerator.device, non_blocking=True)
|
image = image.to(accelerator.device, non_blocking=True)
|
||||||
@@ -1196,37 +1223,37 @@ def main(args):
|
|||||||
latents = latents * vae.config.scaling_factor
|
latents = latents * vae.config.scaling_factor
|
||||||
if args.pretrained_vae_model_name_or_path is None:
|
if args.pretrained_vae_model_name_or_path is None:
|
||||||
latents = latents.to(weight_dtype)
|
latents = latents.to(weight_dtype)
|
||||||
|
|
||||||
# Sample noise that we'll add to the latents
|
|
||||||
noise = torch.randn_like(latents)
|
|
||||||
bsz = latents.shape[0]
|
bsz = latents.shape[0]
|
||||||
|
|
||||||
# Sample a random timestep for each image t_n ~ U[0, N - k - 1] without bias.
|
# 2. Sample a random timestep for each image t_n from the ODE solver timesteps without bias.
|
||||||
|
# For the DDIM solver, the timestep schedule is [T - 1, T - k - 1, T - 2 * k - 1, ...]
|
||||||
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
||||||
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
||||||
start_timesteps = solver.ddim_timesteps[index]
|
start_timesteps = solver.ddim_timesteps[index]
|
||||||
timesteps = start_timesteps - topk
|
timesteps = start_timesteps - topk
|
||||||
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
||||||
|
|
||||||
# 20.4.4. Get boundary scalings for start_timesteps and (end) timesteps.
|
# 3. Get boundary scalings for start_timesteps and (end) timesteps.
|
||||||
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
||||||
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
||||||
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
||||||
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
||||||
|
|
||||||
# 20.4.5. Add noise to the latents according to the noise magnitude at each timestep
|
# 4. Sample noise from the prior and add it to the latents according to the noise magnitude at each
|
||||||
# (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
# timestep (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
||||||
|
noise = torch.randn_like(latents)
|
||||||
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
||||||
|
|
||||||
# 20.4.6. Sample a random guidance scale w from U[w_min, w_max] and embed it
|
# 5. Sample a random guidance scale w from U[w_min, w_max]
|
||||||
|
# Note that for LCM-LoRA distillation it is not necessary to use a guidance scale embedding
|
||||||
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
||||||
w = w.reshape(bsz, 1, 1, 1)
|
w = w.reshape(bsz, 1, 1, 1)
|
||||||
w = w.to(device=latents.device, dtype=latents.dtype)
|
w = w.to(device=latents.device, dtype=latents.dtype)
|
||||||
|
|
||||||
# 20.4.8. Prepare prompt embeds and unet_added_conditions
|
# 6. Prepare prompt embeds and unet_added_conditions
|
||||||
prompt_embeds = encoded_text.pop("prompt_embeds")
|
prompt_embeds = encoded_text.pop("prompt_embeds")
|
||||||
|
|
||||||
# 20.4.9. Get online LCM prediction on z_{t_{n + k}}, w, c, t_{n + k}
|
# 7. Get online LCM prediction on z_{t_{n + k}} (noisy_model_input), w, c, t_{n + k} (start_timesteps)
|
||||||
noise_pred = unet(
|
noise_pred = unet(
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
@@ -1235,7 +1262,7 @@ def main(args):
|
|||||||
added_cond_kwargs=encoded_text,
|
added_cond_kwargs=encoded_text,
|
||||||
).sample
|
).sample
|
||||||
|
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
noise_pred,
|
noise_pred,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1246,18 +1273,28 @@ def main(args):
|
|||||||
|
|
||||||
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
||||||
|
|
||||||
# 20.4.10. Use the ODE solver to predict the kth step in the augmented PF-ODE trajectory after
|
# 8. Compute the conditional and unconditional teacher model predictions to get CFG estimates of the
|
||||||
# noisy_latents with both the conditioning embedding c and unconditional embedding 0
|
# predicted noise eps_0 and predicted original sample x_0, then run the ODE solver using these
|
||||||
# Get teacher model prediction on noisy_latents and conditional embedding
|
# estimates to predict the data point in the augmented PF-ODE trajectory corresponding to the next ODE
|
||||||
|
# solver timestep.
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda"):
|
with torch.autocast("cuda"):
|
||||||
|
# 1. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and conditional embedding c
|
||||||
cond_teacher_output = teacher_unet(
|
cond_teacher_output = teacher_unet(
|
||||||
noisy_model_input.to(weight_dtype),
|
noisy_model_input.to(weight_dtype),
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
||||||
added_cond_kwargs={k: v.to(weight_dtype) for k, v in encoded_text.items()},
|
added_cond_kwargs={k: v.to(weight_dtype) for k, v in encoded_text.items()},
|
||||||
).sample
|
).sample
|
||||||
cond_pred_x0 = predicted_origin(
|
cond_pred_x0 = get_predicted_original_sample(
|
||||||
|
cond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
cond_pred_noise = get_predicted_noise(
|
||||||
cond_teacher_output,
|
cond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1266,7 +1303,7 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get teacher model prediction on noisy_latents and unconditional embedding
|
# 2. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and unconditional embedding 0
|
||||||
uncond_added_conditions = copy.deepcopy(encoded_text)
|
uncond_added_conditions = copy.deepcopy(encoded_text)
|
||||||
uncond_added_conditions["text_embeds"] = uncond_pooled_prompt_embeds
|
uncond_added_conditions["text_embeds"] = uncond_pooled_prompt_embeds
|
||||||
uncond_teacher_output = teacher_unet(
|
uncond_teacher_output = teacher_unet(
|
||||||
@@ -1275,7 +1312,15 @@ def main(args):
|
|||||||
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
||||||
added_cond_kwargs={k: v.to(weight_dtype) for k, v in uncond_added_conditions.items()},
|
added_cond_kwargs={k: v.to(weight_dtype) for k, v in uncond_added_conditions.items()},
|
||||||
).sample
|
).sample
|
||||||
uncond_pred_x0 = predicted_origin(
|
uncond_pred_x0 = get_predicted_original_sample(
|
||||||
|
uncond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
uncond_pred_noise = get_predicted_noise(
|
||||||
uncond_teacher_output,
|
uncond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1284,12 +1329,17 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.11. Perform "CFG" to get x_prev estimate (using the LCM paper's CFG formulation)
|
# 3. Calculate the CFG estimate of x_0 (pred_x0) and eps_0 (pred_noise)
|
||||||
|
# Note that this uses the LCM paper's CFG formulation rather than the Imagen CFG formulation
|
||||||
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
||||||
pred_noise = cond_teacher_output + w * (cond_teacher_output - uncond_teacher_output)
|
pred_noise = cond_pred_noise + w * (cond_pred_noise - uncond_pred_noise)
|
||||||
|
# 4. Run one step of the ODE solver to estimate the next point x_prev on the
|
||||||
|
# augmented PF-ODE trajectory (solving backward in time)
|
||||||
|
# Note that the DDIM step depends on both the predicted x_0 and source noise eps_0.
|
||||||
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
||||||
|
|
||||||
# 20.4.12. Get target LCM prediction on x_prev, w, c, t_n
|
# 9. Get target LCM prediction on x_prev, w, c, t_n (timesteps)
|
||||||
|
# Note that we do not use a separate target network for LCM-LoRA distillation.
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda", enabled=True, dtype=weight_dtype):
|
with torch.autocast("cuda", enabled=True, dtype=weight_dtype):
|
||||||
target_noise_pred = unet(
|
target_noise_pred = unet(
|
||||||
@@ -1299,7 +1349,7 @@ def main(args):
|
|||||||
encoder_hidden_states=prompt_embeds.float(),
|
encoder_hidden_states=prompt_embeds.float(),
|
||||||
added_cond_kwargs=encoded_text,
|
added_cond_kwargs=encoded_text,
|
||||||
).sample
|
).sample
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
target_noise_pred,
|
target_noise_pred,
|
||||||
timesteps,
|
timesteps,
|
||||||
x_prev,
|
x_prev,
|
||||||
@@ -1309,7 +1359,7 @@ def main(args):
|
|||||||
)
|
)
|
||||||
target = c_skip * x_prev + c_out * pred_x_0
|
target = c_skip * x_prev + c_out * pred_x_0
|
||||||
|
|
||||||
# 20.4.13. Calculate loss
|
# 10. Calculate loss
|
||||||
if args.loss_type == "l2":
|
if args.loss_type == "l2":
|
||||||
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
||||||
elif args.loss_type == "huber":
|
elif args.loss_type == "huber":
|
||||||
@@ -1317,7 +1367,7 @@ def main(args):
|
|||||||
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.14. Backpropagate on the online student model (`unet`)
|
# 11. Backpropagate on the online student model (`unet`)
|
||||||
accelerator.backward(loss)
|
accelerator.backward(loss)
|
||||||
if accelerator.sync_gradients:
|
if accelerator.sync_gradients:
|
||||||
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class WebdatasetFilter:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Text2ImageDataset:
|
class SDText2ImageDataset:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
train_shards_path_or_url: Union[str, List[str]],
|
train_shards_path_or_url: Union[str, List[str]],
|
||||||
@@ -336,19 +336,43 @@ def scalings_for_boundary_conditions(timestep, sigma_data=0.5, timestep_scaling=
|
|||||||
|
|
||||||
|
|
||||||
# Compare LCMScheduler.step, Step 4
|
# Compare LCMScheduler.step, Step 4
|
||||||
def predicted_origin(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
def get_predicted_original_sample(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
if prediction_type == "epsilon":
|
if prediction_type == "epsilon":
|
||||||
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
|
||||||
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
|
||||||
pred_x_0 = (sample - sigmas * model_output) / alphas
|
pred_x_0 = (sample - sigmas * model_output) / alphas
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_x_0 = model_output
|
||||||
elif prediction_type == "v_prediction":
|
elif prediction_type == "v_prediction":
|
||||||
pred_x_0 = alphas[timesteps] * sample - sigmas[timesteps] * model_output
|
pred_x_0 = alphas * sample - sigmas * model_output
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Prediction type {prediction_type} currently not supported.")
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
return pred_x_0
|
return pred_x_0
|
||||||
|
|
||||||
|
|
||||||
|
# Based on step 4 in DDIMScheduler.step
|
||||||
|
def get_predicted_noise(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
|
if prediction_type == "epsilon":
|
||||||
|
pred_epsilon = model_output
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_epsilon = (sample - alphas * model_output) / sigmas
|
||||||
|
elif prediction_type == "v_prediction":
|
||||||
|
pred_epsilon = alphas * model_output + sigmas * sample
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
|
return pred_epsilon
|
||||||
|
|
||||||
|
|
||||||
def extract_into_tensor(a, t, x_shape):
|
def extract_into_tensor(a, t, x_shape):
|
||||||
b, *_ = t.shape
|
b, *_ = t.shape
|
||||||
out = a.gather(-1, t)
|
out = a.gather(-1, t)
|
||||||
@@ -823,34 +847,35 @@ def main(args):
|
|||||||
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
|
|
||||||
# The scheduler calculates the alpha and sigma schedule for us
|
# DDPMScheduler calculates the alpha and sigma noise schedules (based on the alpha bars) for us
|
||||||
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
||||||
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
||||||
|
# Initialize the DDIM ODE solver for distillation.
|
||||||
solver = DDIMSolver(
|
solver = DDIMSolver(
|
||||||
noise_scheduler.alphas_cumprod.numpy(),
|
noise_scheduler.alphas_cumprod.numpy(),
|
||||||
timesteps=noise_scheduler.config.num_train_timesteps,
|
timesteps=noise_scheduler.config.num_train_timesteps,
|
||||||
ddim_timesteps=args.num_ddim_timesteps,
|
ddim_timesteps=args.num_ddim_timesteps,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 2. Load tokenizers from SD-XL checkpoint.
|
# 2. Load tokenizers from SD 1.X/2.X checkpoint.
|
||||||
tokenizer = AutoTokenizer.from_pretrained(
|
tokenizer = AutoTokenizer.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="tokenizer", revision=args.teacher_revision, use_fast=False
|
args.pretrained_teacher_model, subfolder="tokenizer", revision=args.teacher_revision, use_fast=False
|
||||||
)
|
)
|
||||||
|
|
||||||
# 3. Load text encoders from SD-1.5 checkpoint.
|
# 3. Load text encoders from SD 1.X/2.X checkpoint.
|
||||||
# import correct text encoder classes
|
# import correct text encoder classes
|
||||||
text_encoder = CLIPTextModel.from_pretrained(
|
text_encoder = CLIPTextModel.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="text_encoder", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="text_encoder", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
|
|
||||||
# 4. Load VAE from SD-XL checkpoint (or more stable VAE)
|
# 4. Load VAE from SD 1.X/2.X checkpoint
|
||||||
vae = AutoencoderKL.from_pretrained(
|
vae = AutoencoderKL.from_pretrained(
|
||||||
args.pretrained_teacher_model,
|
args.pretrained_teacher_model,
|
||||||
subfolder="vae",
|
subfolder="vae",
|
||||||
revision=args.teacher_revision,
|
revision=args.teacher_revision,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 5. Load teacher U-Net from SD-XL checkpoint
|
# 5. Load teacher U-Net from SD 1.X/2.X checkpoint
|
||||||
teacher_unet = UNet2DConditionModel.from_pretrained(
|
teacher_unet = UNet2DConditionModel.from_pretrained(
|
||||||
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="unet", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
@@ -860,7 +885,7 @@ def main(args):
|
|||||||
text_encoder.requires_grad_(False)
|
text_encoder.requires_grad_(False)
|
||||||
teacher_unet.requires_grad_(False)
|
teacher_unet.requires_grad_(False)
|
||||||
|
|
||||||
# 8. Create online (`unet`) student U-Nets. This will be updated by the optimizer (e.g. via backpropagation.)
|
# 7. Create online student U-Net. This will be updated by the optimizer (e.g. via backpropagation.)
|
||||||
# Add `time_cond_proj_dim` to the student U-Net if `teacher_unet.config.time_cond_proj_dim` is None
|
# Add `time_cond_proj_dim` to the student U-Net if `teacher_unet.config.time_cond_proj_dim` is None
|
||||||
if teacher_unet.config.time_cond_proj_dim is None:
|
if teacher_unet.config.time_cond_proj_dim is None:
|
||||||
teacher_unet.config["time_cond_proj_dim"] = args.unet_time_cond_proj_dim
|
teacher_unet.config["time_cond_proj_dim"] = args.unet_time_cond_proj_dim
|
||||||
@@ -869,8 +894,8 @@ def main(args):
|
|||||||
unet.load_state_dict(teacher_unet.state_dict(), strict=False)
|
unet.load_state_dict(teacher_unet.state_dict(), strict=False)
|
||||||
unet.train()
|
unet.train()
|
||||||
|
|
||||||
# 9. Create target (`ema_unet`) student U-Net parameters. This will be updated via EMA updates (polyak averaging).
|
# 8. Create target student U-Net. This will be updated via EMA updates (polyak averaging).
|
||||||
# Initialize from unet
|
# Initialize from (online) unet
|
||||||
target_unet = UNet2DConditionModel(**teacher_unet.config)
|
target_unet = UNet2DConditionModel(**teacher_unet.config)
|
||||||
target_unet.load_state_dict(unet.state_dict())
|
target_unet.load_state_dict(unet.state_dict())
|
||||||
target_unet.train()
|
target_unet.train()
|
||||||
@@ -887,7 +912,7 @@ def main(args):
|
|||||||
f"Controlnet loaded as datatype {accelerator.unwrap_model(unet).dtype}. {low_precision_error_string}"
|
f"Controlnet loaded as datatype {accelerator.unwrap_model(unet).dtype}. {low_precision_error_string}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 10. Handle mixed precision and device placement
|
# 9. Handle mixed precision and device placement
|
||||||
# For mixed precision training we cast all non-trainable weigths to half-precision
|
# For mixed precision training we cast all non-trainable weigths to half-precision
|
||||||
# as these weights are only used for inference, keeping weights in full precision is not required.
|
# as these weights are only used for inference, keeping weights in full precision is not required.
|
||||||
weight_dtype = torch.float32
|
weight_dtype = torch.float32
|
||||||
@@ -914,7 +939,7 @@ def main(args):
|
|||||||
sigma_schedule = sigma_schedule.to(accelerator.device)
|
sigma_schedule = sigma_schedule.to(accelerator.device)
|
||||||
solver = solver.to(accelerator.device)
|
solver = solver.to(accelerator.device)
|
||||||
|
|
||||||
# 11. Handle saving and loading of checkpoints
|
# 10. Handle saving and loading of checkpoints
|
||||||
# `accelerate` 0.16.0 will have better support for customized saving
|
# `accelerate` 0.16.0 will have better support for customized saving
|
||||||
if version.parse(accelerate.__version__) >= version.parse("0.16.0"):
|
if version.parse(accelerate.__version__) >= version.parse("0.16.0"):
|
||||||
# create custom saving & loading hooks so that `accelerator.save_state(...)` serializes in a nice format
|
# create custom saving & loading hooks so that `accelerator.save_state(...)` serializes in a nice format
|
||||||
@@ -948,7 +973,7 @@ def main(args):
|
|||||||
accelerator.register_save_state_pre_hook(save_model_hook)
|
accelerator.register_save_state_pre_hook(save_model_hook)
|
||||||
accelerator.register_load_state_pre_hook(load_model_hook)
|
accelerator.register_load_state_pre_hook(load_model_hook)
|
||||||
|
|
||||||
# 12. Enable optimizations
|
# 11. Enable optimizations
|
||||||
if args.enable_xformers_memory_efficient_attention:
|
if args.enable_xformers_memory_efficient_attention:
|
||||||
if is_xformers_available():
|
if is_xformers_available():
|
||||||
import xformers
|
import xformers
|
||||||
@@ -994,13 +1019,14 @@ def main(args):
|
|||||||
eps=args.adam_epsilon,
|
eps=args.adam_epsilon,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 13. Dataset creation and data processing
|
||||||
# Here, we compute not just the text embeddings but also the additional embeddings
|
# Here, we compute not just the text embeddings but also the additional embeddings
|
||||||
# needed for the SD XL UNet to operate.
|
# needed for the SD XL UNet to operate.
|
||||||
def compute_embeddings(prompt_batch, proportion_empty_prompts, text_encoder, tokenizer, is_train=True):
|
def compute_embeddings(prompt_batch, proportion_empty_prompts, text_encoder, tokenizer, is_train=True):
|
||||||
prompt_embeds = encode_prompt(prompt_batch, text_encoder, tokenizer, proportion_empty_prompts, is_train)
|
prompt_embeds = encode_prompt(prompt_batch, text_encoder, tokenizer, proportion_empty_prompts, is_train)
|
||||||
return {"prompt_embeds": prompt_embeds}
|
return {"prompt_embeds": prompt_embeds}
|
||||||
|
|
||||||
dataset = Text2ImageDataset(
|
dataset = SDText2ImageDataset(
|
||||||
train_shards_path_or_url=args.train_shards_path_or_url,
|
train_shards_path_or_url=args.train_shards_path_or_url,
|
||||||
num_train_examples=args.max_train_samples,
|
num_train_examples=args.max_train_samples,
|
||||||
per_gpu_batch_size=args.train_batch_size,
|
per_gpu_batch_size=args.train_batch_size,
|
||||||
@@ -1020,6 +1046,7 @@ def main(args):
|
|||||||
tokenizer=tokenizer,
|
tokenizer=tokenizer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 14. LR Scheduler creation
|
||||||
# Scheduler and math around the number of training steps.
|
# Scheduler and math around the number of training steps.
|
||||||
overrode_max_train_steps = False
|
overrode_max_train_steps = False
|
||||||
num_update_steps_per_epoch = math.ceil(train_dataloader.num_batches / args.gradient_accumulation_steps)
|
num_update_steps_per_epoch = math.ceil(train_dataloader.num_batches / args.gradient_accumulation_steps)
|
||||||
@@ -1034,6 +1061,7 @@ def main(args):
|
|||||||
num_training_steps=args.max_train_steps,
|
num_training_steps=args.max_train_steps,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 15. Prepare for training
|
||||||
# Prepare everything with our `accelerator`.
|
# Prepare everything with our `accelerator`.
|
||||||
unet, optimizer, lr_scheduler = accelerator.prepare(unet, optimizer, lr_scheduler)
|
unet, optimizer, lr_scheduler = accelerator.prepare(unet, optimizer, lr_scheduler)
|
||||||
|
|
||||||
@@ -1055,7 +1083,7 @@ def main(args):
|
|||||||
).input_ids.to(accelerator.device)
|
).input_ids.to(accelerator.device)
|
||||||
uncond_prompt_embeds = text_encoder(uncond_input_ids)[0]
|
uncond_prompt_embeds = text_encoder(uncond_input_ids)[0]
|
||||||
|
|
||||||
# Train!
|
# 16. Train!
|
||||||
total_batch_size = args.train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps
|
total_batch_size = args.train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps
|
||||||
|
|
||||||
logger.info("***** Running training *****")
|
logger.info("***** Running training *****")
|
||||||
@@ -1106,6 +1134,7 @@ def main(args):
|
|||||||
for epoch in range(first_epoch, args.num_train_epochs):
|
for epoch in range(first_epoch, args.num_train_epochs):
|
||||||
for step, batch in enumerate(train_dataloader):
|
for step, batch in enumerate(train_dataloader):
|
||||||
with accelerator.accumulate(unet):
|
with accelerator.accumulate(unet):
|
||||||
|
# 1. Load and process the image and text conditioning
|
||||||
image, text = batch
|
image, text = batch
|
||||||
|
|
||||||
image = image.to(accelerator.device, non_blocking=True)
|
image = image.to(accelerator.device, non_blocking=True)
|
||||||
@@ -1123,29 +1152,28 @@ def main(args):
|
|||||||
|
|
||||||
latents = latents * vae.config.scaling_factor
|
latents = latents * vae.config.scaling_factor
|
||||||
latents = latents.to(weight_dtype)
|
latents = latents.to(weight_dtype)
|
||||||
|
|
||||||
# Sample noise that we'll add to the latents
|
|
||||||
noise = torch.randn_like(latents)
|
|
||||||
bsz = latents.shape[0]
|
bsz = latents.shape[0]
|
||||||
|
|
||||||
# Sample a random timestep for each image t_n ~ U[0, N - k - 1] without bias.
|
# 2. Sample a random timestep for each image t_n from the ODE solver timesteps without bias.
|
||||||
|
# For the DDIM solver, the timestep schedule is [T - 1, T - k - 1, T - 2 * k - 1, ...]
|
||||||
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
||||||
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
||||||
start_timesteps = solver.ddim_timesteps[index]
|
start_timesteps = solver.ddim_timesteps[index]
|
||||||
timesteps = start_timesteps - topk
|
timesteps = start_timesteps - topk
|
||||||
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
||||||
|
|
||||||
# 20.4.4. Get boundary scalings for start_timesteps and (end) timesteps.
|
# 3. Get boundary scalings for start_timesteps and (end) timesteps.
|
||||||
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
||||||
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
||||||
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
||||||
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
||||||
|
|
||||||
# 20.4.5. Add noise to the latents according to the noise magnitude at each timestep
|
# 4. Sample noise from the prior and add it to the latents according to the noise magnitude at each
|
||||||
# (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
# timestep (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
||||||
|
noise = torch.randn_like(latents)
|
||||||
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
||||||
|
|
||||||
# 20.4.6. Sample a random guidance scale w from U[w_min, w_max] and embed it
|
# 5. Sample a random guidance scale w from U[w_min, w_max] and embed it
|
||||||
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
||||||
w_embedding = guidance_scale_embedding(w, embedding_dim=unet.config.time_cond_proj_dim)
|
w_embedding = guidance_scale_embedding(w, embedding_dim=unet.config.time_cond_proj_dim)
|
||||||
w = w.reshape(bsz, 1, 1, 1)
|
w = w.reshape(bsz, 1, 1, 1)
|
||||||
@@ -1153,10 +1181,10 @@ def main(args):
|
|||||||
w = w.to(device=latents.device, dtype=latents.dtype)
|
w = w.to(device=latents.device, dtype=latents.dtype)
|
||||||
w_embedding = w_embedding.to(device=latents.device, dtype=latents.dtype)
|
w_embedding = w_embedding.to(device=latents.device, dtype=latents.dtype)
|
||||||
|
|
||||||
# 20.4.8. Prepare prompt embeds and unet_added_conditions
|
# 6. Prepare prompt embeds and unet_added_conditions
|
||||||
prompt_embeds = encoded_text.pop("prompt_embeds")
|
prompt_embeds = encoded_text.pop("prompt_embeds")
|
||||||
|
|
||||||
# 20.4.9. Get online LCM prediction on z_{t_{n + k}}, w, c, t_{n + k}
|
# 7. Get online LCM prediction on z_{t_{n + k}} (noisy_model_input), w, c, t_{n + k} (start_timesteps)
|
||||||
noise_pred = unet(
|
noise_pred = unet(
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
@@ -1165,7 +1193,7 @@ def main(args):
|
|||||||
added_cond_kwargs=encoded_text,
|
added_cond_kwargs=encoded_text,
|
||||||
).sample
|
).sample
|
||||||
|
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
noise_pred,
|
noise_pred,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1176,17 +1204,27 @@ def main(args):
|
|||||||
|
|
||||||
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
||||||
|
|
||||||
# 20.4.10. Use the ODE solver to predict the kth step in the augmented PF-ODE trajectory after
|
# 8. Compute the conditional and unconditional teacher model predictions to get CFG estimates of the
|
||||||
# noisy_latents with both the conditioning embedding c and unconditional embedding 0
|
# predicted noise eps_0 and predicted original sample x_0, then run the ODE solver using these
|
||||||
# Get teacher model prediction on noisy_latents and conditional embedding
|
# estimates to predict the data point in the augmented PF-ODE trajectory corresponding to the next ODE
|
||||||
|
# solver timestep.
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda"):
|
with torch.autocast("cuda"):
|
||||||
|
# 1. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and conditional embedding c
|
||||||
cond_teacher_output = teacher_unet(
|
cond_teacher_output = teacher_unet(
|
||||||
noisy_model_input.to(weight_dtype),
|
noisy_model_input.to(weight_dtype),
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
||||||
).sample
|
).sample
|
||||||
cond_pred_x0 = predicted_origin(
|
cond_pred_x0 = get_predicted_original_sample(
|
||||||
|
cond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
cond_pred_noise = get_predicted_noise(
|
||||||
cond_teacher_output,
|
cond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1195,13 +1233,21 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get teacher model prediction on noisy_latents and unconditional embedding
|
# 2. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and unconditional embedding 0
|
||||||
uncond_teacher_output = teacher_unet(
|
uncond_teacher_output = teacher_unet(
|
||||||
noisy_model_input.to(weight_dtype),
|
noisy_model_input.to(weight_dtype),
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
||||||
).sample
|
).sample
|
||||||
uncond_pred_x0 = predicted_origin(
|
uncond_pred_x0 = get_predicted_original_sample(
|
||||||
|
uncond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
uncond_pred_noise = get_predicted_noise(
|
||||||
uncond_teacher_output,
|
uncond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1210,12 +1256,16 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.11. Perform "CFG" to get x_prev estimate (using the LCM paper's CFG formulation)
|
# 3. Calculate the CFG estimate of x_0 (pred_x0) and eps_0 (pred_noise)
|
||||||
|
# Note that this uses the LCM paper's CFG formulation rather than the Imagen CFG formulation
|
||||||
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
||||||
pred_noise = cond_teacher_output + w * (cond_teacher_output - uncond_teacher_output)
|
pred_noise = cond_pred_noise + w * (cond_pred_noise - uncond_pred_noise)
|
||||||
|
# 4. Run one step of the ODE solver to estimate the next point x_prev on the
|
||||||
|
# augmented PF-ODE trajectory (solving backward in time)
|
||||||
|
# Note that the DDIM step depends on both the predicted x_0 and source noise eps_0.
|
||||||
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
||||||
|
|
||||||
# 20.4.12. Get target LCM prediction on x_prev, w, c, t_n
|
# 9. Get target LCM prediction on x_prev, w, c, t_n (timesteps)
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda", dtype=weight_dtype):
|
with torch.autocast("cuda", dtype=weight_dtype):
|
||||||
target_noise_pred = target_unet(
|
target_noise_pred = target_unet(
|
||||||
@@ -1224,7 +1274,7 @@ def main(args):
|
|||||||
timestep_cond=w_embedding,
|
timestep_cond=w_embedding,
|
||||||
encoder_hidden_states=prompt_embeds.float(),
|
encoder_hidden_states=prompt_embeds.float(),
|
||||||
).sample
|
).sample
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
target_noise_pred,
|
target_noise_pred,
|
||||||
timesteps,
|
timesteps,
|
||||||
x_prev,
|
x_prev,
|
||||||
@@ -1234,7 +1284,7 @@ def main(args):
|
|||||||
)
|
)
|
||||||
target = c_skip * x_prev + c_out * pred_x_0
|
target = c_skip * x_prev + c_out * pred_x_0
|
||||||
|
|
||||||
# 20.4.13. Calculate loss
|
# 10. Calculate loss
|
||||||
if args.loss_type == "l2":
|
if args.loss_type == "l2":
|
||||||
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
||||||
elif args.loss_type == "huber":
|
elif args.loss_type == "huber":
|
||||||
@@ -1242,7 +1292,7 @@ def main(args):
|
|||||||
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.14. Backpropagate on the online student model (`unet`)
|
# 11. Backpropagate on the online student model (`unet`)
|
||||||
accelerator.backward(loss)
|
accelerator.backward(loss)
|
||||||
if accelerator.sync_gradients:
|
if accelerator.sync_gradients:
|
||||||
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
||||||
@@ -1252,7 +1302,7 @@ def main(args):
|
|||||||
|
|
||||||
# Checks if the accelerator has performed an optimization step behind the scenes
|
# Checks if the accelerator has performed an optimization step behind the scenes
|
||||||
if accelerator.sync_gradients:
|
if accelerator.sync_gradients:
|
||||||
# 20.4.15. Make EMA update to target student model parameters
|
# 12. Make EMA update to target student model parameters (`target_unet`)
|
||||||
update_ema(target_unet.parameters(), unet.parameters(), args.ema_decay)
|
update_ema(target_unet.parameters(), unet.parameters(), args.ema_decay)
|
||||||
progress_bar.update(1)
|
progress_bar.update(1)
|
||||||
global_step += 1
|
global_step += 1
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class WebdatasetFilter:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Text2ImageDataset:
|
class SDXLText2ImageDataset:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
train_shards_path_or_url: Union[str, List[str]],
|
train_shards_path_or_url: Union[str, List[str]],
|
||||||
@@ -324,19 +324,43 @@ def scalings_for_boundary_conditions(timestep, sigma_data=0.5, timestep_scaling=
|
|||||||
|
|
||||||
|
|
||||||
# Compare LCMScheduler.step, Step 4
|
# Compare LCMScheduler.step, Step 4
|
||||||
def predicted_origin(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
def get_predicted_original_sample(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
if prediction_type == "epsilon":
|
if prediction_type == "epsilon":
|
||||||
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
|
||||||
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
|
||||||
pred_x_0 = (sample - sigmas * model_output) / alphas
|
pred_x_0 = (sample - sigmas * model_output) / alphas
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_x_0 = model_output
|
||||||
elif prediction_type == "v_prediction":
|
elif prediction_type == "v_prediction":
|
||||||
pred_x_0 = alphas[timesteps] * sample - sigmas[timesteps] * model_output
|
pred_x_0 = alphas * sample - sigmas * model_output
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Prediction type {prediction_type} currently not supported.")
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
return pred_x_0
|
return pred_x_0
|
||||||
|
|
||||||
|
|
||||||
|
# Based on step 4 in DDIMScheduler.step
|
||||||
|
def get_predicted_noise(model_output, timesteps, sample, prediction_type, alphas, sigmas):
|
||||||
|
alphas = extract_into_tensor(alphas, timesteps, sample.shape)
|
||||||
|
sigmas = extract_into_tensor(sigmas, timesteps, sample.shape)
|
||||||
|
if prediction_type == "epsilon":
|
||||||
|
pred_epsilon = model_output
|
||||||
|
elif prediction_type == "sample":
|
||||||
|
pred_epsilon = (sample - alphas * model_output) / sigmas
|
||||||
|
elif prediction_type == "v_prediction":
|
||||||
|
pred_epsilon = alphas * model_output + sigmas * sample
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Prediction type {prediction_type} is not supported; currently, `epsilon`, `sample`, and `v_prediction`"
|
||||||
|
f" are supported."
|
||||||
|
)
|
||||||
|
|
||||||
|
return pred_epsilon
|
||||||
|
|
||||||
|
|
||||||
def extract_into_tensor(a, t, x_shape):
|
def extract_into_tensor(a, t, x_shape):
|
||||||
b, *_ = t.shape
|
b, *_ = t.shape
|
||||||
out = a.gather(-1, t)
|
out = a.gather(-1, t)
|
||||||
@@ -863,9 +887,10 @@ def main(args):
|
|||||||
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
args.pretrained_teacher_model, subfolder="scheduler", revision=args.teacher_revision
|
||||||
)
|
)
|
||||||
|
|
||||||
# The scheduler calculates the alpha and sigma schedule for us
|
# DDPMScheduler calculates the alpha and sigma noise schedules (based on the alpha bars) for us
|
||||||
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
alpha_schedule = torch.sqrt(noise_scheduler.alphas_cumprod)
|
||||||
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
sigma_schedule = torch.sqrt(1 - noise_scheduler.alphas_cumprod)
|
||||||
|
# Initialize the DDIM ODE solver for distillation.
|
||||||
solver = DDIMSolver(
|
solver = DDIMSolver(
|
||||||
noise_scheduler.alphas_cumprod.numpy(),
|
noise_scheduler.alphas_cumprod.numpy(),
|
||||||
timesteps=noise_scheduler.config.num_train_timesteps,
|
timesteps=noise_scheduler.config.num_train_timesteps,
|
||||||
@@ -919,7 +944,7 @@ def main(args):
|
|||||||
text_encoder_two.requires_grad_(False)
|
text_encoder_two.requires_grad_(False)
|
||||||
teacher_unet.requires_grad_(False)
|
teacher_unet.requires_grad_(False)
|
||||||
|
|
||||||
# 8. Create online (`unet`) student U-Nets. This will be updated by the optimizer (e.g. via backpropagation.)
|
# 7. Create online student U-Net. This will be updated by the optimizer (e.g. via backpropagation.)
|
||||||
# Add `time_cond_proj_dim` to the student U-Net if `teacher_unet.config.time_cond_proj_dim` is None
|
# Add `time_cond_proj_dim` to the student U-Net if `teacher_unet.config.time_cond_proj_dim` is None
|
||||||
if teacher_unet.config.time_cond_proj_dim is None:
|
if teacher_unet.config.time_cond_proj_dim is None:
|
||||||
teacher_unet.config["time_cond_proj_dim"] = args.unet_time_cond_proj_dim
|
teacher_unet.config["time_cond_proj_dim"] = args.unet_time_cond_proj_dim
|
||||||
@@ -928,8 +953,8 @@ def main(args):
|
|||||||
unet.load_state_dict(teacher_unet.state_dict(), strict=False)
|
unet.load_state_dict(teacher_unet.state_dict(), strict=False)
|
||||||
unet.train()
|
unet.train()
|
||||||
|
|
||||||
# 9. Create target (`ema_unet`) student U-Net parameters. This will be updated via EMA updates (polyak averaging).
|
# 8. Create target student U-Net. This will be updated via EMA updates (polyak averaging).
|
||||||
# Initialize from unet
|
# Initialize from (online) unet
|
||||||
target_unet = UNet2DConditionModel(**teacher_unet.config)
|
target_unet = UNet2DConditionModel(**teacher_unet.config)
|
||||||
target_unet.load_state_dict(unet.state_dict())
|
target_unet.load_state_dict(unet.state_dict())
|
||||||
target_unet.train()
|
target_unet.train()
|
||||||
@@ -971,6 +996,7 @@ def main(args):
|
|||||||
# Also move the alpha and sigma noise schedules to accelerator.device.
|
# Also move the alpha and sigma noise schedules to accelerator.device.
|
||||||
alpha_schedule = alpha_schedule.to(accelerator.device)
|
alpha_schedule = alpha_schedule.to(accelerator.device)
|
||||||
sigma_schedule = sigma_schedule.to(accelerator.device)
|
sigma_schedule = sigma_schedule.to(accelerator.device)
|
||||||
|
# Move the ODE solver to accelerator.device.
|
||||||
solver = solver.to(accelerator.device)
|
solver = solver.to(accelerator.device)
|
||||||
|
|
||||||
# 10. Handle saving and loading of checkpoints
|
# 10. Handle saving and loading of checkpoints
|
||||||
@@ -1084,7 +1110,7 @@ def main(args):
|
|||||||
|
|
||||||
return {"prompt_embeds": prompt_embeds, **unet_added_cond_kwargs}
|
return {"prompt_embeds": prompt_embeds, **unet_added_cond_kwargs}
|
||||||
|
|
||||||
dataset = Text2ImageDataset(
|
dataset = SDXLText2ImageDataset(
|
||||||
train_shards_path_or_url=args.train_shards_path_or_url,
|
train_shards_path_or_url=args.train_shards_path_or_url,
|
||||||
num_train_examples=args.max_train_samples,
|
num_train_examples=args.max_train_samples,
|
||||||
per_gpu_batch_size=args.train_batch_size,
|
per_gpu_batch_size=args.train_batch_size,
|
||||||
@@ -1202,6 +1228,7 @@ def main(args):
|
|||||||
for epoch in range(first_epoch, args.num_train_epochs):
|
for epoch in range(first_epoch, args.num_train_epochs):
|
||||||
for step, batch in enumerate(train_dataloader):
|
for step, batch in enumerate(train_dataloader):
|
||||||
with accelerator.accumulate(unet):
|
with accelerator.accumulate(unet):
|
||||||
|
# 1. Load and process the image, text, and micro-conditioning (original image size, crop coordinates)
|
||||||
image, text, orig_size, crop_coords = batch
|
image, text, orig_size, crop_coords = batch
|
||||||
|
|
||||||
image = image.to(accelerator.device, non_blocking=True)
|
image = image.to(accelerator.device, non_blocking=True)
|
||||||
@@ -1223,38 +1250,39 @@ def main(args):
|
|||||||
latents = latents * vae.config.scaling_factor
|
latents = latents * vae.config.scaling_factor
|
||||||
if args.pretrained_vae_model_name_or_path is None:
|
if args.pretrained_vae_model_name_or_path is None:
|
||||||
latents = latents.to(weight_dtype)
|
latents = latents.to(weight_dtype)
|
||||||
|
|
||||||
# Sample noise that we'll add to the latents
|
|
||||||
noise = torch.randn_like(latents)
|
|
||||||
bsz = latents.shape[0]
|
bsz = latents.shape[0]
|
||||||
|
|
||||||
# Sample a random timestep for each image t_n ~ U[0, N - k - 1] without bias.
|
# 2. Sample a random timestep for each image t_n from the ODE solver timesteps without bias.
|
||||||
|
# For the DDIM solver, the timestep schedule is [T - 1, T - k - 1, T - 2 * k - 1, ...]
|
||||||
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
topk = noise_scheduler.config.num_train_timesteps // args.num_ddim_timesteps
|
||||||
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
index = torch.randint(0, args.num_ddim_timesteps, (bsz,), device=latents.device).long()
|
||||||
start_timesteps = solver.ddim_timesteps[index]
|
start_timesteps = solver.ddim_timesteps[index]
|
||||||
timesteps = start_timesteps - topk
|
timesteps = start_timesteps - topk
|
||||||
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
timesteps = torch.where(timesteps < 0, torch.zeros_like(timesteps), timesteps)
|
||||||
|
|
||||||
# 20.4.4. Get boundary scalings for start_timesteps and (end) timesteps.
|
# 3. Get boundary scalings for start_timesteps and (end) timesteps.
|
||||||
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
c_skip_start, c_out_start = scalings_for_boundary_conditions(start_timesteps)
|
||||||
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
c_skip_start, c_out_start = [append_dims(x, latents.ndim) for x in [c_skip_start, c_out_start]]
|
||||||
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
c_skip, c_out = scalings_for_boundary_conditions(timesteps)
|
||||||
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
c_skip, c_out = [append_dims(x, latents.ndim) for x in [c_skip, c_out]]
|
||||||
|
|
||||||
# 20.4.5. Add noise to the latents according to the noise magnitude at each timestep
|
# 4. Sample noise from the prior and add it to the latents according to the noise magnitude at each
|
||||||
# (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
# timestep (this is the forward diffusion process) [z_{t_{n + k}} in Algorithm 1]
|
||||||
|
noise = torch.randn_like(latents)
|
||||||
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
noisy_model_input = noise_scheduler.add_noise(latents, noise, start_timesteps)
|
||||||
|
|
||||||
# 20.4.6. Sample a random guidance scale w from U[w_min, w_max] and embed it
|
# 5. Sample a random guidance scale w from U[w_min, w_max] and embed it
|
||||||
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
w = (args.w_max - args.w_min) * torch.rand((bsz,)) + args.w_min
|
||||||
w_embedding = guidance_scale_embedding(w, embedding_dim=unet.config.time_cond_proj_dim)
|
w_embedding = guidance_scale_embedding(w, embedding_dim=unet.config.time_cond_proj_dim)
|
||||||
w = w.reshape(bsz, 1, 1, 1)
|
w = w.reshape(bsz, 1, 1, 1)
|
||||||
|
# Move to U-Net device and dtype
|
||||||
w = w.to(device=latents.device, dtype=latents.dtype)
|
w = w.to(device=latents.device, dtype=latents.dtype)
|
||||||
|
w_embedding = w_embedding.to(device=latents.device, dtype=latents.dtype)
|
||||||
|
|
||||||
# 20.4.8. Prepare prompt embeds and unet_added_conditions
|
# 6. Prepare prompt embeds and unet_added_conditions
|
||||||
prompt_embeds = encoded_text.pop("prompt_embeds")
|
prompt_embeds = encoded_text.pop("prompt_embeds")
|
||||||
|
|
||||||
# 20.4.9. Get online LCM prediction on z_{t_{n + k}}, w, c, t_{n + k}
|
# 7. Get online LCM prediction on z_{t_{n + k}} (noisy_model_input), w, c, t_{n + k} (start_timesteps)
|
||||||
noise_pred = unet(
|
noise_pred = unet(
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
@@ -1263,7 +1291,7 @@ def main(args):
|
|||||||
added_cond_kwargs=encoded_text,
|
added_cond_kwargs=encoded_text,
|
||||||
).sample
|
).sample
|
||||||
|
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
noise_pred,
|
noise_pred,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1274,18 +1302,28 @@ def main(args):
|
|||||||
|
|
||||||
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
model_pred = c_skip_start * noisy_model_input + c_out_start * pred_x_0
|
||||||
|
|
||||||
# 20.4.10. Use the ODE solver to predict the kth step in the augmented PF-ODE trajectory after
|
# 8. Compute the conditional and unconditional teacher model predictions to get CFG estimates of the
|
||||||
# noisy_latents with both the conditioning embedding c and unconditional embedding 0
|
# predicted noise eps_0 and predicted original sample x_0, then run the ODE solver using these
|
||||||
# Get teacher model prediction on noisy_latents and conditional embedding
|
# estimates to predict the data point in the augmented PF-ODE trajectory corresponding to the next ODE
|
||||||
|
# solver timestep.
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda"):
|
with torch.autocast("cuda"):
|
||||||
|
# 1. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and conditional embedding c
|
||||||
cond_teacher_output = teacher_unet(
|
cond_teacher_output = teacher_unet(
|
||||||
noisy_model_input.to(weight_dtype),
|
noisy_model_input.to(weight_dtype),
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=prompt_embeds.to(weight_dtype),
|
||||||
added_cond_kwargs={k: v.to(weight_dtype) for k, v in encoded_text.items()},
|
added_cond_kwargs={k: v.to(weight_dtype) for k, v in encoded_text.items()},
|
||||||
).sample
|
).sample
|
||||||
cond_pred_x0 = predicted_origin(
|
cond_pred_x0 = get_predicted_original_sample(
|
||||||
|
cond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
cond_pred_noise = get_predicted_noise(
|
||||||
cond_teacher_output,
|
cond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1294,7 +1332,7 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get teacher model prediction on noisy_latents and unconditional embedding
|
# 2. Get teacher model prediction on noisy_model_input z_{t_{n + k}} and unconditional embedding 0
|
||||||
uncond_added_conditions = copy.deepcopy(encoded_text)
|
uncond_added_conditions = copy.deepcopy(encoded_text)
|
||||||
uncond_added_conditions["text_embeds"] = uncond_pooled_prompt_embeds
|
uncond_added_conditions["text_embeds"] = uncond_pooled_prompt_embeds
|
||||||
uncond_teacher_output = teacher_unet(
|
uncond_teacher_output = teacher_unet(
|
||||||
@@ -1303,7 +1341,15 @@ def main(args):
|
|||||||
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
encoder_hidden_states=uncond_prompt_embeds.to(weight_dtype),
|
||||||
added_cond_kwargs={k: v.to(weight_dtype) for k, v in uncond_added_conditions.items()},
|
added_cond_kwargs={k: v.to(weight_dtype) for k, v in uncond_added_conditions.items()},
|
||||||
).sample
|
).sample
|
||||||
uncond_pred_x0 = predicted_origin(
|
uncond_pred_x0 = get_predicted_original_sample(
|
||||||
|
uncond_teacher_output,
|
||||||
|
start_timesteps,
|
||||||
|
noisy_model_input,
|
||||||
|
noise_scheduler.config.prediction_type,
|
||||||
|
alpha_schedule,
|
||||||
|
sigma_schedule,
|
||||||
|
)
|
||||||
|
uncond_pred_noise = get_predicted_noise(
|
||||||
uncond_teacher_output,
|
uncond_teacher_output,
|
||||||
start_timesteps,
|
start_timesteps,
|
||||||
noisy_model_input,
|
noisy_model_input,
|
||||||
@@ -1312,12 +1358,16 @@ def main(args):
|
|||||||
sigma_schedule,
|
sigma_schedule,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.11. Perform "CFG" to get x_prev estimate (using the LCM paper's CFG formulation)
|
# 3. Calculate the CFG estimate of x_0 (pred_x0) and eps_0 (pred_noise)
|
||||||
|
# Note that this uses the LCM paper's CFG formulation rather than the Imagen CFG formulation
|
||||||
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
pred_x0 = cond_pred_x0 + w * (cond_pred_x0 - uncond_pred_x0)
|
||||||
pred_noise = cond_teacher_output + w * (cond_teacher_output - uncond_teacher_output)
|
pred_noise = cond_pred_noise + w * (cond_pred_noise - uncond_pred_noise)
|
||||||
|
# 4. Run one step of the ODE solver to estimate the next point x_prev on the
|
||||||
|
# augmented PF-ODE trajectory (solving backward in time)
|
||||||
|
# Note that the DDIM step depends on both the predicted x_0 and source noise eps_0.
|
||||||
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
x_prev = solver.ddim_step(pred_x0, pred_noise, index)
|
||||||
|
|
||||||
# 20.4.12. Get target LCM prediction on x_prev, w, c, t_n
|
# 9. Get target LCM prediction on x_prev, w, c, t_n (timesteps)
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
with torch.autocast("cuda", dtype=weight_dtype):
|
with torch.autocast("cuda", dtype=weight_dtype):
|
||||||
target_noise_pred = target_unet(
|
target_noise_pred = target_unet(
|
||||||
@@ -1327,7 +1377,7 @@ def main(args):
|
|||||||
encoder_hidden_states=prompt_embeds.float(),
|
encoder_hidden_states=prompt_embeds.float(),
|
||||||
added_cond_kwargs=encoded_text,
|
added_cond_kwargs=encoded_text,
|
||||||
).sample
|
).sample
|
||||||
pred_x_0 = predicted_origin(
|
pred_x_0 = get_predicted_original_sample(
|
||||||
target_noise_pred,
|
target_noise_pred,
|
||||||
timesteps,
|
timesteps,
|
||||||
x_prev,
|
x_prev,
|
||||||
@@ -1337,7 +1387,7 @@ def main(args):
|
|||||||
)
|
)
|
||||||
target = c_skip * x_prev + c_out * pred_x_0
|
target = c_skip * x_prev + c_out * pred_x_0
|
||||||
|
|
||||||
# 20.4.13. Calculate loss
|
# 10. Calculate loss
|
||||||
if args.loss_type == "l2":
|
if args.loss_type == "l2":
|
||||||
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean")
|
||||||
elif args.loss_type == "huber":
|
elif args.loss_type == "huber":
|
||||||
@@ -1345,7 +1395,7 @@ def main(args):
|
|||||||
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
torch.sqrt((model_pred.float() - target.float()) ** 2 + args.huber_c**2) - args.huber_c
|
||||||
)
|
)
|
||||||
|
|
||||||
# 20.4.14. Backpropagate on the online student model (`unet`)
|
# 11. Backpropagate on the online student model (`unet`)
|
||||||
accelerator.backward(loss)
|
accelerator.backward(loss)
|
||||||
if accelerator.sync_gradients:
|
if accelerator.sync_gradients:
|
||||||
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
accelerator.clip_grad_norm_(unet.parameters(), args.max_grad_norm)
|
||||||
@@ -1355,7 +1405,7 @@ def main(args):
|
|||||||
|
|
||||||
# Checks if the accelerator has performed an optimization step behind the scenes
|
# Checks if the accelerator has performed an optimization step behind the scenes
|
||||||
if accelerator.sync_gradients:
|
if accelerator.sync_gradients:
|
||||||
# 20.4.15. Make EMA update to target student model parameters
|
# 12. Make EMA update to target student model parameters (`target_unet`)
|
||||||
update_ema(target_unet.parameters(), unet.parameters(), args.ema_decay)
|
update_ema(target_unet.parameters(), unet.parameters(), args.ema_decay)
|
||||||
progress_bar.update(1)
|
progress_bar.update(1)
|
||||||
global_step += 1
|
global_step += 1
|
||||||
|
|||||||
@@ -64,39 +64,6 @@ check_min_version("0.25.0.dev0")
|
|||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# TODO: This function should be removed once training scripts are rewritten in PEFT
|
|
||||||
def text_encoder_lora_state_dict(text_encoder):
|
|
||||||
state_dict = {}
|
|
||||||
|
|
||||||
def text_encoder_attn_modules(text_encoder):
|
|
||||||
from transformers import CLIPTextModel, CLIPTextModelWithProjection
|
|
||||||
|
|
||||||
attn_modules = []
|
|
||||||
|
|
||||||
if isinstance(text_encoder, (CLIPTextModel, CLIPTextModelWithProjection)):
|
|
||||||
for i, layer in enumerate(text_encoder.text_model.encoder.layers):
|
|
||||||
name = f"text_model.encoder.layers.{i}.self_attn"
|
|
||||||
mod = layer.self_attn
|
|
||||||
attn_modules.append((name, mod))
|
|
||||||
|
|
||||||
return attn_modules
|
|
||||||
|
|
||||||
for name, module in text_encoder_attn_modules(text_encoder):
|
|
||||||
for k, v in module.q_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.q_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.k_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.k_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.v_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.v_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.out_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.out_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
return state_dict
|
|
||||||
|
|
||||||
|
|
||||||
def save_model_card(
|
def save_model_card(
|
||||||
repo_id: str,
|
repo_id: str,
|
||||||
images=None,
|
images=None,
|
||||||
|
|||||||
@@ -64,39 +64,6 @@ check_min_version("0.25.0.dev0")
|
|||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# TODO: This function should be removed once training scripts are rewritten in PEFT
|
|
||||||
def text_encoder_lora_state_dict(text_encoder):
|
|
||||||
state_dict = {}
|
|
||||||
|
|
||||||
def text_encoder_attn_modules(text_encoder):
|
|
||||||
from transformers import CLIPTextModel, CLIPTextModelWithProjection
|
|
||||||
|
|
||||||
attn_modules = []
|
|
||||||
|
|
||||||
if isinstance(text_encoder, (CLIPTextModel, CLIPTextModelWithProjection)):
|
|
||||||
for i, layer in enumerate(text_encoder.text_model.encoder.layers):
|
|
||||||
name = f"text_model.encoder.layers.{i}.self_attn"
|
|
||||||
mod = layer.self_attn
|
|
||||||
attn_modules.append((name, mod))
|
|
||||||
|
|
||||||
return attn_modules
|
|
||||||
|
|
||||||
for name, module in text_encoder_attn_modules(text_encoder):
|
|
||||||
for k, v in module.q_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.q_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.k_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.k_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.v_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.v_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.out_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.out_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
return state_dict
|
|
||||||
|
|
||||||
|
|
||||||
def save_model_card(
|
def save_model_card(
|
||||||
repo_id: str,
|
repo_id: str,
|
||||||
images=None,
|
images=None,
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ accelerate launch --mixed_precision="fp16" train_text_to_image.py \
|
|||||||
|
|
||||||
Once the training is finished the model will be saved in the `output_dir` specified in the command. In this example it's `sd-pokemon-model`. To load the fine-tuned model for inference just pass that path to `StableDiffusionPipeline`
|
Once the training is finished the model will be saved in the `output_dir` specified in the command. In this example it's `sd-pokemon-model`. To load the fine-tuned model for inference just pass that path to `StableDiffusionPipeline`
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
import torch
|
||||||
from diffusers import StableDiffusionPipeline
|
from diffusers import StableDiffusionPipeline
|
||||||
|
|
||||||
model_path = "path_to_saved_model"
|
model_path = "path_to_saved_model"
|
||||||
@@ -114,12 +114,13 @@ image.save("yoda-pokemon.png")
|
|||||||
```
|
```
|
||||||
|
|
||||||
Checkpoints only save the unet, so to run inference from a checkpoint, just load the unet
|
Checkpoints only save the unet, so to run inference from a checkpoint, just load the unet
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
import torch
|
||||||
from diffusers import StableDiffusionPipeline, UNet2DConditionModel
|
from diffusers import StableDiffusionPipeline, UNet2DConditionModel
|
||||||
|
|
||||||
model_path = "path_to_saved_model"
|
model_path = "path_to_saved_model"
|
||||||
|
unet = UNet2DConditionModel.from_pretrained(model_path + "/checkpoint-<N>/unet", torch_dtype=torch.float16)
|
||||||
unet = UNet2DConditionModel.from_pretrained(model_path + "/checkpoint-<N>/unet")
|
|
||||||
|
|
||||||
pipe = StableDiffusionPipeline.from_pretrained("<initial model>", unet=unet, torch_dtype=torch.float16)
|
pipe = StableDiffusionPipeline.from_pretrained("<initial model>", unet=unet, torch_dtype=torch.float16)
|
||||||
pipe.to("cuda")
|
pipe.to("cuda")
|
||||||
|
|||||||
@@ -54,39 +54,6 @@ check_min_version("0.25.0.dev0")
|
|||||||
logger = get_logger(__name__, log_level="INFO")
|
logger = get_logger(__name__, log_level="INFO")
|
||||||
|
|
||||||
|
|
||||||
# TODO: This function should be removed once training scripts are rewritten in PEFT
|
|
||||||
def text_encoder_lora_state_dict(text_encoder):
|
|
||||||
state_dict = {}
|
|
||||||
|
|
||||||
def text_encoder_attn_modules(text_encoder):
|
|
||||||
from transformers import CLIPTextModel, CLIPTextModelWithProjection
|
|
||||||
|
|
||||||
attn_modules = []
|
|
||||||
|
|
||||||
if isinstance(text_encoder, (CLIPTextModel, CLIPTextModelWithProjection)):
|
|
||||||
for i, layer in enumerate(text_encoder.text_model.encoder.layers):
|
|
||||||
name = f"text_model.encoder.layers.{i}.self_attn"
|
|
||||||
mod = layer.self_attn
|
|
||||||
attn_modules.append((name, mod))
|
|
||||||
|
|
||||||
return attn_modules
|
|
||||||
|
|
||||||
for name, module in text_encoder_attn_modules(text_encoder):
|
|
||||||
for k, v in module.q_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.q_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.k_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.k_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.v_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.v_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.out_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.out_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
return state_dict
|
|
||||||
|
|
||||||
|
|
||||||
def save_model_card(repo_id: str, images=None, base_model=str, dataset_name=str, repo_folder=None):
|
def save_model_card(repo_id: str, images=None, base_model=str, dataset_name=str, repo_folder=None):
|
||||||
img_str = ""
|
img_str = ""
|
||||||
for i, image in enumerate(images):
|
for i, image in enumerate(images):
|
||||||
|
|||||||
@@ -63,39 +63,6 @@ check_min_version("0.25.0.dev0")
|
|||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# TODO: This function should be removed once training scripts are rewritten in PEFT
|
|
||||||
def text_encoder_lora_state_dict(text_encoder):
|
|
||||||
state_dict = {}
|
|
||||||
|
|
||||||
def text_encoder_attn_modules(text_encoder):
|
|
||||||
from transformers import CLIPTextModel, CLIPTextModelWithProjection
|
|
||||||
|
|
||||||
attn_modules = []
|
|
||||||
|
|
||||||
if isinstance(text_encoder, (CLIPTextModel, CLIPTextModelWithProjection)):
|
|
||||||
for i, layer in enumerate(text_encoder.text_model.encoder.layers):
|
|
||||||
name = f"text_model.encoder.layers.{i}.self_attn"
|
|
||||||
mod = layer.self_attn
|
|
||||||
attn_modules.append((name, mod))
|
|
||||||
|
|
||||||
return attn_modules
|
|
||||||
|
|
||||||
for name, module in text_encoder_attn_modules(text_encoder):
|
|
||||||
for k, v in module.q_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.q_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.k_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.k_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.v_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.v_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
for k, v in module.out_proj.lora_linear_layer.state_dict().items():
|
|
||||||
state_dict[f"{name}.out_proj.lora_linear_layer.{k}"] = v
|
|
||||||
|
|
||||||
return state_dict
|
|
||||||
|
|
||||||
|
|
||||||
def save_model_card(
|
def save_model_card(
|
||||||
repo_id: str,
|
repo_id: str,
|
||||||
images=None,
|
images=None,
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ from safetensors.torch import load_file as stl
|
|||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from diffusers import AutoencoderKL, ConsistencyDecoderVAE, DiffusionPipeline, StableDiffusionPipeline, UNet2DModel
|
from diffusers import AutoencoderKL, ConsistencyDecoderVAE, DiffusionPipeline, StableDiffusionPipeline, UNet2DModel
|
||||||
|
from diffusers.models.autoencoders.vae import Encoder
|
||||||
from diffusers.models.embeddings import TimestepEmbedding
|
from diffusers.models.embeddings import TimestepEmbedding
|
||||||
from diffusers.models.unet_2d_blocks import ResnetDownsampleBlock2D, ResnetUpsampleBlock2D, UNetMidBlock2D
|
from diffusers.models.unet_2d_blocks import ResnetDownsampleBlock2D, ResnetUpsampleBlock2D, UNetMidBlock2D
|
||||||
from diffusers.models.vae import Encoder
|
|
||||||
|
|
||||||
|
|
||||||
args = ArgumentParser()
|
args = ArgumentParser()
|
||||||
|
|||||||
@@ -159,6 +159,14 @@ vae_conversion_map_attn = [
|
|||||||
("proj_out.", "proj_attn."),
|
("proj_out.", "proj_attn."),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# This is probably not the most ideal solution, but it does work.
|
||||||
|
vae_extra_conversion_map = [
|
||||||
|
("to_q", "q"),
|
||||||
|
("to_k", "k"),
|
||||||
|
("to_v", "v"),
|
||||||
|
("to_out.0", "proj_out"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def reshape_weight_for_sd(w):
|
def reshape_weight_for_sd(w):
|
||||||
# convert HF linear weights to SD conv2d weights
|
# convert HF linear weights to SD conv2d weights
|
||||||
@@ -178,11 +186,20 @@ def convert_vae_state_dict(vae_state_dict):
|
|||||||
mapping[k] = v
|
mapping[k] = v
|
||||||
new_state_dict = {v: vae_state_dict[k] for k, v in mapping.items()}
|
new_state_dict = {v: vae_state_dict[k] for k, v in mapping.items()}
|
||||||
weights_to_convert = ["q", "k", "v", "proj_out"]
|
weights_to_convert = ["q", "k", "v", "proj_out"]
|
||||||
|
keys_to_rename = {}
|
||||||
for k, v in new_state_dict.items():
|
for k, v in new_state_dict.items():
|
||||||
for weight_name in weights_to_convert:
|
for weight_name in weights_to_convert:
|
||||||
if f"mid.attn_1.{weight_name}.weight" in k:
|
if f"mid.attn_1.{weight_name}.weight" in k:
|
||||||
print(f"Reshaping {k} for SD format")
|
print(f"Reshaping {k} for SD format")
|
||||||
new_state_dict[k] = reshape_weight_for_sd(v)
|
new_state_dict[k] = reshape_weight_for_sd(v)
|
||||||
|
for weight_name, real_weight_name in vae_extra_conversion_map:
|
||||||
|
if f"mid.attn_1.{weight_name}.weight" in k or f"mid.attn_1.{weight_name}.bias" in k:
|
||||||
|
keys_to_rename[k] = k.replace(weight_name, real_weight_name)
|
||||||
|
for k, v in keys_to_rename.items():
|
||||||
|
if k in new_state_dict:
|
||||||
|
print(f"Renaming {k} to {v}")
|
||||||
|
new_state_dict[v] = reshape_weight_for_sd(new_state_dict[k])
|
||||||
|
del new_state_dict[k]
|
||||||
return new_state_dict
|
return new_state_dict
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from typing import Callable, Dict, List, Optional, Union
|
|||||||
import safetensors
|
import safetensors
|
||||||
import torch
|
import torch
|
||||||
from huggingface_hub import model_info
|
from huggingface_hub import model_info
|
||||||
|
from huggingface_hub.constants import HF_HUB_OFFLINE
|
||||||
from huggingface_hub.utils import validate_hf_hub_args
|
from huggingface_hub.utils import validate_hf_hub_args
|
||||||
from packaging import version
|
from packaging import version
|
||||||
from torch import nn
|
from torch import nn
|
||||||
@@ -229,7 +230,9 @@ class LoraLoaderMixin:
|
|||||||
# determine `weight_name`.
|
# determine `weight_name`.
|
||||||
if weight_name is None:
|
if weight_name is None:
|
||||||
weight_name = cls._best_guess_weight_name(
|
weight_name = cls._best_guess_weight_name(
|
||||||
pretrained_model_name_or_path_or_dict, file_extension=".safetensors"
|
pretrained_model_name_or_path_or_dict,
|
||||||
|
file_extension=".safetensors",
|
||||||
|
local_files_only=local_files_only,
|
||||||
)
|
)
|
||||||
model_file = _get_model_file(
|
model_file = _get_model_file(
|
||||||
pretrained_model_name_or_path_or_dict,
|
pretrained_model_name_or_path_or_dict,
|
||||||
@@ -255,7 +258,7 @@ class LoraLoaderMixin:
|
|||||||
if model_file is None:
|
if model_file is None:
|
||||||
if weight_name is None:
|
if weight_name is None:
|
||||||
weight_name = cls._best_guess_weight_name(
|
weight_name = cls._best_guess_weight_name(
|
||||||
pretrained_model_name_or_path_or_dict, file_extension=".bin"
|
pretrained_model_name_or_path_or_dict, file_extension=".bin", local_files_only=local_files_only
|
||||||
)
|
)
|
||||||
model_file = _get_model_file(
|
model_file = _get_model_file(
|
||||||
pretrained_model_name_or_path_or_dict,
|
pretrained_model_name_or_path_or_dict,
|
||||||
@@ -294,7 +297,12 @@ class LoraLoaderMixin:
|
|||||||
return state_dict, network_alphas
|
return state_dict, network_alphas
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _best_guess_weight_name(cls, pretrained_model_name_or_path_or_dict, file_extension=".safetensors"):
|
def _best_guess_weight_name(
|
||||||
|
cls, pretrained_model_name_or_path_or_dict, file_extension=".safetensors", local_files_only=False
|
||||||
|
):
|
||||||
|
if local_files_only or HF_HUB_OFFLINE:
|
||||||
|
raise ValueError("When using the offline mode, you must specify a `weight_name`.")
|
||||||
|
|
||||||
targeted_files = []
|
targeted_files = []
|
||||||
|
|
||||||
if os.path.isfile(pretrained_model_name_or_path_or_dict):
|
if os.path.isfile(pretrained_model_name_or_path_or_dict):
|
||||||
|
|||||||
@@ -169,10 +169,12 @@ class FromSingleFileMixin:
|
|||||||
load_safety_checker = kwargs.pop("load_safety_checker", True)
|
load_safety_checker = kwargs.pop("load_safety_checker", True)
|
||||||
prediction_type = kwargs.pop("prediction_type", None)
|
prediction_type = kwargs.pop("prediction_type", None)
|
||||||
text_encoder = kwargs.pop("text_encoder", None)
|
text_encoder = kwargs.pop("text_encoder", None)
|
||||||
|
text_encoder_2 = kwargs.pop("text_encoder_2", None)
|
||||||
vae = kwargs.pop("vae", None)
|
vae = kwargs.pop("vae", None)
|
||||||
controlnet = kwargs.pop("controlnet", None)
|
controlnet = kwargs.pop("controlnet", None)
|
||||||
adapter = kwargs.pop("adapter", None)
|
adapter = kwargs.pop("adapter", None)
|
||||||
tokenizer = kwargs.pop("tokenizer", None)
|
tokenizer = kwargs.pop("tokenizer", None)
|
||||||
|
tokenizer_2 = kwargs.pop("tokenizer_2", None)
|
||||||
|
|
||||||
torch_dtype = kwargs.pop("torch_dtype", None)
|
torch_dtype = kwargs.pop("torch_dtype", None)
|
||||||
|
|
||||||
@@ -274,8 +276,10 @@ class FromSingleFileMixin:
|
|||||||
load_safety_checker=load_safety_checker,
|
load_safety_checker=load_safety_checker,
|
||||||
prediction_type=prediction_type,
|
prediction_type=prediction_type,
|
||||||
text_encoder=text_encoder,
|
text_encoder=text_encoder,
|
||||||
|
text_encoder_2=text_encoder_2,
|
||||||
vae=vae,
|
vae=vae,
|
||||||
tokenizer=tokenizer,
|
tokenizer=tokenizer,
|
||||||
|
tokenizer_2=tokenizer_2,
|
||||||
original_config_file=original_config_file,
|
original_config_file=original_config_file,
|
||||||
config_files=config_files,
|
config_files=config_files,
|
||||||
local_files_only=local_files_only,
|
local_files_only=local_files_only,
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ _import_structure = {}
|
|||||||
|
|
||||||
if is_torch_available():
|
if is_torch_available():
|
||||||
_import_structure["adapter"] = ["MultiAdapter", "T2IAdapter"]
|
_import_structure["adapter"] = ["MultiAdapter", "T2IAdapter"]
|
||||||
_import_structure["autoencoder_asym_kl"] = ["AsymmetricAutoencoderKL"]
|
_import_structure["autoencoders.autoencoder_asym_kl"] = ["AsymmetricAutoencoderKL"]
|
||||||
_import_structure["autoencoder_kl"] = ["AutoencoderKL"]
|
_import_structure["autoencoders.autoencoder_kl"] = ["AutoencoderKL"]
|
||||||
_import_structure["autoencoder_kl_temporal_decoder"] = ["AutoencoderKLTemporalDecoder"]
|
_import_structure["autoencoders.autoencoder_kl_temporal_decoder"] = ["AutoencoderKLTemporalDecoder"]
|
||||||
_import_structure["autoencoder_tiny"] = ["AutoencoderTiny"]
|
_import_structure["autoencoders.autoencoder_tiny"] = ["AutoencoderTiny"]
|
||||||
_import_structure["consistency_decoder_vae"] = ["ConsistencyDecoderVAE"]
|
_import_structure["autoencoders.consistency_decoder_vae"] = ["ConsistencyDecoderVAE"]
|
||||||
_import_structure["controlnet"] = ["ControlNetModel"]
|
_import_structure["controlnet"] = ["ControlNetModel"]
|
||||||
_import_structure["controlnetxs"] = ["ControlNetXSModel"]
|
_import_structure["controlnetxs"] = ["ControlNetXSModel"]
|
||||||
_import_structure["dual_transformer_2d"] = ["DualTransformer2DModel"]
|
_import_structure["dual_transformer_2d"] = ["DualTransformer2DModel"]
|
||||||
@@ -58,11 +58,13 @@ if is_flax_available():
|
|||||||
if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
|
if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
|
||||||
if is_torch_available():
|
if is_torch_available():
|
||||||
from .adapter import MultiAdapter, T2IAdapter
|
from .adapter import MultiAdapter, T2IAdapter
|
||||||
from .autoencoder_asym_kl import AsymmetricAutoencoderKL
|
from .autoencoders import (
|
||||||
from .autoencoder_kl import AutoencoderKL
|
AsymmetricAutoencoderKL,
|
||||||
from .autoencoder_kl_temporal_decoder import AutoencoderKLTemporalDecoder
|
AutoencoderKL,
|
||||||
from .autoencoder_tiny import AutoencoderTiny
|
AutoencoderKLTemporalDecoder,
|
||||||
from .consistency_decoder_vae import ConsistencyDecoderVAE
|
AutoencoderTiny,
|
||||||
|
ConsistencyDecoderVAE,
|
||||||
|
)
|
||||||
from .controlnet import ControlNetModel
|
from .controlnet import ControlNetModel
|
||||||
from .controlnetxs import ControlNetXSModel
|
from .controlnetxs import ControlNetXSModel
|
||||||
from .dual_transformer_2d import DualTransformer2DModel
|
from .dual_transformer_2d import DualTransformer2DModel
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from .autoencoder_asym_kl import AsymmetricAutoencoderKL
|
||||||
|
from .autoencoder_kl import AutoencoderKL
|
||||||
|
from .autoencoder_kl_temporal_decoder import AutoencoderKLTemporalDecoder
|
||||||
|
from .autoencoder_tiny import AutoencoderTiny
|
||||||
|
from .consistency_decoder_vae import ConsistencyDecoderVAE
|
||||||
+4
-4
@@ -16,10 +16,10 @@ from typing import Optional, Tuple, Union
|
|||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
|
|
||||||
from ..configuration_utils import ConfigMixin, register_to_config
|
from ...configuration_utils import ConfigMixin, register_to_config
|
||||||
from ..utils.accelerate_utils import apply_forward_hook
|
from ...utils.accelerate_utils import apply_forward_hook
|
||||||
from .modeling_outputs import AutoencoderKLOutput
|
from ..modeling_outputs import AutoencoderKLOutput
|
||||||
from .modeling_utils import ModelMixin
|
from ..modeling_utils import ModelMixin
|
||||||
from .vae import DecoderOutput, DiagonalGaussianDistribution, Encoder, MaskConditionDecoder
|
from .vae import DecoderOutput, DiagonalGaussianDistribution, Encoder, MaskConditionDecoder
|
||||||
|
|
||||||
|
|
||||||
+6
-6
@@ -16,10 +16,10 @@ from typing import Dict, Optional, Tuple, Union
|
|||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
|
|
||||||
from ..configuration_utils import ConfigMixin, register_to_config
|
from ...configuration_utils import ConfigMixin, register_to_config
|
||||||
from ..loaders import FromOriginalVAEMixin
|
from ...loaders import FromOriginalVAEMixin
|
||||||
from ..utils.accelerate_utils import apply_forward_hook
|
from ...utils.accelerate_utils import apply_forward_hook
|
||||||
from .attention_processor import (
|
from ..attention_processor import (
|
||||||
ADDED_KV_ATTENTION_PROCESSORS,
|
ADDED_KV_ATTENTION_PROCESSORS,
|
||||||
CROSS_ATTENTION_PROCESSORS,
|
CROSS_ATTENTION_PROCESSORS,
|
||||||
Attention,
|
Attention,
|
||||||
@@ -27,8 +27,8 @@ from .attention_processor import (
|
|||||||
AttnAddedKVProcessor,
|
AttnAddedKVProcessor,
|
||||||
AttnProcessor,
|
AttnProcessor,
|
||||||
)
|
)
|
||||||
from .modeling_outputs import AutoencoderKLOutput
|
from ..modeling_outputs import AutoencoderKLOutput
|
||||||
from .modeling_utils import ModelMixin
|
from ..modeling_utils import ModelMixin
|
||||||
from .vae import Decoder, DecoderOutput, DiagonalGaussianDistribution, Encoder
|
from .vae import Decoder, DecoderOutput, DiagonalGaussianDistribution, Encoder
|
||||||
|
|
||||||
|
|
||||||
+8
-8
@@ -16,14 +16,14 @@ from typing import Dict, Optional, Tuple, Union
|
|||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
|
|
||||||
from ..configuration_utils import ConfigMixin, register_to_config
|
from ...configuration_utils import ConfigMixin, register_to_config
|
||||||
from ..loaders import FromOriginalVAEMixin
|
from ...loaders import FromOriginalVAEMixin
|
||||||
from ..utils import is_torch_version
|
from ...utils import is_torch_version
|
||||||
from ..utils.accelerate_utils import apply_forward_hook
|
from ...utils.accelerate_utils import apply_forward_hook
|
||||||
from .attention_processor import CROSS_ATTENTION_PROCESSORS, AttentionProcessor, AttnProcessor
|
from ..attention_processor import CROSS_ATTENTION_PROCESSORS, AttentionProcessor, AttnProcessor
|
||||||
from .modeling_outputs import AutoencoderKLOutput
|
from ..modeling_outputs import AutoencoderKLOutput
|
||||||
from .modeling_utils import ModelMixin
|
from ..modeling_utils import ModelMixin
|
||||||
from .unet_3d_blocks import MidBlockTemporalDecoder, UpBlockTemporalDecoder
|
from ..unet_3d_blocks import MidBlockTemporalDecoder, UpBlockTemporalDecoder
|
||||||
from .vae import DecoderOutput, DiagonalGaussianDistribution, Encoder
|
from .vae import DecoderOutput, DiagonalGaussianDistribution, Encoder
|
||||||
|
|
||||||
|
|
||||||
+4
-4
@@ -18,10 +18,10 @@ from typing import Optional, Tuple, Union
|
|||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from ..configuration_utils import ConfigMixin, register_to_config
|
from ...configuration_utils import ConfigMixin, register_to_config
|
||||||
from ..utils import BaseOutput
|
from ...utils import BaseOutput
|
||||||
from ..utils.accelerate_utils import apply_forward_hook
|
from ...utils.accelerate_utils import apply_forward_hook
|
||||||
from .modeling_utils import ModelMixin
|
from ..modeling_utils import ModelMixin
|
||||||
from .vae import DecoderOutput, DecoderTiny, EncoderTiny
|
from .vae import DecoderOutput, DecoderTiny, EncoderTiny
|
||||||
|
|
||||||
|
|
||||||
+14
-14
@@ -18,20 +18,20 @@ import torch
|
|||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
from torch import nn
|
from torch import nn
|
||||||
|
|
||||||
from ..configuration_utils import ConfigMixin, register_to_config
|
from ...configuration_utils import ConfigMixin, register_to_config
|
||||||
from ..schedulers import ConsistencyDecoderScheduler
|
from ...schedulers import ConsistencyDecoderScheduler
|
||||||
from ..utils import BaseOutput
|
from ...utils import BaseOutput
|
||||||
from ..utils.accelerate_utils import apply_forward_hook
|
from ...utils.accelerate_utils import apply_forward_hook
|
||||||
from ..utils.torch_utils import randn_tensor
|
from ...utils.torch_utils import randn_tensor
|
||||||
from .attention_processor import (
|
from ..attention_processor import (
|
||||||
ADDED_KV_ATTENTION_PROCESSORS,
|
ADDED_KV_ATTENTION_PROCESSORS,
|
||||||
CROSS_ATTENTION_PROCESSORS,
|
CROSS_ATTENTION_PROCESSORS,
|
||||||
AttentionProcessor,
|
AttentionProcessor,
|
||||||
AttnAddedKVProcessor,
|
AttnAddedKVProcessor,
|
||||||
AttnProcessor,
|
AttnProcessor,
|
||||||
)
|
)
|
||||||
from .modeling_utils import ModelMixin
|
from ..modeling_utils import ModelMixin
|
||||||
from .unet_2d import UNet2DModel
|
from ..unet_2d import UNet2DModel
|
||||||
from .vae import DecoderOutput, DiagonalGaussianDistribution, Encoder
|
from .vae import DecoderOutput, DiagonalGaussianDistribution, Encoder
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ class ConsistencyDecoderVAE(ModelMixin, ConfigMixin):
|
|||||||
self.use_slicing = False
|
self.use_slicing = False
|
||||||
self.use_tiling = False
|
self.use_tiling = False
|
||||||
|
|
||||||
# Copied from diffusers.models.autoencoder_kl.AutoencoderKL.enable_tiling
|
# Copied from diffusers.models.autoencoders.autoencoder_kl.AutoencoderKL.enable_tiling
|
||||||
def enable_tiling(self, use_tiling: bool = True):
|
def enable_tiling(self, use_tiling: bool = True):
|
||||||
r"""
|
r"""
|
||||||
Enable tiled VAE decoding. When this option is enabled, the VAE will split the input tensor into tiles to
|
Enable tiled VAE decoding. When this option is enabled, the VAE will split the input tensor into tiles to
|
||||||
@@ -162,7 +162,7 @@ class ConsistencyDecoderVAE(ModelMixin, ConfigMixin):
|
|||||||
"""
|
"""
|
||||||
self.use_tiling = use_tiling
|
self.use_tiling = use_tiling
|
||||||
|
|
||||||
# Copied from diffusers.models.autoencoder_kl.AutoencoderKL.disable_tiling
|
# Copied from diffusers.models.autoencoders.autoencoder_kl.AutoencoderKL.disable_tiling
|
||||||
def disable_tiling(self):
|
def disable_tiling(self):
|
||||||
r"""
|
r"""
|
||||||
Disable tiled VAE decoding. If `enable_tiling` was previously enabled, this method will go back to computing
|
Disable tiled VAE decoding. If `enable_tiling` was previously enabled, this method will go back to computing
|
||||||
@@ -170,7 +170,7 @@ class ConsistencyDecoderVAE(ModelMixin, ConfigMixin):
|
|||||||
"""
|
"""
|
||||||
self.enable_tiling(False)
|
self.enable_tiling(False)
|
||||||
|
|
||||||
# Copied from diffusers.models.autoencoder_kl.AutoencoderKL.enable_slicing
|
# Copied from diffusers.models.autoencoders.autoencoder_kl.AutoencoderKL.enable_slicing
|
||||||
def enable_slicing(self):
|
def enable_slicing(self):
|
||||||
r"""
|
r"""
|
||||||
Enable sliced VAE decoding. When this option is enabled, the VAE will split the input tensor in slices to
|
Enable sliced VAE decoding. When this option is enabled, the VAE will split the input tensor in slices to
|
||||||
@@ -178,7 +178,7 @@ class ConsistencyDecoderVAE(ModelMixin, ConfigMixin):
|
|||||||
"""
|
"""
|
||||||
self.use_slicing = True
|
self.use_slicing = True
|
||||||
|
|
||||||
# Copied from diffusers.models.autoencoder_kl.AutoencoderKL.disable_slicing
|
# Copied from diffusers.models.autoencoders.autoencoder_kl.AutoencoderKL.disable_slicing
|
||||||
def disable_slicing(self):
|
def disable_slicing(self):
|
||||||
r"""
|
r"""
|
||||||
Disable sliced VAE decoding. If `enable_slicing` was previously enabled, this method will go back to computing
|
Disable sliced VAE decoding. If `enable_slicing` was previously enabled, this method will go back to computing
|
||||||
@@ -333,14 +333,14 @@ class ConsistencyDecoderVAE(ModelMixin, ConfigMixin):
|
|||||||
|
|
||||||
return DecoderOutput(sample=x_0)
|
return DecoderOutput(sample=x_0)
|
||||||
|
|
||||||
# Copied from diffusers.models.autoencoder_kl.AutoencoderKL.blend_v
|
# Copied from diffusers.models.autoencoders.autoencoder_kl.AutoencoderKL.blend_v
|
||||||
def blend_v(self, a: torch.Tensor, b: torch.Tensor, blend_extent: int) -> torch.Tensor:
|
def blend_v(self, a: torch.Tensor, b: torch.Tensor, blend_extent: int) -> torch.Tensor:
|
||||||
blend_extent = min(a.shape[2], b.shape[2], blend_extent)
|
blend_extent = min(a.shape[2], b.shape[2], blend_extent)
|
||||||
for y in range(blend_extent):
|
for y in range(blend_extent):
|
||||||
b[:, :, y, :] = a[:, :, -blend_extent + y, :] * (1 - y / blend_extent) + b[:, :, y, :] * (y / blend_extent)
|
b[:, :, y, :] = a[:, :, -blend_extent + y, :] * (1 - y / blend_extent) + b[:, :, y, :] * (y / blend_extent)
|
||||||
return b
|
return b
|
||||||
|
|
||||||
# Copied from diffusers.models.autoencoder_kl.AutoencoderKL.blend_h
|
# Copied from diffusers.models.autoencoders.autoencoder_kl.AutoencoderKL.blend_h
|
||||||
def blend_h(self, a: torch.Tensor, b: torch.Tensor, blend_extent: int) -> torch.Tensor:
|
def blend_h(self, a: torch.Tensor, b: torch.Tensor, blend_extent: int) -> torch.Tensor:
|
||||||
blend_extent = min(a.shape[3], b.shape[3], blend_extent)
|
blend_extent = min(a.shape[3], b.shape[3], blend_extent)
|
||||||
for x in range(blend_extent):
|
for x in range(blend_extent):
|
||||||
@@ -18,11 +18,11 @@ import numpy as np
|
|||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
|
|
||||||
from ..utils import BaseOutput, is_torch_version
|
from ...utils import BaseOutput, is_torch_version
|
||||||
from ..utils.torch_utils import randn_tensor
|
from ...utils.torch_utils import randn_tensor
|
||||||
from .activations import get_activation
|
from ..activations import get_activation
|
||||||
from .attention_processor import SpatialNorm
|
from ..attention_processor import SpatialNorm
|
||||||
from .unet_2d_blocks import (
|
from ..unet_2d_blocks import (
|
||||||
AutoencoderTinyBlock,
|
AutoencoderTinyBlock,
|
||||||
UNetMidBlock2D,
|
UNetMidBlock2D,
|
||||||
get_down_block,
|
get_down_block,
|
||||||
@@ -26,7 +26,7 @@ from ..utils import BaseOutput, logging
|
|||||||
from .attention_processor import (
|
from .attention_processor import (
|
||||||
AttentionProcessor,
|
AttentionProcessor,
|
||||||
)
|
)
|
||||||
from .autoencoder_kl import AutoencoderKL
|
from .autoencoders import AutoencoderKL
|
||||||
from .lora import LoRACompatibleConv
|
from .lora import LoRACompatibleConv
|
||||||
from .modeling_utils import ModelMixin
|
from .modeling_utils import ModelMixin
|
||||||
from .unet_2d_blocks import (
|
from .unet_2d_blocks import (
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import torch.nn as nn
|
|||||||
from ..configuration_utils import ConfigMixin, register_to_config
|
from ..configuration_utils import ConfigMixin, register_to_config
|
||||||
from ..utils import BaseOutput
|
from ..utils import BaseOutput
|
||||||
from ..utils.accelerate_utils import apply_forward_hook
|
from ..utils.accelerate_utils import apply_forward_hook
|
||||||
|
from .autoencoders.vae import Decoder, DecoderOutput, Encoder, VectorQuantizer
|
||||||
from .modeling_utils import ModelMixin
|
from .modeling_utils import ModelMixin
|
||||||
from .vae import Decoder, DecoderOutput, Encoder, VectorQuantizer
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from ...configuration_utils import FrozenDict
|
|||||||
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
||||||
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
||||||
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
||||||
|
from ...models.attention_processor import FusedAttnProcessor2_0
|
||||||
from ...models.lora import adjust_lora_scale_text_encoder
|
from ...models.lora import adjust_lora_scale_text_encoder
|
||||||
from ...schedulers import KarrasDiffusionSchedulers
|
from ...schedulers import KarrasDiffusionSchedulers
|
||||||
from ...utils import (
|
from ...utils import (
|
||||||
@@ -655,6 +656,65 @@ class AltDiffusionPipeline(
|
|||||||
"""Disables the FreeU mechanism if enabled."""
|
"""Disables the FreeU mechanism if enabled."""
|
||||||
self.unet.disable_freeu()
|
self.unet.disable_freeu()
|
||||||
|
|
||||||
|
def fuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""
|
||||||
|
Enables fused QKV projections. For self-attention modules, all projection matrices (i.e., query,
|
||||||
|
key, value) are fused. For cross-attention modules, key and value projection matrices are fused.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
"""
|
||||||
|
self.fusing_unet = False
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
|
if unet:
|
||||||
|
self.fusing_unet = True
|
||||||
|
self.unet.fuse_qkv_projections()
|
||||||
|
self.unet.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not isinstance(self.vae, AutoencoderKL):
|
||||||
|
raise ValueError("`fuse_qkv_projections()` is only supported for the VAE of type `AutoencoderKL`.")
|
||||||
|
|
||||||
|
self.fusing_vae = True
|
||||||
|
self.vae.fuse_qkv_projections()
|
||||||
|
self.vae.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
def unfuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""Disable QKV projection fusion if enabled.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if unet:
|
||||||
|
if not self.fusing_unet:
|
||||||
|
logger.warning("The UNet was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.unet.unfuse_qkv_projections()
|
||||||
|
self.fusing_unet = False
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not self.fusing_vae:
|
||||||
|
logger.warning("The VAE was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.vae.unfuse_qkv_projections()
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||||
"""
|
"""
|
||||||
See https://github.com/google-research/vdm/blob/dc27b98a554f65cdc654b800da5aa1846545d41b/model_vdm.py#L298
|
See https://github.com/google-research/vdm/blob/dc27b98a554f65cdc654b800da5aa1846545d41b/model_vdm.py#L298
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from ...configuration_utils import FrozenDict
|
|||||||
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
||||||
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
||||||
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
||||||
|
from ...models.attention_processor import FusedAttnProcessor2_0
|
||||||
from ...models.lora import adjust_lora_scale_text_encoder
|
from ...models.lora import adjust_lora_scale_text_encoder
|
||||||
from ...schedulers import KarrasDiffusionSchedulers
|
from ...schedulers import KarrasDiffusionSchedulers
|
||||||
from ...utils import (
|
from ...utils import (
|
||||||
@@ -715,6 +716,65 @@ class AltDiffusionImg2ImgPipeline(
|
|||||||
"""Disables the FreeU mechanism if enabled."""
|
"""Disables the FreeU mechanism if enabled."""
|
||||||
self.unet.disable_freeu()
|
self.unet.disable_freeu()
|
||||||
|
|
||||||
|
def fuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""
|
||||||
|
Enables fused QKV projections. For self-attention modules, all projection matrices (i.e., query,
|
||||||
|
key, value) are fused. For cross-attention modules, key and value projection matrices are fused.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
"""
|
||||||
|
self.fusing_unet = False
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
|
if unet:
|
||||||
|
self.fusing_unet = True
|
||||||
|
self.unet.fuse_qkv_projections()
|
||||||
|
self.unet.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not isinstance(self.vae, AutoencoderKL):
|
||||||
|
raise ValueError("`fuse_qkv_projections()` is only supported for the VAE of type `AutoencoderKL`.")
|
||||||
|
|
||||||
|
self.fusing_vae = True
|
||||||
|
self.vae.fuse_qkv_projections()
|
||||||
|
self.vae.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
def unfuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""Disable QKV projection fusion if enabled.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if unet:
|
||||||
|
if not self.fusing_unet:
|
||||||
|
logger.warning("The UNet was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.unet.unfuse_qkv_projections()
|
||||||
|
self.fusing_unet = False
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not self.fusing_vae:
|
||||||
|
logger.warning("The VAE was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.vae.unfuse_qkv_projections()
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||||
"""
|
"""
|
||||||
See https://github.com/google-research/vdm/blob/dc27b98a554f65cdc654b800da5aa1846545d41b/model_vdm.py#L298
|
See https://github.com/google-research/vdm/blob/dc27b98a554f65cdc654b800da5aa1846545d41b/model_vdm.py#L298
|
||||||
|
|||||||
@@ -84,6 +84,12 @@ class AnimateDiffPipeline(DiffusionPipeline, TextualInversionLoaderMixin, IPAdap
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
@@ -147,6 +147,9 @@ class StableDiffusionControlNetPipeline(
|
|||||||
|
|
||||||
The pipeline also inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|||||||
@@ -140,7 +140,11 @@ class StableDiffusionControlNetImg2ImgPipeline(
|
|||||||
|
|
||||||
The pipeline also inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
@@ -251,6 +251,9 @@ class StableDiffusionControlNetInpaintPipeline(
|
|||||||
|
|
||||||
The pipeline also inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
|
|||||||
@@ -148,12 +148,10 @@ class StableDiffusionXLControlNetInpaintPipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
In addition the pipeline inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`]
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
- *Ckpt*: [`loaders.FromSingleFileMixin.from_single_file`]
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
as well as the following saving methods:
|
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`]
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
|
|||||||
@@ -129,8 +129,10 @@ class StableDiffusionXLControlNetPipeline(
|
|||||||
|
|
||||||
The pipeline also inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
- [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
- [`loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
|
|||||||
@@ -155,9 +155,10 @@ class StableDiffusionXLControlNetImg2ImgPipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
In addition the pipeline inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- *Textual-Inversion*: [`loaders.TextualInversionLoaderMixin.load_textual_inversion`]
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`]
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
|
|||||||
@@ -98,7 +98,9 @@ class StableDiffusionControlNetXSPipeline(
|
|||||||
|
|
||||||
The pipeline also inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
- [`loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
|
|||||||
@@ -102,8 +102,9 @@ class StableDiffusionXLControlNetXSPipeline(
|
|||||||
|
|
||||||
The pipeline also inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
- [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
- [`loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
|
|||||||
@@ -283,6 +283,9 @@ class ShapEImg2ImgPipeline(DiffusionPipeline):
|
|||||||
f"Only the output types `pil`, `np`, `latent` and `mesh` are supported not output_type={output_type}"
|
f"Only the output types `pil`, `np`, `latent` and `mesh` are supported not output_type={output_type}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Offload all models
|
||||||
|
self.maybe_free_model_hooks()
|
||||||
|
|
||||||
if output_type == "latent":
|
if output_type == "latent":
|
||||||
return ShapEPipelineOutput(images=latents)
|
return ShapEPipelineOutput(images=latents)
|
||||||
|
|
||||||
@@ -312,9 +315,6 @@ class ShapEImg2ImgPipeline(DiffusionPipeline):
|
|||||||
if output_type == "pil":
|
if output_type == "pil":
|
||||||
images = [self.numpy_to_pil(image) for image in images]
|
images = [self.numpy_to_pil(image) for image in images]
|
||||||
|
|
||||||
# Offload all models
|
|
||||||
self.maybe_free_model_hooks()
|
|
||||||
|
|
||||||
if not return_dict:
|
if not return_dict:
|
||||||
return (images,)
|
return (images,)
|
||||||
|
|
||||||
|
|||||||
@@ -1153,7 +1153,9 @@ def download_from_original_stable_diffusion_ckpt(
|
|||||||
vae_path=None,
|
vae_path=None,
|
||||||
vae=None,
|
vae=None,
|
||||||
text_encoder=None,
|
text_encoder=None,
|
||||||
|
text_encoder_2=None,
|
||||||
tokenizer=None,
|
tokenizer=None,
|
||||||
|
tokenizer_2=None,
|
||||||
config_files=None,
|
config_files=None,
|
||||||
) -> DiffusionPipeline:
|
) -> DiffusionPipeline:
|
||||||
"""
|
"""
|
||||||
@@ -1232,7 +1234,9 @@ def download_from_original_stable_diffusion_ckpt(
|
|||||||
StableDiffusionInpaintPipeline,
|
StableDiffusionInpaintPipeline,
|
||||||
StableDiffusionPipeline,
|
StableDiffusionPipeline,
|
||||||
StableDiffusionUpscalePipeline,
|
StableDiffusionUpscalePipeline,
|
||||||
|
StableDiffusionXLControlNetInpaintPipeline,
|
||||||
StableDiffusionXLImg2ImgPipeline,
|
StableDiffusionXLImg2ImgPipeline,
|
||||||
|
StableDiffusionXLInpaintPipeline,
|
||||||
StableDiffusionXLPipeline,
|
StableDiffusionXLPipeline,
|
||||||
StableUnCLIPImg2ImgPipeline,
|
StableUnCLIPImg2ImgPipeline,
|
||||||
StableUnCLIPPipeline,
|
StableUnCLIPPipeline,
|
||||||
@@ -1339,7 +1343,11 @@ def download_from_original_stable_diffusion_ckpt(
|
|||||||
else:
|
else:
|
||||||
pipeline_class = StableDiffusionXLPipeline if model_type == "SDXL" else StableDiffusionXLImg2ImgPipeline
|
pipeline_class = StableDiffusionXLPipeline if model_type == "SDXL" else StableDiffusionXLImg2ImgPipeline
|
||||||
|
|
||||||
if num_in_channels is None and pipeline_class == StableDiffusionInpaintPipeline:
|
if num_in_channels is None and pipeline_class in [
|
||||||
|
StableDiffusionInpaintPipeline,
|
||||||
|
StableDiffusionXLInpaintPipeline,
|
||||||
|
StableDiffusionXLControlNetInpaintPipeline,
|
||||||
|
]:
|
||||||
num_in_channels = 9
|
num_in_channels = 9
|
||||||
if num_in_channels is None and pipeline_class == StableDiffusionUpscalePipeline:
|
if num_in_channels is None and pipeline_class == StableDiffusionUpscalePipeline:
|
||||||
num_in_channels = 7
|
num_in_channels = 7
|
||||||
@@ -1686,7 +1694,9 @@ def download_from_original_stable_diffusion_ckpt(
|
|||||||
feature_extractor=feature_extractor,
|
feature_extractor=feature_extractor,
|
||||||
)
|
)
|
||||||
elif model_type in ["SDXL", "SDXL-Refiner"]:
|
elif model_type in ["SDXL", "SDXL-Refiner"]:
|
||||||
if model_type == "SDXL":
|
is_refiner = model_type == "SDXL-Refiner"
|
||||||
|
|
||||||
|
if (is_refiner is False) and (tokenizer is None):
|
||||||
try:
|
try:
|
||||||
tokenizer = CLIPTokenizer.from_pretrained(
|
tokenizer = CLIPTokenizer.from_pretrained(
|
||||||
"openai/clip-vit-large-patch14", local_files_only=local_files_only
|
"openai/clip-vit-large-patch14", local_files_only=local_files_only
|
||||||
@@ -1695,7 +1705,11 @@ def download_from_original_stable_diffusion_ckpt(
|
|||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"With local_files_only set to {local_files_only}, you must first locally save the tokenizer in the following path: 'openai/clip-vit-large-patch14'."
|
f"With local_files_only set to {local_files_only}, you must first locally save the tokenizer in the following path: 'openai/clip-vit-large-patch14'."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (is_refiner is False) and (text_encoder is None):
|
||||||
text_encoder = convert_ldm_clip_checkpoint(checkpoint, local_files_only=local_files_only)
|
text_encoder = convert_ldm_clip_checkpoint(checkpoint, local_files_only=local_files_only)
|
||||||
|
|
||||||
|
if tokenizer_2 is None:
|
||||||
try:
|
try:
|
||||||
tokenizer_2 = CLIPTokenizer.from_pretrained(
|
tokenizer_2 = CLIPTokenizer.from_pretrained(
|
||||||
"laion/CLIP-ViT-bigG-14-laion2B-39B-b160k", pad_token="!", local_files_only=local_files_only
|
"laion/CLIP-ViT-bigG-14-laion2B-39B-b160k", pad_token="!", local_files_only=local_files_only
|
||||||
@@ -1705,95 +1719,69 @@ def download_from_original_stable_diffusion_ckpt(
|
|||||||
f"With local_files_only set to {local_files_only}, you must first locally save the tokenizer in the following path: 'laion/CLIP-ViT-bigG-14-laion2B-39B-b160k' with `pad_token` set to '!'."
|
f"With local_files_only set to {local_files_only}, you must first locally save the tokenizer in the following path: 'laion/CLIP-ViT-bigG-14-laion2B-39B-b160k' with `pad_token` set to '!'."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if text_encoder_2 is None:
|
||||||
config_name = "laion/CLIP-ViT-bigG-14-laion2B-39B-b160k"
|
config_name = "laion/CLIP-ViT-bigG-14-laion2B-39B-b160k"
|
||||||
config_kwargs = {"projection_dim": 1280}
|
config_kwargs = {"projection_dim": 1280}
|
||||||
|
prefix = "conditioner.embedders.0.model." if is_refiner else "conditioner.embedders.1.model."
|
||||||
|
|
||||||
text_encoder_2 = convert_open_clip_checkpoint(
|
text_encoder_2 = convert_open_clip_checkpoint(
|
||||||
checkpoint,
|
checkpoint,
|
||||||
config_name,
|
config_name,
|
||||||
prefix="conditioner.embedders.1.model.",
|
prefix=prefix,
|
||||||
has_projection=True,
|
has_projection=True,
|
||||||
local_files_only=local_files_only,
|
local_files_only=local_files_only,
|
||||||
**config_kwargs,
|
**config_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_accelerate_available(): # SBM Now move model to cpu.
|
if is_accelerate_available(): # SBM Now move model to cpu.
|
||||||
if model_type in ["SDXL", "SDXL-Refiner"]:
|
for param_name, param in converted_unet_checkpoint.items():
|
||||||
for param_name, param in converted_unet_checkpoint.items():
|
set_module_tensor_to_device(unet, param_name, "cpu", value=param)
|
||||||
set_module_tensor_to_device(unet, param_name, "cpu", value=param)
|
|
||||||
|
|
||||||
if controlnet:
|
if controlnet:
|
||||||
pipe = pipeline_class(
|
pipe = pipeline_class(
|
||||||
vae=vae,
|
|
||||||
text_encoder=text_encoder,
|
|
||||||
tokenizer=tokenizer,
|
|
||||||
text_encoder_2=text_encoder_2,
|
|
||||||
tokenizer_2=tokenizer_2,
|
|
||||||
unet=unet,
|
|
||||||
controlnet=controlnet,
|
|
||||||
scheduler=scheduler,
|
|
||||||
force_zeros_for_empty_prompt=True,
|
|
||||||
)
|
|
||||||
elif adapter:
|
|
||||||
pipe = pipeline_class(
|
|
||||||
vae=vae,
|
|
||||||
text_encoder=text_encoder,
|
|
||||||
tokenizer=tokenizer,
|
|
||||||
text_encoder_2=text_encoder_2,
|
|
||||||
tokenizer_2=tokenizer_2,
|
|
||||||
unet=unet,
|
|
||||||
adapter=adapter,
|
|
||||||
scheduler=scheduler,
|
|
||||||
force_zeros_for_empty_prompt=True,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
pipe = pipeline_class(
|
|
||||||
vae=vae,
|
|
||||||
text_encoder=text_encoder,
|
|
||||||
tokenizer=tokenizer,
|
|
||||||
text_encoder_2=text_encoder_2,
|
|
||||||
tokenizer_2=tokenizer_2,
|
|
||||||
unet=unet,
|
|
||||||
scheduler=scheduler,
|
|
||||||
force_zeros_for_empty_prompt=True,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
tokenizer = None
|
|
||||||
text_encoder = None
|
|
||||||
try:
|
|
||||||
tokenizer_2 = CLIPTokenizer.from_pretrained(
|
|
||||||
"laion/CLIP-ViT-bigG-14-laion2B-39B-b160k", pad_token="!", local_files_only=local_files_only
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"With local_files_only set to {local_files_only}, you must first locally save the tokenizer in the following path: 'laion/CLIP-ViT-bigG-14-laion2B-39B-b160k' with `pad_token` set to '!'."
|
|
||||||
)
|
|
||||||
config_name = "laion/CLIP-ViT-bigG-14-laion2B-39B-b160k"
|
|
||||||
config_kwargs = {"projection_dim": 1280}
|
|
||||||
text_encoder_2 = convert_open_clip_checkpoint(
|
|
||||||
checkpoint,
|
|
||||||
config_name,
|
|
||||||
prefix="conditioner.embedders.0.model.",
|
|
||||||
has_projection=True,
|
|
||||||
local_files_only=local_files_only,
|
|
||||||
**config_kwargs,
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_accelerate_available(): # SBM Now move model to cpu.
|
|
||||||
if model_type in ["SDXL", "SDXL-Refiner"]:
|
|
||||||
for param_name, param in converted_unet_checkpoint.items():
|
|
||||||
set_module_tensor_to_device(unet, param_name, "cpu", value=param)
|
|
||||||
|
|
||||||
pipe = StableDiffusionXLImg2ImgPipeline(
|
|
||||||
vae=vae,
|
vae=vae,
|
||||||
text_encoder=text_encoder,
|
text_encoder=text_encoder,
|
||||||
tokenizer=tokenizer,
|
tokenizer=tokenizer,
|
||||||
text_encoder_2=text_encoder_2,
|
text_encoder_2=text_encoder_2,
|
||||||
tokenizer_2=tokenizer_2,
|
tokenizer_2=tokenizer_2,
|
||||||
unet=unet,
|
unet=unet,
|
||||||
|
controlnet=controlnet,
|
||||||
scheduler=scheduler,
|
scheduler=scheduler,
|
||||||
requires_aesthetics_score=True,
|
force_zeros_for_empty_prompt=True,
|
||||||
force_zeros_for_empty_prompt=False,
|
|
||||||
)
|
)
|
||||||
|
elif adapter:
|
||||||
|
pipe = pipeline_class(
|
||||||
|
vae=vae,
|
||||||
|
text_encoder=text_encoder,
|
||||||
|
tokenizer=tokenizer,
|
||||||
|
text_encoder_2=text_encoder_2,
|
||||||
|
tokenizer_2=tokenizer_2,
|
||||||
|
unet=unet,
|
||||||
|
adapter=adapter,
|
||||||
|
scheduler=scheduler,
|
||||||
|
force_zeros_for_empty_prompt=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
pipeline_kwargs = {
|
||||||
|
"vae": vae,
|
||||||
|
"text_encoder": text_encoder,
|
||||||
|
"tokenizer": tokenizer,
|
||||||
|
"text_encoder_2": text_encoder_2,
|
||||||
|
"tokenizer_2": tokenizer_2,
|
||||||
|
"unet": unet,
|
||||||
|
"scheduler": scheduler,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeline_class == StableDiffusionXLImg2ImgPipeline) or (
|
||||||
|
pipeline_class == StableDiffusionXLInpaintPipeline
|
||||||
|
):
|
||||||
|
pipeline_kwargs.update({"requires_aesthetics_score": is_refiner})
|
||||||
|
|
||||||
|
if is_refiner:
|
||||||
|
pipeline_kwargs.update({"force_zeros_for_empty_prompt": False})
|
||||||
|
|
||||||
|
pipe = pipeline_class(**pipeline_kwargs)
|
||||||
else:
|
else:
|
||||||
text_config = create_ldm_bert_config(original_config)
|
text_config = create_ldm_bert_config(original_config)
|
||||||
text_model = convert_ldm_bert_checkpoint(checkpoint, text_config)
|
text_model = convert_ldm_bert_checkpoint(checkpoint, text_config)
|
||||||
|
|||||||
@@ -143,6 +143,11 @@ class CycleDiffusionPipeline(DiffusionPipeline, TextualInversionLoaderMixin, Lor
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from ...configuration_utils import FrozenDict
|
|||||||
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
||||||
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
||||||
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
||||||
|
from ...models.attention_processor import FusedAttnProcessor2_0
|
||||||
from ...models.lora import adjust_lora_scale_text_encoder
|
from ...models.lora import adjust_lora_scale_text_encoder
|
||||||
from ...schedulers import KarrasDiffusionSchedulers
|
from ...schedulers import KarrasDiffusionSchedulers
|
||||||
from ...utils import (
|
from ...utils import (
|
||||||
@@ -650,6 +651,67 @@ class StableDiffusionPipeline(
|
|||||||
"""Disables the FreeU mechanism if enabled."""
|
"""Disables the FreeU mechanism if enabled."""
|
||||||
self.unet.disable_freeu()
|
self.unet.disable_freeu()
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.fuse_qkv_projections
|
||||||
|
def fuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""
|
||||||
|
Enables fused QKV projections. For self-attention modules, all projection matrices (i.e., query,
|
||||||
|
key, value) are fused. For cross-attention modules, key and value projection matrices are fused.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
"""
|
||||||
|
self.fusing_unet = False
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
|
if unet:
|
||||||
|
self.fusing_unet = True
|
||||||
|
self.unet.fuse_qkv_projections()
|
||||||
|
self.unet.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not isinstance(self.vae, AutoencoderKL):
|
||||||
|
raise ValueError("`fuse_qkv_projections()` is only supported for the VAE of type `AutoencoderKL`.")
|
||||||
|
|
||||||
|
self.fusing_vae = True
|
||||||
|
self.vae.fuse_qkv_projections()
|
||||||
|
self.vae.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.unfuse_qkv_projections
|
||||||
|
def unfuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""Disable QKV projection fusion if enabled.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if unet:
|
||||||
|
if not self.fusing_unet:
|
||||||
|
logger.warning("The UNet was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.unet.unfuse_qkv_projections()
|
||||||
|
self.fusing_unet = False
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not self.fusing_vae:
|
||||||
|
logger.warning("The VAE was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.vae.unfuse_qkv_projections()
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
||||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+3
@@ -177,6 +177,9 @@ class StableDiffusionAttendAndExcitePipeline(DiffusionPipeline, TextualInversion
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from ...configuration_utils import FrozenDict
|
|||||||
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
||||||
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
||||||
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
||||||
|
from ...models.attention_processor import FusedAttnProcessor2_0
|
||||||
from ...models.lora import adjust_lora_scale_text_encoder
|
from ...models.lora import adjust_lora_scale_text_encoder
|
||||||
from ...schedulers import KarrasDiffusionSchedulers
|
from ...schedulers import KarrasDiffusionSchedulers
|
||||||
from ...utils import (
|
from ...utils import (
|
||||||
@@ -718,6 +719,67 @@ class StableDiffusionImg2ImgPipeline(
|
|||||||
"""Disables the FreeU mechanism if enabled."""
|
"""Disables the FreeU mechanism if enabled."""
|
||||||
self.unet.disable_freeu()
|
self.unet.disable_freeu()
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.fuse_qkv_projections
|
||||||
|
def fuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""
|
||||||
|
Enables fused QKV projections. For self-attention modules, all projection matrices (i.e., query,
|
||||||
|
key, value) are fused. For cross-attention modules, key and value projection matrices are fused.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
"""
|
||||||
|
self.fusing_unet = False
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
|
if unet:
|
||||||
|
self.fusing_unet = True
|
||||||
|
self.unet.fuse_qkv_projections()
|
||||||
|
self.unet.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not isinstance(self.vae, AutoencoderKL):
|
||||||
|
raise ValueError("`fuse_qkv_projections()` is only supported for the VAE of type `AutoencoderKL`.")
|
||||||
|
|
||||||
|
self.fusing_vae = True
|
||||||
|
self.vae.fuse_qkv_projections()
|
||||||
|
self.vae.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.unfuse_qkv_projections
|
||||||
|
def unfuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""Disable QKV projection fusion if enabled.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if unet:
|
||||||
|
if not self.fusing_unet:
|
||||||
|
logger.warning("The UNet was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.unet.unfuse_qkv_projections()
|
||||||
|
self.fusing_unet = False
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not self.fusing_vae:
|
||||||
|
logger.warning("The VAE was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.vae.unfuse_qkv_projections()
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
||||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from ...configuration_utils import FrozenDict
|
|||||||
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
from ...image_processor import PipelineImageInput, VaeImageProcessor
|
||||||
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
from ...loaders import FromSingleFileMixin, IPAdapterMixin, LoraLoaderMixin, TextualInversionLoaderMixin
|
||||||
from ...models import AsymmetricAutoencoderKL, AutoencoderKL, ImageProjection, UNet2DConditionModel
|
from ...models import AsymmetricAutoencoderKL, AutoencoderKL, ImageProjection, UNet2DConditionModel
|
||||||
|
from ...models.attention_processor import FusedAttnProcessor2_0
|
||||||
from ...models.lora import adjust_lora_scale_text_encoder
|
from ...models.lora import adjust_lora_scale_text_encoder
|
||||||
from ...schedulers import KarrasDiffusionSchedulers
|
from ...schedulers import KarrasDiffusionSchedulers
|
||||||
from ...utils import USE_PEFT_BACKEND, deprecate, logging, scale_lora_layers, unscale_lora_layers
|
from ...utils import USE_PEFT_BACKEND, deprecate, logging, scale_lora_layers, unscale_lora_layers
|
||||||
@@ -232,6 +233,7 @@ class StableDiffusionInpaintPipeline(
|
|||||||
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`, `AsymmetricAutoencoderKL`]):
|
vae ([`AutoencoderKL`, `AsymmetricAutoencoderKL`]):
|
||||||
@@ -843,6 +845,67 @@ class StableDiffusionInpaintPipeline(
|
|||||||
"""Disables the FreeU mechanism if enabled."""
|
"""Disables the FreeU mechanism if enabled."""
|
||||||
self.unet.disable_freeu()
|
self.unet.disable_freeu()
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.fuse_qkv_projections
|
||||||
|
def fuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""
|
||||||
|
Enables fused QKV projections. For self-attention modules, all projection matrices (i.e., query,
|
||||||
|
key, value) are fused. For cross-attention modules, key and value projection matrices are fused.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
"""
|
||||||
|
self.fusing_unet = False
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
|
if unet:
|
||||||
|
self.fusing_unet = True
|
||||||
|
self.unet.fuse_qkv_projections()
|
||||||
|
self.unet.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not isinstance(self.vae, AutoencoderKL):
|
||||||
|
raise ValueError("`fuse_qkv_projections()` is only supported for the VAE of type `AutoencoderKL`.")
|
||||||
|
|
||||||
|
self.fusing_vae = True
|
||||||
|
self.vae.fuse_qkv_projections()
|
||||||
|
self.vae.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.unfuse_qkv_projections
|
||||||
|
def unfuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""Disable QKV projection fusion if enabled.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if unet:
|
||||||
|
if not self.fusing_unet:
|
||||||
|
logger.warning("The UNet was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.unet.unfuse_qkv_projections()
|
||||||
|
self.fusing_unet = False
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not self.fusing_vae:
|
||||||
|
logger.warning("The VAE was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.vae.unfuse_qkv_projections()
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
||||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ class StableDiffusionKDiffusionPipeline(DiffusionPipeline, TextualInversionLoade
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
<Tip warning={true}>
|
<Tip warning={true}>
|
||||||
|
|
||||||
This is an experimental pipeline and is likely to change in the future.
|
This is an experimental pipeline and is likely to change in the future.
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ class StableDiffusionLatentUpscalePipeline(DiffusionPipeline, FromSingleFileMixi
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ class StableDiffusionModelEditingPipeline(DiffusionPipeline, TextualInversionLoa
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ class Pix2PixZeroAttnProcessor:
|
|||||||
|
|
||||||
class StableDiffusionPix2PixZeroPipeline(DiffusionPipeline):
|
class StableDiffusionPix2PixZeroPipeline(DiffusionPipeline):
|
||||||
r"""
|
r"""
|
||||||
Pipeline for pixel-levl image editing using Pix2Pix Zero. Based on Stable Diffusion.
|
Pipeline for pixel-level image editing using Pix2Pix Zero. Based on Stable Diffusion.
|
||||||
|
|
||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ class StableDiffusionUpscalePipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ class StableUnCLIPPipeline(DiffusionPipeline, TextualInversionLoaderMixin, LoraL
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prior_tokenizer ([`CLIPTokenizer`]):
|
prior_tokenizer ([`CLIPTokenizer`]):
|
||||||
A [`CLIPTokenizer`].
|
A [`CLIPTokenizer`].
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ class StableUnCLIPImg2ImgPipeline(DiffusionPipeline, TextualInversionLoaderMixin
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
feature_extractor ([`CLIPImageProcessor`]):
|
feature_extractor ([`CLIPImageProcessor`]):
|
||||||
Feature extractor for image pre-processing before being encoded.
|
Feature extractor for image pre-processing before being encoded.
|
||||||
|
|||||||
@@ -595,10 +595,11 @@ class StableDiffusionPipelineSafe(DiffusionPipeline, IPAdapterMixin):
|
|||||||
```py
|
```py
|
||||||
import torch
|
import torch
|
||||||
from diffusers import StableDiffusionPipelineSafe
|
from diffusers import StableDiffusionPipelineSafe
|
||||||
|
from diffusers.pipelines.stable_diffusion_safe import SafetyConfig
|
||||||
|
|
||||||
pipeline = StableDiffusionPipelineSafe.from_pretrained(
|
pipeline = StableDiffusionPipelineSafe.from_pretrained(
|
||||||
"AIML-TUDA/stable-diffusion-safe", torch_dtype=torch.float16
|
"AIML-TUDA/stable-diffusion-safe", torch_dtype=torch.float16
|
||||||
)
|
).to("cuda")
|
||||||
prompt = "the four horsewomen of the apocalypse, painting by tom of finland, gaston bussiere, craig mullins, j. c. leyendecker"
|
prompt = "the four horsewomen of the apocalypse, painting by tom of finland, gaston bussiere, craig mullins, j. c. leyendecker"
|
||||||
image = pipeline(prompt=prompt, **SafetyConfig.MEDIUM).images[0]
|
image = pipeline(prompt=prompt, **SafetyConfig.MEDIUM).images[0]
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -159,12 +159,12 @@ class StableDiffusionXLPipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
In addition the pipeline inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`]
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
- *Ckpt*: [`loaders.FromSingleFileMixin.from_single_file`]
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
as well as the following saving methods:
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`]
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
|
|||||||
+68
-6
@@ -35,6 +35,7 @@ from ...loaders import (
|
|||||||
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
||||||
from ...models.attention_processor import (
|
from ...models.attention_processor import (
|
||||||
AttnProcessor2_0,
|
AttnProcessor2_0,
|
||||||
|
FusedAttnProcessor2_0,
|
||||||
LoRAAttnProcessor2_0,
|
LoRAAttnProcessor2_0,
|
||||||
LoRAXFormersAttnProcessor,
|
LoRAXFormersAttnProcessor,
|
||||||
XFormersAttnProcessor,
|
XFormersAttnProcessor,
|
||||||
@@ -176,12 +177,12 @@ class StableDiffusionXLImg2ImgPipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
In addition the pipeline inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`]
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
- *Ckpt*: [`loaders.FromSingleFileMixin.from_single_file`]
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
as well as the following saving methods:
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`]
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
@@ -864,6 +865,67 @@ class StableDiffusionXLImg2ImgPipeline(
|
|||||||
"""Disables the FreeU mechanism if enabled."""
|
"""Disables the FreeU mechanism if enabled."""
|
||||||
self.unet.disable_freeu()
|
self.unet.disable_freeu()
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.fuse_qkv_projections
|
||||||
|
def fuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""
|
||||||
|
Enables fused QKV projections. For self-attention modules, all projection matrices (i.e., query,
|
||||||
|
key, value) are fused. For cross-attention modules, key and value projection matrices are fused.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
"""
|
||||||
|
self.fusing_unet = False
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
|
if unet:
|
||||||
|
self.fusing_unet = True
|
||||||
|
self.unet.fuse_qkv_projections()
|
||||||
|
self.unet.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not isinstance(self.vae, AutoencoderKL):
|
||||||
|
raise ValueError("`fuse_qkv_projections()` is only supported for the VAE of type `AutoencoderKL`.")
|
||||||
|
|
||||||
|
self.fusing_vae = True
|
||||||
|
self.vae.fuse_qkv_projections()
|
||||||
|
self.vae.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.unfuse_qkv_projections
|
||||||
|
def unfuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""Disable QKV projection fusion if enabled.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if unet:
|
||||||
|
if not self.fusing_unet:
|
||||||
|
logger.warning("The UNet was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.unet.unfuse_qkv_projections()
|
||||||
|
self.fusing_unet = False
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not self.fusing_vae:
|
||||||
|
logger.warning("The VAE was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.vae.unfuse_qkv_projections()
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
||||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+68
-6
@@ -36,6 +36,7 @@ from ...loaders import (
|
|||||||
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
from ...models import AutoencoderKL, ImageProjection, UNet2DConditionModel
|
||||||
from ...models.attention_processor import (
|
from ...models.attention_processor import (
|
||||||
AttnProcessor2_0,
|
AttnProcessor2_0,
|
||||||
|
FusedAttnProcessor2_0,
|
||||||
LoRAAttnProcessor2_0,
|
LoRAAttnProcessor2_0,
|
||||||
LoRAXFormersAttnProcessor,
|
LoRAXFormersAttnProcessor,
|
||||||
XFormersAttnProcessor,
|
XFormersAttnProcessor,
|
||||||
@@ -321,12 +322,12 @@ class StableDiffusionXLInpaintPipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
In addition the pipeline inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`]
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
- *Ckpt*: [`loaders.FromSingleFileMixin.from_single_file`]
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
as well as the following saving methods:
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`]
|
- [`~loaders.IPAdapterMixin.load_ip_adapter`] for loading IP Adapters
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
@@ -1084,6 +1085,67 @@ class StableDiffusionXLInpaintPipeline(
|
|||||||
"""Disables the FreeU mechanism if enabled."""
|
"""Disables the FreeU mechanism if enabled."""
|
||||||
self.unet.disable_freeu()
|
self.unet.disable_freeu()
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.fuse_qkv_projections
|
||||||
|
def fuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""
|
||||||
|
Enables fused QKV projections. For self-attention modules, all projection matrices (i.e., query,
|
||||||
|
key, value) are fused. For cross-attention modules, key and value projection matrices are fused.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
"""
|
||||||
|
self.fusing_unet = False
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
|
if unet:
|
||||||
|
self.fusing_unet = True
|
||||||
|
self.unet.fuse_qkv_projections()
|
||||||
|
self.unet.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not isinstance(self.vae, AutoencoderKL):
|
||||||
|
raise ValueError("`fuse_qkv_projections()` is only supported for the VAE of type `AutoencoderKL`.")
|
||||||
|
|
||||||
|
self.fusing_vae = True
|
||||||
|
self.vae.fuse_qkv_projections()
|
||||||
|
self.vae.set_attn_processor(FusedAttnProcessor2_0())
|
||||||
|
|
||||||
|
# Copied from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl.StableDiffusionXLPipeline.unfuse_qkv_projections
|
||||||
|
def unfuse_qkv_projections(self, unet: bool = True, vae: bool = True):
|
||||||
|
"""Disable QKV projection fusion if enabled.
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
This API is 🧪 experimental.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
Args:
|
||||||
|
unet (`bool`, defaults to `True`): To apply fusion on the UNet.
|
||||||
|
vae (`bool`, defaults to `True`): To apply fusion on the VAE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if unet:
|
||||||
|
if not self.fusing_unet:
|
||||||
|
logger.warning("The UNet was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.unet.unfuse_qkv_projections()
|
||||||
|
self.fusing_unet = False
|
||||||
|
|
||||||
|
if vae:
|
||||||
|
if not self.fusing_vae:
|
||||||
|
logger.warning("The VAE was not initially fused for QKV projections. Doing nothing.")
|
||||||
|
else:
|
||||||
|
self.vae.unfuse_qkv_projections()
|
||||||
|
self.fusing_vae = False
|
||||||
|
|
||||||
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
# Copied from diffusers.pipelines.latent_consistency_models.pipeline_latent_consistency_text2img.LatentConsistencyModelPipeline.get_guidance_scale_embedding
|
||||||
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
def get_guidance_scale_embedding(self, w, embedding_dim=512, dtype=torch.float32):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+5
-5
@@ -126,11 +126,11 @@ class StableDiffusionXLInstructPix2PixPipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
In addition the pipeline inherits the following loading methods:
|
The pipeline also inherits the following loading methods:
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`]
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
as well as the following saving methods:
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
- *LoRA*: [`loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`]
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
|
|||||||
@@ -178,6 +178,12 @@ class StableDiffusionXLAdapterPipeline(
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.FromSingleFileMixin.from_single_file`] for loading `.ckpt` files
|
||||||
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.StableDiffusionXLLoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
adapter ([`T2IAdapter`] or [`MultiAdapter`] or `List[T2IAdapter]`):
|
adapter ([`T2IAdapter`] or [`MultiAdapter`] or `List[T2IAdapter]`):
|
||||||
Provides additional conditioning to the unet during the denoising process. If you set multiple Adapter as a
|
Provides additional conditioning to the unet during the denoising process. If you set multiple Adapter as a
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ class TextToVideoSDPipeline(DiffusionPipeline, TextualInversionLoaderMixin, Lora
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.
|
Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.
|
||||||
|
|||||||
+5
@@ -159,6 +159,11 @@ class VideoToVideoSDPipeline(DiffusionPipeline, TextualInversionLoaderMixin, Lor
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods
|
||||||
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
implemented for all pipelines (downloading, saving, running on a particular device, etc.).
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.TextualInversionLoaderMixin.load_textual_inversion`] for loading textual inversion embeddings
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vae ([`AutoencoderKL`]):
|
vae ([`AutoencoderKL`]):
|
||||||
Variational Auto-Encoder (VAE) Model to encode and decode videos to and from latent representations.
|
Variational Auto-Encoder (VAE) Model to encode and decode videos to and from latent representations.
|
||||||
|
|||||||
@@ -477,8 +477,9 @@ class UnCLIPPipeline(DiffusionPipeline):
|
|||||||
image = super_res_latents
|
image = super_res_latents
|
||||||
# done super res
|
# done super res
|
||||||
|
|
||||||
# post processing
|
self.maybe_free_model_hooks()
|
||||||
|
|
||||||
|
# post processing
|
||||||
image = image * 0.5 + 0.5
|
image = image * 0.5 + 0.5
|
||||||
image = image.clamp(0, 1)
|
image = image.clamp(0, 1)
|
||||||
image = image.cpu().permute(0, 2, 3, 1).float().numpy()
|
image = image.cpu().permute(0, 2, 3, 1).float().numpy()
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ class UnCLIPImageVariationPipeline(DiffusionPipeline):
|
|||||||
image = super_res_latents
|
image = super_res_latents
|
||||||
|
|
||||||
# done super res
|
# done super res
|
||||||
|
self.maybe_free_model_hooks()
|
||||||
|
|
||||||
# post processing
|
# post processing
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import torch
|
|||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
|
|
||||||
from ...configuration_utils import ConfigMixin, register_to_config
|
from ...configuration_utils import ConfigMixin, register_to_config
|
||||||
|
from ...models.autoencoders.vae import DecoderOutput, VectorQuantizer
|
||||||
from ...models.modeling_utils import ModelMixin
|
from ...models.modeling_utils import ModelMixin
|
||||||
from ...models.vae import DecoderOutput, VectorQuantizer
|
|
||||||
from ...models.vq_model import VQEncoderOutput
|
from ...models.vq_model import VQEncoderOutput
|
||||||
from ...utils.accelerate_utils import apply_forward_hook
|
from ...utils.accelerate_utils import apply_forward_hook
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ class WuerstchenPriorPipeline(DiffusionPipeline, LoraLoaderMixin):
|
|||||||
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods the
|
||||||
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
||||||
|
|
||||||
|
The pipeline also inherits the following loading methods:
|
||||||
|
- [`~loaders.LoraLoaderMixin.load_lora_weights`] for loading LoRA weights
|
||||||
|
- [`~loaders.LoraLoaderMixin.save_lora_weights`] for saving LoRA weights
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prior ([`Prior`]):
|
prior ([`Prior`]):
|
||||||
The canonical unCLIP prior to approximate the image embedding from the text embedding.
|
The canonical unCLIP prior to approximate the image embedding from the text embedding.
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ class CMStochasticIterativeScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.custom_timesteps = False
|
self.custom_timesteps = False
|
||||||
self.is_scale_input_called = False
|
self.is_scale_input_called = False
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
||||||
if schedule_timesteps is None:
|
if schedule_timesteps is None:
|
||||||
@@ -230,6 +231,7 @@ class CMStochasticIterativeScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.timesteps = torch.from_numpy(timesteps).to(device=device)
|
self.timesteps = torch.from_numpy(timesteps).to(device=device)
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Modified _convert_to_karras implementation that takes in ramp as argument
|
# Modified _convert_to_karras implementation that takes in ramp as argument
|
||||||
def _convert_to_karras(self, ramp):
|
def _convert_to_karras(self, ramp):
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ class DEISMultistepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.model_outputs = [None] * solver_order
|
self.model_outputs = [None] * solver_order
|
||||||
self.lower_order_nums = 0
|
self.lower_order_nums = 0
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def step_index(self):
|
def step_index(self):
|
||||||
@@ -254,6 +255,7 @@ class DEISMultistepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
|
|
||||||
# add an index counter for schedulers that allow duplicated timesteps
|
# add an index counter for schedulers that allow duplicated timesteps
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
||||||
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ class DPMSolverMultistepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.model_outputs = [None] * solver_order
|
self.model_outputs = [None] * solver_order
|
||||||
self.lower_order_nums = 0
|
self.lower_order_nums = 0
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def step_index(self):
|
def step_index(self):
|
||||||
@@ -290,6 +291,7 @@ class DPMSolverMultistepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
|
|
||||||
# add an index counter for schedulers that allow duplicated timesteps
|
# add an index counter for schedulers that allow duplicated timesteps
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
||||||
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ class DPMSolverMultistepInverseScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.model_outputs = [None] * solver_order
|
self.model_outputs = [None] * solver_order
|
||||||
self.lower_order_nums = 0
|
self.lower_order_nums = 0
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
self.use_karras_sigmas = use_karras_sigmas
|
self.use_karras_sigmas = use_karras_sigmas
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -289,6 +290,7 @@ class DPMSolverMultistepInverseScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
|
|
||||||
# add an index counter for schedulers that allow duplicated timesteps
|
# add an index counter for schedulers that allow duplicated timesteps
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
||||||
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ class DPMSolverSDEScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.noise_sampler = None
|
self.noise_sampler = None
|
||||||
self.noise_sampler_seed = noise_sampler_seed
|
self.noise_sampler_seed = noise_sampler_seed
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler.index_for_timestep
|
# Copied from diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler.index_for_timestep
|
||||||
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
||||||
@@ -347,6 +348,7 @@ class DPMSolverSDEScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.mid_point_sigma = None
|
self.mid_point_sigma = None
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
self.noise_sampler = None
|
self.noise_sampler = None
|
||||||
|
|
||||||
# for exp beta schedules, such as the one for `pipeline_shap_e.py`
|
# for exp beta schedules, such as the one for `pipeline_shap_e.py`
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ class DPMSolverSinglestepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.sample = None
|
self.sample = None
|
||||||
self.order_list = self.get_order_list(num_train_timesteps)
|
self.order_list = self.get_order_list(num_train_timesteps)
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
def get_order_list(self, num_inference_steps: int) -> List[int]:
|
def get_order_list(self, num_inference_steps: int) -> List[int]:
|
||||||
"""
|
"""
|
||||||
@@ -288,6 +289,7 @@ class DPMSolverSinglestepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
|
|
||||||
# add an index counter for schedulers that allow duplicated timesteps
|
# add an index counter for schedulers that allow duplicated timesteps
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
||||||
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ class EulerAncestralDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.is_scale_input_called = False
|
self.is_scale_input_called = False
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def init_noise_sigma(self):
|
def init_noise_sigma(self):
|
||||||
@@ -249,6 +250,7 @@ class EulerAncestralDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
|
|
||||||
self.timesteps = torch.from_numpy(timesteps).to(device=device)
|
self.timesteps = torch.from_numpy(timesteps).to(device=device)
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler._init_step_index
|
# Copied from diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler._init_step_index
|
||||||
def _init_step_index(self, timestep):
|
def _init_step_index(self, timestep):
|
||||||
|
|||||||
@@ -237,6 +237,7 @@ class EulerDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.use_karras_sigmas = use_karras_sigmas
|
self.use_karras_sigmas = use_karras_sigmas
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def init_noise_sigma(self):
|
def init_noise_sigma(self):
|
||||||
@@ -341,6 +342,7 @@ class EulerDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
|
|
||||||
self.sigmas = torch.cat([sigmas, torch.zeros(1, device=sigmas.device)])
|
self.sigmas = torch.cat([sigmas, torch.zeros(1, device=sigmas.device)])
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
def _sigma_to_t(self, sigma, log_sigmas):
|
def _sigma_to_t(self, sigma, log_sigmas):
|
||||||
# get log sigma
|
# get log sigma
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ class HeunDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.use_karras_sigmas = use_karras_sigmas
|
self.use_karras_sigmas = use_karras_sigmas
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
||||||
if schedule_timesteps is None:
|
if schedule_timesteps is None:
|
||||||
@@ -269,6 +270,7 @@ class HeunDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.dt = None
|
self.dt = None
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# (YiYi Notes: keep this for now since we are keeping add_noise function which use index_for_timestep)
|
# (YiYi Notes: keep this for now since we are keeping add_noise function which use index_for_timestep)
|
||||||
# for exp beta schedules, such as the one for `pipeline_shap_e.py`
|
# for exp beta schedules, such as the one for `pipeline_shap_e.py`
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ class KDPM2AncestralDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
# set all values
|
# set all values
|
||||||
self.set_timesteps(num_train_timesteps, None, num_train_timesteps)
|
self.set_timesteps(num_train_timesteps, None, num_train_timesteps)
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler.index_for_timestep
|
# Copied from diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler.index_for_timestep
|
||||||
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
||||||
@@ -295,6 +296,7 @@ class KDPM2AncestralDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self._index_counter = defaultdict(int)
|
self._index_counter = defaultdict(int)
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler._sigma_to_t
|
# Copied from diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler._sigma_to_t
|
||||||
def _sigma_to_t(self, sigma, log_sigmas):
|
def _sigma_to_t(self, sigma, log_sigmas):
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ class KDPM2DiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.set_timesteps(num_train_timesteps, None, num_train_timesteps)
|
self.set_timesteps(num_train_timesteps, None, num_train_timesteps)
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler.index_for_timestep
|
# Copied from diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler.index_for_timestep
|
||||||
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
def index_for_timestep(self, timestep, schedule_timesteps=None):
|
||||||
@@ -284,6 +285,7 @@ class KDPM2DiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self._index_counter = defaultdict(int)
|
self._index_counter = defaultdict(int)
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_in_first_order(self):
|
def state_in_first_order(self):
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ class LMSDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.is_scale_input_called = False
|
self.is_scale_input_called = False
|
||||||
|
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def init_noise_sigma(self):
|
def init_noise_sigma(self):
|
||||||
@@ -279,6 +280,7 @@ class LMSDiscreteScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.sigmas = torch.from_numpy(sigmas).to(device=device)
|
self.sigmas = torch.from_numpy(sigmas).to(device=device)
|
||||||
self.timesteps = torch.from_numpy(timesteps).to(device=device)
|
self.timesteps = torch.from_numpy(timesteps).to(device=device)
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
self.derivatives = []
|
self.derivatives = []
|
||||||
|
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ class UniPCMultistepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
self.solver_p = solver_p
|
self.solver_p = solver_p
|
||||||
self.last_sample = None
|
self.last_sample = None
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def step_index(self):
|
def step_index(self):
|
||||||
@@ -268,6 +269,7 @@ class UniPCMultistepScheduler(SchedulerMixin, ConfigMixin):
|
|||||||
|
|
||||||
# add an index counter for schedulers that allow duplicated timesteps
|
# add an index counter for schedulers that allow duplicated timesteps
|
||||||
self._step_index = None
|
self._step_index = None
|
||||||
|
self.sigmas.to("cpu") # to avoid too much CPU/GPU communication
|
||||||
|
|
||||||
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample
|
||||||
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor:
|
||||||
|
|||||||
@@ -820,7 +820,9 @@ def _is_torch_fp16_available(device):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
x = torch.zeros((2, 2), dtype=torch.float16).to(device)
|
x = torch.zeros((2, 2), dtype=torch.float16).to(device)
|
||||||
_ = x @ x
|
_ = torch.mul(x, x)
|
||||||
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if device.type == "cuda":
|
if device.type == "cuda":
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@@ -838,7 +840,9 @@ def _is_torch_fp64_available(device):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
x = torch.zeros((2, 2), dtype=torch.float64).to(device)
|
x = torch.zeros((2, 2), dtype=torch.float64).to(device)
|
||||||
_ = x @ x
|
_ = torch.mul(x, x)
|
||||||
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if device.type == "cuda":
|
if device.type == "cuda":
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
|||||||
@@ -343,6 +343,21 @@ class LoraLoaderMixinTests(unittest.TestCase):
|
|||||||
image = sd_pipe(**inputs).images
|
image = sd_pipe(**inputs).images
|
||||||
assert image.shape == (1, 64, 64, 3)
|
assert image.shape == (1, 64, 64, 3)
|
||||||
|
|
||||||
|
@unittest.skipIf(not torch.cuda.is_available() or not is_xformers_available(), reason="xformers requires cuda")
|
||||||
|
def test_stable_diffusion_set_xformers_attn_processors(self):
|
||||||
|
# disable_full_determinism()
|
||||||
|
device = "cuda" # ensure determinism for the device-dependent torch.Generator
|
||||||
|
components, _ = self.get_dummy_components()
|
||||||
|
sd_pipe = StableDiffusionPipeline(**components)
|
||||||
|
sd_pipe = sd_pipe.to(device)
|
||||||
|
sd_pipe.set_progress_bar_config(disable=None)
|
||||||
|
|
||||||
|
_, _, inputs = self.get_dummy_inputs()
|
||||||
|
|
||||||
|
# run normal sd pipe
|
||||||
|
image = sd_pipe(**inputs).images
|
||||||
|
assert image.shape == (1, 64, 64, 3)
|
||||||
|
|
||||||
# run lora xformers attention
|
# run lora xformers attention
|
||||||
attn_processors, _ = create_unet_lora_layers(sd_pipe.unet)
|
attn_processors, _ = create_unet_lora_layers(sd_pipe.unet)
|
||||||
attn_processors = {
|
attn_processors = {
|
||||||
@@ -607,7 +622,7 @@ class LoraLoaderMixinTests(unittest.TestCase):
|
|||||||
orig_image_slice, orig_image_slice_two, atol=1e-3
|
orig_image_slice, orig_image_slice_two, atol=1e-3
|
||||||
), "Unloading LoRA parameters should lead to results similar to what was obtained with the pipeline without any LoRA parameters."
|
), "Unloading LoRA parameters should lead to results similar to what was obtained with the pipeline without any LoRA parameters."
|
||||||
|
|
||||||
@unittest.skipIf(torch_device != "cuda", "This test is supposed to run on GPU")
|
@unittest.skipIf(torch_device != "cuda" or not is_xformers_available(), "This test is supposed to run on GPU")
|
||||||
def test_lora_unet_attn_processors_with_xformers(self):
|
def test_lora_unet_attn_processors_with_xformers(self):
|
||||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||||
self.create_lora_weight_file(tmpdirname)
|
self.create_lora_weight_file(tmpdirname)
|
||||||
@@ -644,7 +659,7 @@ class LoraLoaderMixinTests(unittest.TestCase):
|
|||||||
if isinstance(module, Attention):
|
if isinstance(module, Attention):
|
||||||
self.assertIsInstance(module.processor, XFormersAttnProcessor)
|
self.assertIsInstance(module.processor, XFormersAttnProcessor)
|
||||||
|
|
||||||
@unittest.skipIf(torch_device != "cuda", "This test is supposed to run on GPU")
|
@unittest.skipIf(torch_device != "cuda" or not is_xformers_available(), "This test is supposed to run on GPU")
|
||||||
def test_lora_save_load_with_xformers(self):
|
def test_lora_save_load_with_xformers(self):
|
||||||
pipeline_components, lora_components = self.get_dummy_components()
|
pipeline_components, lora_components = self.get_dummy_components()
|
||||||
sd_pipe = StableDiffusionPipeline(**pipeline_components)
|
sd_pipe = StableDiffusionPipeline(**pipeline_components)
|
||||||
@@ -2270,8 +2285,8 @@ class LoraIntegrationTests(unittest.TestCase):
|
|||||||
lora_model_id = "hf-internal-testing/sdxl-1.0-lora"
|
lora_model_id = "hf-internal-testing/sdxl-1.0-lora"
|
||||||
lora_filename = "sd_xl_offset_example-lora_1.0.safetensors"
|
lora_filename = "sd_xl_offset_example-lora_1.0.safetensors"
|
||||||
|
|
||||||
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
|
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16)
|
||||||
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename)
|
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename, torch_dtype=torch.float16)
|
||||||
pipe.enable_model_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
@@ -2284,13 +2299,13 @@ class LoraIntegrationTests(unittest.TestCase):
|
|||||||
|
|
||||||
del pipe
|
del pipe
|
||||||
|
|
||||||
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
|
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16)
|
||||||
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename)
|
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename, torch_dtype=torch.float16)
|
||||||
pipe.fuse_lora()
|
pipe.fuse_lora()
|
||||||
pipe.enable_model_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator().manual_seed(0)
|
||||||
|
start_time = time.time()
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
pipe(
|
pipe(
|
||||||
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=2
|
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=2
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ from diffusers.utils.testing_utils import (
|
|||||||
floats_tensor,
|
floats_tensor,
|
||||||
load_image,
|
load_image,
|
||||||
nightly,
|
nightly,
|
||||||
|
numpy_cosine_similarity_distance,
|
||||||
require_peft_backend,
|
require_peft_backend,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
slow,
|
slow,
|
||||||
@@ -1713,7 +1714,7 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
release_memory(pipe)
|
release_memory(pipe)
|
||||||
|
|
||||||
def test_sdxl_1_0_lora(self):
|
def test_sdxl_1_0_lora(self):
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator("cpu").manual_seed(0)
|
||||||
|
|
||||||
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
|
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
|
||||||
pipe.enable_model_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
@@ -1736,7 +1737,7 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
|
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
|
||||||
pipe.enable_model_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
|
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator("cpu").manual_seed(0)
|
||||||
|
|
||||||
lora_model_id = "latent-consistency/lcm-lora-sdxl"
|
lora_model_id = "latent-consistency/lcm-lora-sdxl"
|
||||||
|
|
||||||
@@ -1753,7 +1754,8 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
image_np = pipe.image_processor.pil_to_numpy(image)
|
image_np = pipe.image_processor.pil_to_numpy(image)
|
||||||
expected_image_np = pipe.image_processor.pil_to_numpy(expected_image)
|
expected_image_np = pipe.image_processor.pil_to_numpy(expected_image)
|
||||||
|
|
||||||
self.assertTrue(np.allclose(image_np, expected_image_np, atol=1e-2))
|
max_diff = numpy_cosine_similarity_distance(image_np.flatten(), expected_image_np.flatten())
|
||||||
|
assert max_diff < 1e-4
|
||||||
|
|
||||||
pipe.unload_lora_weights()
|
pipe.unload_lora_weights()
|
||||||
|
|
||||||
@@ -1764,7 +1766,7 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
pipe.to("cuda")
|
pipe.to("cuda")
|
||||||
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
|
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
|
||||||
|
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator("cpu").manual_seed(0)
|
||||||
|
|
||||||
lora_model_id = "latent-consistency/lcm-lora-sdv1-5"
|
lora_model_id = "latent-consistency/lcm-lora-sdv1-5"
|
||||||
pipe.load_lora_weights(lora_model_id)
|
pipe.load_lora_weights(lora_model_id)
|
||||||
@@ -1780,7 +1782,8 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
image_np = pipe.image_processor.pil_to_numpy(image)
|
image_np = pipe.image_processor.pil_to_numpy(image)
|
||||||
expected_image_np = pipe.image_processor.pil_to_numpy(expected_image)
|
expected_image_np = pipe.image_processor.pil_to_numpy(expected_image)
|
||||||
|
|
||||||
self.assertTrue(np.allclose(image_np, expected_image_np, atol=1e-2))
|
max_diff = numpy_cosine_similarity_distance(image_np.flatten(), expected_image_np.flatten())
|
||||||
|
assert max_diff < 1e-4
|
||||||
|
|
||||||
pipe.unload_lora_weights()
|
pipe.unload_lora_weights()
|
||||||
|
|
||||||
@@ -1795,7 +1798,7 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
"https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main/img2img/fantasy_landscape.png"
|
"https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main/img2img/fantasy_landscape.png"
|
||||||
)
|
)
|
||||||
|
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator("cpu").manual_seed(0)
|
||||||
|
|
||||||
lora_model_id = "latent-consistency/lcm-lora-sdv1-5"
|
lora_model_id = "latent-consistency/lcm-lora-sdv1-5"
|
||||||
pipe.load_lora_weights(lora_model_id)
|
pipe.load_lora_weights(lora_model_id)
|
||||||
@@ -1816,7 +1819,8 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
image_np = pipe.image_processor.pil_to_numpy(image)
|
image_np = pipe.image_processor.pil_to_numpy(image)
|
||||||
expected_image_np = pipe.image_processor.pil_to_numpy(expected_image)
|
expected_image_np = pipe.image_processor.pil_to_numpy(expected_image)
|
||||||
|
|
||||||
self.assertTrue(np.allclose(image_np, expected_image_np, atol=1e-2))
|
max_diff = numpy_cosine_similarity_distance(image_np.flatten(), expected_image_np.flatten())
|
||||||
|
assert max_diff < 1e-4
|
||||||
|
|
||||||
pipe.unload_lora_weights()
|
pipe.unload_lora_weights()
|
||||||
|
|
||||||
@@ -1849,7 +1853,7 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
release_memory(pipe)
|
release_memory(pipe)
|
||||||
|
|
||||||
def test_sdxl_1_0_lora_unfusion(self):
|
def test_sdxl_1_0_lora_unfusion(self):
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator("cpu").manual_seed(0)
|
||||||
|
|
||||||
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
|
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
|
||||||
lora_model_id = "hf-internal-testing/sdxl-1.0-lora"
|
lora_model_id = "hf-internal-testing/sdxl-1.0-lora"
|
||||||
@@ -1860,16 +1864,16 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
pipe.enable_model_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
|
|
||||||
images = pipe(
|
images = pipe(
|
||||||
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=2
|
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=3
|
||||||
).images
|
).images
|
||||||
images_with_fusion = images[0, -3:, -3:, -1].flatten()
|
images_with_fusion = images.flatten()
|
||||||
|
|
||||||
pipe.unfuse_lora()
|
pipe.unfuse_lora()
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator("cpu").manual_seed(0)
|
||||||
images = pipe(
|
images = pipe(
|
||||||
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=2
|
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=3
|
||||||
).images
|
).images
|
||||||
images_without_fusion = images[0, -3:, -3:, -1].flatten()
|
images_without_fusion = images.flatten()
|
||||||
|
|
||||||
self.assertTrue(np.allclose(images_with_fusion, images_without_fusion, atol=1e-3))
|
self.assertTrue(np.allclose(images_with_fusion, images_without_fusion, atol=1e-3))
|
||||||
release_memory(pipe)
|
release_memory(pipe)
|
||||||
@@ -1913,10 +1917,8 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
lora_model_id = "hf-internal-testing/sdxl-1.0-lora"
|
lora_model_id = "hf-internal-testing/sdxl-1.0-lora"
|
||||||
lora_filename = "sd_xl_offset_example-lora_1.0.safetensors"
|
lora_filename = "sd_xl_offset_example-lora_1.0.safetensors"
|
||||||
|
|
||||||
pipe = DiffusionPipeline.from_pretrained(
|
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16)
|
||||||
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.bfloat16
|
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename, torch_dtype=torch.float16)
|
||||||
)
|
|
||||||
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename, torch_dtype=torch.bfloat16)
|
|
||||||
pipe.enable_model_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
@@ -1929,19 +1931,17 @@ class LoraSDXLIntegrationTests(unittest.TestCase):
|
|||||||
|
|
||||||
del pipe
|
del pipe
|
||||||
|
|
||||||
pipe = DiffusionPipeline.from_pretrained(
|
pipe = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16)
|
||||||
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.bfloat16
|
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename, torch_dtype=torch.float16)
|
||||||
)
|
|
||||||
pipe.load_lora_weights(lora_model_id, weight_name=lora_filename, torch_dtype=torch.bfloat16)
|
|
||||||
pipe.fuse_lora()
|
pipe.fuse_lora()
|
||||||
|
|
||||||
# We need to unload the lora weights since in the previous API `fuse_lora` led to lora weights being
|
# We need to unload the lora weights since in the previous API `fuse_lora` led to lora weights being
|
||||||
# silently deleted - otherwise this will CPU OOM
|
# silently deleted - otherwise this will CPU OOM
|
||||||
pipe.unload_lora_weights()
|
pipe.unload_lora_weights()
|
||||||
|
|
||||||
pipe.enable_model_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
generator = torch.Generator().manual_seed(0)
|
generator = torch.Generator().manual_seed(0)
|
||||||
|
start_time = time.time()
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
pipe(
|
pipe(
|
||||||
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=2
|
"masterpiece, best quality, mountain", output_type="np", generator=generator, num_inference_steps=2
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from diffusers import (
|
|||||||
UNet2DConditionModel,
|
UNet2DConditionModel,
|
||||||
UNetMotionModel,
|
UNetMotionModel,
|
||||||
)
|
)
|
||||||
from diffusers.utils import logging
|
from diffusers.utils import is_xformers_available, logging
|
||||||
from diffusers.utils.testing_utils import numpy_cosine_similarity_distance, require_torch_gpu, slow, torch_device
|
from diffusers.utils.testing_utils import numpy_cosine_similarity_distance, require_torch_gpu, slow, torch_device
|
||||||
|
|
||||||
from ..pipeline_params import TEXT_TO_IMAGE_BATCH_PARAMS, TEXT_TO_IMAGE_PARAMS
|
from ..pipeline_params import TEXT_TO_IMAGE_BATCH_PARAMS, TEXT_TO_IMAGE_PARAMS
|
||||||
@@ -233,6 +233,35 @@ class AnimateDiffPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
inputs["prompt_embeds"] = torch.randn((1, 4, 32), device=torch_device)
|
inputs["prompt_embeds"] = torch.randn((1, 4, 32), device=torch_device)
|
||||||
pipe(**inputs)
|
pipe(**inputs)
|
||||||
|
|
||||||
|
@unittest.skipIf(
|
||||||
|
torch_device != "cuda" or not is_xformers_available(),
|
||||||
|
reason="XFormers attention is only available with CUDA and `xformers` installed",
|
||||||
|
)
|
||||||
|
def test_xformers_attention_forwardGenerator_pass(self):
|
||||||
|
components = self.get_dummy_components()
|
||||||
|
pipe = self.pipeline_class(**components)
|
||||||
|
for component in pipe.components.values():
|
||||||
|
if hasattr(component, "set_default_attn_processor"):
|
||||||
|
component.set_default_attn_processor()
|
||||||
|
pipe.to(torch_device)
|
||||||
|
pipe.set_progress_bar_config(disable=None)
|
||||||
|
|
||||||
|
inputs = self.get_dummy_inputs(torch_device)
|
||||||
|
output_without_offload = pipe(**inputs).frames[0]
|
||||||
|
output_without_offload = (
|
||||||
|
output_without_offload.cpu() if torch.is_tensor(output_without_offload) else output_without_offload
|
||||||
|
)
|
||||||
|
|
||||||
|
pipe.enable_xformers_memory_efficient_attention()
|
||||||
|
inputs = self.get_dummy_inputs(torch_device)
|
||||||
|
output_with_offload = pipe(**inputs).frames[0]
|
||||||
|
output_with_offload = (
|
||||||
|
output_with_offload.cpu() if torch.is_tensor(output_with_offload) else output_without_offload
|
||||||
|
)
|
||||||
|
|
||||||
|
max_diff = np.abs(to_np(output_with_offload) - to_np(output_without_offload)).max()
|
||||||
|
self.assertLess(max_diff, 1e-4, "XFormers attention should not affect the inference results")
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -661,6 +661,37 @@ class StableDiffusionPipelineFastTests(
|
|||||||
output[0, -3:, -3:, -1], output_no_freeu[0, -3:, -3:, -1]
|
output[0, -3:, -3:, -1], output_no_freeu[0, -3:, -3:, -1]
|
||||||
), "Disabling of FreeU should lead to results similar to the default pipeline results."
|
), "Disabling of FreeU should lead to results similar to the default pipeline results."
|
||||||
|
|
||||||
|
def test_fused_qkv_projections(self):
|
||||||
|
device = "cpu" # ensure determinism for the device-dependent torch.Generator
|
||||||
|
components = self.get_dummy_components()
|
||||||
|
sd_pipe = StableDiffusionPipeline(**components)
|
||||||
|
sd_pipe = sd_pipe.to(device)
|
||||||
|
sd_pipe.set_progress_bar_config(disable=None)
|
||||||
|
|
||||||
|
inputs = self.get_dummy_inputs(device)
|
||||||
|
image = sd_pipe(**inputs).images
|
||||||
|
original_image_slice = image[0, -3:, -3:, -1]
|
||||||
|
|
||||||
|
sd_pipe.fuse_qkv_projections()
|
||||||
|
inputs = self.get_dummy_inputs(device)
|
||||||
|
image = sd_pipe(**inputs).images
|
||||||
|
image_slice_fused = image[0, -3:, -3:, -1]
|
||||||
|
|
||||||
|
sd_pipe.unfuse_qkv_projections()
|
||||||
|
inputs = self.get_dummy_inputs(device)
|
||||||
|
image = sd_pipe(**inputs).images
|
||||||
|
image_slice_disabled = image[0, -3:, -3:, -1]
|
||||||
|
|
||||||
|
assert np.allclose(
|
||||||
|
original_image_slice, image_slice_fused, atol=1e-2, rtol=1e-2
|
||||||
|
), "Fusion of QKV projections shouldn't affect the outputs."
|
||||||
|
assert np.allclose(
|
||||||
|
image_slice_fused, image_slice_disabled, atol=1e-2, rtol=1e-2
|
||||||
|
), "Outputs, with QKV projection fusion enabled, shouldn't change when fused QKV projections are disabled."
|
||||||
|
assert np.allclose(
|
||||||
|
original_image_slice, image_slice_disabled, atol=1e-2, rtol=1e-2
|
||||||
|
), "Original outputs should match when fused QKV projections are disabled."
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -804,8 +804,7 @@ class StableDiffusionAdapterPipelineSlowTests(unittest.TestCase):
|
|||||||
pipe = StableDiffusionAdapterPipeline.from_pretrained(sd_model, adapter=adapter, safety_checker=None)
|
pipe = StableDiffusionAdapterPipeline.from_pretrained(sd_model, adapter=adapter, safety_checker=None)
|
||||||
pipe.to(torch_device)
|
pipe.to(torch_device)
|
||||||
pipe.set_progress_bar_config(disable=None)
|
pipe.set_progress_bar_config(disable=None)
|
||||||
pipe.enable_attention_slicing()
|
pipe.enable_model_cpu_offload()
|
||||||
|
|
||||||
generator = torch.Generator(device="cpu").manual_seed(0)
|
generator = torch.Generator(device="cpu").manual_seed(0)
|
||||||
out = pipe(prompt=prompt, image=image, generator=generator, num_inference_steps=2, output_type="np").images
|
out = pipe(prompt=prompt, image=image, generator=generator, num_inference_steps=2, output_type="np").images
|
||||||
|
|
||||||
|
|||||||
@@ -681,7 +681,7 @@ class AdapterSDXLPipelineSlowTests(unittest.TestCase):
|
|||||||
variant="fp16",
|
variant="fp16",
|
||||||
)
|
)
|
||||||
pipe.load_lora_weights("CiroN2022/toy-face", weight_name="toy_face_sdxl.safetensors")
|
pipe.load_lora_weights("CiroN2022/toy-face", weight_name="toy_face_sdxl.safetensors")
|
||||||
pipe.enable_sequential_cpu_offload()
|
pipe.enable_model_cpu_offload()
|
||||||
pipe.set_progress_bar_config(disable=None)
|
pipe.set_progress_bar_config(disable=None)
|
||||||
|
|
||||||
generator = torch.Generator(device="cpu").manual_seed(0)
|
generator = torch.Generator(device="cpu").manual_seed(0)
|
||||||
@@ -694,8 +694,6 @@ class AdapterSDXLPipelineSlowTests(unittest.TestCase):
|
|||||||
|
|
||||||
assert images[0].shape == (768, 512, 3)
|
assert images[0].shape == (768, 512, 3)
|
||||||
|
|
||||||
original_image = images[0, -3:, -3:, -1].flatten()
|
image_slice = images[0, -3:, -3:, -1].flatten()
|
||||||
expected_image = np.array(
|
expected_slice = np.array([0.4284, 0.4337, 0.4319, 0.4255, 0.4329, 0.4280, 0.4338, 0.4420, 0.4226])
|
||||||
[0.50346327, 0.50708383, 0.50719553, 0.5135172, 0.5155377, 0.5066059, 0.49680984, 0.5005894, 0.48509413]
|
assert numpy_cosine_similarity_distance(image_slice, expected_slice) < 1e-4
|
||||||
)
|
|
||||||
assert numpy_cosine_similarity_distance(original_image, expected_image) < 1e-4
|
|
||||||
|
|||||||
Reference in New Issue
Block a user