1
0
mirror of https://github.com/huggingface/diffusers.git synced 2026-10-24 20:59:27 +03:00
Files
diffusers/tests/pipelines/cosmos/testing_utils.py
Sayak Paul a262497cd0 [tests] refactor c* pipeline tests. (#14626)
* refactor c* pipeline tests.

Migrate the remaining `tests/pipelines/` directories starting with C to the config class +
composable pytest mixins introduced in #14113: chroma, chronoedit, cogview3, consisid,
consistency_models, controlnet, controlnet_flux, controlnet_hunyuandit, controlnet_sd3 and
cosmos. cogvideo and cogview4 were already migrated.

Notable points beyond the mechanical conversion:

- Expected slices switch from the `"np"` layout (`[0, -3:, -3:, -1]`) to the `"pt"` one
  (`[0, -1, -3:, -3:]`); the values themselves are unchanged.
- The Cosmos `safety_checker` overrides (save/load, variants, dtype dict, encode_prompt)
  were duplicated across five files and now live in a shared
  `CosmosSafetyCheckerTesterMixin` in `tests/pipelines/cosmos/testing_utils.py`.
- chroma and controlnet_flux import `FluxIPAdapterTesterMixin` from `..flux.testing_utils`
  rather than the old `..test_pipelines_common` one.
- `PipelineTesterMixin.test_save_load_float16` now passes the non-deprecated `dtype=` to
  `from_pretrained` instead of `torch_dtype=`, which the Cosmos2.5 `from_pretrained`
  wrappers read when casting the safety checker they inject.
- Dropped along the way, matching #14619: `PipelineLatentTesterMixin`,
  `PipelineKarrasSchedulerTesterMixin`, the attention-slicing and xformers tests, and the
  `test_ip_adapter` overrides that only supplied an `expected_pipe_slice`.

`pytest tests/pipelines/{chroma,chronoedit,cogview3,consisid,consistency_models,controlnet,controlnet_flux,controlnet_hunyuandit,controlnet_sd3,cosmos}`
gives 14 failed, 1014 passed, 82 skipped. All 14 failures are in cosmos and reproduce
unchanged on main: `DummyCosmosSafetyChecker` is a parameter-less `ModelMixin` with a single
non-persistent buffer, so accelerate does not hook it for sequential offload and a reloaded
pipeline gets a fresh fp32 one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 08:13:24 +05:30

96 lines
4.5 KiB
Python

# Copyright 2026 The HuggingFace Team.
#
# 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.
import json
import os
import pytest
import torch
from .cosmos_guardrail import DummyCosmosSafetyChecker
class CosmosSafetyCheckerTesterMixin:
"""Overrides of the shared pipeline tests that the Cosmos `safety_checker` component gets in the way of.
Every Cosmos pipeline takes a `safety_checker`, and the fast tests substitute `DummyCosmosSafetyChecker` for the
real Cosmos Guardrail, which is far too large to build on CI. The dummy is not serialized like the other model
components and a pipeline constructed without one falls back to the real guardrail, so the tests that save,
reload or enumerate components need the component handled explicitly.
Compose it *before* `PipelineTesterMixin` so these overrides win, e.g.
`class TestCosmosXPipeline(CosmosXPipelineTesterConfig, CosmosSafetyCheckerTesterMixin, PipelineTesterMixin)`.
"""
def test_save_load_optional_components(self, tmp_path, expected_max_difference=1e-4):
# `safety_checker` is listed as optional, but a pipeline built without one falls back to the real Cosmos
# Guardrail — so keep it out of the components the base test nulls.
self.pipeline_class._optional_components.remove("safety_checker")
try:
super().test_save_load_optional_components(tmp_path, expected_max_difference=expected_max_difference)
finally:
self.pipeline_class._optional_components.append("safety_checker")
def test_serialization_with_variants(self, tmp_path):
# Same as the base test, except `safety_checker` is not serialized like the other model components.
pipe = self.get_pipeline()
model_components = [
component_name
for component_name, component in pipe.components.items()
if isinstance(component, torch.nn.Module)
]
model_components.remove("safety_checker")
variant = "fp16"
pipe.save_pretrained(tmp_path, variant=variant, safe_serialization=False)
with open(f"{tmp_path}/model_index.json", "r") as f:
config = json.load(f)
for subfolder in os.listdir(tmp_path):
if not os.path.isfile(subfolder) and subfolder in model_components:
folder_path = os.path.join(tmp_path, subfolder)
is_folder = os.path.isdir(folder_path) and subfolder in config
assert is_folder and any(p.split(".")[1].startswith(variant) for p in os.listdir(folder_path))
def test_torch_dtype_dict(self, tmp_path):
# Same as the base test, except the safety checker has to be passed back in on load and is left out of the
# dtype check (the dummy tracks its dtype through a non-persistent buffer).
components = self.get_dummy_components()
pipe = self.get_pipeline(**components)
specified_key = next(iter(components.keys()))
pipe.save_pretrained(str(tmp_path), safe_serialization=False)
torch_dtype_dict = {specified_key: torch.bfloat16, "default": torch.float16}
loaded_pipe = self.pipeline_class.from_pretrained(
str(tmp_path), safety_checker=DummyCosmosSafetyChecker(), dtype=torch_dtype_dict
)
for name, component in loaded_pipe.components.items():
if name == "safety_checker":
continue
if isinstance(component, torch.nn.Module) and hasattr(component, "dtype"):
expected_dtype = torch_dtype_dict.get(name, torch_dtype_dict.get("default", torch.float32))
assert component.dtype == expected_dtype, (
f"Component '{name}' has dtype {component.dtype} but expected {expected_dtype}"
)
@pytest.mark.skip(
"The pipeline should not be runnable without a safety checker. The test creates a pipeline without passing in "
"a safety checker, which makes the pipeline default to the actual Cosmos Guardrail. The Cosmos Guardrail is "
"too large and slow to run on CI."
)
def test_encode_prompt_works_in_isolation(self):
pass