Skip to content

Commit d5cfaf2

Browse files
authored
Merge branch 'main' into flux_controlnet_pipeline_callback_tensor_inputs
2 parents 88f9dcc + f103993 commit d5cfaf2

File tree

13 files changed

+294
-16
lines changed

13 files changed

+294
-16
lines changed

.github/workflows/pr_tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Fast tests for PRs
33
on:
44
pull_request:
55
branches: [main]
6-
types: [synchronize]
76
paths:
87
- "src/diffusers/**.py"
98
- "benchmarks/**.py"

examples/dreambooth/train_dreambooth_lora.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,17 +1119,22 @@ def compute_text_embeddings(prompt):
11191119
)
11201120

11211121
# Scheduler and math around the number of training steps.
1122-
overrode_max_train_steps = False
1123-
num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps)
1122+
# Check the PR https://github.com/huggingface/diffusers/pull/8312 for detailed explanation.
1123+
num_warmup_steps_for_scheduler = args.lr_warmup_steps * accelerator.num_processes
11241124
if args.max_train_steps is None:
1125-
args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch
1126-
overrode_max_train_steps = True
1125+
len_train_dataloader_after_sharding = math.ceil(len(train_dataloader) / accelerator.num_processes)
1126+
num_update_steps_per_epoch = math.ceil(len_train_dataloader_after_sharding / args.gradient_accumulation_steps)
1127+
num_training_steps_for_scheduler = (
1128+
args.num_train_epochs * accelerator.num_processes * num_update_steps_per_epoch
1129+
)
1130+
else:
1131+
num_training_steps_for_scheduler = args.max_train_steps * accelerator.num_processes
11271132

11281133
lr_scheduler = get_scheduler(
11291134
args.lr_scheduler,
11301135
optimizer=optimizer,
1131-
num_warmup_steps=args.lr_warmup_steps * accelerator.num_processes,
1132-
num_training_steps=args.max_train_steps * accelerator.num_processes,
1136+
num_warmup_steps=num_warmup_steps_for_scheduler,
1137+
num_training_steps=num_training_steps_for_scheduler,
11331138
num_cycles=args.lr_num_cycles,
11341139
power=args.lr_power,
11351140
)
@@ -1146,8 +1151,15 @@ def compute_text_embeddings(prompt):
11461151

11471152
# We need to recalculate our total training steps as the size of the training dataloader may have changed.
11481153
num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps)
1149-
if overrode_max_train_steps:
1154+
if args.max_train_steps is None:
11501155
args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch
1156+
if num_training_steps_for_scheduler != args.max_train_steps:
1157+
logger.warning(
1158+
f"The length of the 'train_dataloader' after 'accelerator.prepare' ({len(train_dataloader)}) does not match "
1159+
f"the expected length ({len_train_dataloader_after_sharding}) when the learning rate scheduler was created. "
1160+
f"This inconsistency may result in the learning rate scheduler not functioning properly."
1161+
)
1162+
11511163
# Afterwards we recalculate our number of training epochs
11521164
args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch)
11531165

examples/research_projects/realfill/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ torch==2.2.0
66
torchvision>=0.16
77
ftfy==6.1.1
88
tensorboard==2.14.0
9-
Jinja2==3.1.5
9+
Jinja2==3.1.6

src/diffusers/loaders/lora_conversion_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ def _convert(original_key, diffusers_key, state_dict, new_state_dict):
654654

655655
_convert(k, diffusers_key, state_dict, new_state_dict)
656656

657+
remaining_all_unet = False
657658
if state_dict:
658659
remaining_all_unet = all(k.startswith("lora_unet_") for k in state_dict)
659660
if remaining_all_unet:

src/diffusers/pipelines/flux/pipeline_flux.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ def __call__(
694694
Custom sigmas to use for the denoising process with schedulers which support a `sigmas` argument in
695695
their `set_timesteps` method. If not defined, the default behavior when `num_inference_steps` is passed
696696
will be used.
697-
guidance_scale (`float`, *optional*, defaults to 7.0):
697+
guidance_scale (`float`, *optional*, defaults to 3.5):
698698
Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).
699699
`guidance_scale` is defined as `w` of equation 2. of [Imagen
700700
Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >

src/diffusers/pipelines/flux/pipeline_flux_control.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ def __call__(
660660
Custom sigmas to use for the denoising process with schedulers which support a `sigmas` argument in
661661
their `set_timesteps` method. If not defined, the default behavior when `num_inference_steps` is passed
662662
will be used.
663-
guidance_scale (`float`, *optional*, defaults to 7.0):
663+
guidance_scale (`float`, *optional*, defaults to 3.5):
664664
Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).
665665
`guidance_scale` is defined as `w` of equation 2. of [Imagen
666666
Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >

src/diffusers/pipelines/flux/pipeline_flux_fill.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ def __call__(
738738
Custom sigmas to use for the denoising process with schedulers which support a `sigmas` argument in
739739
their `set_timesteps` method. If not defined, the default behavior when `num_inference_steps` is passed
740740
will be used.
741-
guidance_scale (`float`, *optional*, defaults to 7.0):
741+
guidance_scale (`float`, *optional*, defaults to 30.0):
742742
Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).
743743
`guidance_scale` is defined as `w` of equation 2. of [Imagen
744744
Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >

tests/pipelines/hunyuandit/test_hunyuan_dit.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# limitations under the License.
1515

1616
import gc
17+
import tempfile
1718
import unittest
1819

1920
import numpy as np
@@ -212,6 +213,99 @@ def test_fused_qkv_projections(self):
212213
def test_encode_prompt_works_in_isolation(self):
213214
pass
214215

216+
def test_save_load_optional_components(self):
217+
components = self.get_dummy_components()
218+
pipe = self.pipeline_class(**components)
219+
pipe.to(torch_device)
220+
pipe.set_progress_bar_config(disable=None)
221+
222+
inputs = self.get_dummy_inputs(torch_device)
223+
224+
prompt = inputs["prompt"]
225+
generator = inputs["generator"]
226+
num_inference_steps = inputs["num_inference_steps"]
227+
output_type = inputs["output_type"]
228+
229+
(
230+
prompt_embeds,
231+
negative_prompt_embeds,
232+
prompt_attention_mask,
233+
negative_prompt_attention_mask,
234+
) = pipe.encode_prompt(prompt, device=torch_device, dtype=torch.float32, text_encoder_index=0)
235+
236+
(
237+
prompt_embeds_2,
238+
negative_prompt_embeds_2,
239+
prompt_attention_mask_2,
240+
negative_prompt_attention_mask_2,
241+
) = pipe.encode_prompt(
242+
prompt,
243+
device=torch_device,
244+
dtype=torch.float32,
245+
text_encoder_index=1,
246+
)
247+
248+
# inputs with prompt converted to embeddings
249+
inputs = {
250+
"prompt_embeds": prompt_embeds,
251+
"prompt_attention_mask": prompt_attention_mask,
252+
"negative_prompt_embeds": negative_prompt_embeds,
253+
"negative_prompt_attention_mask": negative_prompt_attention_mask,
254+
"prompt_embeds_2": prompt_embeds_2,
255+
"prompt_attention_mask_2": prompt_attention_mask_2,
256+
"negative_prompt_embeds_2": negative_prompt_embeds_2,
257+
"negative_prompt_attention_mask_2": negative_prompt_attention_mask_2,
258+
"generator": generator,
259+
"num_inference_steps": num_inference_steps,
260+
"output_type": output_type,
261+
"use_resolution_binning": False,
262+
}
263+
264+
# set all optional components to None
265+
for optional_component in pipe._optional_components:
266+
setattr(pipe, optional_component, None)
267+
268+
output = pipe(**inputs)[0]
269+
270+
with tempfile.TemporaryDirectory() as tmpdir:
271+
pipe.save_pretrained(tmpdir)
272+
pipe_loaded = self.pipeline_class.from_pretrained(tmpdir)
273+
pipe_loaded.to(torch_device)
274+
pipe_loaded.set_progress_bar_config(disable=None)
275+
276+
for optional_component in pipe._optional_components:
277+
self.assertTrue(
278+
getattr(pipe_loaded, optional_component) is None,
279+
f"`{optional_component}` did not stay set to None after loading.",
280+
)
281+
282+
inputs = self.get_dummy_inputs(torch_device)
283+
284+
generator = inputs["generator"]
285+
num_inference_steps = inputs["num_inference_steps"]
286+
output_type = inputs["output_type"]
287+
288+
# inputs with prompt converted to embeddings
289+
inputs = {
290+
"prompt_embeds": prompt_embeds,
291+
"prompt_attention_mask": prompt_attention_mask,
292+
"negative_prompt_embeds": negative_prompt_embeds,
293+
"negative_prompt_attention_mask": negative_prompt_attention_mask,
294+
"prompt_embeds_2": prompt_embeds_2,
295+
"prompt_attention_mask_2": prompt_attention_mask_2,
296+
"negative_prompt_embeds_2": negative_prompt_embeds_2,
297+
"negative_prompt_attention_mask_2": negative_prompt_attention_mask_2,
298+
"generator": generator,
299+
"num_inference_steps": num_inference_steps,
300+
"output_type": output_type,
301+
"use_resolution_binning": False,
302+
}
303+
304+
output_loaded = pipe_loaded(**inputs)[0]
305+
306+
max_diff = np.abs(to_np(output) - to_np(output_loaded)).max()
307+
self.assertLess(max_diff, 1e-4)
308+
215309

216310
@slow
217311
@require_torch_accelerator

tests/pipelines/latte/test_latte.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import gc
1717
import inspect
18+
import tempfile
1819
import unittest
1920

2021
import numpy as np
@@ -39,7 +40,7 @@
3940
)
4041

4142
from ..pipeline_params import TEXT_TO_IMAGE_BATCH_PARAMS, TEXT_TO_IMAGE_IMAGE_PARAMS, TEXT_TO_IMAGE_PARAMS
42-
from ..test_pipelines_common import PipelineTesterMixin, PyramidAttentionBroadcastTesterMixin
43+
from ..test_pipelines_common import PipelineTesterMixin, PyramidAttentionBroadcastTesterMixin, to_np
4344

4445

4546
enable_full_determinism()
@@ -217,6 +218,73 @@ def test_xformers_attention_forwardGenerator_pass(self):
217218
def test_encode_prompt_works_in_isolation(self):
218219
pass
219220

221+
def test_save_load_optional_components(self):
222+
if not hasattr(self.pipeline_class, "_optional_components"):
223+
return
224+
225+
components = self.get_dummy_components()
226+
pipe = self.pipeline_class(**components)
227+
228+
for component in pipe.components.values():
229+
if hasattr(component, "set_default_attn_processor"):
230+
component.set_default_attn_processor()
231+
pipe.to(torch_device)
232+
pipe.set_progress_bar_config(disable=None)
233+
234+
inputs = self.get_dummy_inputs(torch_device)
235+
236+
prompt = inputs["prompt"]
237+
generator = inputs["generator"]
238+
239+
(
240+
prompt_embeds,
241+
negative_prompt_embeds,
242+
) = pipe.encode_prompt(prompt)
243+
244+
# inputs with prompt converted to embeddings
245+
inputs = {
246+
"prompt_embeds": prompt_embeds,
247+
"negative_prompt": None,
248+
"negative_prompt_embeds": negative_prompt_embeds,
249+
"generator": generator,
250+
"num_inference_steps": 2,
251+
"guidance_scale": 5.0,
252+
"height": 8,
253+
"width": 8,
254+
"video_length": 1,
255+
"mask_feature": False,
256+
"output_type": "pt",
257+
"clean_caption": False,
258+
}
259+
260+
# set all optional components to None
261+
for optional_component in pipe._optional_components:
262+
setattr(pipe, optional_component, None)
263+
264+
output = pipe(**inputs)[0]
265+
266+
with tempfile.TemporaryDirectory() as tmpdir:
267+
pipe.save_pretrained(tmpdir, safe_serialization=False)
268+
pipe_loaded = self.pipeline_class.from_pretrained(tmpdir)
269+
pipe_loaded.to(torch_device)
270+
271+
for component in pipe_loaded.components.values():
272+
if hasattr(component, "set_default_attn_processor"):
273+
component.set_default_attn_processor()
274+
275+
pipe_loaded.set_progress_bar_config(disable=None)
276+
277+
for optional_component in pipe._optional_components:
278+
self.assertTrue(
279+
getattr(pipe_loaded, optional_component) is None,
280+
f"`{optional_component}` did not stay set to None after loading.",
281+
)
282+
283+
output_loaded = pipe_loaded(**inputs)[0]
284+
285+
max_diff = np.abs(to_np(output) - to_np(output_loaded)).max()
286+
self.assertLess(max_diff, 1.0)
287+
220288

221289
@slow
222290
@require_torch_accelerator

0 commit comments

Comments
 (0)