尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

国产算力·昇腾 910C 大模型推理优化(下):源码修改与算子优化,提速30%|得物技术

国产算力·昇腾 910C 大模型推理优化(下):源码修改与算子优化,提速30%|得物技术 本文为《昇腾 910C 大模型推理优化实践》下篇。上篇已覆盖昇腾 910C 的软硬件环境、性能基线与瓶颈分析以及无需改动源码的镜像升级与参数调优。本篇承接上篇继续深入 vllm-ascend 源码修改、算子层优化与 MTP 投机解码并给出优化前后的完整性能对比与方法论总结。一、优化实践二vllm-ascend 源码修改参数调优见顶之后我们深入 vllm 与 vllm_ascend 源码围绕上篇定位的瓶颈做了一系列修改。MoE 共享专家多流重叠multistream_overlap_shared_expert动机与原理MoE 层的标准执行顺序是routed expertsGroupedMatmul→ shared expert → AllReduce三者串行。分析发现两个问题shared expert 的计算与 routed experts 没有数据依赖完全可以并行。在 MC2 通信模式下maybe_all_reduce_tensor_model_parallel 对 MC2 是 no-opshared expert 的 AllReduce 是唯一的通信开销同样可以与计算重叠。优化思路把 shared expert 放到独立的 side streamshared_experts_calculation_stream上与 default stream 上的 routed expert 并行shared expert 的 AllReduce 也留在 side stream 上最后 default stream 等待 side stream 完成。实现vllm_ascend/ops/fused_moe/fused_moe_0_23_0.py改动集中在两处。第一处是 _forward_shared_experts进入时用 npu_stream_switch 切到 side streamshared expert 计算完成后不再切回 default stream 做 AllReduce而是继续在 side stream 上完成 AllReduce。overlap_enabled self.multistream_overlap_shared_expert and not get_forward_context().capturing with npu_stream_switch(shared_experts_calculation_stream(), enabledoverlap_enabled): shared_out ... # shared expert 计算gate_up matmul down matmul if need_all_reduce: # moe_comm_type in {ALLTOALL, MC2, FUSED_MC2} 且非 shared-expert-DP with torch.npu.stream(shared_experts_calculation_stream()): tensor_model_parallel_all_reduce(shared_out) # AR 留在 side stream torch.npu.current_stream().wait_stream(shared_experts_calculation_stream())bf16 非量化路径下shared expert 的 part1gate_up matmul与 part2down matmul对同一 hidden_states 独立不依赖 routed expert 输出因此并行是安全的。减少事件开销并行化之后routed 侧原先用于与 shared 侧同步的 dispatch/combine/gmm2 事件不再需要。继续保留这些 record_event/wait_event 会在每个 MoE 层产生额外开销。我们新增 forward context 标志 skip_dispatch_combine_events在 overlap 路径进入前置位、退出后复位moe_comm_method.pybefore_dispatch_evt、before_combine_evt 置 Nonemoe_mlp.py三处 before_gmm2_evt 置 Noneascend_forward_context.pyextra_attrs 白名单加入该标志。与 FUSED_MC2 共存及收益上游代码中有一处互斥检查VLLM_ASCEND_ENABLE_FUSED_MC21 时会强制把 multistream_overlap_shared_expert 置为 False。分析确认两者并不冲突overlap 管计算流并行FUSED_MC2 管通信算子融合我们移除了该限制使两项优化叠加生效。收益汇总均基于前序优化叠加初版的多流并行优化提升 0.3msc1shared expert 通过跳过冗余 event shared expert 权重预取填补再提升 0.2ms最终未开投机解码时 c1 TPOT 从 8.2ms 压到 8.0ms。优化 decode host 侧开销c1 decode 时每个 step 的 batch 结构几乎不变但上游 model_runner 每步都无条件执行一大串 copy_to_gpu/fill_/commit 操作。这些拷贝虽标为 non_blocking仍会插入多余的 host→device DMA、拉长异步流水。我们在 vllm_ascend/worker/model_runner_v1.py 中引入「上一轮状态」跟踪结构不变就跳过lazy-init 跟踪变量 _prev_num_reqs/prev_total_tokens/prev_bt_checksumblock table 提交仅当 num_reqs1 且与上一步相同时用 block_table.np[0].sum() 校验和判断是否变化不变则跳过 commit_block_table()尾部清零seq_lens、query_start_loc、optimistic_seq_lens 的 fill只在请求数收缩时执行discard_request_indices/mask、req_indices、query_pos、num_scheduled_tokens 的 copy_to_gpu 分别按「确有 discard / num_reqs 变化 / 总 token 数变化」条件化执行positions 计算路径重写原来在 GPU 上用 index_select cast add 三个 kernel 现算改为直接使用 CPU 侧已经算好的 pinned buffer一次 H2D copy 完成self.positions[:n].copy(self._positions_cpu_buf[:n], non_blockingTrue)。配套的还有 copy_snapshot_to_gpu 的 pinned staging 缓存改造vllm_ascend/worker/utils.py上游每次调用都 clone().pin_memory() 重新分配锁页内存改为每个 buffer 复用一块预分配的 pinned staging只拷数据不换内存。Block Table 的 CPU 快路径slot mapping 的计算把每个 token 的逻辑位置映射到 KV Cache 的物理 slot默认情况下这个映射计算是在 NPU 设备上通过一个 Triton Kernel_compute_slot_mapping_kernel并行完成的。profile 发现 _compute_slot_mapping_kernel 在昇腾上固定约 131us 的 launch 开销——在解码Decode阶段每次迭代通常只处理极少量 tokenbatch size 很小。此时为一个很小的计算任务去启动一个 NPU Kernel其启动延迟可能远大于计算本身的时间对这种只做简单整数运算的小 kerneldispatch 开销远大于计算本身小 batch 下不划算。我们在 vllm_ascend/worker/block_table.py 的 compute_slot_mapping() 中加入 CPU 快路径当未启动上下文并行且提供了 CPU 侧 positions 与 query_start_loc且 num_tokens 80 时positions 是每个 token 在序列中的绝对位置query_start_loc 是每个请求在 batch 中的起始 token 索引这两个数据在 Host 侧CPU 内存已有现成的 NumPy 数组无需额外从设备拷贝回 CPU因此可以直接使用直接用 numpy 在 host 侧完成映射再一次非阻塞 H2D 写回。req_idxnp.repeat(np.arange(num_reqs,dtypenp.int32),query_start_loc_cpu[1:]-query_start_loc_cpu[:-1])pos_arrpositions_cpu[:num_tokens].astype(np.int64)pos_blockpos_arr//self.block_size pos_offsetpos_arr%self.block_size block_idsself.block_table.np[req_idx,pos_block].astype(np.int64)slots(block_ids*self.block_sizepos_offset).astype(np.int32)self.slot_mapping.np[:num_tokens]slots self.slot_mapping.copy_to_gpu(num_tokens)# 单次非阻塞 H2Dc1~8 decode 的 num_tokens 恒小于 80因此该快路径在目标场景 100% 命中每步省下约 131us 的 kernel launch 与相关同步。commit_block_table 也同步改为复用 pinned staging_bt_pinned避免每步重复分配锁页内存。GDN线性注意力路径专项优化Qwen3.5 的 30 层 GDN 是 decode 时间线上算子最密集的区域原实现为causal_conv1d → mixed_qkv 拆分rearrange→ l2norm → recurrent kernel每层多个小 kernelhost 开销与 HBM 往返严重我们从三个方向下手。L2Norm 融合进 recurrent kernelAscendC 算子改造decode 路径上每层对 q、k 各调用一次 triton l2norm_fwd kernel每层 2 次 launch。把 L2Norm 直接融合进 npu_recurrent_gated_delta_rule 的 AscendC kernel 内部让 q/k/v 在片上完成归一化后直接参与状态更新避免多次 HBM 往返与 kernel launch。csrc 侧改动csrc/attention/recurrent_gated_delta_rule/op_kernel/recurrent_gated_delta_rule_tiling_data.htiling 结构体新增 useL2Norm 字段op_kernel/recurrent_gated_delta_rule.h构造函数读取 useL2Norm在 CopyInQKV 阶段 Cast 之后、Mul 之前插入内联 L2 norm 计算op_host/recurrent_gated_delta_rule_tiling.cppuseL2Norm1 写入 tilingPython 侧 vllm_ascend/ops/gdn.py删除 decode 路径的两次 l2norm_fwd(query/key) 调用。编译C 编译完成后执行 python3 setup.py build_ext --inplace 重新生成 .so。启动需配合 VLLM_ASCEND_KEEP_MAMBA_MODE1。收益c1 TPOT 8.9→8.5ms-0.4ms、c4 11.7→11.5ms-0.2msc8 出现 0.5ms 劣化。host 侧小开销的优化conv 权重转置缓存causal_conv1d 每层每步都要对 conv 权重做 transpose(0,1).contiguous()按权重 data_ptr 一次性缓存转置结果conv_weights_T消除约 4.3us × 30 层 ≈ 129us/steprearrange 视图化原实现用 torch.cat 拼接/重排 mixed_qkv每层产生 Concat 操作新增 rearrange_mixed_qkvc1 decode 时 split 出的 slice 在最后一维本就连续直接 reshape 返回视图省掉每层 Concat 操作约 123us/step。mamba state 拷贝与计算重叠多流并行GDN 层的 ssm_statemamba state在请求切换/淘汰时需要做 block 拷贝。原实现放在关键路径上同步执行。我们把 do_mamba_copy_block 挪到 global_stream 上与 update_cos_sin / index_select 重叠执行并用预分配的 torch.npu.Event 做同步——事件对象预分配复用避免每 step 创建/销毁 event 的约 10us host 开销。采样与投机解码路径优化TPOT 降幅最大的一组这一组优化把 c1 TPOT 从 7.02ms 直接压到 5.12ms单项 -27%并进一步压到 5.0ms。主要优化思想是贪婪采样只需要 argmax不需要计算并存储整个词汇表中每个 token 的 logits/概率。MinTokens EOS 掩码缓存rejection_sampler问题上游 MinTokensLogitsProcessor.apply_with_spec_decode 在每个 decode step 都在 host 侧用 numpy 重建 (rows, toks) 掩码然后两次 torch.from_numpy(…).to(device, non_blockingTrue) 拷到设备。由于源内存是分页内存非锁页这类 H2D 拷贝实际是同步的——host 必须等设备排空并完成拷贝异步调度流水被硬生生打断实测占单步时间约 30%。解决分析发现掩码在「稳态期」是常量——只要每个请求剩余的最小生成长度 remaining min_tokens - len(output) ≥ num_draft_tokens掩码内容就不变。因此我们在 vllm_ascend/sample/rejection_sampler.py 实现 _apply_min_tokens_spec_cached_min_tokens_spec_steady_structure判断是否处于稳态临近 min_tokens 尾部或 batch 索引过期时返回 None回退上游逐位置逻辑语义完全一致get_min_tokens_spec_mask_indices把掩码预计算成 device 端 int64 张量 (rows_t, toks_t, bonus_rows_t, bonus_toks_t) 并按 (batch 结构, 请求结构) 缓存仅在结构变化时重建重建时用锁页内存异步拷贝每步应用只执行一次纯设备端的 logits.index_put((rows_t, toks_t), neg_inf_tensor)无 numpy 重建、无 H2D 拷贝、无同步。另一个关键细节昇腾上 masked_select 会编译为 NonZero 算子并触发 host-device 同步因此所有掩码应用都改为纯整数 advanced indexing。该优化单项贡献 -1.9ms/token7.02→5.12ms是全部源码优化中收益最大的一项。词表并行 argmax(Argument of the Maximum)跳过全词表 all-gatherargmax 找的是能让函数值达到最大的那个输入索引或变量而非最大值本身。问题上游 compute_logits 会对全词表 logits 做 TP all-gather通信量 O(batch × vocab_size)。对贪婪采样而言最终只需要每行的 argmax。解决先在每个 TP 分片内做局部计算只聚合 (max_value, max_index) 对通信量降为 O(batch × 2 × tp_size)——按 15 万词表、TP2 估算通信量下降约 31000 倍。实现在 vllm_ascend/spec_decode/step3p5.py 的 _draft_greedy_shard_argmaxlogitslm_head.quant_method.apply(lm_head,hidden_states,biasNone)# 只算本分片logits[...,-num_pad:]-float(inf)# mask 掉分片内 vocab paddinglocal_max_vals,local_max_indiceslogits.max(dim-1)global_indiceslocal_max_indicesvocab_start# 分片内索引 - 全局词表索引local_pairtorch.stack([local_max_vals.float(),global_indices.float()],dim-1)gatheredtensor_model_parallel_all_gather(local_pair,dim-1)# 只 gather (值,索引) 对max_rank_idxgathered[:,:,0].argmax(dim-1,keepdimTrue)# 按值选最大分片top_tokensgathered[:,:,1].gather(dim-1,indexmax_rank_idx)# 取对应 token id正确性论证soft_captanh与 scale 都是单调变换不影响 argmaxpadding 位置已置 -inf「分片内 argmax 跨分片比大小」与「全词表 argmax」严格等价。该模式在三个位置落地draft 侧MTP 草稿生成_draft_greedy_shard_argmaxdraft 的 greedy 只需 argmax不需要完整 logits 与 probstarget 验证侧spec-decode verifymodel_runner_v1.py 的 _spec_greedy_shard_argmaxlm_head 分片计算 本地分片 EOS 掩码与上文「MinTokens EOS 掩码缓存」的缓存索引复用掩码在 host 侧构建时就过滤到本分片并转换为分片内列号普通 decode 侧model_runner_v1.py 的 _vocab_parallel_argmax_eos_masked在 execute_model 阶段预采样ExecuteModelState.pre_sampled_tokenssample 阶段直接构造 SamplerOutput绕开全词表物化与通信。贪婪采样快路径跳过 bf16-fp32 的转换通用采样路径会先把 bf16 logits 全量转成 fp32。对纯贪婪采样这一步可以安全跳过bf16 的指数位比 fp16 更宽任意 bf16 值都可以被 fp32 精确表示因此 argmax(bf16) argmax(bf16.to(fp32))逐元素比较顺序不会变化。vllm_ascend/sample/sampler.py 的 AscendSampler.forward 增加快路径当满足 all_greedy、没有 logprobs、没有 penalties、没有 allowed-token/bad-words 约束、且不改变 argmax 的 logits processor 条件时直接对 bf16 logits 取 argmax 返回省掉一次全词表约 248K 元素/步的 cast kernel。预采样直接提供给拒绝采样上述词表并行 argmax 产出的 token id 被直接喂给拒绝采样rejection_sampler.py 新增 forward_greedy_presampled接收全量 greedy 批次的预采样 argmax idtarget draft 行 每请求一行 bonus 行直接走 triton/pytorch 的 rejection_greedy_sample 完成验证全程不再需要全词表 logits、fp32 的拷贝。其他源码级小优化单看每项都不起眼但 decode 时间线就是由这些「每层每步几微秒」累加而成的RMSNorm (1.0weight) 缓存Gemma 风格 RMSNorm 每次 forward 都执行 1.0 self.weight 与 .contiguous()。权重在推理期不变按 id(self) 缓存结果layernorm.py 的 GEMMA_WEIGHT_CACHE、patch_qwen3_5.py 的 get_weight_plus_one全模型每步省下 40 层 × 2 处的加法拷贝。rotary embedding 表达式合并RoPE旋转位置编码通过旋转 Query/Key 的向量来注入位置信息。计算时需要根据每个 token 的位置从预计算的 cos/sin 缓存中取出对应的值。update_cos_sin 是根据当前 batch 中每个 token 的位置索引准备好形状匹配的 cos 和 sin 张量供后续旋转操作使用由于 RoPE 的 cos 和 sin 在数值上是对称的形状和变换流程完全一致可以合并优化update_cos_sin 原先对 cos/sin 各做一次 index_select view repeat chunk可以把 cos 和 sin 合并成一个张量先做一次 index_select 和形状变换最后再 chunk 拆回 cos 和 sin消除一半的重复操作这些操作对 cos 和 sin 是完全重复的形状、变换方式一模一样只是数据不同。去掉冗余 copyrope_dsv4.py 中 ComplexExpRotaryEmbedding.forward 原先把结果 copy 到预分配 buffer 再返回改为直接返回 x.view(ori_shape) 视图。Attention 权重双流预取weight prefetch 机制原本只覆盖 MoE 权重。我们利用「层按顺序构建」的特性建立层注册表让第 L 层在进入自己的 MoE全层最长的计算 AR 窗口时在 prefetch 流上预取第 L1 层的 attention 投影权重qkv_proj/o_proj 等第 L1 层在消费前等待 prefetch 流把 attention 权重的 HBM 加载藏进上一层的 MoE 窗口patch_qwen3_5.pyVLLM_ASCEND_ATTN_WEIGHT_PREFETCH 默认开启。二、优化实践三算子层优化与编译融合decode 关键路径上大量时间消耗在「matmul → AllReduce → 残差加 → RMSNorm」这种层间固定序列以及 MoE 的通信-计算交织上。我们通过编译 MC2 通信融合、SuperKernel 与自研 910C 融合算子四条路径逐层压缩这些开销。FUSED_MC2MoE 通信-计算融合MC2Mixture-of-experts Communication Computation是昇腾针对 MoE dispatch/combine 通信的融合机制把 AllToAll 通信与 GroupedMatmul 计算在算子内部交织。vllm-ascend 通过环境变量提供两级开关export VLLM_ASCEND_ENABLE_FUSED_MC21 # 启用计算通信融合算子。实测 1 有稳定收益2更激进的融合级别在 35B-A3B 上无额外收益。配套地我们把 ascend_forward_context.py 中 MC2 路径的 token 容量上限从 min(num_tokens_per_tp_rank, 512) 放宽到 1024让更大 batch 也走 MC2 的 RSAG 路径而非 ALLTOALL为未来扩大 capture 尺寸留余量。SuperKernel把小 kernel 合并为大 kernel 一起加载低并发下单个 kernel 的计算时间常常只有几微秒此时 kernel 的加载与发射开销占比极高。SuperKernel 的思路是把多个连续的小 kernel 在编译期合并为一个大的 SuperKernel同步 launch减少 kernel 加载次数与通信开销同时天然形成算子间的流水重叠。在 vllm-ascend 侧通过编译选项启用我们迁移后默认随静态 kernel 一起打开见 compiler_interface.pyoptions[static_kernel_compile] Trueoptions[super_kernel_optimize] True options[_vllm_aclnn_static_kernel_sym_range] \ _compute_decode_cudagraph_batch_sizes(vllm_config) # 限定静态编译的 batch 尺寸其中 sym_range 把静态 kernel 编译限定在 cudagraph 捕获的 batch 尺寸上避免编译时间爆炸。开启 SuperKernel 后叠加前序全部优化未开投机解码的 c1 TPOT 从 8.5ms 降到 8.2ms-0.3ms开启 MTP 后收益进一步放大详见下文「开启 MTP 投机解码」。同时编译器 hash 因子中加入 super_kernel_optimize保证开关变化时编译缓存正确失效。融合算子matmul_allreduce_add_rmsnorm_910c动机设置 VLLM_ASCEND_ENABLE_MATMUL_ALLREDUCE 开启计算和通信算子融合功能的时候在 910C 上报「SoC version ascend910_93 verification failed」——算子库未覆盖该 SoC。自研了一个专为 910C 双 die TP2 拓扑设计的融合算子把 decoder 层内最重的序列o_proj(matmul) AllReduce residual add RMSNorm(1w)压进单个算子。对应的 Python 侧封装在 vllm_ascend/ops/fused_ar_norm.py由 VLLM_ASCEND_FUSED_O_PROJ_AR1 开关控制并在 patch_qwen3_5.py 的 AscendQwen3_5DecoderLayer.forward 中接入attention 模块在算完 attn_output 后直接把 residual 与 (1w) 归一化权重交给融合算子整个 epilogue 一次完成层前向只需接收融合输出作为新的 residual。算子架构AIC/AIV 双核流水算子源码位于 csrc/mc2/matmul_allreduce_add_rmsnorm910c/采用 AscendC 的 AICCube AIVVector双核协同设计AIC 侧基于 Catlass 实现细粒度 matmulL1 tile 16×224×512双缓冲每算完一个 (mTile, nTile) 输出 tile就在 GM全局内存上置位对应的 tile-ready flag。AIV 侧轮询 AIC 的 tile flagWaitForAicTiletile 就绪后立即启动跨 rank 的细粒度归约——两个 die 通过 HCCS 直接读写对方的 DataBank/StatusBankRANK_DATA_STRIDE1MB 布局完成 reduce-add 后再做 RMSNorm先各自求平方和、跨 rank 汇总求倒数、归一化输出全程不回到 host。流水协议GM 上的 flag 区分为三段AIC tile 就绪 flag、跨 rank 协议状态protocol/add ready、RMS 就绪AIC 算得越往后AIV 的归约与归一化越能与之重叠形成 matmul 与通信的细粒度流水。形状约束与可靠性设计算子支持 M ≤ 40 行覆盖 MTP bs8 × (41)40 行的验证场景、TP2、bf16、2048 维Qwen3.5-35B-A3B 的 hidden sizePython 侧做第一道守卫不满足条件返回 None 走未融合路径算子内部还有第二道防线——不支持的形状会通过 c10::Dispatcher 回退到标准算子组合matmul vllm::all_reduce add_rms_norm这正是新增头文件 csrc/mc2/call_vllm_tensor_op.h 提供的能力。双层回退保证了正确性永远不依赖融合算子的形状覆盖度。收益该算子接入后叠加全部前序优化c1 TPOT 5.2→5.1ms、c4 9.2→9.0ms、c8 12.9→12.3msp99 从 18.8ms 降到 14.8ms同时 TTFT c1 从 213ms 降到 179ms-16%、c8 从 432ms 降到 307ms-29%因为 prefill 阶段同样会走该融合算子。静态 kernel 编译修复从 37/43 到 43/43静态 kernel 预编译见上篇依赖对图内所有算子的成功编译。实际编译 43 个自定义算子时起初只有 37 个成功。排查发现两类问题头文件路径硬编码编译脚本引用 /tmp/vllm-ascend/…/cann_compat.h 绝对路径容器重启后即失效改为基于 PYF_PATH 的相对路径后恢复到 42/43。CausalConv1d 空输入处理该算子的 bias/initialStateMode/numAcceptedTokens 参数传 None 时tiling 描述的位置发生错位修复方式是用「nullptr」空 tensor 描述 剥离 stride/offset/is_view 属性最终 43/43 全部编译成功100%。编译成功率提升的直接收益是 cudagraph 捕获覆盖所有 decode 形状解码吞吐提升约 4.2%。静态 kernel 与 MTP 的兼容性静态 kernel 与 MTP 投机解码同时开启时服务在发推理请求时直接报错——draftMTP 草稿模型的静态编译在 cudagraph capture 阶段触发 AICore 越界。分析发现根因MTP draft 模型的 FX 图与目标模型不同其 fc 层消费的是「token embedding 与目标 hidden states 拼接成的 2×hidden_size 张量」这个图编译成静态 kernel 会越界。解决方法compiler_interface 带上 super_kernel_optimizestatic kernel super kernel 协同该组合下 MTP 图可正常编译cudagraph 捕获 5/5 通过。cudagraph 捕获尺寸必须匹配投机后的 token 数初次开启 MTP 时出现严重劣化c4 TPOT 从 10.4ms 飙到 42.2ms、c8 从 13.5ms 飙到 42.9ms。排查发现原因开启投机后每个 decode step 实际执行的 token 数变为 并发数/DP × (1 num_speculative_tokens) 再加上可能的 bonus例如 c4/TP2 对应约 10~20 个 token而默认捕获尺寸 [1,2,4,5,8] 完全覆盖不到这些形状导致投机步骤落不进图中。修复方法是按公式重新设置捕获尺寸--compilation-config {cudagraph_mode: FULL_DECODE_ONLY, cudagraph_capture_sizes: [5, 20, 40]}修复后 c4 TPOT 42.2-10.4ms、c8 42.9-13.5ms。三、优化前后性能对比c1 优化瀑布每一步优化贡献了多少下表按时间顺序汇总 Qwen3.5-35B-A3B 在 c1、输入 1024/输出 512、不开投机解码条件下各优化措施叠加后的 TPOT 演进752t 单卡双 dieTP2可以看到最大的三个单项是版本升级-15.4%、静态 kernel-18.7%与 HCCL AIV-6.6%合计贡献约七成降幅其余十余项合计贡献三成。总览一未开启投机解码random 数据集 - 真实数据集叠加全部非投机优化后910C-560t单卡双 dieTP2与基线及 H20 的对比总览二开启 MTP 投机解码(针对MTP进行源码优化后)在 8.2 基础上开启 MTPnum_speculative_tokens4 SuperKernel总览三真实业务场景 RL 微调模型 真实业务场景数据集最终状态最终状态下真实业务数据集上 c1 TPOT 达 5.0ms较基线下降 64.8%。生产验证使用真实业务场景 RLGRPO/PPO基于 verl微调后的 Qwen3.5-35B-A3B 模型配合三类真实数据集压测。在叠加最后一批源码优化min_tokens 掩码缓存、词表并行 argmax、lm_head 分片计算后在 gsm8k 公开数据集数学推理token 分布与真实业务场景不同上优化效果更为突出两个数据集的差异也提示投机解码的收益与接受率强相关而接受率受数据分布影响评估国产化替代效果时应以真实业务数据集为准公开数据集只能作参考。推广验证Qwen3.6-27B为验证优化方案的通用性我们在同一套环境910C-560t、v0.23.0 内部分支上对稠密模型 Qwen3.6-27B 做了同步验证。注意该模型与 MTP 静态 kernel 的组合存在兼容性限制混用在发推理请求时报错需关闭 enable_super_kernel/static_kernel 之一详见上文「静态 kernel 与 MTP 的兼容性」一节的问题背景后续 0.26.0rc 版本镜像已解决。27B 稠密模型上非 MoE、非混合注意力模型同样有效。TTFT 与其他指标TPOT 之外其他指标的优化情况TTFT基线阶段昇腾本已优于 H20。源码优化后进一步改善融合算子接入使 c1 TTFT 213→179ms-16%、c8 432→307ms-29%。端到端延迟优化后 1024-512 请求的端到端延迟从 5.09s 降到 4.04s-21%。高并发吞吐静态编译修复43/43使并发 10 的解码吞吐提升 4.2%cudagraph 捕获范围从 49 扩到 70 后c10 吞吐 173→477 tok/s——说明低并发优化方法论之外高并发还需要单独调优捕获范围与调度。四、经验总结与展望方法论总结Profile所有优化都始于 msprof 时间线上的具体瓶颈某个算子的 launch 开销、某段 host 空窗、某次同步拷贝每项优化都做单变量 A/B 压测并记录无效尝试也要记录。低并发优化要减少 host 开销c1 时 device 侧算子都在微秒级TPOT 的大头是 host 调度、kernel launch、H2D 拷贝与同步等待。静态 kernel、SuperKernel、CPU 快路径、掩码缓存、冗余拷贝跳过本质都是在压缩 host 侧每一微秒。通信优化词表并行 argmax 把通信量降 3 万倍fuse_allreduce_rms、MC2、910C 融合算子把通信压进计算流水。多流重叠让 shared expert 的通信与 routed 计算同时进行。投机解码MTP 对 TPOT 的优化提升明显先做基线优化、再开投机解码。版本更新版本升级之后此前基于旧版本的所有源码修改都要重新迁移验证采用「先迁移基线优化、再逐个叠加」的方式完成了从 0.23.0rc2 到正式版 0.23.0 的迁移。不足与展望高并发方向本轮优化聚焦在线低并发c≤8高并发下的调度、显存与吞吐优化如 PD 分离、更大 capture 范围、DP attention是下一阶段重点。编译优化探索 PGOProfile-Guided Optimization反馈优化、更激进的算子融合如 QKV proj 与 RoPE 的融合。上游协同把通用性好的优化min_tokens 掩码缓存、词表并行 argmax、block_table CPU 快路径等整理后向 vllm-ascend 社区回馈减少长期维护成本。规模扩展将同一套方法论与最佳实践脚本复制到更多机型单机多卡、多机与更多模型Qwen3.5-9B/27B、后续稠密大模型上同步积累国产算力推理优化的经验。往期回顾1.国产算力·昇腾 910C 大模型推理优化上镜像更新与参数调优提速 40%得物技术2.动态规则的 Agent 实践用确定性工程驾驭 LLM 的资产智能验收3.发一张图它居然跃出屏幕了一文读懂得物 3D 空间图片技术实践4.别再只卷向量检索了得物交易搜索如何用“生成式”实现召回范式跃迁5.指标平台从语义底座到智能消费的实践路径得物技术文 / 映川、行星关注得物技术每周更新技术干货要是觉得文章对你有帮助的话欢迎评论转发点赞未经得物技术许可严禁转载否则依法追究法律责任。
返回列表