huggingface / huggingface/diffusers
kandinsky5 model/pipeline review
- Lenguaje dominante
- Python
- Estrellas
- 34.5k
- Forks
- 7.3k
- Merge medio
- 3 d 3 h
- PR fusionados (30 d)
- 91
Descripción
# `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.
Guía de contribución
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- python, pytorch
- Área
- documentation, machine-learning, testing-qa
- Tipo de issue
- Error
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Estado de actividad
- Tranquilo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 28/100