From ee106757df4c8de4fce3f28667562cb329d3ea61 Mon Sep 17 00:00:00 2001 From: Junhao Liu Date: Tue, 17 Mar 2026 01:10:46 -0700 Subject: [PATCH] [diffusion] fix: fix Diffusers backend ignores model-specific sampling parameter (#20080) Co-authored-by: Mick --- python/sglang/multimodal_gen/registry.py | 4 +++- .../runtime/pipelines/diffusers_pipeline.py | 20 +++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/python/sglang/multimodal_gen/registry.py b/python/sglang/multimodal_gen/registry.py index a8e810a68..1b1f57ec5 100644 --- a/python/sglang/multimodal_gen/registry.py +++ b/python/sglang/multimodal_gen/registry.py @@ -360,12 +360,14 @@ def _get_diffusers_model_info( DiffusersPipeline, ) + sampling_param_cls = DiffusersGenericSamplingParams pipeline_config_cls = DiffusersGenericPipelineConfig # If there is a registered native config for this model, inherit its task_type if model_path is not None: config_info = _get_config_info(model_path, model_id=model_id) if config_info is not None: + sampling_param_cls = config_info.sampling_param_cls native_task_type = config_info.pipeline_config_cls.task_type if native_task_type != DiffusersGenericPipelineConfig.task_type: pipeline_config_cls = dataclasses.make_dataclass( @@ -386,7 +388,7 @@ def _get_diffusers_model_info( return ModelInfo( pipeline_cls=DiffusersPipeline, - sampling_param_cls=DiffusersGenericSamplingParams, + sampling_param_cls=sampling_param_cls, pipeline_config_cls=pipeline_config_cls, ) diff --git a/python/sglang/multimodal_gen/runtime/pipelines/diffusers_pipeline.py b/python/sglang/multimodal_gen/runtime/pipelines/diffusers_pipeline.py index 6a7d0446a..b0c5ea8ee 100644 --- a/python/sglang/multimodal_gen/runtime/pipelines/diffusers_pipeline.py +++ b/python/sglang/multimodal_gen/runtime/pipelines/diffusers_pipeline.py @@ -288,7 +288,7 @@ class DiffusersExecutionStage(PipelineStage): if batch.generator is not None: kwargs["generator"] = batch.generator elif batch.seed is not None: - device = self._get_pipeline_device() + device = self._get_generator_device(batch) kwargs["generator"] = torch.Generator(device=device).manual_seed(batch.seed) # Image input for img2img or inpainting @@ -307,15 +307,15 @@ class DiffusersExecutionStage(PipelineStage): return kwargs - def _get_pipeline_device(self) -> str: - """Get the device the pipeline is running on.""" - for attr in ["unet", "transformer", "vae"]: - component = getattr(self.diffusers_pipe, attr, None) - if component is not None: - try: - return str(next(component.parameters()).device) - except StopIteration: - pass + def _get_generator_device(self, batch: Req) -> str: + """Resolve RNG device consistently with the non-diffusers path. + + Diffusers CPU offload can temporarily park modules on CPU, but that + should not silently switch a CUDA request to CPU RNG, otherwise the + same seed produces different outputs depending on runtime placement. + """ + if batch.generator_device == "cpu": + return "cpu" return current_platform.device_type def _load_input_image(self, batch: Req) -> Image.Image | None: