Ascend qwen3.6 optimizate baseline - #301
Open
appleinsky wants to merge 22 commits into
Open
Conversation
- Add Ascend Triton implementation of triton_split_qkv_rmsnorm_mrope. - Patch Qwen3NextAttention.forward to use the fused kernel on qwen3_5 model_type. - Register the op via torch custom op (PrivateUse1) with fallback guard. - Extend triton_utils with extract_slice/insert_slice helpers. - Update README and add patches README. Tested on Qwen3.6-27B with graph + chunked prefill; all benchmark cases pass.
…lugin-FL - Add backend-specific hooks to vllm_fl/compilation/graph.py so vendors can register capture/replay mixins. - Introduce ACLGraphBackendMixin for Ascend NPU graph capture/replay. - Implement attention/MLA graph-param upgrade in the Ascend backend. - Port npugraph_ex graph-fusion pass manager and Ascend-specific passes. - Wire Ascend patches into the FL dispatch patch set and platform config. - Fix vLLM 0.13 import paths in graph_fusion_pass_manager and passes. - Add NPU profiler wrapper and HCCL graph-capture support. Smoke-tested with NPU graph capture/replay.
- Add patch_dynamo_safe_ops() that replaces SiluAndMulFL, GeluAndMulFL, RMSNormFL and RotaryEmbeddingFL forward_oot with direct calls to the Ascend/reference implementations, bypassing the FL OpManager/RLock path that Dynamo cannot trace under torch.compile(fullgraph=True). - Avoid assigning to RotaryEmbeddingFL.cos_sin_cache inside forward_oot, which is forbidden when cudagraph is used inside torch.compile. - Keep the dispatch manager intact for eager-mode and non-graph paths. - Disable CUDA-specific post-grad fusion passes on NPU to avoid undefined pass classes when torch.compile is active.
Add Ascend-specific patches and backend adaptations so that Qwen3.5/Qwen3.6 MoE checkpoints (e.g. Qwen3.6-35B-A3B) can load and run the upstream Qwen3NextMTP drafter for speculative decoding: - patch_qwen3_mtp.py: KV-cache binding for target+drafter attention layers, local token embeddings on the last PP rank, config rewriting from qwen3_5/qwen3_5_moe to Qwen3NextConfig, graph-safe M-RoPE fallback, Ascend-compatible rejection sampler helpers, and packed MoE expert weight unpacking for the MTP drafter. - patch.py / __init__.py: wire the new patches into the Ascend backend. - fused_moe.py: replace the pure-PyTorch loop with graph-safe npu_moe_init_routing_v2 + npu_grouped_matmul + npu_moe_token_unpermute. - attention.py: add build_for_drafting metadata helper. - model_runner.py: pass cu_num_sampled_tokens to the proposer. - README.md: document patch_qwen3_mtp.py. Validated with Qwen3.6-35B-A3B, TP=4, graph mode, chunked prefill, MTP=1; all benchmark requests succeeded and SpecDecoding metrics reported token acceptance.
…m (e.g. 256)
Ascend PFA TND only supports head_dim in {64,128,192} (plus a special
qD=kD=192/vD=128 case). Qwen3.6-27B dense uses head_dim=256, which caused
npu_fused_infer_attention_score to fail with error 561002.
This change detects unsupported head sizes in AscendAttentionBackendImpl and
falls back to torch_npu.npu_fusion_attention for non-decode states:
- PrefillNoCache uses the dense input key/value directly.
- ChunkedPrefill/PrefillCacheHit gather paged KV cache into dense tensors.
- DecodeOnly keeps using _npu_paged_attention, which already supports 256.
A 2048x2048 lower-triangular bool causal mask is cached for npu_fusion_attention,
which expects True=allowed positions.
…上的 GDN(Gated Delta Net)推理优化。 > 涵盖:AscendC 融合算子接入、CANN 自定义算子环境自举、PTO megakernel prefill 加速、batch64 回退修复、Slice 热点修复。
…上的 GDN(Gated Delta Net)推理优化。 > 涵盖:AscendC 融合算子接入、CANN 自定义算子环境自举、PTO megakernel prefill 加速、batch64 回退修复、Slice 热点修复。
Author
|
vllm-plugin-FL baseline Operator time consumption: Number of operators:68 -> 50 -> 43 -> 39 |
…nsky/vllm-plugin-FL into qwen36_dense_moe
…pretransposed 权重加载预转置
Qwen36 dense moe
…ize-gdn-decode Port of the 6-commit GDN decode optimization series (z-zanez fork, based on a3644b2) onto appleinsky/add-qwen3_6_pto_chunk_gdn (42337cd) for a cross-fork PR. The upstream decode path (npu_causal_conv1d_custom + npu_fused_gdn_gating + 2x l2norm_fwd + npu_recurrent_gated_delta_rule + decomposed RMSNormGated) is complementary to the upstream PTO prefill work, so the port applies cleanly: (1) non-speculative decode runs fused_recurrent_delta_rule_update (single Triton kernel: q/k L2 norm + delta-rule state update, state in native (Hv, Dv, Dk) v-major layout, dummy first grid program to work around an Ascend Triton miscompile of the first scheduled program); (2) RMSNormGated.forward_oot uses the fused layer_norm_fwd_1pass Triton kernel registered as torch.ops.vllm.rmsnorm_gated_fwd (Dynamo-opaque), replacing the eager silu/pow/mean/rsqrt/mul chain; (3) kill switch: VLLM_FL_DISABLE_FUSED_DECODE_GDN. Smoke-validated on the source branch (TPOT 29.1ms -> 24.99ms, i32_o128 FDO).
feat(ascend): port GDN decode fusion optimizations from z-zanez/optim…
…de batch shrinks Port of z-zanez/fix-decode-pad-block-table (1cfe80b) onto appleinsky/add-qwen3_6_pto_chunk_gdn for a cross-fork PR. At max concurrency the first finished request shrinks the decode batch below the captured graph size (e.g. 64 -> 63), so the full-graph metadata gains a padded row. The block table for that row was filled with -1, which the full-attention FIA kernel dereferences even for seq_len==0 rows, faulting the device (fftsplus aicore error / CCU instruction address check error) and surfacing as aclrtSynchronizeEvent 507011 in sample_tokens bookkeeping. Fill padded block-table rows with block 0 instead; the mamba/GDN pad slots keep their PAD_SLOT_ID=-1 convention via the GDN metadata builders own fills, and slot_mapping padding is unchanged. Verified with the 64-concurrency 256-prompt case: 256/256 successful.
…pstream" This reverts commit 9006d18.
fix(ascend): pad block-table rows with block 0 to fix crash when deco…
…nsky/vllm-plugin-FL into add-qwen3_6_pto_chunk_gdn
Update captured paged-attention graph tasks with runtime sequence lengths and synchronize only graph entries that carry mutable task parameters. Validate graph metadata and resolve attention updaters from initialized backend groups to prevent silent FULL decode deadlocks. Cache the transposed Qwen3.6 GDN convolution weights and use the native NPU SwiGLU path to reduce decode overhead.
…ecode perf(ascend): stabilize Qwen3.6 graph decode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Qwen3.6 Ascend 推理优化技术文档
1. 总览
chunk_gated_delta_rule(prefill 加速)关键结论(TL;DR):
.contiguous()(~1ms/次)。2. AscendC GDN 融合算子接入
2.1 算子与注册
FL 仓库已在
csrc/ascend编译注册到torch.ops._C_ascend(TORCH_LIBRARY_EXPAND(CONCAT(_C, _ascend), ops),csrc/ascend/torch_binding.cpp),单测在tests/custom_ops_tests/:npu_causal_conv1d_custom(output, x, weight, conv_state, bias?, query_start_loc?, cache_indices?, initial_state_mode?, num_accepted_tokens?, activation_mode, pad_slot_id, run_mode) -> Tensorrun_mode=0varlen prefill /1decode·spec update;weight 需(width, dim)npu_fused_gdn_gating(A_log, a, b, dt_bias, beta=1.0, threshold=20.0) -> (g, beta_output)g = -exp(A_log)*softplus(a+dt_bias)(fp32),beta=sigmoid(b)npu_recurrent_gated_delta_rule(q, k, v, state(a!), *, beta?, scale?, actual_seq_lengths?, ssm_state_indices?, num_accepted_tokens?, g?, gk?) -> Tensor(B, Hv, Dv, Dk)原地更新;输出固定 bf16;actual_seq_lengths为 cu_seqlens 风格[0, l1, ..., lB](batch = numel-1);MAX_MTP限制单序列 token 数npu_gemma_rms_norm(x, gamma, epsilon=1e-6) -> (y, rstd)(1+w)语义(已数值验证)npu_add_rms_norm_bias(x1, x2, gamma, beta?, epsilon) -> (y, rstd, x)2.2 patch 实现
新增
vllm_fl/dispatch/backends/vendor/ascend/patches/patch_qwen3_6_gdn.py,注册进patch.py::apply_ascend_patches(),参照 vllm-ascendvllm_ascend/ops/gdn.py(AscendGatedDeltaNetAttention)与ops/layernorm.py移植到 vllm 0.13 的GDNAttentionMetadata:Qwen3NextGatedDeltaNet._forward_core(上游类;FL 的Qwen3_5GatedDeltaNet继承它,经torch.ops.vllm.gdn_attention_core按 prefix 分发):npu_causal_conv1d_custom(run_mode=1, num_accepted_tokens=...)+ rgdr(ssm_state_indices=spec_state_indices_tensor.flatten())npu_causal_conv1d_custom(run_mode=0, initial_state_mode=has_initial_state)+ Tritonchunk_gated_delta_rule(保留)npu_causal_conv1d_custom(run_mode=1)+ rgdr(q/k 先l2norm_fwd,actual_seq_lengths=[0,1,...])npu_fused_gdn_gating(A_log, a, b, dt_bias.to(A_log.dtype))get_state_shape:ssm state 由 0.13 的(Hv, Dk, Dv)换成 kernel 原生(Hv, Dv, Dk)(从csrc/ascend/attention/recurrent_gated_delta_ruletiling 源码确认:state.DIM_2==Dv, DIM_3==Dk);prefill chunk 边界 transpose。GemmaRMSNorm.forward_oot→npu_gemma_rms_norm(无 residual)/npu_add_rms_norm_bias(有 residual)。MambaStateShapeCalculator本来就返回(state_len, dim)(conv_state_shape交换后的结果),直接传入,无需 transpose。indices[seq0 + accepted - 1]读取,逐 token 状态写回indices[seq_i]。2.3 关键 bug:mamba cache 布局与算子 dense 假设冲突(端到端乱码根因)
0.13 的
_reshape_kv_cache_tensors把 conv+ssm 两种 state 交织在一个(带 padding 的)page 里,state 视图首维 stride ≠ dense block 大小。AscendC 算子按 dense 假设寻址:修复:
patch_qwen3_6_gdn.py::_patch_mamba_cache_dense_layout()包装ModelRunnerFL._reshape_kv_cache_tensors,把 mamba state 视图重组为 dense 逐 state 视图(同一 raw 存储内按 state 分组;Triton 路径用显式 strides,布局无关,不受影响)。2.4 数值与端到端验证
num_accepted_tokens槽位语义)。VLLM_FL_DISABLE_ASCENDC_GDN=1强制回退 Triton。4. PTO megakernel
chunk_gated_delta_rule(prefill 加速)4.1 接入
参照 vllm-ascend PR #8872(
/workspace/patch/pto_gdn.patch)。FL 已内置vllm_fl/ops/pto_chunk_gdn/(6 阶段融合:cumsum → scaled_dot_kkt → solve_tril → wy_fast → chunk_h → chunk_o,单次 launch)。适配(
chunk_gated_delta_wrapper.py):l2norm/run_mega_kernel 导入改 FL 路径;_triton()回退调用去掉 FL chunk 不支持的prebuilt_meta。compile.py增加.so已存在则跳过(避免 4 个 TP worker 每次启动并发重编)。回退语义:仅零
initial_state的 prefill 走 PTO;decode(非零 initial state)、PCP>1、头维不匹配回退 Triton。4.2 kernel 修复 1:头维 32B 对齐(支持 H=12)
Qwen3.6-27B TP4 → 每 rank
H=NV/TP=12, Hg=NK/TP=4,而mega_transpose_TH_to_HT的pto::Tile静态形状要求H*sizeof(T) % 32 == 0(fp32 需 8 的倍数,fp16 需 16 的倍数),H=12 直接编译失败。修复(
csrc/ascend/pto_chunk_gdn/mega_kernel.cpp):tile 静态形状用补齐头维HA=ceil32(H*ES)/ES,GM 侧 stride/valid 仍用 H,加载后TFILLPAD_INPLACE补零(仅有效行写回 GM)。注意:不能靠 wrapper 外层补头——GQA 比例H/Hg=3会被破坏。4.3 kernel 修复 2:final_state UB 异步写竞争(多序列状态损坏根因)
现象:单序列 prefill 全对,多序列时除末尾序列外所有序列的
final_state全错。定位:错误 work item = 每个 core 上除最后一个外的所有 item(3 序列时第 1 序列 12 头全错、第 2 序列前 4 头错、第 3 序列全对)。根因:
chunk_h.cpp的 fsTSTORE(MTE3 异步)未排干,下一 work item 的清零/TCVT 覆写同一 UB,导致写回 GM 的 final state 被污染。修复:fs TSTORE 后补
set_flag/wait_flag(PIPE_MTE3, PIPE_V)排干。修复后 1/2/3/4 序列、变长(56~512)o 与 final_state 全部与 Triton chunk 一致。4.4 验证
.so按 (H,Hg,D,C) 缓存于vllm_fl/ops/pto_chunk_gdn/kernels/compiled_lib/,新配置首用编译 ~9s。5. batch64 性能回退分析与修复
5.1 现象与数据
batch64(1024
16384 输入 × 1024 输出 × 64 并发)下 PTO 比无 PTO eager 慢 510%(309 vs 346 tok/s @1024)。5.2 根因(微基准定量)
kernel 本身更快。回退来自 wrapper 在每个 GDN 层每个 prefill 步引入的 2 次 device→host 同步:
torch.any(initial_state != 0)(回退判断)_total_chunks的cu_seqlens.cpu().tolist()(chunk 计数)48 层 × 2 = 96 次同步/步 ≈ 5~10% 开销。且稳态 batch(decode 行混入)下 initial_state 非零 → 必然回退 Triton,白付同步。
5.3 修复(免同步决策)
patch_qwen3_6_gdn.py::_patch_gdn_metadata_host_flags():包装GDNAttentionMetadataBuilder.build,在 CPU 侧给 metadata 附加:any_initial_state_cpu(由num_computed_tokens_cpu > 0计算,零同步)cu_seqlens_host(由query_start_loc_cpu直接转换)_forward_coreprefill 分支:any_initial_state_cpu is False(全新 prefill 批)→ 直接调_chunk_gdn_pto(内置 l2norm+fp16 cast+total_chunks透传),否则走 Triton chunk;不再经过任何带同步的 wrapper。mega_kernel.py增加total_chunks可选参数,跳过.cpu()同步。patch_pto_chunk_gdnwrapper 注册。5.4 验证
batch64 1024 case:348.65 tok/s ≥ 无 PTO 基线 346.24,回退消除(此前 wrapper 版 309.17)。
6. Slice 热点修复(KV 缓存连续布局)
6.1 现象
profile 算子统计中
Slice类 kernel 合计 1.1ms,占设备时间 62%。6.2 定位(排除法)
kernel_details.csv呈双峰:848 次 × 2.7us(正常)+ 1024 次 × ~1068us。split_qkv_rmsnorm_mrope之后、ReshapeAndCache/FIAS之前。impl/attention.py::forward()中kv_cache = [i.contiguous() for i in kv_cache]。6.3 根因(两个叠加问题)
_update_hybrid_attention_mamba_layout(混合模型缓存布局调整)把(2, num_blocks, ...)连续 KV 缓存重排为 k/v 逐块交织的 strided 视图 →kv_cache[0]/[1]非连续。if attn_metadata != AscendAttentionState.DecodeOnly:拿元数据对象与枚举比较,恒为 True → 每次调用都对整份 k/v cache 各做一次.contiguous()(~340MB/份,实测 ~870us,profile 中 ~1ms)。16 层 ≈ 32ms/步(约占 TPOT 16%)。6.4 修复
vllm_fl/worker/model_runner.py::_update_hybrid_attention_mamba_layout:跳过 re-stride,缓存保持连续(2, num_blocks, ...)布局;所有访问经同一组视图,语义透明,.contiguous()变 no-op(870us → 2us)。impl/attention.py:改为attn_metadata.attn_state != AscendAttentionState.DecodeOnly。6.5 验证(i32_o32 profile)
正确性:贪心解码 2/3 prompt 与基线逐 token 全等,1/3 仅末尾 token 级分叉。
注:eager 单并发 TPOT 受 host 侧 launch 开销主导,设备侧收益在 aclgraph 图模式/大并发下体现更直接。
附:变更文件清单
vllm_fl/dispatch/backends/vendor/ascend/patches/patch_qwen3_6_gdn.py_forward_core/get_state_shape、GemmaRMSNorm、mamba dense 布局、PTO 免同步接入、环境 bootstrapvllm_fl/dispatch/backends/vendor/ascend/patch.pypatch_qwen3_6_gdnvllm_fl/dispatch/backends/vendor/ascend/patches/README.mdvllm_fl/__init__.py_bootstrap_cann_custom_op_env(OPP 路径 + RTLD_LOCAL 预载)vllm_fl/ops/pto_chunk_gdn/chunk_gated_delta_wrapper.py_triton参数适配vllm_fl/ops/pto_chunk_gdn/compile.py.so存在则跳过编译vllm_fl/ops/pto_chunk_gdn/mega_kernel.pytotal_chunks可选参数csrc/ascend/pto_chunk_gdn/mega_kernel.cppcsrc/ascend/pto_chunk_gdn/chunk_h.cppvllm_fl/worker/model_runner.py_update_hybrid_attention_mamba_layout跳过 re-stridevllm_fl/dispatch/backends/vendor/ascend/impl/attention.pyattn_state比较修正