[diffusion] refactor: deprecate workloadtype (#15267)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
parent
5529ab5895
commit
c0f9b51992
@@ -19,6 +19,7 @@ from sglang.multimodal_gen.configs.models import (
|
||||
VAEConfig,
|
||||
)
|
||||
from sglang.multimodal_gen.configs.models.encoders import BaseEncoderOutput
|
||||
from sglang.multimodal_gen.configs.sample.sampling_params import DataType
|
||||
from sglang.multimodal_gen.configs.utils import update_config_from_args
|
||||
from sglang.multimodal_gen.runtime.distributed import (
|
||||
get_sp_parallel_rank,
|
||||
@@ -36,17 +37,42 @@ from sglang.multimodal_gen.utils import (
|
||||
logger = init_logger(__name__)
|
||||
|
||||
|
||||
# NOTE: possible duplication with DataType, WorkloadType
|
||||
# NOTE: possible duplication with DataType
|
||||
# this may focus on the model's original ability
|
||||
class ModelTaskType(Enum):
|
||||
# TODO: check if I2V/TI2V models can work w/wo text
|
||||
|
||||
I2V = auto() # Image to Video
|
||||
T2V = auto() # Text to Video
|
||||
TI2V = auto() # Text and Image to Video
|
||||
|
||||
T2I = auto() # Text to Image
|
||||
I2I = auto() # Image to Image
|
||||
TI2I = auto() # Image to Image or Text-Image to Image
|
||||
|
||||
def is_image_gen(self):
|
||||
return self == ModelTaskType.T2I or self == ModelTaskType.I2I
|
||||
def is_image_gen(self) -> bool:
|
||||
return (
|
||||
self == ModelTaskType.T2I
|
||||
or self == ModelTaskType.I2I
|
||||
or self == ModelTaskType.TI2I
|
||||
)
|
||||
|
||||
def requires_image_input(self) -> bool:
|
||||
return self == ModelTaskType.I2V or self == ModelTaskType.I2I
|
||||
|
||||
def accepts_image_input(self) -> bool:
|
||||
return (
|
||||
self == ModelTaskType.I2V
|
||||
or self == ModelTaskType.I2I
|
||||
or self == ModelTaskType.TI2I
|
||||
or self == ModelTaskType.TI2V
|
||||
)
|
||||
|
||||
def data_type(self) -> DataType:
|
||||
if self.is_image_gen():
|
||||
return DataType.IMAGE
|
||||
else:
|
||||
return DataType.VIDEO
|
||||
|
||||
|
||||
class STA_Mode(str, Enum):
|
||||
@@ -121,6 +147,9 @@ class PipelineConfig:
|
||||
model_path: str = ""
|
||||
pipeline_config_path: str | None = None
|
||||
|
||||
# precision and autocast
|
||||
enable_autocast: bool = True
|
||||
|
||||
# generation parameters
|
||||
# controls the timestep embedding generation
|
||||
should_use_guidance: bool = True
|
||||
@@ -651,11 +680,12 @@ class ImagePipelineConfig(PipelineConfig):
|
||||
sp_world_size, rank_in_sp_group = get_sp_world_size(), get_sp_parallel_rank()
|
||||
seq_len = latents.shape[1]
|
||||
|
||||
# TODO: reuse code in PipelineConfig::shard_latents_for_sp
|
||||
# Pad to next multiple of SP degree if needed
|
||||
if seq_len % sp_world_size != 0:
|
||||
pad_len = sp_world_size - (seq_len % sp_world_size)
|
||||
pad = torch.zeros(
|
||||
(latents.shape[0], pad_len, latents.shape[2]),
|
||||
(*latents.shape[:1], pad_len, *latents.shape[2:]),
|
||||
dtype=latents.dtype,
|
||||
device=latents.device,
|
||||
)
|
||||
|
||||
@@ -53,6 +53,8 @@ class FluxPipelineConfig(ImagePipelineConfig):
|
||||
# VAE
|
||||
vae_config: VAEConfig = field(default_factory=FluxVAEConfig)
|
||||
|
||||
enable_autocast: bool = False
|
||||
|
||||
# Text encoding stage
|
||||
text_encoder_configs: tuple[EncoderConfig, ...] = field(
|
||||
default_factory=lambda: (CLIPTextConfig(), T5Config())
|
||||
@@ -405,7 +407,7 @@ def flux2_pack_latents(latents):
|
||||
class Flux2PipelineConfig(FluxPipelineConfig):
|
||||
embedded_cfg_scale: float = 4.0
|
||||
|
||||
task_type: ModelTaskType = ModelTaskType.I2I
|
||||
task_type: ModelTaskType = ModelTaskType.TI2I
|
||||
|
||||
text_encoder_precisions: tuple[str, ...] = field(default_factory=lambda: ("bf16",))
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@ class QwenImagePipelineConfig(ImagePipelineConfig):
|
||||
# VAE
|
||||
vae_config: VAEConfig = field(default_factory=QwenImageVAEConfig)
|
||||
|
||||
enable_autocast: bool = False
|
||||
|
||||
# Text encoding stage
|
||||
text_encoder_configs: tuple[EncoderConfig, ...] = field(
|
||||
default_factory=lambda: (Qwen2_5VLConfig(),)
|
||||
|
||||
@@ -16,7 +16,6 @@ from dataclasses import dataclass
|
||||
from enum import Enum, auto
|
||||
from typing import Any
|
||||
|
||||
from sglang.multimodal_gen.runtime.server_args import ServerArgs
|
||||
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
||||
from sglang.multimodal_gen.utils import StoreBoolean, align_to
|
||||
|
||||
@@ -195,33 +194,55 @@ class SamplingParams:
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
assert self.num_frames >= 1
|
||||
self.data_type = DataType.VIDEO if self.num_frames > 1 else DataType.IMAGE
|
||||
|
||||
if self.width is None:
|
||||
self.width_not_provided = True
|
||||
if self.height is None:
|
||||
self.height_not_provided = True
|
||||
|
||||
self._validate()
|
||||
|
||||
# Allow env var to override num_inference_steps (for faster CI testing on AMD)
|
||||
env_steps = os.environ.get("SGLANG_TEST_NUM_INFERENCE_STEPS")
|
||||
if env_steps is not None and self.num_inference_steps is not None:
|
||||
self.num_inference_steps = int(env_steps)
|
||||
|
||||
def _validate(self):
|
||||
"""
|
||||
check if the sampling params is correct by itself
|
||||
"""
|
||||
if self.prompt_path and not self.prompt_path.endswith(".txt"):
|
||||
raise ValueError("prompt_path must be a txt file")
|
||||
|
||||
def check_sampling_param(self):
|
||||
if self.prompt_path and not self.prompt_path.endswith(".txt"):
|
||||
raise ValueError("prompt_path must be a txt file")
|
||||
|
||||
def _validate_with_pipeline_config(self, pipeline_config):
|
||||
"""
|
||||
check if the sampling params is compatible and valid with server_args
|
||||
"""
|
||||
if pipeline_config.task_type.requires_image_input():
|
||||
# requires image input
|
||||
if self.image_path is None:
|
||||
raise ValueError(
|
||||
f"Served model with task type '{pipeline_config.task_type.name}' requires an 'image_path' input, but none was provided"
|
||||
)
|
||||
|
||||
def _adjust(
|
||||
self,
|
||||
server_args: ServerArgs,
|
||||
server_args,
|
||||
):
|
||||
"""
|
||||
final adjustment, called after merged with user params
|
||||
"""
|
||||
# TODO: SamplingParams should not rely on ServerArgs
|
||||
pipeline_config = server_args.pipeline_config
|
||||
if not isinstance(self.prompt, str):
|
||||
raise TypeError(f"`prompt` must be a string, but got {type(self.prompt)}")
|
||||
|
||||
self.data_type = server_args.pipeline_config.task_type.data_type()
|
||||
|
||||
# Process negative prompt
|
||||
if self.negative_prompt is not None and not self.negative_prompt.isspace():
|
||||
# avoid stripping default negative prompt: ' ' for qwen-image
|
||||
@@ -260,7 +281,6 @@ class SamplingParams:
|
||||
# settle num_frames
|
||||
logger.debug(f"num_frames set to 1 for image generation model")
|
||||
self.num_frames = 1
|
||||
self.data_type = DataType.IMAGE
|
||||
elif self.adjust_frames:
|
||||
# NOTE: We must apply adjust_num_frames BEFORE the SP alignment logic below.
|
||||
# If we apply it after, adjust_num_frames might modify the frame count
|
||||
@@ -320,7 +340,7 @@ class SamplingParams:
|
||||
self.num_frames = new_num_frames
|
||||
|
||||
self._set_output_file_name()
|
||||
self.log(server_args=server_args)
|
||||
self.log(pipeline_config=server_args.pipeline_config)
|
||||
|
||||
@classmethod
|
||||
def from_pretrained(cls, model_path: str, **kwargs) -> "SamplingParams":
|
||||
@@ -339,6 +359,8 @@ class SamplingParams:
|
||||
sampling_params._merge_with_user_params(user_sampling_params)
|
||||
sampling_params._adjust(server_args)
|
||||
|
||||
sampling_params._validate_with_pipeline_config(server_args.pipeline_config)
|
||||
|
||||
return sampling_params
|
||||
|
||||
def output_size_str(self) -> str:
|
||||
@@ -658,7 +680,7 @@ class SamplingParams:
|
||||
def output_file_path(self):
|
||||
return os.path.join(self.output_path, self.output_file_name)
|
||||
|
||||
def log(self, server_args: ServerArgs):
|
||||
def log(self, pipeline_config):
|
||||
# TODO: in some cases (e.g., TI2I), height and weight might be undecided at this moment
|
||||
if self.height:
|
||||
target_height = align_to(self.height, 16)
|
||||
@@ -680,9 +702,9 @@ class SamplingParams:
|
||||
infer_steps: {self.num_inference_steps}
|
||||
num_outputs_per_prompt: {self.num_outputs_per_prompt}
|
||||
guidance_scale: {self.guidance_scale}
|
||||
embedded_guidance_scale: {server_args.pipeline_config.embedded_cfg_scale}
|
||||
embedded_guidance_scale: {pipeline_config.embedded_cfg_scale}
|
||||
n_tokens: {self.n_tokens}
|
||||
flow_shift: {server_args.pipeline_config.flow_shift}
|
||||
flow_shift: {pipeline_config.flow_shift}
|
||||
image_path: {self.image_path}
|
||||
save_output: {self.save_output}
|
||||
output_file_path: {self.output_file_path()}
|
||||
|
||||
Reference in New Issue
Block a user