huggingface / huggingface/diffusers

kandinsky5 model/pipeline review

Đang mở
#13,639 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
34.5k
Fork
7.3k
Merge trung bình
3 ngày 3 giờ
Pull request đã merge (30 ngày)
91

Mô tả

# `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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Bắt đầu bằng cách đọc các tệp pipeline và transformer Kandinsky5 bị ảnh hưởng được liệt kê trong phần review, sau đó chạy các bản tái hiện được cung cấp và kiểm tra các bài kiểm thử Kandinsky5 hiện có cùng ví dụ trong tài liệu. Đây là một review trên phạm vi rộng, bao quát batching, đầu ra, đầu vào hình ảnh, các hợp đồng của model, tài liệu và độ bao phủ kiểm thử; công việc hoàn tất khi mỗi phát hiện được liệt kê đều có một cách khắc phục đã được thống nhất và các bài kiểm thử hoặc bước kiểm tra tài liệu tương ứng đều đạt.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python, pytorch
Lĩnh vực
documentation, machine-learning, testing-qa
Loại issue
Lỗi
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
28/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.