Skip to content

[2026春季][T2-1-3] surprisely#498

Open
surprisely wants to merge 13 commits into
InfiniTensor:mainfrom
surprisely:2026-spring-surprisely-T2-1-3
Open

[2026春季][T2-1-3] surprisely#498
surprisely wants to merge 13 commits into
InfiniTensor:mainfrom
surprisely:2026-spring-surprisely-T2-1-3

Conversation

@surprisely

Copy link
Copy Markdown

摘要

  • 新增 auto|legacy|fused MoE 后端策略;auto 仅对受支持的 CUDA、FP16/BF16、非量化 Qwen3-MoE 选择 Fused MoE。
  • max_batch_size 贯通到 Paged CUDA Graph compiler,只捕获 scheduler 可达 batch,并稀疏化高 batch Graph;未捕获 shape 保留 eager fallback。
  • 为高并发 Qwen3-MoE 设置 4096-token prefill admission 默认值,降低激活峰值和 OOM 风险。
  • 普通 packed prefill 仅投影每个请求的末位 logits;非量化 Qwen3-MoE 的 LM head 按 TP rank 切分词表,并为 raw/non-greedy 调用保留完整 logits。
  • 非量化 Qwen3-MoE 的 CUDA Graph replay 跳过无状态 module-tree reset;其他模型保留原 reset 语义;cache 重配置后按新容量重建 Graph bucket。
  • 新增 7 个策略边界测试、公开 CLI/API 文档与 scripts/run_qwen3_moe_contest.sh 一键复现入口。

动机

Qwen3-30B-A3B-Thinking-2507 在 4×RTX 4090D、BF16、TP=4 的多并发/长文本服务中,主要受 Graph capture 常驻显存、packed-prefill 激活峰值和重复/全位置词表投影限制。未修改上游在 c64 长点会出现大量 server timeout。

服务端均为 InfiniLM,客户端均为 vLLM 0.9.2 openai-chatrequest-rate=inf。同点使用相同模型、TP、tokenizer、目标长度和 KV 容量;c64 短点使用 128 blocks,c64 长点使用 120 blocks 与 4096-token prefill budget。

未修改上游使用在 4×24 GiB 上可运行的 Paged eager,优化侧使用 Fused MoE + Paged Attention + device CUDA Graph。以下是端到端可服务栈对比,不冒充任一新增补丁的独立收益。

并发 / 输入 / 输出 上游输出 tok/s 优化输出 tok/s 上游总 tok/s 优化总 tok/s
1 / 32 / 256 24.48 116.25 27.45 130.84
64 / 32 / 256 36.29 1860.27 40.83 2093.00
64 / 256 / 1024 31.71 586.13 48.05 732.45

优化值均来自最终 HEAD 4a44bd3、seed 714 的 vLLM 0.9.2 openai-chat 重跑;c64 长点为三次运行的中位数,三次 output throughput 为 592.49 / 586.13 / 576.82 tok/s。c64 长点上游与优化侧实际输入均为 16335 tokens;优化侧三次均为 64/64 达到至少 1000 输出 tokens,上游仅 20/64 达到该长度,其余 44 个因 server timeout 提前结束。因此长点不视为等输出 token 数的延迟对比。

保留补丁的隔离结果:

  • max_batch_size 裁剪 Graph:b1/in32/out256 稳态延迟降低 3.87%,初始化降低 38.35%,峰值显存减少 2276~2284 MiB/GPU。
  • Last-token LM head:b1/in4096/out256 从 OOM 变为稳定运行,device Graph median 为 3396.78 ms。
  • Vocab-parallel LM head:三个配对点分别降低 5.09% / 3.64% / 6.76%,峰值显存减少 340~348 MiB/GPU。
  • Qwen3-MoE non-quant reset gate:三个配对点分别降低 2.54% / 1.04% / 2.58%。

变更类型

  • feat — 新增功能/API
  • fix — cache 重配置后重建 Graph bucket
  • perf — 性能优化
  • refactor — 仅重构
  • test — 新增测试
  • docs — 更新文档
  • build / ci
  • chore
  • Breaking change

涉及模型在支持平台上的测试结果

smoke c64long

smoke 截图展示最终 HEAD 的真模型正确性验证;c64long截图展示一次现场复测,输出吞吐为 602.42 tok/s、总吞吐为
752.75 tok/s。上方性能主表采用此前三次最终 HEAD 复测的中位数 586.13 tok/s 和 732.45 tok/s,两者测试配置一致,但不是同一条运行记录。

平台 模型 / 配置 结果
4×NVIDIA RTX 4090D,CUDA 12.8 Qwen3-30B-A3B-Thinking-2507,BF16,TP=4,Paged Attention + device CUDA Graph PASS:构建/import、7/7 策略测试、auto -> fused、真模型 smoke
同上 Paged Graph vs eager PASS:保存的 c64 结果 64/64 output IDs exact;b4 与跨 KV block 检查通过
同上 vLLM 0.9.2 赛题风格 HTTP burst PASS:c1 短点、c64 短点、c64 长点成功;超时和输出达标情况如上披露
其他 NVIDIA GPU / CUDA 版本 未测试 无对应硬件,不外推性能数据
CPU 及其他硬件后端 未测试 无对应硬件,不声称性能支持

性能影响与测试口径

  • 模型:Qwen3-30B-A3B-Thinking-2507,BF16,128 experts,top-8。
  • 硬件:4×RTX 4090D(24 GiB/卡),PCIe 4.0,TP=4,无 NVLink/P2P。
  • 客户端:vLLM 0.9.2 只负责随机请求、OpenAI Chat HTTP transport 和指标计算;推理服务端为 InfiniLM。
  • workload:request-rate=infnum-prompts=max-concurrency,seed 714;c1/c64 短点为最终 HEAD 单次值,c64 长点为最终 HEAD 三次中位数。
  • KV 容量:c64/in32/out256 为 128 blocks;c64/in256/out1024 为 120 blocks + 4096-token prefill budget;上游与优化侧同点一致。
  • 生成 token 数来自 vLLM benchmark JSON,超时与达标状态分开披露。

评审说明

  • InfiniCore 无源码改动。Fused MoE、Paged Attention 和 CUDA Graph 是框架原有能力,本 PR 不将其表述为新增 kernel。
  • moe_backend=auto 保留显式 Legacy override,仅对 CUDA FP16/BF16、非量化 qwen3_moe 选择 fused。
  • Vocab-parallel 本地 logits 仅用于受支持的 distributed-greedy 生成;raw logits、非 greedy、speculative/all-position、其他模型、TP=1 和量化模型均保留完整 logits。
  • Host 侧读取 packed input_offsets 前检查 CPU residency,避免解引用 device 地址。
  • Paged Graph 捕获 1~16、16 以上的 8 的倍数以及配置的最大 batch;其他 high-batch shape 使用原有 eager fallback。
  • GPTQ/AWQ 不纳入本 PR 性能结论;自动策略对量化模型回退 Legacy。
  • 完整参考资源、独立修改边界和开源协议见 REFERENCE.md

CI / ChatOps

创建 PR 后手动触发 Actions CI,或请维护者使用 /retest


提交前检查

标题、分支与提交

  • PR 标题使用赛事规定格式:[2026春季][T2-1-3] surprisely
  • 分支名使用赛事规定格式:2026-spring-surprisely-T2-1-3
  • 13 个提交均使用 Conventional Commits,可独立审查。
  • 分支基于最新 upstream/main,无 merge commit、fixup!squash!wip
  • N/A:赛事标题/分支格式优先于通用 PR 模板中的 Conventional Commit 标题和 <type>/... 分支规则。

范围与代码质量

  • 改动限于 Qwen3-MoE 服务策略、Graph 容量、LM-head/logits 路径、cache 重配置、测试和相关文档。
  • 无纯调试输出、profiling hook、注释掉的代码块或无归属 TODO。
  • 公开 API/CLI 已记录并有策略测试。
  • 修改文件保留单个行尾换行,git diff --check 通过。
  • 代码注释和错误消息使用英文。

C++ / Python

  • 未引入原始内存分配、未初始化读取或无边界检查的 host pointer 访问。
  • python scripts/format.py --ref upstream/main --check 和 Ruff 检查通过。
  • 未修改 csrc/models/llama_legacy/python/infinilm/auto_config.py
  • 新增 Python docstring 符合 PEP 257。

测试、构建与文档

  • 在 NVIDIA RTX 4090D 上从空构建目录完成编译、安装和 import。
  • examples/test_infer.py 等价单请求真模型 smoke 通过。
  • test/llm/test_moe_policy.py:7/7 通过。
  • N/A:未在最终 cleanup HEAD 重跑 examples/bench.pytest/bench/test_benchmark.py;本 PR 的性能口径为赛题参考的 vLLM HTTP 服务 benchmark。
  • N/A:未使用 scripts/test_perf.py;使用赛题参考的 vLLM 0.9.2 客户端。
  • README 已记录 --moe-backend=auto|legacy|fused,无 breaking change。
  • 创建 PR 后触发 CI 或请求 /retest

安全与合规

  • 仓库不含密码、token、内部 URL、私有服务器地址或个人数据。
  • 未复制第三方项目源码;技术思路和工具使用已在 REFERENCE.md 披露。
  • 新增 packed-index 和 local-logit 路径具有边界、device 与 sampling-mode 检查。

Expose auto, legacy, and fused policies. Auto selects fused only for non-quantized CUDA FP16/BF16 qwen3_moe workloads and preserves explicit legacy behavior elsewhere.
Propagate max_batch_size through the Python and C++ cache configuration so Paged CUDA Graph captures only scheduler-reachable batch shapes.
Keep exact graphs for batches 1 through 16 and coarse exact buckets above 16. Missing shapes retain the existing eager fallback and the configured maximum remains captured.
Use a 4096-token scheduler admission default only for high-concurrency Paged qwen3_moe serving. Explicit overrides, other models, and small capacities keep their prior behavior.
Project normal single-request prefill logits only at the sampled final position. sample_all_positions callers and decode retain complete logits semantics.
Shard the non-quantized Qwen3-MoE vocabulary projection across tensor-parallel ranks. Preserve complete-logit fallbacks for raw and non-greedy callers.
Skip recursive runtime-state reset only when the model is explicitly non-quantized. Quantized Marlin lock and workspace resets remain unchanged.
Derive the decode capture set from the current PagedKVCacheConfig on every compile so cache resets cannot retain stale batch limits or permanently discard larger buckets.
Exercise automatic backend gating, explicit compatibility overrides, quantization fallback, and the high-concurrency prefill budget boundaries.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends InfiniLM’s Qwen3-MoE serving stack with an auto|legacy|fused MoE backend policy, tighter paged CUDA Graph capture based on max_batch_size, and several Qwen3-MoE-specific performance/memory optimizations (prefill budgeting, last-token logits projection, vocab-parallel LM head/logits handling), alongside new tests, docs, and reproduction scripts.

Changes:

  • Add MoE backend policy resolution (auto|legacy|fused) and expose it via server CLI/API, with compatibility handling for the legacy boolean switch.
  • Propagate max_batch_size into paged KV/cache config and paged Graph compiler to limit captured shapes and reduce resident memory.
  • Optimize Qwen3-MoE inference paths (prefill admission defaulting, last-token logits, vocab-parallel logits for distributed greedy), plus add contest benchmark scripts and policy boundary tests.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/llm/test_moe_policy.py Adds policy/budget boundary tests for moe_backend=auto and Qwen3-MoE prefill budgeting.
scripts/run_vllm_bench_serve_client.py Adds a lightweight launcher for vLLM serving benchmark client with --extra-body support.
scripts/run_qwen3_moe_contest.sh Adds a one-command entrypoint to run correctness + contest-style serving benchmarks.
README.md Documents --moe-backend=auto|legacy|fused behavior for Qwen3-MoE.
python/infinilm/server/inference_server.py Threads moe_backend into the server’s AsyncLLMEngine construction.
python/infinilm/llm/model_runner/model_runner.py Passes max_batch_size into paged KV cache config creation.
python/infinilm/llm/llm.py Implements _resolve_moe_backend, adds Qwen3-MoE prefill budget defaulting, and updates LLM/AsyncLLMEngine args.
python/infinilm/infer_engine.py Adds allow_local_vocab_logits plumbing for distributed-greedy local logits consumption.
python/infinilm/cache/cache.py Extends PagedKVCacheConfig Python wrapper to include max_batch_size.
python/infinilm/base_config.py Adds --moe-backend CLI option and adjusts MoE-related argument wiring.
examples/test_infer.py Updates example to use new MoE policy parameters (skip_legacy_moe=None, moe_backend).
csrc/pybind11/engine/engine.hpp Exposes allow_local_vocab_logits to Python bindings.
csrc/pybind11/cache/cache.hpp Extends PagedKVCacheConfig binding to include max_batch_size.
csrc/models/infinilm_model.hpp Adds fields for last-token logits and vocab-parallel logits control; adds uses_vocab_parallel_logits().
csrc/models/infinilm_model.cpp Skips module-tree runtime reset for non-quantized Qwen3-MoE.
csrc/layers/causal_lm_templates/text_causal_lm.hpp Implements last-token-only logits path and vocab-parallel LM head + allgather as needed.
csrc/engine/rank_worker.hpp Adds allow_local_vocab_logits and greedy detection helper.
csrc/engine/rank_worker.cpp Adds distributed greedy over sharded vocab logits; adjusts graph usage gating.
csrc/engine/infer_engine.cpp Enforces CPU residency for input_offsets and computes last-token indices for packed prefill.
csrc/engine/compiler/static_batching_compiler.cpp Marks compiled inputs as local-vocab-logits-capable and rejects incompatible requests.
csrc/engine/compiler/paged_compiler.cpp Limits captured decode batch shapes by max_batch_size and sparsifies high-batch buckets.
csrc/cache/kv_cache.hpp Adds max_batch_size to PagedKVCacheConfig API.
csrc/cache/kv_cache.cpp Implements max_batch_size plumbing and preserves legacy 2-arg ctor default.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 191 to 199
self.engine = AsyncLLMEngine(
model_path=self.model_path,
device=self.device,
dtype=self.dtype,
tensor_parallel_size=self.tensor_parallel_size,
moe_ep_backend=self.moe_ep_backend,
moe_ep_size=self.moe_ep_size,
moe_backend=self.moe_backend,
cache_type=self.cache_type,
Comment on lines +120 to +127
export INFINI_ROOT
export CUDA_VISIBLE_DEVICES
export LD_LIBRARY_PATH="$INFINI_ROOT/lib:${LD_LIBRARY_PATH:-}"
if [ -n "$INFINICORE_DIR" ]; then
export PYTHONPATH="$INFINICORE_DIR/python:$REPO_DIR/python:${PYTHONPATH:-}"
else
export PYTHONPATH="$REPO_DIR/python:${PYTHONPATH:-}"
fi
@surprisely

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants