diff --git a/python/sglang/multimodal_gen/configs/sample/sampling_params.py b/python/sglang/multimodal_gen/configs/sample/sampling_params.py index 61e08ac6a..b05fb62e9 100644 --- a/python/sglang/multimodal_gen/configs/sample/sampling_params.py +++ b/python/sglang/multimodal_gen/configs/sample/sampling_params.py @@ -138,7 +138,7 @@ class SamplingParams: return_trajectory_latents: bool = False # returns all latents for each timestep return_trajectory_decoded: bool = False # returns decoded latents for each timestep # if True, allow user params to override subclass-defined protected fields - override_protected_fields: bool = False + no_override_protected_fields: bool = True # whether to adjust num_frames for multi-GPU friendly splitting (default: True) adjust_frames: bool = True @@ -290,15 +290,6 @@ class SamplingParams: self._set_output_file_name() self.log(server_args=server_args) - def update(self, source_dict: dict[str, Any]) -> None: - for key, value in source_dict.items(): - if hasattr(self, key): - setattr(self, key, value) - else: - logger.exception("%s has no attribute %s", type(self).__name__, key) - - self.__post_init__() - @classmethod def from_pretrained(cls, model_path: str, **kwargs) -> "SamplingParams": from sglang.multimodal_gen.registry import get_model_info @@ -522,12 +513,11 @@ class SamplingParams: help="Whether to return the decoded trajectory", ) parser.add_argument( - "--override-protected-fields", + "--no-override-protected-fields", action="store_true", - default=SamplingParams.override_protected_fields, + default=SamplingParams.no_override_protected_fields, help=( - "If set, allow user params to override fields defined in subclasses " - "(protected by default)." + "If set, disallow user params to override fields defined in subclasses." ), ) parser.add_argument( @@ -583,32 +573,21 @@ class SamplingParams: subclass_defined_fields = set(type(self).__annotations__.keys()) # global switch: if True, allow overriding protected fields - allow_override_protected = bool( - user_params.override_protected_fields or self.override_protected_fields - ) - - # Compare against current instance to avoid constructing a default instance - default_params = SamplingParams() + allow_override_protected = not user_params.no_override_protected_fields for field in dataclasses.fields(user_params): field_name = field.name user_value = getattr(user_params, field_name) - default_value = getattr(default_params, field_name) + default_value = getattr(self, field_name) # A field is considered user-modified if its value is different from - # the default, with an exception for `output_file_name` which is - # auto-generated with a random component. - is_user_modified = ( - user_value != default_value - if field_name != "output_file_name" - else user_params.output_file_path is not None - ) + # the default + is_user_modified = user_value != default_value if is_user_modified and ( allow_override_protected or field_name not in subclass_defined_fields ): if hasattr(self, field_name): setattr(self, field_name, user_value) - self.height_not_provided = user_params.height_not_provided self.width_not_provided = user_params.width_not_provided self.__post_init__() diff --git a/python/sglang/multimodal_gen/runtime/entrypoints/cli/generate.py b/python/sglang/multimodal_gen/runtime/entrypoints/cli/generate.py index 9b4f8b591..2256eaebc 100644 --- a/python/sglang/multimodal_gen/runtime/entrypoints/cli/generate.py +++ b/python/sglang/multimodal_gen/runtime/entrypoints/cli/generate.py @@ -10,10 +10,7 @@ from typing import cast import sglang.multimodal_gen.envs as envs from sglang.multimodal_gen import DiffGenerator -from sglang.multimodal_gen.configs.sample.sampling_params import ( - SamplingParams, - generate_request_id, -) +from sglang.multimodal_gen.configs.sample.sampling_params import SamplingParams from sglang.multimodal_gen.runtime.entrypoints.cli.cli_types import CLISubcommand from sglang.multimodal_gen.runtime.entrypoints.cli.utils import ( RaiseNotImplementedAction, @@ -89,8 +86,7 @@ def maybe_dump_performance(args: argparse.Namespace, server_args, prompt: str, r def generate_cmd(args: argparse.Namespace): """The entry point for the generate command.""" - # FIXME(mick): do not hard code - args.request_id = generate_request_id() + args.request_id = "mocked_fake_id_for_offline_generate" # Auto-enable stage logging if dump path is provided if args.perf_dump_path: diff --git a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/denoising.py b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/denoising.py index ed2f7aab8..8bbdb3d89 100644 --- a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/denoising.py +++ b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/denoising.py @@ -297,6 +297,30 @@ class DenoisingStage(PipelineStage): return reserved_frames_mask_sp, z_sp + def _handle_boundary_ratio( + self, + server_args, + batch, + ): + """ + (Wan2.2) Calculate timestep to switch from high noise expert to low noise expert + """ + boundary_ratio = server_args.pipeline_config.dit_config.boundary_ratio + if batch.boundary_ratio is not None: + logger.info( + "Overriding boundary ratio from %s to %s", + boundary_ratio, + batch.boundary_ratio, + ) + boundary_ratio = batch.boundary_ratio + + if boundary_ratio is not None: + boundary_timestep = boundary_ratio * self.scheduler.num_train_timesteps + else: + boundary_timestep = None + + return boundary_timestep + def _prepare_denoising_loop(self, batch: Req, server_args: ServerArgs): """ Prepare all necessary invariant variables for the denoising loop. @@ -362,20 +386,7 @@ class DenoisingStage(PipelineStage): assert neg_prompt_embeds is not None # Removed Tensor truthiness assert to avoid GPU sync - # (Wan2.2) Calculate timestep to switch from high noise expert to low noise expert - boundary_ratio = server_args.pipeline_config.dit_config.boundary_ratio - if batch.boundary_ratio is not None: - logger.info( - "Overriding boundary ratio from %s to %s", - boundary_ratio, - batch.boundary_ratio, - ) - boundary_ratio = batch.boundary_ratio - - if boundary_ratio is not None: - boundary_timestep = boundary_ratio * self.scheduler.num_train_timesteps - else: - boundary_timestep = None + boundary_timestep = self._handle_boundary_ratio(server_args, batch) # specifically for Wan2_2_TI2V_5B_Config, not applicable for FastWan2_2_TI2V_5B_Config should_preprocess_for_wan_ti2v = ( diff --git a/python/sglang/multimodal_gen/test/server/testcase_configs.py b/python/sglang/multimodal_gen/test/server/testcase_configs.py index 75022e0b8..3e8ed441a 100644 --- a/python/sglang/multimodal_gen/test/server/testcase_configs.py +++ b/python/sglang/multimodal_gen/test/server/testcase_configs.py @@ -269,18 +269,19 @@ ONE_GPU_CASES_A: list[DiffusionTestCase] = [ ), ), # === Text and Image to Image (TI2I) === - # TODO: Timeout with Torch2.9. Add back when it can pass CI - # DiffusionTestCase( - # id="qwen_image_edit_ti2i", - # model_path="Qwen/Qwen-Image-Edit", - # modality="image", - # prompt=None, # not used for editing - # output_size="1024x1536", - # warmup_text=0, - # warmup_edit=1, - # edit_prompt="Convert 2D style to 3D style", - # image_path="https://github.com/lm-sys/lm-sys.github.io/releases/download/test/TI2I_Qwen_Image_Edit_Input.jpg", - # ), + DiffusionTestCase( + "qwen_image_edit_ti2i", + DiffusionServerArgs( + model_path="Qwen/Qwen-Image-Edit", + modality="image", + warmup_text=0, + warmup_edit=1, + ), + DiffusionSamplingParams( + prompt="Convert 2D style to 3D style", + image_path="https://github.com/lm-sys/lm-sys.github.io/releases/download/test/TI2I_Qwen_Image_Edit_Input.jpg", + ), + ), ] ONE_GPU_CASES_B: list[DiffusionTestCase] = [ diff --git a/python/sglang/multimodal_gen/test/slack_utils.py b/python/sglang/multimodal_gen/test/slack_utils.py index 7237c891a..706197be3 100644 --- a/python/sglang/multimodal_gen/test/slack_utils.py +++ b/python/sglang/multimodal_gen/test/slack_utils.py @@ -49,7 +49,7 @@ except Exception as e: def _get_status_message(run_id, current_case_id, thread_messages=None): date_str = datetime.now().strftime("%d/%m") - base_header = f""""*🧵 for nightly test of {date_str}* + base_header = f"""🧵 for nightly test of {date_str}* *Git Revision:* {get_git_commit_hash()} *GitHub Run ID:* {run_id} *Total Tasks:* {len(ALL_CASES)}