Skip to content

stable_diffusion_3 model/pipeline review #13611

Description

@hlky

stable_diffusion_3 model/pipeline review

Commit tested: 0f1abc4ae8b0eb2a3b40e82a310507281144c423

Review performed against the repository review rules.

Issue 1: SD3 inpaint decode drops the VAE shift

Affected code:

ifnotoutput_type=="latent":
image=self.vae.decode(latents/self.vae.config.scaling_factor, return_dict=False, generator=generator)[
0
]

Problem:
StableDiffusion3InpaintPipeline encodes VAE latents with (latents - shift_factor) * scaling_factor, but decodes with only latents / scaling_factor. The missing + self.vae.config.shift_factor makes inpaint decoding inconsistent with the other SD3 pipelines and with its own encode path. Duplicate search found no matching issue/PR.

Impact:
User-visible inpaint outputs are decoded from the wrong latent distribution whenever the VAE has a nonzero shift_factor, which SD3 VAEs do.

Reproduction:

importtorchfromdiffusersimportAutoencoderKLvae=AutoencoderKL(
sample_size=8, in_channels=3, out_channels=3, block_out_channels=(4,),
layers_per_block=1, latent_channels=16, norm_num_groups=1,
use_quant_conv=False, use_post_quant_conv=False,
shift_factor=0.25, scaling_factor=2.0,
)
latents=torch.randn(1, 16, 8, 8)
current=vae.decode(latents/vae.config.scaling_factor, return_dict=False)[0]
expected=vae.decode((latents/vae.config.scaling_factor) +vae.config.shift_factor, return_dict=False)[0]
print((current-expected).abs().max())

Relevant precedent:

else:
latents= (latents/self.vae.config.scaling_factor) +self.vae.config.shift_factor
image=self.vae.decode(latents, return_dict=False)[0]
image=self.image_processor.postprocess(image, output_type=output_type)

else:
latents= (latents/self.vae.config.scaling_factor) +self.vae.config.shift_factor
image=self.vae.decode(latents, return_dict=False)[0]
image=self.image_processor.postprocess(image, output_type=output_type)

Suggested fix:

latents= (latents/self.vae.config.scaling_factor) +self.vae.config.shift_factorimage=self.vae.decode(latents, return_dict=False, generator=generator)[0]

Issue 2: SD3 ControlNet pipelines cannot use dynamic-shifting schedulers

Affected code:

# 4. Prepare timesteps
ifXLA_AVAILABLE:
timestep_device="cpu"
else:
timestep_device=device
timesteps, num_inference_steps=retrieve_timesteps(
self.scheduler, num_inference_steps, timestep_device, sigmas=sigmas
)

# 4. Prepare timesteps
ifXLA_AVAILABLE:
timestep_device="cpu"
else:
timestep_device=device
timesteps, num_inference_steps=retrieve_timesteps(

Problem:
The base SD3 pipelines compute and pass mu when FlowMatchEulerDiscreteScheduler.config.use_dynamic_shifting=True. The ControlNet SD3 pipelines call retrieve_timesteps() without mu handling and expose no mu argument. Duplicate search found no matching issue/PR.

Impact:
SD3.5-style scheduler configs with dynamic shifting fail before inference, so ControlNet is inconsistent with the rest of the SD3 family.

Reproduction:

fromdiffusersimportFlowMatchEulerDiscreteSchedulerfromdiffusers.pipelines.controlnet_sd3.pipeline_stable_diffusion_3_controlnetimportretrieve_timestepsscheduler=FlowMatchEulerDiscreteScheduler(use_dynamic_shifting=True)
retrieve_timesteps(scheduler, num_inference_steps=2, device="cpu")

Relevant precedent:

ifself.scheduler.config.get("use_dynamic_shifting", None) andmuisNone:
_, _, height, width=latents.shape
image_seq_len= (height//self.transformer.config.patch_size) * (
width//self.transformer.config.patch_size
)
mu=calculate_shift(
image_seq_len,
self.scheduler.config.get("base_image_seq_len", 256),
self.scheduler.config.get("max_image_seq_len", 4096),
self.scheduler.config.get("base_shift", 0.5),
self.scheduler.config.get("max_shift", 1.16),
)
scheduler_kwargs["mu"] =mu
elifmuisnotNone:
scheduler_kwargs["mu"] =mu
ifXLA_AVAILABLE:
timestep_device="cpu"
else:
timestep_device=device
timesteps, num_inference_steps=retrieve_timesteps(
self.scheduler,
num_inference_steps,
timestep_device,
sigmas=sigmas,
**scheduler_kwargs,
)

ifself.scheduler.config.get("use_dynamic_shifting", None) andmuisNone:
image_seq_len= (int(height) //self.vae_scale_factor//self.transformer.config.patch_size) * (
int(width) //self.vae_scale_factor//self.transformer.config.patch_size
)
mu=calculate_shift(
image_seq_len,
self.scheduler.config.get("base_image_seq_len", 256),
self.scheduler.config.get("max_image_seq_len", 4096),
self.scheduler.config.get("base_shift", 0.5),
self.scheduler.config.get("max_shift", 1.16),
)
scheduler_kwargs["mu"] =mu
elifmuisnotNone:
scheduler_kwargs["mu"] =mu
ifXLA_AVAILABLE:
timestep_device="cpu"
else:
timestep_device=device
timesteps, num_inference_steps=retrieve_timesteps(
self.scheduler, num_inference_steps, timestep_device, sigmas=sigmas, **scheduler_kwargs
)

Suggested fix:
Add the same mu argument, calculate_shift() logic, and scheduler_kwargs["mu"] handling used by the base SD3 pipelines before calling retrieve_timesteps().

Issue 3: Duplicate: controlnet_pooled_projections tensor path is broken

Affected code:

ifcontrolnet_config.force_zeros_for_pooled_projection:
# instantx sd3 controlnet used zero pooled projection
controlnet_pooled_projections=torch.zeros_like(pooled_prompt_embeds)
else:
controlnet_pooled_projections=controlnet_pooled_projectionsorpooled_prompt_embeds

ifcontrolnet_pooled_projectionsisNone:
controlnet_pooled_projections=torch.zeros_like(pooled_prompt_embeds)
else:
controlnet_pooled_projections=controlnet_pooled_projectionsorpooled_prompt_embeds

Problem:
This is already reported in open issue #9686. When a user passes a tensor for controlnet_pooled_projections, the code evaluates it with Python or, which raises RuntimeError: Boolean value of Tensor with more than one value is ambiguous.

Impact:
The public controlnet_pooled_projections argument cannot be used reliably, and SD3 ControlNet inference/training validation can diverge from the intended pooled-projection conditioning path.

Reproduction:

importtorchcontrolnet_pooled_projections=torch.ones(1, 8)
pooled_prompt_embeds=torch.zeros(1, 8)
controlnet_pooled_projections=controlnet_pooled_projectionsorpooled_prompt_embeds

Relevant precedent:
Existing duplicate: #9686

Suggested fix:

ifcontrolnet_config.force_zeros_for_pooled_projection:
controlnet_pooled_projections=torch.zeros_like(pooled_prompt_embeds)
elifcontrolnet_pooled_projectionsisNone:
controlnet_pooled_projections=pooled_prompt_embeds

Issue 4: SD3ControlNetModel.from_transformer() mutates the source transformer config

Affected code:

@classmethod
deffrom_transformer(
cls, transformer, num_layers=12, num_extra_conditioning_channels=1, load_weights_from_transformer=True
):
config=transformer.config
config["num_layers"] =num_layersorconfig.num_layers
config["extra_conditioning_channels"] =num_extra_conditioning_channels
controlnet=cls.from_config(config)

Problem:
config = transformer.config aliases the transformer's live config, then writes ControlNet-specific values into it. Duplicate search found no matching issue/PR.

Impact:
Calling from_transformer() silently changes transformer.config.num_layers and adds extra_conditioning_channels, which can corrupt later serialization, logging, or pipeline construction using the original transformer.

Reproduction:

fromdiffusersimportSD3ControlNetModel, SD3Transformer2DModeltransformer=SD3Transformer2DModel(
sample_size=4, patch_size=1, in_channels=4, out_channels=4, num_layers=3,
attention_head_dim=4, num_attention_heads=2, caption_projection_dim=8,
joint_attention_dim=8, pooled_projection_dim=8,
)
print(dict(transformer.config).get("num_layers"))
SD3ControlNetModel.from_transformer(transformer, num_layers=1, num_extra_conditioning_channels=2, load_weights_from_transformer=False)
print(dict(transformer.config).get("num_layers"), dict(transformer.config).get("extra_conditioning_channels"))

Relevant precedent:

config=dict(transformer.config)
config["num_layers"] =num_layers
config["num_single_layers"] =num_single_layers
config["attention_head_dim"] =attention_head_dim
config["num_attention_heads"] =num_attention_heads
controlnet=cls.from_config(config)

config=dict(transformer.config)
config["num_layers"] =num_layers
config["attention_head_dim"] =attention_head_dim
config["num_attention_heads"] =num_attention_heads
config["extra_condition_channels"] =extra_condition_channels
controlnet=cls.from_config(config)

Suggested fix:

config=dict(transformer.config)
config["num_layers"] =num_layersortransformer.config.num_layersconfig["extra_conditioning_channels"] =num_extra_conditioning_channelscontrolnet=cls.from_config(config)

Issue 5: ControlNet inpaint rejects documented IP-Adapter image embeds

Affected code:

ifip_adapter_image_embedsisnotNone:
ifnotisinstance(ip_adapter_image_embeds, list):
raiseValueError(
f"`ip_adapter_image_embeds` has to be of type `list` but is {type(ip_adapter_image_embeds)}"
)
elifip_adapter_image_embeds[0].ndimnotin [3, 4]:
raiseValueError(
f"`ip_adapter_image_embeds` has to be a list of 3D or 4D tensors but is {ip_adapter_image_embeds[0].ndim}D"

# Copied from diffusers.pipelines.stable_diffusion_3.pipeline_stable_diffusion_3.StableDiffusion3Pipeline.prepare_ip_adapter_image_embeds
defprepare_ip_adapter_image_embeds(
self,
ip_adapter_image: PipelineImageInput|None=None,
ip_adapter_image_embeds: torch.Tensor|None=None,
device: torch.device|None=None,
num_images_per_prompt: int=1,
do_classifier_free_guidance: bool=True,
) ->torch.Tensor:
"""Prepares image embeddings for use in the IP-Adapter.
Either `ip_adapter_image` or `ip_adapter_image_embeds` must be passed.
Args:
ip_adapter_image (`PipelineImageInput`, *optional*):
The input image to extract features from for IP-Adapter.
ip_adapter_image_embeds (`torch.Tensor`, *optional*):
Precomputed image embeddings.
device: (`torch.device`, *optional*):
Torch device.
num_images_per_prompt (`int`, defaults to 1):
Number of images that should be generated per prompt.
do_classifier_free_guidance (`bool`, defaults to True):
Whether to use classifier free guidance or not.
"""
device=deviceorself._execution_device
ifip_adapter_image_embedsisnotNone:
ifdo_classifier_free_guidance:
single_negative_image_embeds, single_image_embeds=ip_adapter_image_embeds.chunk(2)
else:
single_image_embeds=ip_adapter_image_embeds
elifip_adapter_imageisnotNone:
single_image_embeds=self.encode_image(ip_adapter_image, device)
ifdo_classifier_free_guidance:
single_negative_image_embeds=torch.zeros_like(single_image_embeds)
else:
raiseValueError("Neither `ip_adapter_image_embeds` or `ip_adapter_image_embeds` were provided.")
image_embeds=torch.cat([single_image_embeds] *num_images_per_prompt, dim=0)
ifdo_classifier_free_guidance:

ip_adapter_image_embeds (`torch.Tensor`, *optional*):
Pre-generated image embeddings for IP-Adapter. Should be a tensor of shape `(batch_size, num_images,
emb_dim)`. It should contain the negative image embedding if `do_classifier_free_guidance` is set to
`True`. If not provided, embeddings are computed from the `ip_adapter_image` input argument.

Problem:
The docstring and prepare_ip_adapter_image_embeds() path expect ip_adapter_image_embeds to be a tensor, but check_inputs() rejects tensors and requires a list. Duplicate search found no matching issue/PR.

Impact:
Users cannot pass precomputed IP-Adapter image embeddings to StableDiffusion3ControlNetInpaintingPipeline even though the public signature documents that path.

Reproduction:

importtorchfromdiffusersimportStableDiffusion3ControlNetInpaintingPipelinepipe=object.__new__(StableDiffusion3ControlNetInpaintingPipeline)
pipe.vae_scale_factor=1pipe.patch_size=1pipe._callback_tensor_inputs= ["latents"]
pipe.controlnet=object()
pipe.check_inputs(
height=8, width=8, image=torch.zeros(1, 3, 8, 8),
prompt=None, prompt_2=None, prompt_3=None,
prompt_embeds=torch.zeros(1, 2, 8),
pooled_prompt_embeds=torch.zeros(1, 8),
ip_adapter_image_embeds=torch.zeros(1, 2, 8),
control_guidance_start=[0.0], control_guidance_end=[1.0],
)

Relevant precedent:

ifip_adapter_image_embedsisnotNone:
ifdo_classifier_free_guidance:
single_negative_image_embeds, single_image_embeds=ip_adapter_image_embeds.chunk(2)
else:
single_image_embeds=ip_adapter_image_embeds
elifip_adapter_imageisnotNone:
single_image_embeds=self.encode_image(ip_adapter_image, device)
ifdo_classifier_free_guidance:
single_negative_image_embeds=torch.zeros_like(single_image_embeds)
else:
raiseValueError("Neither `ip_adapter_image_embeds` or `ip_adapter_image_embeds` were provided.")
image_embeds=torch.cat([single_image_embeds] *num_images_per_prompt, dim=0)
ifdo_classifier_free_guidance:
negative_image_embeds=torch.cat([single_negative_image_embeds] *num_images_per_prompt, dim=0)
image_embeds=torch.cat([negative_image_embeds, image_embeds], dim=0)
returnimage_embeds.to(device=device)

Suggested fix:

ifip_adapter_image_embedsisnotNoneandip_adapter_image_embeds.ndimnotin [3, 4]:
raiseValueError(
f"`ip_adapter_image_embeds` has to be a 3D or 4D tensor but is {ip_adapter_image_embeds.ndim}D"
)

Issue 6: Slow tests are missing for SD3 inpaint and SD3 ControlNet inpaint

Affected code:

classStableDiffusion3InpaintPipelineFastTests(PipelineLatentTesterMixin, unittest.TestCase, PipelineTesterMixin):
pipeline_class=StableDiffusion3InpaintPipeline
params=TEXT_GUIDED_IMAGE_INPAINTING_PARAMS
required_optional_params=PipelineTesterMixin.required_optional_params
batch_params=TEXT_GUIDED_IMAGE_INPAINTING_BATCH_PARAMS
image_params=frozenset(
[]
) # TO-DO: update image_params once pipeline is refactored with VaeImageProcessor.preprocess
image_latents_params=frozenset([])
callback_cfg_params=TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"mask", "masked_image_latents"})
defget_dummy_components(self):
torch.manual_seed(0)
transformer=SD3Transformer2DModel(
sample_size=32,
patch_size=1,
in_channels=16,
num_layers=1,
attention_head_dim=8,
num_attention_heads=4,
joint_attention_dim=32,
caption_projection_dim=32,
pooled_projection_dim=64,
out_channels=16,
)
clip_text_encoder_config=CLIPTextConfig(
bos_token_id=0,
eos_token_id=2,
hidden_size=32,
intermediate_size=37,
layer_norm_eps=1e-05,
num_attention_heads=4,
num_hidden_layers=5,
pad_token_id=1,
vocab_size=1000,
hidden_act="gelu",
projection_dim=32,
)
torch.manual_seed(0)
text_encoder=CLIPTextModelWithProjection(clip_text_encoder_config)
torch.manual_seed(0)
text_encoder_2=CLIPTextModelWithProjection(clip_text_encoder_config)
torch.manual_seed(0)
config=AutoConfig.from_pretrained("hf-internal-testing/tiny-random-t5")
text_encoder_3=T5EncoderModel(config)
tokenizer=CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")
tokenizer_2=CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")
tokenizer_3=AutoTokenizer.from_pretrained("hf-internal-testing/tiny-random-t5")
torch.manual_seed(0)
vae=AutoencoderKL(
sample_size=32,
in_channels=3,
out_channels=3,
block_out_channels=(4,),
layers_per_block=1,
latent_channels=16,
norm_num_groups=1,
use_quant_conv=False,
use_post_quant_conv=False,
shift_factor=0.0609,
scaling_factor=1.5035,
)
scheduler=FlowMatchEulerDiscreteScheduler()
return {
"scheduler": scheduler,
"text_encoder": text_encoder,
"text_encoder_2": text_encoder_2,
"text_encoder_3": text_encoder_3,
"tokenizer": tokenizer,
"tokenizer_2": tokenizer_2,
"tokenizer_3": tokenizer_3,
"transformer": transformer,
"vae": vae,
"image_encoder": None,
"feature_extractor": None,
}
defget_dummy_inputs(self, device, seed=0):
image=floats_tensor((1, 3, 32, 32), rng=random.Random(seed)).to(device)
mask_image=torch.ones((1, 1, 32, 32)).to(device)
ifstr(device).startswith("mps"):
generator=torch.manual_seed(seed)
else:
generator=torch.Generator(device="cpu").manual_seed(seed)
inputs= {
"prompt": "A painting of a squirrel eating a burger",
"image": image,
"mask_image": mask_image,
"height": 32,
"width": 32,
"generator": generator,
"num_inference_steps": 2,
"guidance_scale": 5.0,
"output_type": "np",
"strength": 0.8,
}
returninputs
deftest_inference(self):
components=self.get_dummy_components()
pipe=self.pipeline_class(**components)
inputs=self.get_dummy_inputs(torch_device)
image=pipe(**inputs).images[0]
generated_slice=image.flatten()
generated_slice=np.concatenate([generated_slice[:8], generated_slice[-8:]])
# fmt: off
expected_slice=np.array([0.5035, 0.6661, 0.5859, 0.413, 0.4224, 0.4234, 0.7181, 0.5062, 0.5183, 0.6877, 0.5074, 0.585, 0.6111, 0.5422, 0.5306, 0.5891])
# fmt: on
self.assertTrue(
np.allclose(generated_slice, expected_slice, atol=1e-3), "Output does not match expected slice."
)
@unittest.skip("Skip for now.")
deftest_multi_vae(self):
pass

classStableDiffusion3ControlInpaintNetPipelineFastTests(unittest.TestCase, PipelineTesterMixin):
pipeline_class=StableDiffusion3ControlNetInpaintingPipeline
params=frozenset(
[
"prompt",
"height",
"width",
"guidance_scale",
"negative_prompt",
"prompt_embeds",
"negative_prompt_embeds",
]
)
batch_params=frozenset(["prompt", "negative_prompt"])
defget_dummy_components(self):
torch.manual_seed(0)
transformer=SD3Transformer2DModel(
sample_size=32,
patch_size=1,
in_channels=8,
num_layers=4,
attention_head_dim=8,
num_attention_heads=4,
joint_attention_dim=32,
caption_projection_dim=32,
pooled_projection_dim=64,
out_channels=8,
)
torch.manual_seed(0)
controlnet=SD3ControlNetModel(
sample_size=32,
patch_size=1,
in_channels=8,
num_layers=1,
attention_head_dim=8,
num_attention_heads=4,
joint_attention_dim=32,
caption_projection_dim=32,
pooled_projection_dim=64,
out_channels=8,
extra_conditioning_channels=1,
)
clip_text_encoder_config=CLIPTextConfig(
bos_token_id=0,
eos_token_id=2,
hidden_size=32,
intermediate_size=37,
layer_norm_eps=1e-05,
num_attention_heads=4,
num_hidden_layers=5,
pad_token_id=1,
vocab_size=1000,
hidden_act="gelu",
projection_dim=32,
)
torch.manual_seed(0)
text_encoder=CLIPTextModelWithProjection(clip_text_encoder_config)
torch.manual_seed(0)
text_encoder_2=CLIPTextModelWithProjection(clip_text_encoder_config)
torch.manual_seed(0)
config=AutoConfig.from_pretrained("hf-internal-testing/tiny-random-t5")
text_encoder_3=T5EncoderModel(config)
tokenizer=CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")
tokenizer_2=CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")
tokenizer_3=AutoTokenizer.from_pretrained("hf-internal-testing/tiny-random-t5")
torch.manual_seed(0)
vae=AutoencoderKL(
sample_size=32,
in_channels=3,
out_channels=3,
block_out_channels=(4,),
layers_per_block=1,
latent_channels=8,
norm_num_groups=1,
use_quant_conv=False,
use_post_quant_conv=False,
shift_factor=0.0609,
scaling_factor=1.5035,
)
scheduler=FlowMatchEulerDiscreteScheduler()
return {
"scheduler": scheduler,
"text_encoder": text_encoder,
"text_encoder_2": text_encoder_2,
"text_encoder_3": text_encoder_3,
"tokenizer": tokenizer,
"tokenizer_2": tokenizer_2,
"tokenizer_3": tokenizer_3,
"transformer": transformer,
"vae": vae,
"controlnet": controlnet,
"image_encoder": None,
"feature_extractor": None,
}
defget_dummy_inputs(self, device, seed=0):
ifstr(device).startswith("mps"):
generator=torch.manual_seed(seed)
else:
generator=torch.Generator(device="cpu").manual_seed(seed)
control_image=randn_tensor(
(1, 3, 32, 32),
generator=generator,
device=torch.device(device),
dtype=torch.float16,
)
control_mask=randn_tensor(
(1, 1, 32, 32),
generator=generator,
device=torch.device(device),
dtype=torch.float16,
)
controlnet_conditioning_scale=0.95
inputs= {
"prompt": "A painting of a squirrel eating a burger",
"generator": generator,
"num_inference_steps": 2,
"guidance_scale": 7.0,
"output_type": "np",
"control_image": control_image,
"control_mask": control_mask,
"controlnet_conditioning_scale": controlnet_conditioning_scale,
}
returninputs
deftest_controlnet_inpaint_sd3(self):
components=self.get_dummy_components()
sd_pipe=StableDiffusion3ControlNetInpaintingPipeline(**components)
sd_pipe=sd_pipe.to(torch_device, dtype=torch.float16)
sd_pipe.set_progress_bar_config(disable=None)
inputs=self.get_dummy_inputs(torch_device)
output=sd_pipe(**inputs)
image=output.images
image_slice=image[0, -3:, -3:, -1]
assertimage.shape== (1, 32, 32, 3)
expected_slice=np.array(
[0.51708984, 0.7421875, 0.4580078, 0.6435547, 0.65625, 0.43603516, 0.5151367, 0.65722656, 0.60839844]
)
assertnp.abs(image_slice.flatten() -expected_slice).max() <1e-2, (
f"Expected: {expected_slice}, got: {image_slice.flatten()}"
)
@unittest.skip("xFormersAttnProcessor does not work with SD3 Joint Attention")
deftest_xformers_attention_forwardGenerator_pass(self):
pass

Problem:
Both files only define fast tests. The target family has slow coverage for SD3 text-to-image, SD3 img2img, and SD3 ControlNet, but not for the two inpaint variants. Duplicate search found no matching issue/PR.

Impact:
Real checkpoint behavior, offload behavior, VAE shift handling, and image/mask preprocessing are not covered for the inpaint variants. This gap would have allowed Issue 1 to remain invisible in CI.

Reproduction:

frompathlibimportPathforpathin [
Path("tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3_inpaint.py"),
Path("tests/pipelines/controlnet_sd3/test_controlnet_inpaint_sd3.py"),
]:
text=path.read_text()
print(path, "@slow"intext, "SlowTests"intext)

Relevant precedent:

@slow
@require_big_accelerator
classStableDiffusion3PipelineSlowTests(unittest.TestCase):
pipeline_class=StableDiffusion3Pipeline
repo_id="stabilityai/stable-diffusion-3-medium-diffusers"
defsetUp(self):
super().setUp()
gc.collect()

@slow
@require_big_accelerator
classStableDiffusion3Img2ImgPipelineSlowTests(unittest.TestCase):
pipeline_class=StableDiffusion3Img2ImgPipeline
repo_id="stabilityai/stable-diffusion-3-medium-diffusers"

@slow
@require_big_accelerator
classStableDiffusion3ControlNetPipelineSlowTests(unittest.TestCase):
pipeline_class=StableDiffusion3ControlNetPipeline
defsetUp(self):
super().setUp()
gc.collect()
backend_empty_cache(torch_device)
deftearDown(self):
super().tearDown()
gc.collect()
backend_empty_cache(torch_device)
deftest_canny(self):
controlnet=SD3ControlNetModel.from_pretrained("InstantX/SD3-Controlnet-Canny", torch_dtype=torch.float16)
pipe=StableDiffusion3ControlNetPipeline.from_pretrained(

Suggested fix:
Add @slow / @require_big_accelerator classes for StableDiffusion3InpaintPipeline and StableDiffusion3ControlNetInpaintingPipeline using real SD3-family checkpoints, CPU/GPU offload, and deterministic output-slice assertions.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions