mirror of
https://github.com/huggingface/diffusers.git
synced 2026-03-20 23:48:19 +08:00
Compare commits
9 Commits
claude-ci-
...
tests-load
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28052b0691 | ||
|
|
522b523e40 | ||
|
|
443d73584b | ||
|
|
faca9b90a7 | ||
|
|
a1f63a398c | ||
|
|
bf846f722c | ||
|
|
78a86e85cf | ||
|
|
7673ab1757 | ||
|
|
b7648557d4 |
@@ -1,34 +0,0 @@
|
||||
# PR Review Rules
|
||||
|
||||
Rules for Claude to check during PR reviews. Focus on correctness — style is handled by ruff.
|
||||
|
||||
## Code style
|
||||
- Inline logic — minimize small helper/utility functions. A reader should follow the full flow without jumping between functions.
|
||||
- No defensive code or unused code paths — no fallback paths, safety checks, or config options "just in case".
|
||||
- No silent fallbacks — raise a concise error for unsupported cases rather than guessing user intent.
|
||||
|
||||
## Dependencies
|
||||
- No new mandatory dependencies without prior discussion.
|
||||
- Optional deps must be guarded with `is_X_available()` and have a dummy in `utils/dummy_*.py`.
|
||||
- Never use `einops` — rewrite with native PyTorch (`reshape`, `permute`, `unflatten`).
|
||||
|
||||
## Models
|
||||
- All layer calls must be visible directly in `forward()` — no helper functions hiding `nn.Module` calls.
|
||||
- No NumPy operations in `forward()` — breaks `torch.compile` with `fullgraph=True`.
|
||||
- No hardcoded dtypes (e.g. `torch.float32`, `torch.bfloat16`) in forward — use input tensor dtype or `self.dtype`.
|
||||
- Attention must use `dispatch_attention_fn`, not `F.scaled_dot_product_attention` directly.
|
||||
- Every `__init__` parameter in a `ModelMixin` subclass must be captured by `register_to_config`.
|
||||
- New classes must be registered in `__init__.py` with lazy imports (both `_import_structure` and `_lazy_modules`).
|
||||
|
||||
## Pipelines
|
||||
- Must inherit from `DiffusionPipeline`.
|
||||
- `@torch.no_grad()` on pipeline `__call__` — forgetting this causes OOM from gradient accumulation.
|
||||
- Do NOT subclass an existing pipeline for a variant (e.g. don't subclass `FluxPipeline` for `FluxImg2ImgPipeline`).
|
||||
- Support `output_type="latent"` for skipping VAE decode.
|
||||
- Support `generator` parameter for reproducibility.
|
||||
|
||||
## Copied code
|
||||
- Never edit a `# Copied from` block directly — run `make fix-copies` to propagate changes from the source.
|
||||
- Remove the `# Copied from` header to intentionally break the sync link.
|
||||
|
||||
## Common mistakes (add new rules below this line)
|
||||
27
.github/workflows/claude_review.yml
vendored
27
.github/workflows/claude_review.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Claude PR Review
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: read
|
||||
|
||||
jobs:
|
||||
claude-review:
|
||||
if: |
|
||||
github.event.issue.pull_request &&
|
||||
github.event.issue.state == 'open' &&
|
||||
contains(github.event.comment.body, '@claude') &&
|
||||
(github.event.comment.author_association == 'MEMBER' ||
|
||||
github.event.comment.author_association == 'OWNER' ||
|
||||
github.event.comment.author_association == 'COLLABORATOR')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
claude_args: |
|
||||
--append-system-prompt "Review this PR against the rules in .ai/review-rules.md. Focus on correctness, not style (ruff handles style). Only review changes under src/diffusers/."
|
||||
@@ -28,7 +28,6 @@ from diffusers.utils.import_utils import is_peft_available
|
||||
|
||||
from ..testing_utils import (
|
||||
floats_tensor,
|
||||
is_flaky,
|
||||
require_peft_backend,
|
||||
require_peft_version_greater,
|
||||
skip_mps,
|
||||
@@ -46,7 +45,6 @@ from .utils import PeftLoraLoaderMixinTests # noqa: E402
|
||||
|
||||
@require_peft_backend
|
||||
@skip_mps
|
||||
@is_flaky(max_attempts=10, description="very flaky class")
|
||||
class WanVACELoRATests(unittest.TestCase, PeftLoraLoaderMixinTests):
|
||||
pipeline_class = WanVACEPipeline
|
||||
scheduler_cls = FlowMatchEulerDiscreteScheduler
|
||||
@@ -73,8 +71,8 @@ class WanVACELoRATests(unittest.TestCase, PeftLoraLoaderMixinTests):
|
||||
"base_dim": 3,
|
||||
"z_dim": 4,
|
||||
"dim_mult": [1, 1, 1, 1],
|
||||
"latents_mean": torch.randn(4).numpy().tolist(),
|
||||
"latents_std": torch.randn(4).numpy().tolist(),
|
||||
"latents_mean": [-0.7571, -0.7089, -0.9113, -0.7245],
|
||||
"latents_std": [2.8184, 1.4541, 2.3275, 2.6558],
|
||||
"num_res_blocks": 1,
|
||||
"temperal_downsample": [False, True, True],
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ from typing import Callable
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
from huggingface_hub import hf_hub_download
|
||||
|
||||
import diffusers
|
||||
from diffusers import AutoModel, ComponentsManager, ModularPipeline, ModularPipelineBlocks
|
||||
@@ -32,6 +33,33 @@ from ..testing_utils import (
|
||||
)
|
||||
|
||||
|
||||
def _get_specified_components(path_or_repo_id, cache_dir=None):
|
||||
if os.path.isdir(path_or_repo_id):
|
||||
config_path = os.path.join(path_or_repo_id, "modular_model_index.json")
|
||||
else:
|
||||
try:
|
||||
config_path = hf_hub_download(
|
||||
repo_id=path_or_repo_id,
|
||||
filename="modular_model_index.json",
|
||||
local_dir=cache_dir,
|
||||
)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
with open(config_path) as f:
|
||||
config = json.load(f)
|
||||
|
||||
components = set()
|
||||
for k, v in config.items():
|
||||
if isinstance(v, (str, int, float, bool)):
|
||||
continue
|
||||
for entry in v:
|
||||
if isinstance(entry, dict) and (entry.get("repo") or entry.get("pretrained_model_name_or_path")):
|
||||
components.add(k)
|
||||
break
|
||||
return components
|
||||
|
||||
|
||||
class ModularPipelineTesterMixin:
|
||||
"""
|
||||
It provides a set of common tests for each modular pipeline,
|
||||
@@ -360,6 +388,39 @@ class ModularPipelineTesterMixin:
|
||||
|
||||
assert torch.abs(image_slices[0] - image_slices[1]).max() < 1e-3
|
||||
|
||||
def test_load_expected_components_from_pretrained(self, tmp_path):
|
||||
pipe = self.get_pipeline()
|
||||
expected = _get_specified_components(self.pretrained_model_name_or_path, cache_dir=tmp_path)
|
||||
if not expected:
|
||||
pytest.skip("Skipping test as we couldn't fetch the expected components.")
|
||||
|
||||
actual = {
|
||||
name
|
||||
for name in pipe.components
|
||||
if getattr(pipe, name, None) is not None
|
||||
and getattr(getattr(pipe, name), "_diffusers_load_id", None) not in (None, "null")
|
||||
}
|
||||
assert expected == actual, f"Component mismatch: missing={expected - actual}, unexpected={actual - expected}"
|
||||
|
||||
def test_load_expected_components_from_save_pretrained(self, tmp_path):
|
||||
pipe = self.get_pipeline()
|
||||
save_dir = str(tmp_path / "saved-pipeline")
|
||||
pipe.save_pretrained(save_dir)
|
||||
|
||||
expected = _get_specified_components(save_dir)
|
||||
loaded_pipe = ModularPipeline.from_pretrained(save_dir)
|
||||
loaded_pipe.load_components(torch_dtype=torch.float32)
|
||||
|
||||
actual = {
|
||||
name
|
||||
for name in loaded_pipe.components
|
||||
if getattr(loaded_pipe, name, None) is not None
|
||||
and getattr(getattr(loaded_pipe, name), "_diffusers_load_id", None) not in (None, "null")
|
||||
}
|
||||
assert expected == actual, (
|
||||
f"Component mismatch after save/load: missing={expected - actual}, unexpected={actual - expected}"
|
||||
)
|
||||
|
||||
def test_modular_index_consistency(self, tmp_path):
|
||||
pipe = self.get_pipeline()
|
||||
components_spec = pipe._component_specs
|
||||
|
||||
Reference in New Issue
Block a user