Skip to content

Commit 850bdd9

Browse files
authored
Merge branch 'main' into alexanderar-ltx-dfr-on-upstream
2 parents 0608d73 + 61a11f2 commit 850bdd9

64 files changed

Lines changed: 3577 additions & 6777 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ai/references/testing.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ Follow the style introduced in [#14113](https://github.com/huggingface/diffusers
3434
- `torch.nn.MultiheadAttention` is the common instance: it passes `self.out_proj.weight` straight to `torch.nn.functional.multi_head_attention_forward` instead of calling `self.out_proj`, so the hook on `out_proj` never fires. `SiglipVisionModel`'s attention pooling head wraps one — see `tests/pipelines/hunyuan_video/test_hunyuan_video_framepack.py`, whose `image_encoder` is excluded for this reason.
3535
- `HunyuanDiTAttentionPool` (`src/diffusers/models/embeddings.py`) shows the same failure without an MHA module: a plain `nn.Module` that hands its `q_proj` / `k_proj` / `v_proj` / `c_proj` weights to `torch.nn.functional.multi_head_attention_forward`, so all four projections stay offloaded rather than just one. `HunyuanDiT2DModel` opts out of group offloading entirely with `_supports_group_offloading = False`.
3636
- Before adding a skip or an exclusion, confirm the failure still reproduces — several existing skips are stale, having outlived the upstream cause.
37+
- **A migration that surfaces a `src/` gap marks the test `xfail`, it does not patch the pipeline.** Give the marker a module-level name and a `reason` naming the exact gap (`PNDM_*` in `tests/pipelines/pndm/test_pndm.py` is the worked example), and prefer `strict=True` so the marker reports XPASS — and gets deleted — the day the pipeline is fixed. Use `strict=False` only when one mark covers a group whose members do not all fail. Marking a whole test class keeps the mixin's own marks (`@is_memory`, `@require_accelerator`) intact; overriding individual inherited tests drops the decorators they were declared with, so re-declare those too.
38+
- **`from_pipe` tests** (a pipeline that is a variant of an existing one — PAG, AnimateDiff, ...) compose the shared `FromPipeTesterMixin` (`tests/pipelines/testing_utils/from_pipe.py`, exported from `..testing_utils`) in their own test class. It derives the original pipeline from `pipeline_class.__name__`; set `original_pipeline_repo` on the test class to pull it from a repo other than the default for that class. The unittest-era `PipelineFromPipeTesterMixin` in `tests/pipelines/test_pipelines_common.py` is what it replaces.
39+
- **A hardware gap is a conditional skip, not an xfail.** When a test fails only because the runner's cuDNN build has no kernel for an op — `RuntimeError: GET was unable to find an engine to execute this computation`, as Sana's depthwise `Conv2d` hits in bfloat16 — wrap the call in `skip_if_no_cudnn_engine()` (`tests/testing_utils.py`). It skips on that error and re-raises every other `RuntimeError`, so the test still runs wherever the kernel exists.
40+
- **PAG pipelines** also compose `PAGPipelineTesterMixin` (`tests/pipelines/pag/testing_utils.py`) in place of `PipelineTesterMixin`: it adds `test_pag_disable_enable` and `test_pag_inference` on top, driven by `base_pipeline_class` and the `pag_*` knobs on the test class. Keep `test_pag_applied_layers` per pipeline — which layers PAG resolves to is model-specific.
3741
- **`encode_prompt` reading a component that isn't a text encoder or tokenizer?** `test_encode_prompt_works_in_isolation` rebuilds the pipeline with only the components whose names contain `text` or `tokenizer`. When `encode_prompt` also needs another one — a `processor` used for chat templating, say — list it in `text_stack_component_names` on the config class rather than re-implementing the test.
3842
- **IP-Adapter tests** live in their own class decorated with `@is_ip_adapter`, subclassing only the config (not `PipelineTesterMixin`). UNet pipelines that load adapters through the standard `IPAdapterMixin` API compose the shared `IPAdapterTesterMixin` (`tests/pipelines/testing_utils/ip_adapter.py`, exported from `..testing_utils`); pipelines whose IP-Adapter API differs (Flux, for example) keep a bespoke mixin next to their own tests.
3943

src/diffusers/pipelines/omnigen/pipeline_omnigen.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,7 @@ def retrieve_timesteps(
116116
return timesteps, num_inference_steps
117117

118118

119-
class OmniGenPipeline(
120-
DiffusionPipeline,
121-
):
119+
class OmniGenPipeline(DiffusionPipeline):
122120
r"""
123121
The OmniGen pipeline for multimodal-to-image generation.
124122

tests/pipelines/animatediff/test_animatediff.py

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
AutoencoderKL,
1111
DDIMScheduler,
1212
MotionAdapter,
13-
StableDiffusionPipeline,
1413
UNet2DConditionModel,
1514
)
1615

@@ -22,16 +21,15 @@
2221
torch_device,
2322
)
2423
from ..pipeline_params import TEXT_TO_IMAGE_BATCH_PARAMS, TEXT_TO_IMAGE_PARAMS
25-
from ..test_pipelines_common import PipelineFromPipeTesterMixin
2624
from ..testing_utils import (
25+
FromPipeTesterMixin,
2726
IPAdapterTesterMixin,
2827
LoraMemoryTesterMixin,
2928
LoraTesterMixin,
3029
MemoryTesterMixin,
3130
UNetLoraTesterMixin,
3231
)
3332
from .testing_utils import (
34-
FROM_PIPE_SKIP_REASON,
3533
FreeInitTesterMixin,
3634
FreeNoiseSplitInferenceTesterMixin,
3735
MotionPipelineTesterConfig,
@@ -128,32 +126,6 @@ class TestAnimateDiffPipeline(
128126
FreeInitTesterMixin,
129127
FreeNoiseSplitInferenceTesterMixin,
130128
):
131-
def test_from_pipe_consistent_config(self):
132-
original_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"
133-
134-
# create StableDiffusionPipeline
135-
pipe_original = StableDiffusionPipeline.from_pretrained(original_repo, requires_safety_checker=False)
136-
137-
# StableDiffusionPipeline -> AnimateDiffPipeline
138-
pipe_components = self.get_dummy_components()
139-
pipe_additional_components = {
140-
name: component for name, component in pipe_components.items() if name not in pipe_original.components
141-
}
142-
pipe = self.pipeline_class.from_pipe(pipe_original, **pipe_additional_components)
143-
144-
# AnimateDiffPipeline -> StableDiffusionPipeline
145-
original_pipe_additional_components = {}
146-
for name, component in pipe_original.components.items():
147-
if name not in pipe.components or not isinstance(component, pipe.components[name].__class__):
148-
original_pipe_additional_components[name] = component
149-
150-
pipe_original_2 = StableDiffusionPipeline.from_pipe(pipe, **original_pipe_additional_components)
151-
152-
# compare the config
153-
original_config = {k: v for k, v in pipe_original.config.items() if not k.startswith("_")}
154-
original_config_2 = {k: v for k, v in pipe_original_2.config.items() if not k.startswith("_")}
155-
assert original_config_2 == original_config
156-
157129
def test_dict_tuple_outputs_equivalent(self, expected_slice=None, expected_max_difference=1e-4):
158130
if torch_device == "cpu" and expected_slice is None:
159131
# fmt: off
@@ -244,10 +216,7 @@ def test_animatediff(self):
244216
assert numpy_cosine_similarity_distance(image_slice.flatten(), expected_slice.flatten()) < 1e-3
245217

246218

247-
@pytest.mark.skip(FROM_PIPE_SKIP_REASON)
248-
class TestAnimateDiffPipelineFromPipe(AnimateDiffPipelineTesterConfig, PipelineFromPipeTesterMixin):
249-
"""`from_pipe` forward-pass parity and offload round trip for the AnimateDiff pipeline.
219+
class TestAnimateDiffPipelineFromPipe(AnimateDiffPipelineTesterConfig, FromPipeTesterMixin):
220+
"""`from_pipe` round-trip tests against `StableDiffusionPipeline` for the AnimateDiff pipeline."""
250221

251-
Parked, not deleted: `test_from_pipe_consistent_config` runs for real as a method on the main test class above,
252-
but the forward-pass checks in `PipelineFromPipeTesterMixin` have no pytest-style equivalent yet.
253-
"""
222+
original_pipeline_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"

tests/pipelines/animatediff/test_animatediff_controlnet.py

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import pytest
21
import torch
32
from PIL import Image
43
from transformers import CLIPTextConfig, CLIPTextModel, CLIPTokenizer
@@ -9,22 +8,20 @@
98
ControlNetModel,
109
DDIMScheduler,
1110
MotionAdapter,
12-
StableDiffusionPipeline,
1311
UNet2DConditionModel,
1412
)
1513

1614
from ...testing_utils import torch_device
1715
from ..pipeline_params import TEXT_TO_IMAGE_BATCH_PARAMS, TEXT_TO_IMAGE_PARAMS
18-
from ..test_pipelines_common import PipelineFromPipeTesterMixin
1916
from ..testing_utils import (
17+
FromPipeTesterMixin,
2018
IPAdapterTesterMixin,
2119
LoraMemoryTesterMixin,
2220
LoraTesterMixin,
2321
MemoryTesterMixin,
2422
UNetLoraTesterMixin,
2523
)
2624
from .testing_utils import (
27-
FROM_PIPE_SKIP_REASON,
2825
FreeInitTesterMixin,
2926
FreeNoiseTesterMixin,
3027
MotionPipelineTesterConfig,
@@ -142,32 +139,6 @@ def get_free_noise_inputs(self):
142139
# `get_dummy_inputs` rather than by overriding `num_frames` on the returned dict.
143140
return self.get_dummy_inputs(num_frames=16)
144141

145-
def test_from_pipe_consistent_config(self):
146-
original_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"
147-
148-
# create StableDiffusionPipeline
149-
pipe_original = StableDiffusionPipeline.from_pretrained(original_repo, requires_safety_checker=False)
150-
151-
# StableDiffusionPipeline -> AnimateDiffControlNetPipeline
152-
pipe_components = self.get_dummy_components()
153-
pipe_additional_components = {
154-
name: component for name, component in pipe_components.items() if name not in pipe_original.components
155-
}
156-
pipe = self.pipeline_class.from_pipe(pipe_original, **pipe_additional_components)
157-
158-
# AnimateDiffControlNetPipeline -> StableDiffusionPipeline
159-
original_pipe_additional_components = {}
160-
for name, component in pipe_original.components.items():
161-
if name not in pipe.components or not isinstance(component, pipe.components[name].__class__):
162-
original_pipe_additional_components[name] = component
163-
164-
pipe_original_2 = StableDiffusionPipeline.from_pipe(pipe, **original_pipe_additional_components)
165-
166-
# compare the config
167-
original_config = {k: v for k, v in pipe_original.config.items() if not k.startswith("_")}
168-
original_config_2 = {k: v for k, v in pipe_original_2.config.items() if not k.startswith("_")}
169-
assert original_config_2 == original_config
170-
171142
def test_dict_tuple_outputs_equivalent(self, expected_slice=None, expected_max_difference=1e-4):
172143
if torch_device == "cpu" and expected_slice is None:
173144
# fmt: off
@@ -198,12 +169,7 @@ class TestAnimateDiffControlNetPipelineLoRAMemory(AnimateDiffControlNetPipelineT
198169
"""LoRA x memory-optimization tests (group offload, CPU offload) for the pipeline."""
199170

200171

201-
@pytest.mark.skip(FROM_PIPE_SKIP_REASON)
202-
class TestAnimateDiffControlNetPipelineFromPipe(
203-
AnimateDiffControlNetPipelineTesterConfig, PipelineFromPipeTesterMixin
204-
):
205-
"""`from_pipe` forward-pass parity and offload round trip for the AnimateDiff ControlNet pipeline.
172+
class TestAnimateDiffControlNetPipelineFromPipe(AnimateDiffControlNetPipelineTesterConfig, FromPipeTesterMixin):
173+
"""`from_pipe` round-trip tests against `StableDiffusionPipeline` for the AnimateDiff ControlNet pipeline."""
206174

207-
Parked, not deleted: `test_from_pipe_consistent_config` runs for real as a method on the main test class above,
208-
but the forward-pass checks in `PipelineFromPipeTesterMixin` have no pytest-style equivalent yet.
209-
"""
175+
original_pipeline_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"

tests/pipelines/animatediff/test_animatediff_sparsectrl.py

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import pytest
21
import torch
32
from PIL import Image
43
from transformers import CLIPTextConfig, CLIPTextModel, CLIPTokenizer
@@ -9,22 +8,20 @@
98
DDIMScheduler,
109
MotionAdapter,
1110
SparseControlNetModel,
12-
StableDiffusionPipeline,
1311
UNet2DConditionModel,
1412
)
1513

1614
from ...testing_utils import assert_tensors_close, torch_device
1715
from ..pipeline_params import TEXT_TO_IMAGE_BATCH_PARAMS, TEXT_TO_IMAGE_PARAMS
18-
from ..test_pipelines_common import PipelineFromPipeTesterMixin
1916
from ..testing_utils import (
17+
FromPipeTesterMixin,
2018
IPAdapterTesterMixin,
2119
LoraMemoryTesterMixin,
2220
LoraTesterMixin,
2321
MemoryTesterMixin,
2422
UNetLoraTesterMixin,
2523
)
2624
from .testing_utils import (
27-
FROM_PIPE_SKIP_REASON,
2825
FreeInitTesterMixin,
2926
MotionPipelineTesterConfig,
3027
MotionPipelineTesterMixin,
@@ -138,32 +135,6 @@ class TestAnimateDiffSparseControlNetPipeline(
138135
MotionPipelineTesterMixin,
139136
FreeInitTesterMixin,
140137
):
141-
def test_from_pipe_consistent_config(self):
142-
original_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"
143-
144-
# create StableDiffusionPipeline
145-
pipe_original = StableDiffusionPipeline.from_pretrained(original_repo, requires_safety_checker=False)
146-
147-
# StableDiffusionPipeline -> AnimateDiffSparseControlNetPipeline
148-
pipe_components = self.get_dummy_components()
149-
pipe_additional_components = {
150-
name: component for name, component in pipe_components.items() if name not in pipe_original.components
151-
}
152-
pipe = self.pipeline_class.from_pipe(pipe_original, **pipe_additional_components)
153-
154-
# AnimateDiffSparseControlNetPipeline -> StableDiffusionPipeline
155-
original_pipe_additional_components = {}
156-
for name, component in pipe_original.components.items():
157-
if name not in pipe.components or not isinstance(component, pipe.components[name].__class__):
158-
original_pipe_additional_components[name] = component
159-
160-
pipe_original_2 = StableDiffusionPipeline.from_pipe(pipe, **original_pipe_additional_components)
161-
162-
# compare the config
163-
original_config = {k: v for k, v in pipe_original.config.items() if not k.startswith("_")}
164-
original_config_2 = {k: v for k, v in pipe_original_2.config.items() if not k.startswith("_")}
165-
assert original_config_2 == original_config
166-
167138
def test_dict_tuple_outputs_equivalent(self, expected_slice=None, expected_max_difference=1e-4):
168139
if torch_device == "cpu" and expected_slice is None:
169140
# fmt: off
@@ -229,12 +200,9 @@ class TestAnimateDiffSparseControlNetPipelineLoRAMemory(
229200
"""LoRA x memory-optimization tests (group offload, CPU offload) for the pipeline."""
230201

231202

232-
@pytest.mark.skip(FROM_PIPE_SKIP_REASON)
233203
class TestAnimateDiffSparseControlNetPipelineFromPipe(
234-
AnimateDiffSparseControlNetPipelineTesterConfig, PipelineFromPipeTesterMixin
204+
AnimateDiffSparseControlNetPipelineTesterConfig, FromPipeTesterMixin
235205
):
236-
"""`from_pipe` forward-pass parity and offload round trip for the AnimateDiff SparseControlNet pipeline.
206+
"""`from_pipe` round-trip tests against `StableDiffusionPipeline` for the AnimateDiff SparseControlNet pipeline."""
237207

238-
Parked, not deleted: `test_from_pipe_consistent_config` runs for real as a method on the main test class above,
239-
but the forward-pass checks in `PipelineFromPipeTesterMixin` have no pytest-style equivalent yet.
240-
"""
208+
original_pipeline_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"

tests/pipelines/animatediff/test_animatediff_video2video.py

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import pytest
21
import torch
32
from PIL import Image
43
from transformers import CLIPTextConfig, CLIPTextModel, CLIPTokenizer
@@ -8,22 +7,20 @@
87
AutoencoderKL,
98
DDIMScheduler,
109
MotionAdapter,
11-
StableDiffusionPipeline,
1210
UNet2DConditionModel,
1311
)
1412

1513
from ...testing_utils import torch_device
1614
from ..pipeline_params import TEXT_TO_IMAGE_PARAMS, VIDEO_TO_VIDEO_BATCH_PARAMS
17-
from ..test_pipelines_common import PipelineFromPipeTesterMixin
1815
from ..testing_utils import (
16+
FromPipeTesterMixin,
1917
IPAdapterTesterMixin,
2018
LoraMemoryTesterMixin,
2119
LoraTesterMixin,
2220
MemoryTesterMixin,
2321
UNetLoraTesterMixin,
2422
)
2523
from .testing_utils import (
26-
FROM_PIPE_SKIP_REASON,
2724
FreeInitTesterMixin,
2825
FreeNoiseSplitInferenceTesterMixin,
2926
MotionPipelineTesterConfig,
@@ -133,32 +130,6 @@ def get_free_noise_inputs(self):
133130
inputs["strength"] = 0.5
134131
return inputs
135132

136-
def test_from_pipe_consistent_config(self):
137-
original_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"
138-
139-
# create StableDiffusionPipeline
140-
pipe_original = StableDiffusionPipeline.from_pretrained(original_repo, requires_safety_checker=False)
141-
142-
# StableDiffusionPipeline -> AnimateDiffVideoToVideoPipeline
143-
pipe_components = self.get_dummy_components()
144-
pipe_additional_components = {
145-
name: component for name, component in pipe_components.items() if name not in pipe_original.components
146-
}
147-
pipe = self.pipeline_class.from_pipe(pipe_original, **pipe_additional_components)
148-
149-
# AnimateDiffVideoToVideoPipeline -> StableDiffusionPipeline
150-
original_pipe_additional_components = {}
151-
for name, component in pipe_original.components.items():
152-
if name not in pipe.components or not isinstance(component, pipe.components[name].__class__):
153-
original_pipe_additional_components[name] = component
154-
155-
pipe_original_2 = StableDiffusionPipeline.from_pipe(pipe, **original_pipe_additional_components)
156-
157-
# compare the config
158-
original_config = {k: v for k, v in pipe_original.config.items() if not k.startswith("_")}
159-
original_config_2 = {k: v for k, v in pipe_original_2.config.items() if not k.startswith("_")}
160-
assert original_config_2 == original_config
161-
162133
def test_latent_inputs(self):
163134
pipe = self.get_pipeline().to(torch_device)
164135

@@ -191,12 +162,7 @@ class TestAnimateDiffVideoToVideoPipelineLoRAMemory(
191162
"""LoRA x memory-optimization tests (group offload, CPU offload) for the pipeline."""
192163

193164

194-
@pytest.mark.skip(FROM_PIPE_SKIP_REASON)
195-
class TestAnimateDiffVideoToVideoPipelineFromPipe(
196-
AnimateDiffVideoToVideoPipelineTesterConfig, PipelineFromPipeTesterMixin
197-
):
198-
"""`from_pipe` forward-pass parity and offload round trip for the AnimateDiff video-to-video pipeline.
165+
class TestAnimateDiffVideoToVideoPipelineFromPipe(AnimateDiffVideoToVideoPipelineTesterConfig, FromPipeTesterMixin):
166+
"""`from_pipe` round-trip tests against `StableDiffusionPipeline` for the AnimateDiff video-to-video pipeline."""
199167

200-
Parked, not deleted: `test_from_pipe_consistent_config` runs for real as a method on the main test class above,
201-
but the forward-pass checks in `PipelineFromPipeTesterMixin` have no pytest-style equivalent yet.
202-
"""
168+
original_pipeline_repo = "hf-internal-testing/tinier-stable-diffusion-pipe"

0 commit comments

Comments
 (0)