[diffusion] chore: auto-enable best parallel setting if unspecified (#22763)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,8 +130,8 @@ class ServerArgs:
|
||||
dp_size: int = 1
|
||||
# number of gpu in a dp group
|
||||
dp_degree: int = 1
|
||||
# cfg parallel
|
||||
enable_cfg_parallel: bool = False
|
||||
# cfg parallel (None = auto-decide based on num_gpus)
|
||||
enable_cfg_parallel: Optional[bool] = None
|
||||
|
||||
hsdp_replicate_dim: int = 1
|
||||
hsdp_shard_dim: Optional[int] = None
|
||||
@@ -428,6 +428,7 @@ class ServerArgs:
|
||||
sp_unspecified = self.sp_degree is None
|
||||
ulysses_unspecified = self.ulysses_degree is None
|
||||
ring_unspecified = self.ring_degree is None
|
||||
cfg_unspecified = self.enable_cfg_parallel is None
|
||||
|
||||
if self.hsdp_shard_dim is None:
|
||||
self.hsdp_shard_dim = self.num_gpus
|
||||
@@ -435,6 +436,30 @@ class ServerArgs:
|
||||
if self.tp_size is None:
|
||||
self.tp_size = 1
|
||||
|
||||
# Auto-enable CFG parallel when user hasn't set any parallelism flags
|
||||
# and there are enough GPUs. Only auto-enable for models whose default
|
||||
# SamplingParams use classifier-free guidance (negative_prompt is not None),
|
||||
# because non-CFG models (e.g. FLUX) crash when CFG parallel splits ranks.
|
||||
if cfg_unspecified:
|
||||
cfg_group_size = self.dp_size * self.tp_size * 2
|
||||
if (
|
||||
self.num_gpus >= 2
|
||||
and self.num_gpus % cfg_group_size == 0
|
||||
and sp_unspecified
|
||||
and ulysses_unspecified
|
||||
and ring_unspecified
|
||||
and self._model_default_uses_cfg()
|
||||
):
|
||||
self.enable_cfg_parallel = True
|
||||
logger.info(
|
||||
"Automatically enabled CFG parallel for %d GPUs. "
|
||||
"Use --sp-degree / --ulysses-degree to use sequence "
|
||||
"parallelism instead.",
|
||||
self.num_gpus,
|
||||
)
|
||||
else:
|
||||
self.enable_cfg_parallel = False
|
||||
|
||||
# adjust sp_degree: allocate all remaining GPUs after TP and DP
|
||||
if self.sp_degree is None:
|
||||
num_gpus_per_group = self.dp_size * self.tp_size
|
||||
@@ -466,6 +491,28 @@ class ServerArgs:
|
||||
self.ring_degree = 1
|
||||
logger.debug(f"Ring degree not set, using default value {self.ring_degree}")
|
||||
|
||||
def _model_default_uses_cfg(self) -> bool:
|
||||
"""
|
||||
Check whether the model uses classifier-free guidance by default.
|
||||
|
||||
CFG is active when *both* ``negative_prompt is not None`` and ``guidance_scale > 1``.
|
||||
"""
|
||||
from sglang.multimodal_gen.registry import get_model_info
|
||||
|
||||
model_info = get_model_info(self.model_path, self.backend, self.model_id)
|
||||
if model_info is None:
|
||||
return False
|
||||
default_params = model_info.sampling_param_cls()
|
||||
|
||||
# for ltx2.3, cfg-parallel performs worse than ulysses-sp
|
||||
is_ltx = "ltx" in type(default_params).__name__.lower()
|
||||
if is_ltx:
|
||||
return False
|
||||
return (
|
||||
getattr(default_params, "negative_prompt", None) is not None
|
||||
and getattr(default_params, "guidance_scale", 0) > 1.0
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _is_ltx23_model_path(model_path: str | None) -> bool:
|
||||
if not model_path:
|
||||
@@ -679,8 +726,8 @@ class ServerArgs:
|
||||
parser.add_argument(
|
||||
"--enable-cfg-parallel",
|
||||
action="store_true",
|
||||
default=ServerArgs.enable_cfg_parallel,
|
||||
help="Enable cfg parallel.",
|
||||
default=None,
|
||||
help="Enable cfg parallel. Auto-enabled when num_gpus >= 2 and no SP flags are set.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--data-parallel-size",
|
||||
|
||||
@@ -1655,7 +1655,8 @@
|
||||
},
|
||||
"expected_e2e_ms": 149864.99,
|
||||
"expected_avg_denoise_ms": 3608.89,
|
||||
"expected_median_denoise_ms": 2400.38
|
||||
"expected_median_denoise_ms": 2400.38,
|
||||
"estimated_full_test_time_s": 253.9
|
||||
},
|
||||
"wan2_1_t2v_14b_2gpu": {
|
||||
"stages_ms": {
|
||||
|
||||
@@ -154,7 +154,9 @@ def diffusion_server(case: DiffusionTestCase) -> ServerContext:
|
||||
# pipeline class. This avoids hard failures when a model needs a
|
||||
# newer diffusers release than what is currently installed in CI.
|
||||
msg = str(exc)
|
||||
if "not found in diffusers" in msg or "has no attribute" in msg:
|
||||
if "not found in diffusers" in msg or (
|
||||
"has no attribute" in msg and "diffusers" in msg.lower()
|
||||
):
|
||||
pytest.skip(
|
||||
f"Skipping {case.id}: required diffusers pipeline class "
|
||||
f"is not available in the installed version. "
|
||||
|
||||
@@ -808,6 +808,7 @@ TWO_GPU_CASES_A = [
|
||||
modality="video",
|
||||
custom_validator="video",
|
||||
num_gpus=2,
|
||||
extras=["--ulysses-degree=2"],
|
||||
),
|
||||
T2V_sampling_params,
|
||||
),
|
||||
@@ -821,6 +822,7 @@ TWO_GPU_CASES_A = [
|
||||
modality="video",
|
||||
custom_validator="video",
|
||||
num_gpus=2,
|
||||
extras=["--ulysses-degree=2"],
|
||||
),
|
||||
DiffusionSamplingParams(
|
||||
prompt=T2V_PROMPT,
|
||||
@@ -912,7 +914,7 @@ TWO_GPU_CASES_A = [
|
||||
model_path="Lightricks/LTX-2",
|
||||
modality="video",
|
||||
num_gpus=2,
|
||||
extras=["--pipeline-class-name LTX2TwoStagePipeline"],
|
||||
extras=["--pipeline-class-name LTX2TwoStagePipeline", "--ulysses-degree=2"],
|
||||
),
|
||||
T2V_sampling_params,
|
||||
),
|
||||
@@ -936,6 +938,7 @@ TWO_GPU_CASES_B = [
|
||||
modality="video",
|
||||
custom_validator="video",
|
||||
num_gpus=2,
|
||||
extras=["--ulysses-degree=2"],
|
||||
),
|
||||
TI2V_sampling_params,
|
||||
),
|
||||
@@ -958,6 +961,7 @@ TWO_GPU_CASES_B = [
|
||||
custom_validator="video",
|
||||
num_gpus=2,
|
||||
lora_path="starsfriday/Wan2.1-Divine-Power-LoRA",
|
||||
extras=["--ulysses-degree=2"],
|
||||
),
|
||||
TI2V_sampling_params,
|
||||
run_lora_basic_api_check=True,
|
||||
@@ -969,6 +973,7 @@ TWO_GPU_CASES_B = [
|
||||
modality="video",
|
||||
custom_validator="video",
|
||||
num_gpus=2,
|
||||
extras=["--ulysses-degree=2"],
|
||||
),
|
||||
TI2V_sampling_params,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user