huggingface / huggingface/diffusers

kandinsky5 model/pipeline review

Offen
#13,639 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
34.5k
Forks
7.3k
Ø Merge
3 T. 3 Std.
Gemergte PRs (30 T.)
91

Beschreibung

# `kandinsky5` model/pipeline review

Commit tested: `0f1abc4ae8b0eb2a3b40e82a310507281144c423`

Review performed against the repository review rules.

Duplicate search performed against `huggingface/diffusers` Issues and PRs for `kandinsky5`, affected class names, output fields, prompt embedding batching, I2I tensor inputs, docs examples, `return_dict`, dtype/offload behavior, `_no_split_modules`, and slow-test coverage. Existing related items are noted inline. No GitHub issue was created before this `CREATE ISSUE` request.

## Issue 1: Precomputed prompt embeddings break batching and CFG

Affected code:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky.py#L788-L842
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_i2v.py#L866-L923
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_t2i.py#L640-L695
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_i2i.py#L678-L737

Problem:
When `prompt_embeds_qwen` is supplied, the pipelines skip `encode_prompt`, so embeddings and `prompt_cu_seqlens` are not expanded for `num_images_per_prompt` / `num_videos_per_prompt`, but latents are. CFG also sizes default/string negative prompts from `len(prompt)`, which fails when `prompt=None` and embeddings are used.

Impact:
Valid precomputed-embedding calls either crash with batch mismatches or fail before denoising. This affects all four Kandinsky5 pipelines.

Reproduction:
```python
import torch
from types import SimpleNamespace
from diffusers import FlowMatchEulerDiscreteScheduler, Kandinsky5T2IPipeline

class ReproPipeline(Kandinsky5T2IPipeline):
@property
def _execution_device(self):
return torch.device("cpu")

class DummyModule(torch.nn.Module):
@property
def dtype(self):
return torch.float32

class DummyTransformer(DummyModule):
config = SimpleNamespace(in_visual_dim=4)
visual_cond = False
def forward(self, hidden_states, encoder_hidden_states, **kwargs):
assert hidden_states.shape[0] == encoder_hidden_states.shape[0], (
hidden_states.shape,
encoder_hidden_states.shape,
)
return SimpleNamespace(sample=torch.zeros_like(hidden_states[..., :4]))

class DummyVAE(DummyModule):
config = SimpleNamespace(scaling_factor=1.0)

pipe = ReproPipeline(DummyTransformer(), DummyVAE(), DummyModule(), None, DummyModule(), None, FlowMatchEulerDiscreteScheduler())
pipe.resolutions = [(64, 64)]
pipe.set_progress_bar_config(disable=True)

emb = torch.zeros(2, 4, 8)
pooled = torch.zeros(2, 6)
cu = torch.tensor([0, 4, 8], dtype=torch.int32)

pipe(
prompt=None,
prompt_embeds_qwen=emb,
prompt_embeds_clip=pooled,
prompt_cu_seqlens=cu,
negative_prompt_embeds_qwen=emb,
negative_prompt_embeds_clip=pooled,
negative_prompt_cu_seqlens=cu,
height=64,
width=64,
guidance_scale=4.0,
num_images_per_prompt=2,
num_inference_steps=1,
output_type="latent",
)
```

Relevant precedent:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/qwenimage/pipeline_qwenimage.py#L615-L631

Suggested fix:
```python
# Route provided embeds through a helper that mirrors encode_prompt's repeat logic.
if prompt_embeds_qwen is not None:
prompt_embeds_qwen, prompt_embeds_clip, prompt_cu_seqlens = self._repeat_prompt_embeds(
prompt_embeds_qwen, prompt_embeds_clip, prompt_cu_seqlens, num_images_per_prompt, device
)

negative_batch_size = batch_size
if isinstance(negative_prompt, str):
negative_prompt = [negative_prompt] * negative_batch_size
elif negative_prompt is not None and len(negative_prompt) != negative_batch_size:
raise ValueError(...)
```

## Issue 2: Image pipelines return `.image` instead of the standard `.images`

Affected code:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_output.py#L23-L35
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_t2i.py#L813-L816
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_i2i.py#L858-L861

Problem:
Kandinsky5 image pipelines return `KandinskyImagePipelineOutput(image=...)`. Diffusers image pipelines conventionally return an `images` field. The source docstring examples also call `.frames[0]`, which is neither the actual field nor the image-pipeline convention.

Impact:
User code expecting standard Diffusers output (`pipe(...).images`) fails, and generated docs from source examples are misleading.

Reproduction:
```python
import torch
from diffusers.pipelines.kandinsky5.pipeline_output import KandinskyImagePipelineOutput

out = KandinskyImagePipelineOutput(image=torch.zeros(1, 3, 4, 4))
print(list(out.keys()))
print(hasattr(out, "images"), hasattr(out, "frames"))
```

Relevant precedent:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/pipeline_utils.py#L121-L131

Suggested fix:
```python
from ..pipeline_utils import ImagePipelineOutput

# T2I / I2I return path
return ImagePipelineOutput(images=image)
```

Update tests and docs to use `.images[0]`.

## Issue 3: I2I advertises `PipelineImageInput` but only handles PIL images in prompt encoding

Affected code:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_i2i.py#L184-L212
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_i2i.py#L650-L651

Problem:
`Kandinsky5I2IPipeline.__call__` and `_encode_prompt_qwen` use PIL-only `.size` and `.resize` access. The public type is `PipelineImageInput`, and the docstring says tensors are accepted, but tensor/NumPy inputs fail before preprocessing can normalize them.

Impact:
Valid Diffusers image input types are rejected for I2I, despite being accepted by the VAE image processor path.

Reproduction:
```python
import torch
from diffusers import Kandinsky5I2IPipeline

pipe = object.__new__(Kandinsky5I2IPipeline)
pipe._encode_prompt_qwen(
prompt=["edit it"],
image=torch.zeros(1, 3, 64, 64),
device=torch.device("cpu"),
dtype=torch.float32,
)
```

Relevant precedent:
`VaeImageProcessor.preprocess` is already used later for the VAE path; the Qwen image path should normalize the same public input types before resizing.

Suggested fix:
```python
if not isinstance(image, list):
image = [image]

# Normalize non-PIL inputs before calling Qwen processor.
image = [self.image_processor.numpy_to_pil(i)[0] if not hasattr(i, "resize") else i for i in image]
image = [i.resize((i.size[0] // 2, i.size[1] // 2)) for i in image]
```

## Issue 4: Transformer return, dtype, and device-map contracts are inconsistent

Affected code:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/models/transformers/transformer_kandinsky.py#L309-L312
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/models/transformers/transformer_kandinsky.py#L522-L527
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/models/transformers/transformer_kandinsky.py#L665-L668

Problem:
`return_dict=False` returns a bare tensor instead of a one-element tuple. The rotary helper hard-casts through `torch.bfloat16`, quantizing non-bf16 runs. The class also declares repeated blocks but no `_no_split_modules`.

Impact:
The public model return contract differs from related transformers, dtype behavior is not clean for fp32/fp16, and `device_map="auto"` lacks block no-split guidance.

Reproduction:
```python
import torch
from diffusers import Kandinsky5Transformer3DModel

model = Kandinsky5Transformer3DModel(
in_visual_dim=4, in_text_dim=8, in_text_dim2=6, time_dim=8, out_visual_dim=4,
patch_size=(1, 1, 1), model_dim=8, ff_dim=16, num_text_blocks=1,
num_visual_blocks=1, axes_dims=(2, 2, 4), attention_type="regular",
).eval()

out = model(
hidden_states=torch.randn(1, 1, 2, 2, 4),
encoder_hidden_states=torch.randn(1, 3, 8),
timestep=torch.tensor([1.0]),
pooled_projections=torch.randn(1, 6),
visual_rope_pos=[torch.arange(1), torch.arange(2), torch.arange(2)],
text_rope_pos=torch.arange(3),
return_dict=False,
)
print(type(out), getattr(out, "shape", None))
print(getattr(Kandinsky5Transformer3DModel, "_no_split_modules", None))
```

Relevant precedent:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/models/transformers/transformer_flux.py#L775-L778
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/models/transformers/transformer_qwenimage.py#L990-L993
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/models/transformers/transformer_wan.py#L705-L708

Duplicate status:
The dtype/no-split parts overlap with https://github.com/huggingface/diffusers/issues/13597 and the older dtype/autocast fix in https://github.com/huggingface/diffusers/pull/12814 / https://github.com/huggingface/diffusers/issues/12809. The `return_dict=False` tuple issue was not found as a duplicate.

Suggested fix:
```python
# Rotary helper
orig_dtype = x.dtype
x_ = x.reshape(*x.shape[:-1], -1, 1, 2).float()
x_out = (rope * x_).sum(dim=-1)
return x_out.reshape(*x.shape).to(orig_dtype)

# Class metadata
_no_split_modules = ["Kandinsky5TransformerEncoderBlock", "Kandinsky5TransformerDecoderBlock"]

# return_dict=False
if not return_dict:
return (x,)
```

## Issue 5: I2V documentation example is not runnable

Affected code:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/docs/source/en/api/pipelines/kandinsky5_video.md#L171-L204

Problem:
The I2V example imports and instantiates `Kandinsky5T2VPipeline` for an I2V checkpoint, uses `pipeline.*` even though the variable is named `pipe`, uses `load_image` without importing it, and never passes `image=image` to the call.

Impact:
Users following the docs cannot run image-to-video inference.

Reproduction:
```python
from pathlib import Path

text = Path("docs/source/en/api/pipelines/kandinsky5_video.md").read_text()
section = text.split("### Basic Image-to-Video Generation", 1)[1].split("## Kandinsky5T2VPipeline", 1)[0]

assert "from diffusers import Kandinsky5I2VPipeline" in section
assert "from diffusers.utils import export_to_video, load_image" in section
assert "pipe.enable_model_cpu_offload()" in section
assert "image=image" in section
```

Relevant precedent:
The source docstring for `Kandinsky5I2VPipeline` uses the correct pipeline class and imports:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/src/diffusers/pipelines/kandinsky5/pipeline_kandinsky_i2v.py#L61-L88

Suggested fix:
```python
from diffusers import Kandinsky5I2VPipeline
from diffusers.utils import export_to_video, load_image

pipe = Kandinsky5I2VPipeline.from_pretrained(model_id, torch_dtype=torch.bfloat16)
pipe.to("cuda")
pipe.transformer.set_attention_backend("flex")
pipe.enable_model_cpu_offload()

output = pipe(
image=image,
prompt=prompt,
negative_prompt=negative_prompt,
height=height,
width=width,
num_frames=121,
num_inference_steps=50,
guidance_scale=5.0,
).frames[0]
```

## Issue 6: Slow tests are missing and several fast coverage paths are skipped

Affected code:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/tests/pipelines/kandinsky5/test_kandinsky5.py#L200-L209
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/tests/pipelines/kandinsky5/test_kandinsky5_i2v.py#L201-L210
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/tests/pipelines/kandinsky5/test_kandinsky5_i2i.py#L195-L212
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/tests/pipelines/kandinsky5/test_kandinsky5_t2i.py#L193-L207

Problem:
There are fast tests for all four pipelines, but no `@slow` or integration tests for Kandinsky5. Multiple fast tests for encode-prompt isolation, callback inputs, batch behavior, `num_images_per_prompt`, and float16 are skipped.

Impact:
The public failures above are not covered. In particular, embedding-only calls, tensor I2I inputs, callback behavior, and official checkpoint smoke tests are missing.

Reproduction:
```python
from pathlib import Path

for path in sorted(Path("tests/pipelines/kandinsky5").glob("test_*.py")):
text = path.read_text(encoding="utf-8")
print(path.as_posix(), "slow=", "@slow" in text, "nightly=", "@nightly" in text, "skip=", "@unittest.skip" in text)

print([
p.as_posix()
for p in Path("tests/models").rglob("test_*.py")
if "Kandinsky5Transformer3DModel" in p.read_text(errors="ignore")
])
```

Relevant precedent:
Existing Kandinsky families include slow/integration coverage:
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/tests/pipelines/kandinsky3/test_kandinsky3.py#L174-L199
https://github.com/huggingface/diffusers/blob/0f1abc4ae8b0eb2a3b40e82a310507281144c423/tests/pipelines/kandinsky2_2/test_kandinsky.py#L227-L262

Suggested fix:
Add slow smoke tests for the published T2V, I2V, T2I, and I2I checkpoints, and unskip or replace the fast tests for encode-prompt isolation, callbacks, batching, `num_images_per_prompt`, and dtype behavior. Local `.venv` fast-test execution currently fails at collection because the installed torch lacks `torch._C._distributed_c10d`, so I could not run the shared `PipelineTesterMixin` suite end to end in this environment.

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Start by reading the affected Kandinsky5 pipeline and transformer files listed in the review, then run the provided reproductions and inspect the existing Kandinsky5 tests and documentation example. This is a broad review covering batching, outputs, image inputs, model contracts, docs, and test coverage; it is done when each listed finding has an agreed fix and corresponding tests or documentation checks pass.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python, pytorch
Bereich
documentation, machine-learning, testing-qa
Issue-Typ
Bug
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Ruhig
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
28/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.