Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion docs/cookbook/diffusion/SenseNova/SenseNova-U1.5-8B-MoT.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,29 @@ in one batch must use the same resolution, inference steps, guidance settings,
and output options. Requests with multiple outputs or `think_mode=true` are
executed sequentially.

### 5.2 Ascend NPU optimizations
### 5.2 CFG parallelism on two GPUs

With classifier-free guidance enabled (the default `guidance_scale` is 4.0),
every denoising step runs a conditional and an unconditional forward pass.
`--enable-cfg-parallel` places one branch on each of two GPUs, so each GPU runs
one forward pass per step and the two exchange the predicted velocity. The
image is bit-identical to the single-GPU result.

```bash Command
sglang serve \
--model-path sensenova/SenseNova-U1.5-8B-MoT \
--port 30000 \
--num-gpus 2 \
--enable-cfg-parallel
```

Each GPU holds a full copy of the weights. Requests with `guidance_scale` 1 have
a single branch, which both GPUs compute. SenseNova-U1 does not support tensor,
sequence or data parallelism yet, so `--num-gpus 2` requires
`--enable-cfg-parallel`. CFG parallelism works with `think_mode`, but not yet
with dynamic request batching (`--batching-max-size` greater than 1).

### 5.3 Ascend NPU optimizations

On Ascend NPU, SenseNova-U1 automatically uses fused inference attention,
RMSNorm, and SwiGLU MLP operators for supported inputs. FIA and SwiGLU fall back
Expand Down Expand Up @@ -172,6 +194,21 @@ first use.
------------------------------------------------------------
```
</Tab>
<Tab title="NVIDIA H200 CFG parallel">

Environment: two NVIDIA H200 GPUs connected by NVLink; workload: the
Section 3.1 `sglang generate` command (2048 x 2048, 50 denoising steps,
CFG 4, seed 42) with `--warmup-mode request`; repetitions: 2 per row, both
within 0.03 s; latency: the warmed-up request time.

| GPUs | Extra flags | Latency (s) | Speedup | Peak reserved memory on GPU 0 (MB) |
|---:|---|---:|---:|---:|
| 1 | | 16.26 | 1.00x | 36446 |
| 2 | `--num-gpus 2 --enable-cfg-parallel` | 8.32 | 1.95x | 35606 |

Both configurations produce byte-identical PNG files.

</Tab>
<Tab title="Ascend 910C">

Environment: one Ascend 910C; workload: four concurrent 2048 x 2048
Expand Down
14 changes: 10 additions & 4 deletions docs/src/snippets/configs/SenseNova/sensenova-u15.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ export const config = (() => {
})[s.checkpoint || "default"];
const plan = (s) => {
const flags = ["--model-path " + modelOf(s), ...["--port {{PORT}}"]];
let gpus = 1;
const gpus = Number(s.gpus_per_node);
let t = { tp_size: 1, ulysses_degree: 1, ring_degree: 1 };
const env = [];
const warnings = [];
const errors = [];
if (s.batching === "on") flags.push("--batching-max-size 2", "--batching-delay-ms 100");
if (gpus === 2) {
flags.push("--num-gpus 2", "--enable-cfg-parallel");
warnings.push(
"CFG parallelism runs one guidance branch per GPU; requests with guidance_scale 1 compute the same branch on both GPUs.",
);
if (s.batching === "on") errors.push("Dynamic batching does not support CFG parallelism yet; use one GPU.");
} else if (s.batching === "on") flags.push("--batching-max-size 2", "--batching-delay-ms 100");
return { flags, gpus, topology: t, env, warnings, errors };
};
const defaults = {
Expand Down Expand Up @@ -44,7 +50,7 @@ export const config = (() => {
commandBuilder: {
defaultSelection: defaults,
resource: {
limits: { nodes: { min: 1, max: 1 }, gpus_per_node: { min: 1, max: 1 } },
limits: { nodes: { min: 1, max: 1 }, gpus_per_node: { min: 1, max: 2 } },
verifiedRecipes: ["cuda"].map((hw) => {
const s = { ...defaults, hw };
const p = plan(s);
Expand All @@ -64,7 +70,7 @@ export const config = (() => {
if (!config.supportedHardware.includes(s.hw)) errors.push("Choose a listed hardware platform.");
if (Number(s.nodes) !== 1) errors.push("This recipe covers one node.");
const count = Number(s.gpus_per_node);
if (!Number.isInteger(count) || count < 1 || count > 1)
if (!Number.isInteger(count) || count < 1 || count > 2)
errors.push("Choose an integer GPU count within the documented limits.");
if (Number(s.gpus_per_node) !== p.gpus) errors.push("This recipe requires " + p.gpus + " GPUs / node.");
if (["tp_size", "ulysses_degree", "ring_degree"].some((key) => Number(t[key]) !== p.topology[key]))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,32 @@ def _component_residency_requests_offload(value) -> bool:
return False


def validate_sensenova_u1_parallelism(server_args) -> None:
# ServerArgs rejects CFG parallel on one GPU, so one GPU needs no more checks.
if server_args.num_gpus == 1:
return
if not (
server_args.num_gpus == 2
and server_args.enable_cfg_parallel
and server_args.cfg_parallel_degree == 2
and server_args.tp_size == 1
and server_args.sp_degree == 1
and server_args.dp_size == 1
):
raise ValueError(
"SenseNovaU1Pipeline supports num_gpus=1, or num_gpus=2 with "
"--enable-cfg-parallel (one CFG branch per GPU). Native tensor, "
"sequence and data parallelism are not implemented yet."
)
# Each rank times the batching delay on its own clock, so the two CFG
# ranks can dispatch different batches and deadlock in a collective.
if server_args.batching_max_size > 1:
raise ValueError(
"SenseNovaU1Pipeline does not support dynamic batching "
"(--batching-max-size > 1) with --enable-cfg-parallel yet."
)


def _set_compatible_runtime_defaults(server_args) -> None:
compatible_defaults = {
"component_residency": None,
Expand Down Expand Up @@ -80,7 +106,6 @@ class SenseNovaU1PipelineConfig(PipelineConfig):
task_type: ModelTaskType = ModelTaskType.T2I
model_precision: str = "bf16"
should_use_guidance: bool = True
supports_cfg_parallel: bool = False

def supports_dynamic_batching(self):
return True
Expand Down Expand Up @@ -108,11 +133,7 @@ def supports_sequential_multi_output_inference(self):
return True

def validate_server_args(self, server_args) -> None:
if server_args.num_gpus != 1:
raise ValueError(
"SenseNovaU1Pipeline currently supports num_gpus=1. "
"Native tensor/pipeline parallelism is not implemented yet."
)
validate_sensenova_u1_parallelism(server_args)
if getattr(server_args, "enable_torch_compile", False):
raise ValueError(
"SenseNovaU1Pipeline does not support torch.compile yet. "
Expand Down Expand Up @@ -193,7 +214,6 @@ def get_model_deployment_config(self) -> ModelDeploymentConfig:
speed_mode_enable_torch_compile_by_default=False,
keep_resident_min_available_gb=80,
auto_enable_cfg_parallel=False,
supports_cfg_parallel=False,
)


Expand Down
5 changes: 5 additions & 0 deletions python/sglang/multimodal_gen/configs/sample/sensenova_u1.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ def get_cli_args(cls, args):
if key in _PUBLIC_OVERRIDE_FIELDS
}

def should_use_classifier_free_guidance(self) -> bool:
# The model builds its own empty-prompt unconditional branch, so CFG
# depends on the guidance scale alone, not on negative_prompt.
return self.guidance_scale > 1.0

def __post_init__(self) -> None:
if isinstance(self.cfg_interval, list):
self.cfg_interval = tuple(float(x) for x in self.cfg_interval)
Expand Down
Loading
Loading