feat(pytorch): add glm5.3-flash support - #4968
qescccczmr wants to merge 46 commits into
Conversation
Reuse MLA/MoE loaders, FA3, mHC, sparse Top-K and compact DeepGEMM. Add KDA state adaptation and multimodal GLM configuration/processing. Preserve existing defaults and the positional MoE prefix argument.
| device=device, | ||
| is_tp=True, | ||
| quant_config=None, | ||
| dp_disable_tp=True, |
There was a problem hiding this comment.
Keep KV-B sharding consistent with the attention TP group
When dp > 1 and attn_tp > 1, dp_disable_tp=True makes kv_b_proj retain all attention heads, while DeepseekV2BMM still shards kc/vc by attn_tp. The inherited process_weights_after_loading() then copies the full KV-B-derived weights directly into these sharded tensors.
There was a problem hiding this comment.
Fixed in 3fcabb7. Removed dp_disable_tp=True from GLM's KV-B projection so it uses the existing attention-TP sharding and weight loader, consistent with DeepseekV2BMM KC/VC absorption.
The focused CPU test exercises the real builder/loader/absorption in nine DP/TP/rank combinations and checks the exact local weight slices. This is loader-contract validation, not an EP+DP distributed-service validation; the unrelated EP+DP experiments are not included.
|
@qescccczmr Hi, is this PR ready to review? |
| from .step_metadata import register_step_metadata_impl | ||
|
|
||
|
|
||
| def _select_state(state: torch.Tensor, metadata: Any) -> torch.Tensor: |
There was a problem hiding this comment.
can we use existing _state_select , _state_scatter in here?
There was a problem hiding this comment.
Addressed in 3fcabb7. KDA now reuses the existing GDN _state_select / _state_scatter helpers for both AR and MTP. The ordinary AR bank is exposed as a one-slot ring, rather than introducing another state kernel.
The shared helpers mask invalid state/slot IDs: reads return zero and writes are skipped, preventing padded rows from overwriting a live request. Actual CUDA tests cover FP32/BF16, irregular shapes, negative/out-of-range IDs, initialization, dummy/live-row collisions, and replay after updating graph inputs.
| head_dim: int, | ||
| lower_bound: float, | ||
| ) -> torch.Tensor: | ||
| if (metadata.spec_state_offsets is not None |
There was a problem hiding this comment.
mtp may need support as well
There was a problem hiding this comment.
Updated in 3fcabb7. KDA restores state using accepted history and saves every verified token's convolution/recurrent checkpoint, including partial rejection, reordering and dummy rows. MTP now also honors index_share_for_mtp_iteration through the existing DSATopKIndicesBuffer; cache updates still run on every draft step. Growing the shared buffer changes the graph key so old allocations are not replayed.
We also found and fixed a sampling-distribution bug: rejection/recovery did not apply AR's top-k/top-p/min-p filters. The fix reuses FusedLogitsProcessor filtering, preserves greedy fast-path behavior, and leaves source logits intact. Focused CUDA tests verify that filtered-out tokens cannot be accepted or recovered.
| Mode | LMDeploy | vLLM |
|---|---|---|
| Greedy, fixed 256 tokens | 62.9341% | 62.7595% |
| Sampling, fixed 256 tokens | 54.7305% | 53.5599% |
| Greedy, natural EOS (max 256) | 62.4700% | 61.5550% |
| Sampling, natural EOS (max 256) | 56.9082% | 57.5145% |
H200, TP4/EP1, CUDA Graph on, prefix cache off, BF16 KV, BS1, 1024-token prefill chunks. Inputs: 20 GSM8K prompts plus four 8436-token long prompts, each run under all four policies; sampling uses temperature=1, top_p=0.95, seed=42 and disabled top-k. Stop IDs/minimum lengths are matched.
| inputs = [x.unflatten(1, (batch_size, steps)) | ||
| for x in (mixed_qkv, raw_gate, raw_beta)] | ||
| outputs = [] | ||
| for step in range(steps): |
There was a problem hiding this comment.
this may lead to poor performance. If fla does not provide this verification kernel, we may need to change the tilelang kernel of gated_delta_rule.
There was a problem hiding this comment.
Agreed; addressed in 3fcabb7 without a new kernel file. The existing GDN TileLang recurrent kernel's transposed-state path now supports KDA channelwise decay. Convolution windows are batched through FLA, then all verification tokens use one recurrent-kernel call. The kernel is parallel across batch/head/state tiles; causally dependent timesteps remain sequential inside that call, and each state is checkpointed for partial acceptance. The default GDN scalar-gate path is preserved.
Fresh CUDA regressions cover scalar/channelwise gates, AR versus multi-token state equality, dummy rows, graph replay and the original GDN tests. An earlier module-only CUDA Graph benchmark (3 verification tokens, 8 heads, head dim 128) measured 0.190/0.247/0.349 ms for the serial reference versus 0.057/0.059/0.065 ms for the shared path at BS1/4/16. This is KDA-local evidence, not a whole-model or vLLM performance-parity claim.
Reuse GDN state helpers and channelwise TileLang verification; honor MTP index sharing and invalidate graphs after buffer growth. Share AR sampling filters with rejection/recovery and stabilize GLM TP/mHC and sparse-index arithmetic. Keep EP/DP, prefix-cache and performance experiments outside this patch.
|
@RunningLeon The MTP correctness/reuse changes are ready for another review in 3fcabb7. I am keeping this PR in Draft while whole-model accuracy/performance validation remains incomplete. This update modifies 11 existing production files, with no new production module/kernel. It addresses the four review comments: attention-TP KV-B sharding, shared state helpers, accepted-history MTP state recovery, and reuse of GDN's TileLang verification kernel. It also fixes rejection sampling's missing AR filters, MTP index sharing and graph-buffer growth, and includes the GLM opt-in FP32 TP / mHC / stable sparse-index changes used for AR/MTP numerical stability. Existing defaults for other model callers are preserved. EP+DP, prefix-cache, FlashInfer communication and compact-MoE scheduling experiments are excluded. |
| config.state_cache_specs = [ | ||
| StateCacheSpec( | ||
| GLM5_KDA_CONV_STATE, | ||
| (num_linear_layers, *ring_shape, conv_dim, conv_kernel_size), |
There was a problem hiding this comment.
this layout could the be the same as Qwen3.5 and reuse the causal conv kernel when mtp is on.
lmdeploy/lmdeploy/pytorch/configurations/qwen3_5.py
Lines 65 to 66 in af4ad9b
There was a problem hiding this comment.
Updated in 41563c7.
The convolution cache now uses (num_linear_layers, conv_dim, conv_kernel_size + num_spec_tokens), matching Qwen3.5. MTP decode calls the existing causal_conv1d_update with accepted-history cache_seqlens and request state indices. This removes the per-draft convolution-window checkpoints; recurrent/KPool checkpoints remain unchanged. For kernel width 4 and MTP5, convolution-state storage drops from 24 to 9 elements per channel.
The shared kernel now accepts the actual weight/bias dtype, preserving GLM's FP32 convolution weights with BF16 activations. Prefill retains FLA's existing short-chunk handling and maps its chronological window into the compact token ring.
Validation on the isolated patch: 59 CPU checks passed; the CUDA-enabled regression run passed 75 checks, including MTP2/MTP5 partial-acceptance recovery (bit-exact against sequential AR in the tested KDA cases), request reordering/padding, and CUDA Graph replay. The 24 upstream optional Dao-reference cases were skipped because that dependency is unavailable; six additional independent FP16/BF16/FP32 non-circular convolution checks passed. Ruff and git diff --check also passed. These are local operator/contract checks, not a fresh whole-model acceptance or performance benchmark.
| prefix: str = '', | ||
| *, | ||
| fp32_acc: bool = False, | ||
| output_scale: float = 1.0, |
There was a problem hiding this comment.
[P1] Honor or explicitly reject the new MoE options across backend branches
build_fused_moe() now exposes fp32_acc and output_scale, but only the blocked-FP8 branch forwards them. The BF16 and W8A8 branches silently ignore these arguments, so the same public API has different numerical semantics depending on the selected backend.
This causes a concrete correctness issue for GLM’s BF16 path: the router returns unscaled weights and relies on output_scale=2.5 in the expert reduction. Dropping that argument produces an incorrectly scaled routed-expert contribution.
Please propagate these options through supported implementations, preserving the FP32 weighted reduction → output scaling → output cast order. For implementations that do not support this contract yet, explicitly reject non-default values rather than silently ignoring them. Keep False / 1.0 as defaults to preserve existing behavior, and add regression tests for parameter propagation, numerical correctness, and unsupported-backend rejection.
The scale must apply only to the routed-expert contribution, not to the shared-expert output.
There was a problem hiding this comment.
Fixed in
96423321.
- The BF16 fused-MoE path now forwards
fp32_accandoutput_scalethrough its build spec and applies them in the CUDA reduction as FP32 weighted reduction → scale → output cast.- The scale is applied inside the routed-expert reduction, before the caller combines the result with the shared expert output.
- W8A8, static-FP8, W4A16, and DeepEP branches now explicitly reject non-default values instead of silently ignoring them.
- Added propagation, unsupported-backend, and CUDA numerical regression tests in
tests/pytorch/nn/test_moe_options.py.Validation:
pytest -q tests/pytorch/nn/test_moe_options.py(4 passed, 1 CUDA test skipped because CUDA is unavailable in this environment); Ruff and compile checks pass.
|
|
||
|
|
||
| @torch.compile(dynamic=True) | ||
| def apply_rotary_pos_emb_fp32(query: Tensor, |
There was a problem hiding this comment.
does glm5.3 need to do this on fp32?
| return out.to(result_dtype) | ||
|
|
||
|
|
||
| class FP32LayerNorm(nn.Module): |
There was a problem hiding this comment.
Where do we use this module?
| layer_idx: int | ||
| output_dtype: torch.dtype | ||
| num_max_dispatch_tokens_per_rank: int | ||
| fp32_acc: bool = False |
There was a problem hiding this comment.
consider dlinfer backend for these two arguments
|
|
||
| # Model-specific defaults that must be present before the distributed | ||
| # process group is initialized. Explicit process environment values win. | ||
| process_group_env_defaults: dict[str, str] = field(default_factory=dict) |
Reject unsupported DLINFER MoE reduction options instead of ignoring them. Leave NCCL NVLS policy to the runtime and remove model-specific environment plumbing. Document GLM FP32 operator usage and cover dtype, reduction, and environment contracts. Validation: 110 focused tests passed on CPU/H200; Ruff passed for lmdeploy and tests/pytorch. DLINFER rejection regressions failed before the fix and pass afterward.
Apply the configured string and docstring formatters to GLM PR files. Verified executable AST is unchanged; both previously failing hooks and Ruff pass locally.
Propagate GLM activation and routed scaling through DeepEP prefill and decode. Use FP32 local expert reduction for non-default output scaling while preserving the default BF16 path and transport. Avoid reducing combined experts twice and keep shared experts unscaled. Pad sparse FlashMLA indices with invalid entries for its tile alignment and accept the current DeepGEMM masked-GEMM symbol.
Use an FP32 accumulator in ep_gather independently of the output dtype, matching vLLM's DeepGEMM unpermute-and-reduce. Store the result directly as BF16 for DeepEP combine, removing the FP32 output buffer and separate cast from GLM's normal path. Remove the private fp32_acc plumbing from the blocked-FP8 DeepEP builder and normal execution paths. Preserve activation callbacks, FP32 scaled routing weights, and the existing low-latency combine implementation. The shared gather now uses FP32 for other callers, including BF16 experts. Validation: 16 H200 kernel cases matched vLLM 606d124b and the previous FP32-output-then-cast path exactly; covered BF16/FP16, top-k 1/8, scales 1/2.5, missing experts, row strides, and more than 1024 tokens. CUDA graph replay and cancellation regression passed. Ruff 0.15.4, Python compile, and git diff --check passed. Full-model/multi-rank inference not rerun.
Restore fp32_acc=False plumbing through the DeepEP Normal builder and both execution entry points. Pass the flag into ep_gather as a Triton constexpr so default callers retain output-dtype accumulation while GLM's scaled routed-expert path explicitly uses FP32. Keep the BF16 gather output and cast inside the kernel, avoiding the previous FP32 temporary and separate output cast. Preserve activation callbacks, routing-weight scaling and the low-latency combine path. Validation: 16 H200 cases matched legacy accumulation with the default and explicit False, and vLLM/previous GLM FP32 results with True. CUDA graph replay, cancellation, builder/sync/async parameter propagation, Ruff 0.15.4, Python compile and git diff --check passed. Full-model and multi-rank inference were not rerun.
…opt-in Restore moe_reduce's positional/keyword fp32_acc=False argument and the legacy weighted-product precision for default callers. Keep output_scale keyword-only and apply it after expert reduction before the output cast. GLM explicitly sets fused_moe_fp32_acc=True. Propagate it through the shared model, builder, typed specs, BF16/blocked-FP8 backends and kernels. DeepEP Normal uses this flag independently of routing scale. Reject unsupported non-default requests instead of silently dropping them. Restore compressed_tensors_w4a16.py exactly to main: its existing explicit FP32 calls are compatible again. The PR now changes 65 files, with no new production or test files introduced by this update. Validation: 22 focused H200/CPU checks passed, including exact legacy and previous GLM reduction parity, positional/keyword API compatibility, FP32 scaling, CUDA graph replay, parameter propagation, unsupported backend rejection and actual BF16/blocked-FP8 expert pipelines. Ruff and git diff --check passed. Full-model and distributed inference not rerun.
Compile the FP32 input conversion for contiguous HC inputs with at least 8192 token rows. Preserve the existing FP32 GEMM and RMS statistics, rounding boundaries, and short-request execution path. H200 TP4/BS1/MTP5, output 5, 30 paired requests: 8K TTFT falls from 446.23 to 433.35 ms and total latency from 475.91 to 462.68 ms (2.78%). Full-model generated tokens and captured logits remain bitwise equal. 28 numeric/CUDA Graph checks pass; 2K shows no established speedup.
Batch KDA gate projections through the linear backend while preserving checkpoint loaders, TP shards and the original LoRA path. Reuse MTP key/score projections, fuse raw token-cache indexing, and share target KPool metadata within each eager or captured forward. Prepare the next mHC FP32 input in post-expand after the original BF16 rounding boundary. Keep FP32 GEMM, normalization and TP reductions intact. Validation: full-model 2K/8K token and logits parity; ragged/rejection cache replay; TP1/4/8 and DP4/EP4 loading; real LoRA TP4 checks; existing HC tests; paired serving A/B and separate four-rank Torch Profiler.
Summary
Add GLM-5.3 Flash text/image/video support to the PyTorch engine, including MTP and combined data/expert parallelism. Extend existing LMDeploy components for model loading, hybrid cache layout, multimodal preprocessing, and CUDA Graph execution.
HcPrePost, sparse-index Top-K, and blocked-FP8 MoE. GLM sparse attention uses the common FlashMLA backend.Optimizations
Measured optimization gains
H200, TP4/EP1/DP1, BS1, MTP5, BF16 KV, output 5 tokens, unless specified. Serving timing excludes active profiling. Speedup = before/after; reduction = (before−after)/before. Each stage has its own control; gains are not additive or multiplicative.
End-to-end staged measurements
19307597): 3 warmup +30 measured pairs, 8K TTFT/total improve in 30/30 pairs; paired 95% intervals are [−14.90,−11.38]/[−14.36,−11.65] ms. No established 2K or TPOT gain.932285b0plus the already validated f_a/g_a merge and MTP projection reuse. Three warmup +30 measured pairs, alternating order, separate captured graphs. TPOT paired 95% intervals are [−0.822,−0.246] ms (2K) and [−0.527,−0.373] ms (8K); both total-latency intervals also exclude zero. TTFT intervals cross zero.The earlier TP stack at
ec2ec448matches the preceding LMDeploy path on generated token IDs and 96 full-vocabulary logits tensor pairs (24,161,280 elements; max error 0). TP/LoRA loading, ragged cache/rejection, changed-input graph replay, and existing HC tests pass. This is implementation parity, not a new full task-accuracy run.Cumulative Q/K-length metadata fusion passes exact full-model logits (102 tensors / 25,090,560 values) and generated-token checks, but paired TPOT 95% intervals cross zero: [−0.116,+0.103] ms / [−0.130,+0.037] ms. It is excluded from the final stack; no new production files or source changes are retained.
DP/EP staged rows use input 2048, output 1024, global concurrency 32, 8 H200s, TP1/DP8/EP8, BF16 KV and FP32 recurrent state:
ec2ec448→ed1eea00, 32 warmup + 256 measured requests per K and revision. These are sequential fresh-service measurements, not paired confidence intervals. The dominant gain is masked activation/quantization; the additional KPool-copy removal changed mean TPOT by only 0.42% / 1.63% / 0.34% for K=1/3/5, so its small serving effect is not statistically established. K=5 throughput fell 0.93% in that incremental run.Optional prefill CUDA graphs:
209a7552→b2665817, same 64 warmup + 256 measured requests per K. These three rows are fresh-service comparisons. A separate controlled K=5 experiment (six alternating pairs, 64 requests/arm/pair; 384/arm) measured 9.495 → 9.028 ms mean TPOT; mean paired reduction 4.92%, paired bootstrap 95% interval [3.29%, 6.56%], all six pairs improved. Burst throughput was variable (pooled −0.35%); a repeatable throughput gain is not established by that paired experiment. The paired experiment uses the same 2048-row path; the final revision additionally keeps partial buckets eager to preserve BF16 projection rounding. Paired burst metrics and the independent final serving table are different experiments.Operator-level gains
Isolated GPU measurements; these are not whole-model serving speedups. Historical and newer controls are separate experiments.
The valid-aware path still checkpoints every valid token; B1/S6 shows no gain. The new projection/mHC microbenchmarks preserve numerical outputs. Separate full-model Torch Profiler attribution records 34 fewer target-verification kernels for batched gates and 89 fewer for mHC preparation; their timings are not added to serving gains.
The split-K prototype preserves selected KV and FP32 partial reduction, passes operator references/strided-cache/graph tests, but changes unconstrained 2K generation. Fixed-history target/draft logits reach max errors 2.2734 / 1.6932 (2K/8K); target verification alone reaches 1.53125. It is not enabled, and no end-to-end speedup is claimed. This also shows that removing head padding alone is insufficient.
The mHC row-count microbenchmarks preserve the original BF16 rounding before producing the FP32 input for the next HC projection; seven alternating timing pairs per shape, CUDA Graph replay, TF32 disabled. The DeepEP microbenchmarks use 36 local experts, intermediate width 2048, and padded expert rows 512/1024/1536; valid-row counts are fixed and recorded. The KPool microbenchmarks use 8/16/24 rows, 929,984 score columns and 768 valid groups. These isolate wasted work; neither predicts the serving speedup. Removing the score copy does not bound DeepGEMM’s underlying decode-logits allocation.
Capacity improvement: bounded KPool scoring
KPool reuses the configurable DSA score budget, flattens KV once, selects deterministic Top-K per query chunk, and reserves score workspace explicitly. The payload limit includes DeepGEMM alignment; it is not a bound on all allocator memory. Full-model 128K/256K requests completed with identical selected indices. This is a capacity fix, not a latency claim.
FlashKDA and the four-way KDA input merge remain excluded after numerical failures. One-warp recurrence and explicit prefill-copy removal showed no benefit; native-head FA3 lacks a validated LMDeploy backend. FP32 reduction semantics are unchanged.
LMDeploy vs vLLM
Tensor parallel: TP4 / EP1 / DP1
Retained TP reference (2026-09-30): LMDeploy
ec2ec448; vLLM606d124b. This table predates the additional DP/EP optimizations below; it is not a fresh TP benchmark of the new head. Cumulative Q/K-length metadata fusion and native-head sparse MLA remain excluded for unconfirmed serving gains and failed numerical checks, respectively. Both services were restarted and run sequentially on the same four H200 GPUs (4–7), checkpoint and prompt manifest, using the unmodified vLLM streaming HTTP client. vLLM follows the official Hopper recipe.TP4/EP1/DP1, BS1, MTP5 on both engines, BF16 KV, FP32 recurrent-state buffers, 5 output tokens, max batch 16, prefill chunk 2048, session length 270336, prefix cache off, greedy/seed 42. 3 warmups + 30 measured requests per input/engine; independent medians. Profiling was inactive during these measurements.
This replaces the previous chunk=8192 table; it is a configuration rerun, not a new optimization gain. The 8K input now requires four prefill chunks in both traces. Historical staged A/B and operator gains above keep their original controls. Neither input establishes a TPOT win over vLLM in this rerun.
TPOT = (last SSE choices response − first SSE choices response)/(5−1). Each median is computed independently. The client includes LMDeploy’s final empty-text finish response; in the diagnostic captures this adds 1.03–1.22 ms to the response window (0.26–0.30 ms to TPOT). MTP can return multiple tokens per SSE event. These are short-output serving metrics, not single-forward GPU latency, steady-state throughput or token-parity results. The same prompt does not always produce identical text across engines; vLLM’s 8K captures also differ in acceptance/outputs.
LMDeploy uses FP32 NCCL/FLA, with FlashInfer/symmetric-memory all-reduce and FlashKDA off; vLLM retains native backends. Memory budgets retain their native meanings: LMDeploy free-memory fraction 0.8; vLLM total-memory utilization 0.9.
Native API-server launch commands
Use the matching installed environments and the FP8 checkpoint at revision
3f1971b7b5f7a528c9c4ef6212c8785298a8c24a. Run the two services sequentially. These commands start the services; BS1, greedy sampling andmax_tokens=5are client request settings.LMDeploy CLI
MODEL=/path/to/GLM-5.3-Flash CUDA_VISIBLE_DEVICES=4,5,6,7 NCCL_NVLS_ENABLE=0 FLA_FLASH_KDA=0 \ LMDEPLOY_ENABLE_FLASHINFER_ALLREDUCE=0 \ LMDEPLOY_ENABLE_SYMM_MEM_ALLREDUCE=0 \ lmdeploy serve api_server "$MODEL" \ --backend pytorch --tp 4 --ep 1 --dp 1 \ --dtype bfloat16 --quant-policy 0 \ --max-batch-size 16 --session-len 270336 \ --max-prefill-token-num 2048 --cache-max-entry-count 0.8 \ --distributed-executor-backend ray \ --speculative-algorithm deepseek_mtp --speculative-num-draft-tokens 5 \ --model-name glm53 --server-name 127.0.0.1 --server-port 23982 \ --trust-remote-code --log-level INFOBF16 KV follows
dtype=bfloat16with KV quantization disabled; GLM’s recurrent-state allocation is FP32. The local measured environment also used a DeepGEMM masked-GEMM compatibility alias and propagated backend/profile environment variables to Ray workers; ensure a compatible DeepGEMM build and consistent worker environments when reproducing.vLLM CLI
vLLM uses its default DP1 and no expert-parallel enable flag (EP1). Leave the profiler inactive for timing. CPU+CUDA captures below were collected separately, after all formal requests.
Torch Profiler / Perfetto: TP decode windows
Separate CPU+CUDA diagnostic captures, rank 0 / trial 0 consistently. Actual Perfetto screenshots below. Client timestamps are overlaid after capture:
decode_windowDuration / 4 = TPOT for 5 output tokens. Native CPU forward scopes and GPU verification spans are different measurements; profiled values do not replace the unprofiled table.2,048-token input: LMDeploy and vLLM decode windows
LMDeploy
vLLM
8,192-token input: LMDeploy and vLLM decode windows
LMDeploy
vLLM
Four-rank traces, measured client overlays and source hashes are recorded in the screenshots and SQL provenance.
Data and expert parallel: DP8 / EP8 / TP1
2026-09-30, LMDeploy
b2665817; vLLM606d124b. Eight H200 GPUs, identical checkpoint and fixed ShareGPT-derived input IDs: 2048 input / 1024 output tokens / global concurrency 32. K is the number of MTP draft tokens (1/3/5); verification can contain K+1 tokens. BF16 KV, FP32 recurrent state, max batch 32 per rank, prefill chunk 2048 per rank, session length 8192, prefix caching off, greedy/seed42 and ignore-EOS for a fixed output length.Fresh native-CLI reruns use 64 warmup + 256/256 successful measured requests, four concurrent client workers per DP rank. The unmodified vLLM HTTP streaming client supplies timing; active profiling is excluded. LMDeploy uses native DeepEP Normal for globally mixed/prefill steps and Low Latency for global decode; vLLM explicitly uses
deepep_low_latency. This is an engine comparison, not an isolated communication-backend A/B.Mean TPOT remains 10.68% / 4.91% / 5.71% higher than vLLM for K=1/3/5; parity has not been reached. Acceptance = accepted/proposed draft tokens; mean accepted length = 1 + accepted/draft iterations. TPOT uses the first-to-last SSE response interval divided by 1023; ITL is SSE-event spacing, since MTP may emit several tokens per event. The original screenshot’s prompt manifest was unavailable, so this verifies its stated configuration rather than claiming identical acceptance values.
Latest LMDeploy measurements enable all retained optimizations together, including mHC FP32 preparation up to 32 rows and optional prefill CUDA graphs (
--piecewise-cudagraph-max-tokens 2048). LMDeploy was freshly restarted for every K; vLLM retains the preceding native-CLI reference with the same 64-warmup protocol, checkpoint, input manifest and workload. Earlier DP/EP staged rows used 32 warmups. The final LMDeploy P99 TPOT values are 19.690 / 17.249 / 20.627 ms for K=1/3/5.Native API-server commands. Use each engine’s tested environment and installed source revision. Run engines sequentially; set
K=1,3or5. The LMDeploy CLI starts eight rank APIs on ports 24100–24107 automatically; the benchmark sends four streams to each rank. vLLM uses one public API and theX-data-parallel-rankheader to preserve the same distribution.NVSHMEM_REMOTE_TRANSPORT=noneis for this single-node NVLink run. vLLM uses a compatible DeepEP V1 build (567632d); LMDeploy uses its existingc997a4ebuild. Memory fractions have engine-specific meanings (LMDeploy 0.8 of free memory; vLLM 0.9 of total).Accuracy
MMMU-Pro vision/test
LMDeploy is +0.1720 percentage points from the 76.88% reference. Both engines finish with 0 request errors and 0 remaining length stops.
Protocol: all 1,730 vision/test items from dataset revision
563f3e84bb3b90893083a1f039cfa13077f2302b; original image bytes; identical image-first prompts; pinned NeMo prompt and answer-extraction helpers (778f31a). Temperature 1.0, top_p 0.95, top_k disabled, maximum 327,680 new tokens, seed 42, reasoning effort max. TP4/EP1/DP1/MTP5, client concurrency 8, maximum batch 16, session length 344,064, prefill chunk 8,192; LMDeploy uses NCCL. Both backends use FP8 checkpoint3f1971b7b5f7a528c9c4ef6212c8785298a8c24aon disjoint groups of four H200 GPUs.NCCL_NVLS_ENABLE=0is an explicit benchmark setting for both.The 76.88% reference is a BF16 baseline reported in the NVIDIA GLM-5.3 Flash model card. This FP8 evaluation is not an exact reproduction of that baseline or its unpublished harness details.
Final scores include one fresh-service retry of the single LMDeploy length-stopped item, using the same sampling parameters and 327,680-token output cap. All length-selected replacements are retained regardless of correctness; incorrect answers alone do not trigger retries.
GPQA Diamond and SciCode
Evaluated revision: the scores below were measured on frozen LMDeploy commit
38779f12. The PR has since advanced to18a8c917, including MoE-reduction changes. This table does not include a full-model accuracy rerun of those later commits.Same GLM-5.3 Flash FP8 checkpoint as above; LMDeploy
38779f12, vLLM606d124b. Both run TP4/EP1/DP1/MTP5 on separate four-H200 groups. LMDeploy uses NCCL; FlashInfer/symmetric-memory all-reduce is disabled. Temperature 1.0, top_p 0.95, top_k disabled, repetition penalty 1, seed 42, reasoning effort max, one sample per item. Client concurrency 8, maximum batch 16, BF16 KV, FP32 recurrent state, prefix caching off, prefill chunk 8,192,NCCL_NVLS_ENABLE=0.Generation starts with a 327,680-token output limit and context 393,216. Length-stopped items are retried once at 655,360 output tokens and context 720,896; SciCode also regenerates their dependent downstream steps. The table includes every selected replacement, regardless of whether it improves the score. Incorrect answers alone do not trigger retries.
SciCode evaluation fix: restore the published
Maxwell,Block, andEnlargedBlockclass definitions omitted by the pinned helper, then regenerate all 14 dependent subproblems for both engines. The final scores above include these corrected runs. No numerical assertion or tolerance was changed.GPQA uses all 198 Diamond questions, frozen zero-shot prompts/option permutations validated against the source answers, and the pinned NeMo MCQ extractor. Cross-engine prompt-token count differences: 0 / 198.
SciCode uses all 65 test problems with background, 288 scored subproblems, and the three official prefilled steps excluded from the scored denominator. Main score requires every scored subproblem in that problem to pass. Each next prompt uses that engine’s previous generated code. Dataset revision; NeMo prompt/generation helpers. Original numerical assertions run in an isolated Python 3.11 environment with NumPy 1.26.4, SciPy 1.10.1, SymPy 1.12, h5py 3.11.0; 1,800-second per-step timeout, one BLAS thread, Python/NumPy execution seed 42. Development-reference validation passed 48/50: 70.8 and 78.3 also fail using the original SciCode helpers (large-phase numerical mismatch and wall-clock-dependent trajectory shape respectively). These are development cases; no test case was excluded and no scoring tolerance was relaxed
GSM8K
TP4/MTP5, client concurrency 32, greedy, maximum 2,048 output tokens, identical prompt token IDs and parser. Errors and length stops remain in the denominator; explicit final answers are scored even at a length stop. Score proximity does not establish token parity or absence of regression.