From 780ee84b49e056cb61327aaa2b9d226aad0c6e59 Mon Sep 17 00:00:00 2001 From: Devam0311 Date: Tue, 1 Sep 2026 16:04:11 +0530 Subject: [PATCH] Accept tensor ip_adapter_image_embeds in SD3 ControlNet inpainting `StableDiffusion3ControlNetInpaintingPipeline.check_inputs` required `ip_adapter_image_embeds` to be a `list`, but the `__call__` docstring documents a tensor of shape `(batch_size, num_images, emb_dim)` and `prepare_ip_adapter_image_embeds` types it as `torch.Tensor` and calls `.chunk(2)` on it. Passing the documented tensor therefore always failed validation, so precomputed IP-Adapter embeddings could not be used at all. Validate the tensor's rank instead, matching the documented contract. Add regression tests for both the accepted tensor and the rejected rank. Ref #13611 (Issue 5) Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XBYeq5vB4DNZDEaqUsroKR --- ...table_diffusion_3_controlnet_inpainting.py | 13 +++----- .../test_controlnet_inpaint_sd3.py | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/diffusers/pipelines/controlnet_sd3/pipeline_stable_diffusion_3_controlnet_inpainting.py b/src/diffusers/pipelines/controlnet_sd3/pipeline_stable_diffusion_3_controlnet_inpainting.py index d2890d55811c..1acdfbb10b0e 100644 --- a/src/diffusers/pipelines/controlnet_sd3/pipeline_stable_diffusion_3_controlnet_inpainting.py +++ b/src/diffusers/pipelines/controlnet_sd3/pipeline_stable_diffusion_3_controlnet_inpainting.py @@ -777,15 +777,10 @@ def check_inputs( "Provide either `ip_adapter_image` or `ip_adapter_image_embeds`. Cannot leave both `ip_adapter_image` and `ip_adapter_image_embeds` defined." ) - if ip_adapter_image_embeds is not None: - if not isinstance(ip_adapter_image_embeds, list): - raise ValueError( - f"`ip_adapter_image_embeds` has to be of type `list` but is {type(ip_adapter_image_embeds)}" - ) - elif ip_adapter_image_embeds[0].ndim not in [3, 4]: - raise ValueError( - f"`ip_adapter_image_embeds` has to be a list of 3D or 4D tensors but is {ip_adapter_image_embeds[0].ndim}D" - ) + if ip_adapter_image_embeds is not None and ip_adapter_image_embeds.ndim not in [3, 4]: + raise ValueError( + f"`ip_adapter_image_embeds` has to be a 3D or 4D tensor but is {ip_adapter_image_embeds.ndim}D" + ) # Copied from diffusers.pipelines.stable_diffusion_3.pipeline_stable_diffusion_3.StableDiffusion3Pipeline.prepare_latents def prepare_latents( diff --git a/tests/pipelines/controlnet_sd3/test_controlnet_inpaint_sd3.py b/tests/pipelines/controlnet_sd3/test_controlnet_inpaint_sd3.py index 554fbc150e09..470fe4d602c5 100644 --- a/tests/pipelines/controlnet_sd3/test_controlnet_inpaint_sd3.py +++ b/tests/pipelines/controlnet_sd3/test_controlnet_inpaint_sd3.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest import torch from transformers import ( AutoConfig, @@ -195,6 +196,35 @@ def test_controlnet_inpaint_sd3(self): assert_tensors_close(image_slice.flatten().cpu(), expected_slice, atol=1e-2) + def _check_inputs_with_ip_adapter_embeds(self, pipe, ip_adapter_image_embeds): + pipe.check_inputs( + height=32, + width=32, + image=torch.zeros(1, 3, 32, 32), + prompt=None, + prompt_2=None, + prompt_3=None, + prompt_embeds=torch.zeros(1, 2, 32), + pooled_prompt_embeds=torch.zeros(1, 64), + ip_adapter_image_embeds=ip_adapter_image_embeds, + control_guidance_start=[0.0], + control_guidance_end=[1.0], + ) + + def test_check_inputs_accepts_ip_adapter_image_embeds_tensor(self): + # Regression: `check_inputs` required a `list`, but the `__call__` docstring and + # `prepare_ip_adapter_image_embeds` (which calls `.chunk(2)` on it) both document and use a + # tensor, so the documented argument could never be passed. + pipe = self.get_pipeline() + + self._check_inputs_with_ip_adapter_embeds(pipe, torch.zeros(1, 2, 32)) + + def test_check_inputs_rejects_ip_adapter_image_embeds_with_bad_ndim(self): + pipe = self.get_pipeline() + + with pytest.raises(ValueError, match="has to be a 3D or 4D tensor"): + self._check_inputs_with_ip_adapter_embeds(pipe, torch.zeros(1, 32)) + class TestStableDiffusion3ControlNetInpaintingPipelineMemory( StableDiffusion3ControlNetInpaintingPipelineTesterConfig, MemoryTesterMixin