DeepSeek / Qwen 大模型在昇腾上的推理优化实战
昇腾910B大模型部署优化实践 在昇腾910B集群部署DeepSeek-V3和Qwen2.5-72B时,发现默认配置下吞吐仅为GPU的60%。通过系统优化实现276%性能提升,关键经验包括: 性能分析先行:使用CANN的msprof工具定位瓶颈,发现昇腾与GPU的瓶颈差异(计算vs访存) Attention优化:采用FlashAttention实现145-162%提升,针对不同序列长度动态选择压缩
前言
把DeepSeek-V3和Qwen2.5-72B部署到昇腾910B集群上。客户说"GPU上跑得好好的,换昇腾应该也行吧"。结果第一天就被砸懵——同样的模型、同样的batch,昇腾上吞吐只有GPU的60%。不是算力不够,是我根本没搞清楚CANN的优化逻辑和CUDA完全是两套体系。
很多人以为昇腾上跑大模型就是"把CUDA代码编译一下扔给CANN",其实从Attention到显存管理,每个环节的优化路径都不一样。
工程经验: DeepSeek-V3初次部署到昇腾910B,未开优化时decode吞吐580 TPS。开完FlashAttention + PagedAttention + W8A16量化,到2180 TPS,涨了276%。不是算力不够,是默认配置没打开昇腾的加速特性。
推理瓶颈:先 profile 再动手
一上来就改算子调参数,优化半天发现瓶颈在数据搬运。CANN自带的msprof跑一次就知道瓶颈在哪:
# 跑msprof做性能分析
msprof --output=./profiling_output \
--aic-metrics=memory_bandwidth_utilization \
python infer.py --model deepseek-v3 --batch 8
# 看报告:哪种算子占比高
msprof --export=on --output=./profiling_output
# 打开生成的report.html,看"算子耗时分布"
我第一次profile DeepSeek-V3:Attention计算38%、KV Cache访存27%、MoE Router+AllReduce 19%、其他16%。
为什么GPU方案不能直接复用?GPU上Attention占比通常50%+,瓶颈在计算;昇腾Cube的MAC阵列算矩阵乘效率高,但Vector做逐元素运算的吞吐比GPU的SM低——softmax、scale这些逐元素操作反而成瓶颈。GPU优化MatMul就够;昇腾得同时优化计算和访存。
工程经验: msprof的输出在profiling_output/summary/目录下,api_statistic.csv里能看到每个ACL API的耗时。aclmdExecute占比高说明算子调度开销大(要开ATB融合),aclrtMemMalloc占比高说明显存碎片多(要开预分配)。
Attention 优化:FlashAttention 只是起点
ops-transformer里的FlashAttention算子针对达芬奇架构做了Cube/Vector流水线优化:Cube算Q×K^T → Vector算scale+mask+softmax → Cube算P×V,中间数据走L1不落HBM。
# PyTorch接入FlashAttention(torch_npu)
import torch
import torch_npu
# 开FlashAttention(ops-transformer提供)
with torch.no_grad():
output = torch_npu.npu_flash_attention(
query, key, value,
head_num=32,
head_dim=128,
dropout_prob=0.0,
inner_precise=0, # 用FP16,不用FP32累加
)
实测性能(Ascend 910B,FP16):
| 模型 | 未融合FlashAttention | 开FlashAttention | 提升 |
|---|---|---|---|
| Qwen2.5-7B (seq=2048) | 34 tokens/s | 89 tokens/s | +162% |
| DeepSeek-V3-671B (seq=4096) | 580 TPS | 1420 TPS | +145% |
DeepSeek-V4更激进——CSA(4倍压缩)和HCA(128倍压缩)交替使用。128K序列下HCA把KV Cache从7.3GB压到57MB,TPOT < 10ms(950DT,16卡)。不压缩的Full Attention同场景TPOT > 80ms。
工程经验: CSA/HCA压缩率不是越大越好。128倍压缩(HCA)长序列收益明显,但短序列(<4K)反而比Full Attention慢12%——Compressor本身有计算开销。我们的做法:前两层用Window Attention(sliding_window=128),中间层按序列长度动态选CSA或HCA。
KV Cache 优化:省显存是手段,涨 batch 才是目的
Qwen2.5-7B,FP16下每个token的KV Cache约57KB。seq=2048、batch=32时光KV Cache就吃3.6GB。
三条优化路:
PagedAttention:MindIE推理引擎支持,KV Cache分block按需分配,消碎片。
KV Cache量化:INT8存KV Cache,显存省一半。910B实测:3.6GB → 1.8GB,省出1.8GB多跑16个batch。
KV Cache压缩:DeepSeek-V4的HCA 128倍压缩,128K序列KV Cache 57MB。
很多人以为KV Cache优化就是省显存。真正的收益是省出的显存能跑更大batch,更大batch吞吐更高。
# MindIE配置:开PagedAttention + KV Cache量化
from mindie import MindIERuntime, ModelConfig
config = ModelConfig(
model_path="/path/to/deepseek-v3",
# PagedAttention:block_size=128
kv_cache_mode="paged",
block_size=128,
# KV Cache量化:INT8
kv_cache_dtype="int8",
# KV Cache压缩(DeepSeek-V4)
use_hca=True, # 128倍压缩
hca_threshold=4096, # seq>=4096才开HCA
)
runtime = MindIERuntime(config)
工程经验: Qwen2.5-7B在910B单卡,FP16 batch=8吞吐72 tokens/s;开KV Cache量化 + PagedAttention后batch开到32,吞吐147 tokens/s。算力没变,显存够用了,batch从8涨到32,吞吐涨104%。
算子融合:省 Task 调度开销
昇腾上每次算子下发走ACL→GE→Runtime调用链,开销12-15μs。30层Transformer几百次调用,光调度开销就3-5ms。
CANN的graph-autofusion自动融合框架:LayerNorm+MatMul、Softmax+Dropout+MatMul、GatingTopK等。DeepSeek-V4专门做了SAS(统一Window/Sparse/Compress Attention)、Compressor、HCPre/HCPost融合Kernel,已开源在cann-recipes-infer。
// graph-autofusion配置(GE环境变量)
export GE_FUSION_PASS_MODE=aggressive // 激进融合策略
export GE_ENABLE_OP_FUSION=1 // 开算子融合
export ATB_FUSION_MODE=aggressive // ATB也开激进融合
// 融合效果验证:看GE编译日志
// 搜索"Fusion success",看哪些算子融了
grep "Fusion success" ge_compile.log | wc -l
工程经验: DeepSeek-V4 MoE的GatingTopK融合前router输出落HBM再给topk读,融合后直接L1传数据,省一次HBM读写。单层省18μs,40层省720μs。decode每个token快0.7ms,1000个token差0.7秒。
显存管理 + Batch 调优
昇腾HBM管理跟GPU不一样。GPU的caching allocator基本是"申请-使用-释放";昇腾的DMA引擎要求显存预分配、零碎片、复用中间buffer。
实测带宽利用率:动态申请释放35% → 预分配+复用82%。910B的1.2TB/s带宽,82%是984GB/s可用,35%只有420GB/s——差一倍多。
# 开显存预分配(Runtime环境变量)
export ACL_MEM_POOL_SIZE=32GB # 预分配32GB显存池
export ACL_MEM_POOL_REUSE_FLAG=1 # 复用中间buffer
export ACL_MEM_POOL_GUARANTEE_FLAG=1 # 预分配不释放
# Batch调优:动态batch
export ACL_DYNAMIC_BATCH=1
export ACL_DYNAMIC_BATCH_MAX=64 # 最大batch=64
Batch调优也不是越大越好。batch越大Attention的S矩阵越大,L1装不下就溢出:
| batch | 吞吐(tokens/s) | TTFT(ms) | 显存(GB) |
|---|---|---|---|
| 4 | 52 | 8 | 6.8 |
| 8 | 72 | 12 | 20.1 |
| 32 | 147 | 38 | 39.2 |
| 64 | 138 | 72 | OOM |
batch=64吞吐反而降——KV Cache swap到Host内存。选batch看场景:在线对话batch=4-8(TTFT<100ms),离线批处理batch=16-32。我们的做法是动态batch:短输入batch=32,长输入batch=8。
量化:最后一板斧
| 量化方案 | 适用芯片 | 精度损失 | 性能收益 |
|---|---|---|---|
| W8A16 | 910B, A3 | <0.5% | 吞吐+45%,显存-30% |
| W8A8C16 | A3 | <1% | 吞吐+85%,显存-45% |
| Hybrid FP8-MXFP4 | 950PR/DT | <1.5% | 吞吐+120%,显存-60% |
DeepSeek-V4 Flash在950DT(16卡,128K):Hybrid FP8-MXFP4 TPOT<10ms,FP16约35ms,3.5倍提升。
# 量化配置(torch_npu)
from torch_npu.contrib import transfer_param as tp
# W8A16量化
model = tp.param_quantize(
model,
algo="w8a16",
dtype=torch.float16,
)
# W8A8C16量化(A3及以上)
model = tp.param_quantize(
model,
algo="w8a8c16",
dtype=torch.float16,
)
# Hybrid FP8-MXFP4(950PR/DT)
model = tp.param_quantize(
algo="hybrid_fp8_mxfp4",
dtype=torch.bfloat16,
)
工程经验: 量化不是精度损失越低越好。W8A16精度损失<0.5%,但吞吐只涨45%;W8A8C16精度损失<1%,但吞吐涨85%。如果业务能接受1%的精度损失(比如推荐系统、文本摘要),W8A8C16更划算。
踩坑实录
坑1:FlashAttention在seq<512的时候反而不如标准Attention
seq太小,Cube利用率掉得厉害(M/N维度太小,Cube吃不饱),FlashAttention的额外调度开销(Tiling、softmax在线归一化)占比高。
解决:设export ATB_FlashATTENTION_SEQ_THRESHOLD=1024,seq>=1024才开FlashAttention,否则退化成标准Attention。
坑2:PagedAttention在batch动态变化的时候反而慢
batch从8涨到32,PagedAttention要动态分配block,分配开销占比高(~5ms)。
解决:预分配最大batch的block池(export MINDDIE_PAGED_POOL_SIZE=64GB),不动态分配。
坑3:W8A8C16量化在910B上编译失败
W8A8C16需要INT8的矩阵乘指令(CADIN8),910B的Cube不支持(只支持FP16/FP32),要A3及以上的芯片。
解决:910B上用W8A16(只量化权重,激活还是FP16),A3上用W8A8C16。
坑4:DeepSeek-V4的HCA压缩在seq=512的时候反而慢12%
Compressor的计算开销(CSA/HCA压缩+解压)比省下来的KV Cache访存开销大。
解决:设export DEEPEEK_HCA_THRESHOLD=4096,seq>=4096才开HCA,短序列用CSA(4倍压缩)或Full Attention。
https://atomgit.com/cann/ops-transformer
https://atomgit.com/cann/cann-recipes-infer
https://atomgit.com/cann/graph-autofusion
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐


所有评论(0)