昇腾部署DeepSeek并行推理
作者:Apricity
目 录
- DeepSeek模型推理在昇腾上的部署
- DeepSeek模型迁移适配
- DeepSeek模型并行策略及模型性能调优
- DeepSeek量化精度及性能调优
- 常见问题链接
前言
本文是昇腾开发者知识体系的配套材料,转载随意,如反馈bug请移步原文:链接。
本文以DeepSeek模型为例,介绍了在昇腾平台上使用MindIE进行大模型推理部署的流程与优化方法,旨在帮助开发者高效完成模型推理部署与优化。主要内容包括:
- 部署要求:BF16权重需4台Atlas 800I A2服务器,W8A8量化权重仅需2台。
- 量化调优:支持多种量化类型(W4A8、W8A8 Dynamic、W8A8C8等),通过算法选择(如anti_method、act_method)、校准集调整、手动/自动回退等手段提升精度和性能。
- 并行策略:详细说明DP、TP、SP、EP等并行方式配置,推荐不同场景下的组合策略(如低时延、高吞吐)。
- 性能测试:提供纯模型与服务化推理的测试脚本及参数配置示例。
昇腾MindIE部署过程涉及纯模型推理(MindIE-LLM)和 服务化推理(MindIE-Service)两部分组件:
- MindIE LLM(Mind Inference Engine Large Language Model,大语言模型)是MindIE系列的大语言模型推理组件,基于昇腾硬件提供业界通用大模型推理能力,同时提供多并发请求的功能。
- MindIE Service是面向通用模型场景的推理服务化框架,通过开放、可扩展的推理服务化平台架构提供推理服务化能力,支持对接业界主流推理框架接口,满足大语言模型的高性能推理需求。
1. DeepSeek模型推理在昇腾上的部署
1.1 硬件要求
部署DeepSeek-R1模型用BF16权重进行推理至少需要4台Atlas 800I A2(8*64G)服务器,用W8A8量化权重进行推理则至少需要2台Atlas 800I A2 (8*64G)。
1.2 环境准备与部署
1.2.1 权重
1.2.1.1 FP8原始权重下载
目前提供模型权重下载脚本,支持HuggingFace,ModelScope以及Modelers来源的模型下载,用法如下:
鉴于DeepSeek-V2、V3、R1系列模型结构高度相似,模块化后组图代码差异较小。为提升代码复用率并降低冗余,三个模型的共享代码模块已统一整合至[代码仓](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master DeepSeek-V2)文件夹中。
注意:以下引用的atb_models
路径在DeepSeek-V2
路径下:
git clone https://gitee.com/ascend/ModelZoo-PyTorch.git
cd ModelZoo-PyTorch/MindIE/LLM/DeepSeek/DeepSeek-V2/
- 确认
atb_models/build/weights_url.yaml
文件中对应repo_id,当前已默认配置模型官方认可的下载地址,如您有其他信任来源的repo_id,可自行修改,默认配置如下:
HuggingFace: deepseek-ai/DeepSeek-R1
ModelScope: deepseek-ai/DeepSeek-R1
Modelers: None
- 执行下载脚本
atb_models/build/download_weights.py
:
python3 atb_models/build/download_weights.py
1.2.1.2 权重转换(Convert FP8 weights to BF16)
若用户使用上方download_weights.py
脚本下载权重,则无需使用以下git clone命令,直接进入权重转换脚本目录。
git clone https://gitee.com/ascend/ModelZoo-PyTorch.git
cd ModelZoo-PyTorch/MindIE/LLM/DeepSeek/DeepSeek-V2/NPU_inference
python fp8_cast_bf16.py --input-fp8-hf-path {/path/to/DeepSeek-R1} --output-bf16-hf-path {/path/to/deepseek-R1-bf16}
目前npu转换脚本不会自动复制tokenizer等文件,需要将原始权重的tokenizer.json, tokenizer_config.json等文件复制到转换之后的路径下。
注意:
-
/path/to/DeepSeek-R1
表示DeepSeek-R1原始权重路径,/path/to/deepseek-R1-bf16
表示权重转换后的新权重路径。 -
由于模型权重较大,请确保您的磁盘有足够的空间放下所有权重,例如DeepSeek-R1在转换前权重约为640G左右,在转换后权重约为1.3T左右。
-
推理作业时,也请确保您的设备有足够的空间加载模型权重,并为推理计算预留空间。
1.2.1.3 BF16原始权重下载
也可以通过HuggingFace、ModelScope等开源社区直接下载BF16模型权重:
1.2.1.4 W8A8量化权重生成(BF16 to INT8)
目前支持:生成模型W8A8混合量化权重,使用histogram量化方式 (MLA:W8A8量化,MOE:W8A8 dynamic pertoken量化)。详情请参考 DeepSeek模型量化方法介绍
注意:DeepSeek-R1模型权重较大,量化权重生成时间较久,请耐心等待;具体时间与校准数据集大小成正比,10条数据大概需花费3小时。
1.2.1.5 昇腾原生量化W8A8权重下载(动态量化)
也可以通过Modelers等开源社区直接下载昇腾原生量化W8A8模型权重:
Deepseek-R1
1.2.2 推理前置准备
修改模型文件夹属组为1001 -HwHiAiUser属组(容器为Root权限可忽视)。
执行权限为750:
chown -R 1001:1001 {/path-to-weights/DeepSeek-R1}
chmod -R 750 {/path-to-weights/DeepSeek-R1}
修改权重目录下的config.json文件。
将 model_type 更改为 deepseekv2 (全小写且无空格)。
"model_type": "deepseekv2"
注意:在本仓实现中,DeepSeek-R1目前沿用DeepSeek-V2代码框架。
检查机器网络情况
1.检查物理链接
for i in {0..7}; do hccn_tool -i $i -lldp -g | grep Ifname; done
2.检查链接情况
for i in {0..7}; do hccn_tool -i $i -link -g ; done
3.检查网络健康情况
for i in {0..7}; do hccn_tool -i $i -net_health -g ; done
4.查看侦测ip的配置是否正确
for i in {0..7}; do hccn_tool -i $i -netdetect -g ; done
5.查看网关是否配置正确
for i in {0..7}; do hccn_tool -i $i -gateway -g ; done
6.检查NPU底层tls校验行为一致性,建议统一全部设置为0,避免hccl报错
for i in {0..7}; do hccn_tool -i $i -tls -g ; done | grep switch
7.NPU底层tls校验行为置0操作,建议统一全部设置为0,避免hccl报错
for i in {0..7};do hccn_tool -i $i -tls -s enable 0;done
获取每张卡的ip地址
for i in {0..7};do hccn_tool -i $i -ip -g; done
需要用户自行创建rank_table_file.json,参考如下格式配置:
以下是一个双机用例,用户自行添加ip,补全device:
{
"server_count": "2",
"server_list": [
{
"device": [
{
"device_id": "0",
"device_ip": "...",
"rank_id": "0"
},
{
"device_id": "1",
"device_ip": "...",
"rank_id": "1"
},
...
{
"device_id": "7",
"device_ip": "...",
"rank_id": "7"
},
],
"server_id": "...",
"container_ip": "..."
},
{
"device": [
{
"device_id": "0",
"device_ip": "...",
"rank_id": "8"
},
{
"device_id": "1",
"device_ip": "...",
"rank_id": "9"
},
...
{
"device_id": "7",
"device_ip": "...",
"rank_id": "15"
},
],
"server_id": "...",
"container_ip": "..."
},
],
"status": "completed",
"version": "1.0"
}
参数 | 说明 |
---|---|
server_count | 总节点数 |
server_list | server_list中第一个server为主节点 |
device_id | 当前卡的本机编号,取值范围[0, 本机卡数) |
device_ip | 当前卡的ip地址,可通过hccn_tool命令获取 |
rank_id | 当前卡的全局编号,取值范围[0, 总卡数) |
server_id | 当前节点的ip地址 |
container_ip | 容器ip地址(服务化部署时需要),若无特殊配置,则与server_id相同 |
rank_table_file.json配置完成后,需要执行命令修改权限为640。
chmod -R 640 {rank_table_file.json路径}
1.2.3 加载镜像
需要使用MindIe:2.0.T3及其后版本,建议使用MindIE2.0.RC2
前往昇腾社区/开发资源下载适配,下载镜像前需要申请权限,耐心等待权限申请通过后,根据指南下载对应镜像文件。
DeepSeek-R1的镜像版本:2.0.T3-800I-A2-py311-openeuler24.03-lts
镜像加载后的名称:swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:2.0.T3-800I-A2-py311-openeuler24.03-lts
完成之后,请使用`docker images`命令确认查找具体镜像名称与标签。
docker images
组件 | 版本 |
---|---|
MindIE | 2.0.T3 |
CANN | 8.0.T63 |
Pytorch | 6.0.T700 |
MindStudio | Msit: br_noncom_MindStudio_8.0.0_POC_20251231分支 |
Ascend HDK | 24.1.0 |
1.2.4 容器启动
1.2.4.1 启动容器
执行以下命令启动容器(参考):
docker run -itd --privileged --name= {容器名称} --net=host \
--shm-size 500g \
--device=/dev/davinci0 \
--device=/dev/davinci1 \
--device=/dev/davinci2 \
--device=/dev/davinci3 \
--device=/dev/davinci4 \
--device=/dev/davinci5 \
--device=/dev/davinci6 \
--device=/dev/davinci7 \
--device=/dev/davinci_manager \
--device=/dev/hisi_hdc \
--device /dev/devmm_svm \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/Ascend/firmware:/usr/local/Ascend/firmware \
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
-v /usr/local/sbin:/usr/local/sbin \
-v /etc/hccn.conf:/etc/hccn.conf \
-v {/权重路径:/权重路径} \
-v {/rank_table_file.json路径:/rank_table_file.json路径} \
{swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:1.0.0-XXX-800I-A2-arm64-py3.11(根据加载的镜像名称修改)} \
bash
1.2.4.2 进入容器
执行以下命令进入容器(参考):
docker exec -it {容器名称} bash
1.2.4.3 设置基础环境变量
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh
source /usr/local/Ascend/atb-models/set_env.sh
source /usr/local/Ascend/mindie/set_env.sh
1.2.4.4 开启通信环境变量
export ATB_LLM_HCCL_ENABLE=1
export ATB_LLM_COMM_BACKEND="hccl"
export HCCL_CONNECT_TIMEOUT=7200 # 该环境变量需要配置为整数,取值范围[120,7200],单位s
双机:
export WORLD_SIZE=16
四机:
export WORLD_SIZE=32
export HCCL_EXEC_TIMEOUT=0
1.3 模型推理
1.3.1 纯模型推理
使用场景:采用相同输入长度和相同输出长度,构造多Batch去测试纯模型性能
1.3.1.1 精度测试
进入modeltest路径
cd /usr/local/Ascend/atb-models/tests/modeltest/
运行测试脚本
Step1.主副节点分别先清理残余进程:
pkill -9 -f 'mindie|python'
Step2.需在所有机器上同时执行:
bash run.sh pa_[data_type] [dataset] ([shots]) [batch_size] [model_name] ([is_chat_model]) [weight_dir] [rank_table_file] [world_size] [node_num] [rank_id_start] [master_address] ([parallel_params])
参数说明:
-
data_type
:为数据类型,根据权重目录下config.json的data_type选择bf16或者fp16,例如:pa_bf16。 -
dataset
:可选full_BoolQ、full_CEval等,相关数据集可至魔乐社区MindIE下载,(下载之前,需要申请加入组织,下载之后拷贝到/usr/local/Ascend/atb-models/tests/modeltest/路径下)CEval与MMLU等数据集需要设置shots
(通常设为5)。 -
batch_size
:为batch数
。 -
model_name
:为deepseekv2
。 -
is_chat_model
:为是否支持对话模式,若传入此参数,则进入对话模式
。 -
weight_dir
:为模型权重路径。 -
rank_table_file
:为“前置准备”中配置的rank_table_file.json
路径。 -
world_size
:为总卡数。 -
node_num
:为当前节点编号,即rank_table_file.json
的server_list
中顺序确定。 -
rank_id_start
:为当前节点起始卡号,即rank_table_file.json
中当前节点第一张卡的rank_id
,Atlas 800I-A2双机场景下,主节点为0,副节点为8。 -
master_address
:为主节点ip地址,即rank_table_file.json
的server_list
中第一个节点的ip。 -
parallel_params
: 接受一组输入,格式为[dp,tp,moe_tp,moe_ep,pp,microbatch_size],如[8,1,8,-1,-1,-1]
测试脚本运行如下,以双机为例:
样例 -CEval 带shot
主节点
bash run.sh pa_bf16 full_CEval 5 1 deepseekv2 {/path/to/weights/DeepSeek-R1} {/path/to/xxx/ranktable.json} 16 2 0 {主节点IP}
0 代表从0号卡开始推理,之后的机器依次从8,16,24。
副节点
bash run.sh pa_bf16 full_CEval 5 1 deepseekv2 {/path/to/weights/DeepSeek-R1} {/path/to/xxx/ranktable.json} 16 2 8 {主节点IP}
0 代表从0号卡开始推理,之后的机器依次从8,16,24。
样例 -GSM8K 不带shot
主节点
bash run.sh pa_bf16 full_GSM8K 8 deepseekv2 {/path/to/weights/DeepSeek-R1} {/path/to/xxx/ranktable.json} 16 2 0 {主节点IP}
0 代表从0号卡开始推理,之后的机器依次从8,16,24。
副节点
bash run.sh pa_bf16 full_GSM8K 8 deepseekv2 {/path/to/weights/DeepSeek-R1} {/path/to/xxx/ranktable.json} 16 2 8 {主节点IP}
0 代表从0号卡开始推理,之后的机器依次从8,16,24。
1.3.1.2 性能测试
进入modeltest路径:
cd /usr/local/Ascend/atb-models/tests/modeltest/
Step1. 主副节点分别先清理残余进程:
pkill -9 -f 'mindie|python'
Step2. 需在所有机器上同时执行:
bash run.sh pa_[data_type] performance [case_pair] [batch_size] ([prefill_batch_size]) [model_name] ([is_chat_model]) [weight_dir] [rank_table_file] [world_size] [node_num] [rank_id_start] [master_address] ([parallel_params])
参数说明:
-
data_type
:为数据类型,根据权重目录下config.json的data_type选择bf16或者fp16,例如:pa_bf16。 -
case_pair
:[最大输入长度,最大输出长度]。 -
batch_size
:为batch数
。 -
prefill_batch_size
:为可选参数,设置后会固定prefill的batch size。 -
model_name
:为deepseekv2
。 -
is_chat_model
:为是否支持对话模式,若传入此参数,则进入对话模式
。 -
weight_dir
:为模型权重路径。 -
rank_table_file
:为“前置准备”中配置的rank_table_file.json
路径。 -
world_size
:为总卡数。 -
node_num
:为当前节点编号,即rank_table_file.json
的server_list
中顺序确定。 -
rank_id_start
:为当前节点起始卡号,即rank_table_file.json
中当前节点第一张卡的rank_id
,Atlas 800I-A2双机场景下,主节点为0,副节点为8。 -
master_address
:为主节点ip地址,即rank_table_file.json
的server_list
中第一个节点的ip。 -
parallel_params
: 接受一组输入,格式为[dp,tp,moe_tp,moe_ep,pp,microbatch_size],如[8,1,8,-1,-1,-1]
测试脚本运行如下,以双机为例:
主节点
bash run.sh pa_bf16 performance [[256,256]] 1 deepseekv2 {/path/to/weights/DeepSeek-R1} {/path/to/xxx/ranktable.json} 16 2 0 {主节点IP}
0 代表从0号卡开始推理,之后的机器依次从8,16,24。
副节点
bash run.sh pa_bf16 performance [[256,256]] 1 deepseekv2 {/path/to/weights/DeepSeek-R1} {/path/to/xxx/ranktable.json} 16 2 8 {主节点IP}
0 代表从0号卡开始推理,之后的机器依次从8,16,24。
1.3.2 服务化推理
【使用场景】对标真实客户上线场景,使用不同并发、不同发送频率、不同输入长度和输出长度分布,去测试服务化性能
1.3.2.1 配置服务化环境变量
变量含义:expandable_segments-使能内存池扩展段功能,即虚拟内存特性。更多详情请查看昇腾环境变量参考
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
服务化需要rank_table_file.json
中配置container_ip
字段。
所有机器的配置应该保持一致,除了环境变量的MIES_CONTAINER_IP为本机ip地址。
export MIES_CONTAINER_IP= {容器ip地址}
export RANKTABLEFILE= {rank_table_file.json路径}
1.3.2.2 修改服务化参数
cd /usr/local/Ascend/mindie/latest/mindie-service/
vim conf/config.json
修改以下参数:
"httpsEnabled" : false, # 如果网络环境不安全,不开启HTTPS通信,即“httpsEnabled”=“false”时,会存在较高的网络安全风险
"multiNodesInferEnabled" : true, # 开启多机推理
# 若不需要安全认证,则将以下两个参数设为false
"interCommTLSEnabled" : false,
"interNodeTLSEnabled" : false,
...
"npudeviceIds" : \[\[0,1,2,3,4,5,6,7\]\],
...
"modelName" : "DeepSeek-R1", # 不影响服务化拉起
"modelWeightPath" : "权重路径",
"worldSize":8,
Example:仅供参考,请根据实际情况修改。
{
"Version" : "1.0.0",
"LogConfig" :
{
"logLevel" : "Info",
"logFileSize" : 20,
"logFileNum" : 20,
"logPath" : "logs/mindie-server.log"
},
"ServerConfig" :
{
"ipAddress" : "改成主节点IP",
"managementIpAddress" : "改成主节点IP",
"port" : 1025,
"managementPort" : 1026,
"metricsPort" : 1027,
"allowAllZeroIpListening" : false,
"maxLinkNum" : 1000, //如果是4机,建议300
"httpsEnabled" : false,
"fullTextEnabled" : false,
"tlsCaPath" : "security/ca/",
"tlsCaFile" : ["ca.pem"],
"tlsCert" : "security/certs/server.pem",
"tlsPk" : "security/keys/server.key.pem",
"tlsPkPwd" : "security/pass/key_pwd.txt",
"tlsCrlPath" : "security/certs/",
"tlsCrlFiles" : ["server_crl.pem"],
"managementTlsCaFile" : ["management_ca.pem"],
"managementTlsCert" : "security/certs/management/server.pem",
"managementTlsPk" : "security/keys/management/server.key.pem",
"managementTlsPkPwd" : "security/pass/management/key_pwd.txt",
"managementTlsCrlPath" : "security/management/certs/",
"managementTlsCrlFiles" : ["server_crl.pem"],
"kmcKsfMaster" : "tools/pmt/master/ksfa",
"kmcKsfStandby" : "tools/pmt/standby/ksfb",
"inferMode" : "standard",
"interCommTLSEnabled" : false,
"interCommPort" : 1121,
"interCommTlsCaPath" : "security/grpc/ca/",
"interCommTlsCaFiles" : ["ca.pem"],
"interCommTlsCert" : "security/grpc/certs/server.pem",
"interCommPk" : "security/grpc/keys/server.key.pem",
"interCommPkPwd" : "security/grpc/pass/key_pwd.txt",
"interCommTlsCrlPath" : "security/grpc/certs/",
"interCommTlsCrlFiles" : ["server_crl.pem"],
"openAiSupport" : "vllm"
},
"BackendConfig" : {
"backendName" : "mindieservice_llm_engine",
"modelInstanceNumber" : 1,
"npuDeviceIds" : [[0,1,2,3,4,5,6,7]],
"tokenizerProcessNumber" : 8,
"multiNodesInferEnabled" : true,
"multiNodesInferPort" : 1120,
"interNodeTLSEnabled" : false,
"interNodeTlsCaPath" : "security/grpc/ca/",
"interNodeTlsCaFiles" : ["ca.pem"],
"interNodeTlsCert" : "security/grpc/certs/server.pem",
"interNodeTlsPk" : "security/grpc/keys/server.key.pem",
"interNodeTlsPkPwd" : "security/grpc/pass/mindie_server_key_pwd.txt",
"interNodeTlsCrlPath" : "security/grpc/certs/",
"interNodeTlsCrlFiles" : ["server_crl.pem"],
"interNodeKmcKsfMaster" : "tools/pmt/master/ksfa",
"interNodeKmcKsfStandby" : "tools/pmt/standby/ksfb",
"ModelDeployConfig" :
{
"maxSeqLen" : 10000,
"maxInputTokenLen" : 2048,
"truncation" : true,
"ModelConfig" : [
{
"modelInstanceType" : "Standard",
"modelName" : "deepseekr1",
"modelWeightPath" : "/home/data/dsR1_base_step178000",
"worldSize" : 8,
"cpuMemSize" : 5,
"npuMemSize" : -1,
"backendType" : "atb",
"trustRemoteCode" : false
}
]
},
"ScheduleConfig" :
{
"templateType" : "Standard",
"templateName" : "Standard_LLM",
"cacheBlockSize" : 128,
"maxPrefillBatchSize" : 8,
"maxPrefillTokens" : 2048,
"prefillTimeMsPerReq" : 150,
"prefillPolicyType" : 0,
"decodeTimeMsPerReq" : 50,
"decodePolicyType" : 0,
"maxBatchSize" : 8,
"maxIterTimes" : 1024,
"maxPreemptCount" : 0,
"supportSelectBatch" : false,
"maxQueueDelayMicroseconds" : 5000
}
}
}
1.3.2.3 拉起服务化
# 以下命令需在所有机器上同时执行
# 解决权重加载过慢问题
export OMP_NUM_THREADS=1
# 设置显存比
export NPU_MEMORY_FRACTION=0.95
# 拉起服务化
cd /usr/local/Ascend/mindie/latest/mindie-service/
./bin/mindieservice_daemon
执行命令后,首先会打印本次启动所用的所有参数,然后直到出现以下输出:
Daemon start success!
则认为服务成功启动。
另起客户端,进入相同容器,向服务端发送请求。
更多信息可参考官网信息:MindIE Service
1.3.2.4 精度化测试样例
需要开启确定性计算环境变量。
export LCCL_DETERMINISTIC=1
export HCCL_DETERMINISTIC=true
export ATB_MATMUL_SHUFFLE_K_ENABLE=0
并发数需设置为1,确保模型推理时是1batch输入,这样才可以和纯模型比对精度。
使用MMLU比对精度时,MaxOutputLen应该设为20,MindIE Server的config.json文件中maxSeqLen需要设置为3600,该数据集中有约为1.4w条数据,推理耗时会比较长。
benchmark \
--DatasetPath "/数据集路径/MMLU" \
--DatasetType mmlu \
--ModelName DeepSeek-R1 \
--ModelPath "/模型权重路径/DeepSeek-R1" \
--TestType client \
--Http https://{ipAddress}:{port} \
--ManagementHttp https://{managementIpAddress}:{managementPort} \
--Concurrency 1 \
--MaxOutputLen 20 \
--TaskKind stream \
--Tokenizer True \
--TestAccuracy True
ModelName,ModelPath需要与mindie-service里的config.json里的一致,master_ip设置为主节点机器的ip。样例仅供参考,请根据实际情况调整参数。
2. DeepSeek模型迁移适配
2.1 Pytorch接口适配
2.1.1权重加载与传参
DeepSeek模型权重加载功能主要在modeling_deepseekv2.py承载,模型传参功能则主要在flash_causal_deepseekv2.py中承载。模型其他代码在atb_llm的文件目录结构如下:
└───atb_llm
│ └───models
│ └───deepseekv2
│ | | config_deepseekv2.py
│ | | flash_causal_deepseekv2.py
│ | | modeling_deepseekv2.py
│ | | position_embedding_deepseekv2.py
│ | | process_attn_linear_deepseekv2.py
│ | | router_deepseekv2.py
│ | | weight_wrapper_deepseekv2.py
2.1.1.1权重加载
- 当前模型直接采用pytorch-npu将权重加载到NPU设备,采用原生pytorch接口,用户编写容易。模型通过nn.Module类继承形式读取权重,符合社区主流开发范式。
- modeling_deepseekv2.py包含浮点/量化权重加载、混合并行权重切分等重要功能
2.1.1.2组图转化与传参
当前模型采用ATB-models作为执行后端。在模型执行前需要将模型权重转换为ATB能够使用的状态,同时完成计算图的构建。这其中执行逻辑主要在flash_causal_deepseekv2.py
中实现,其完成的主要功能如下:
- 权重转换,将torch权重注册为ATB model权重,包括MLA、MoE性能优化所需要的特殊处理逻辑。
- 特性开关传参,为模型特性提供Python API
- 辅助张量构造,根据输入、为混合并行构造padding idx。
- MTP推理
2.1.2性能优化特性介绍
2.1.2.1融合算子列表
- MLAPO/PA: MLA大融合算子/PagedAttention优化。
- FusedTopk:Topk算子融合
- MoEInitRouting/Unpermute:专家路由、反重排。
- MoeDistributeDispatch/Combine:通算融合,专家路由和All2AllV算子进行融合,提升性能。
- GMM+SwigluQuant: 专家计算和非线性层融合。
2.1.2.2并行特性矩阵
当前MindIE支持多种并行策略,包括模型级的并行例如张量并行、数据并行、专家并行,也包括局部模块小并行策略例如o矩阵张量并行、QKV张量并行、LmHead局部张量并行。
并行策略 | Prefill | Decode |
---|---|---|
TP | √ | √ |
DP | √ | √ |
MOE TP | √ | √ |
MOE EP | √ | √ |
ATTN SP | √ | |
Extra QKV TP | √ | |
Extra Oproj TP | √ | √ |
Local LMHead TP TP | √ | √ |
2.2 ATB-Models组图
2.2.1模型组图设计
整体组图共分为4个部分:Attention(MLA)/ PostAttnProcess-PostFFNProcess / FFN (Dense 层和 MoE)
- MLA: KV cache优化/DP并行
- FFN: MoE/Dense 层实现
- PostAttnProcess/PostFFNprocess 串联各种并行方式的关键接口
2.2.1.1 MLA
MLA实质上是算力bound,因此Prefill和Decode阶段采用不同的组图设计
- Prefill阶段使用基于MHA的组图结构,FA算子算力压力更小
- Decode阶段则使用推理优化MQA的组图,PA算子访存效率更高
2.1.2.2 MoE
针对不同场景,实现三种MoE EP部署形式
- Dispatch/combine: 利用通算融合实现动态shape的ALL2ALL通信,适用于集群推理,速度快,但bs场景受限,暂时只能在decode使用
- All2All动态EP:预先申请通信buffer,通信内容依赖模型侧计算结果,通信量较少;但输入token较少时需要额外的buffer防止精度损失,且计算通信meta信息需要引入大量小算子,适用于prefill阶段。
- Allgather EP:实现最简单,算子依赖少,稳定。但在集群和prefill阶段通信量大。
2.2.2模型代码结构
DeepSeek模型组图在atb_framework/models/deepseekv2、atb_framework/operations/fusion/moe、atb_framework/operations/aclnn中承载。其中:
- atb_framework/models/deepseekv2包括混合并行、MLA等特性。
- atb_framework/operations/fusion/moe包括MoE计算,专家并行等特性。
- atb_framework/operations/aclnn中包括部分融合算子插件
3. DeepSeek模型并行策略及模型性能调优
3.1 DeepSeek并行体系简介
本节介绍 DeepSeek 在昇腾平台上的并行体系结构,涵盖其支持的主要并行方式、典型模块的并行策略、以及常见的并行组合方式。
3.1.1 支持的主要并行方式
DP(Data Parallel,数据并行):不同设备上复制完整权重,每张卡处理不同数据子集,适合横向扩展。
TP(Tensor Parallel,张量并行):将权重矩阵按维度拆分到多张卡上并行计算,适合大模型的矩阵乘法加速。
SP(Sequence Parallel,序列并行):将序列维度划分到多张卡上,提升长序列处理能力。
EP(Expert Parallel,专家并行):主要用于 MoE(Mixture of Experts)模型,按专家维度进行并行。
此外,V3 还支持这些并行方式的组合部署,以平衡通信、显存与性能。
3.1.2 Attention模块支持的并行策略
- DP:按 batch 维度划分样本,每张卡独立执行前向与反向传播,模型参数一致。
- TP:按隐藏层维度切分模型权重,多卡协同完成一个样本的计算任务。
- SP:针对超长序列,将序列维度切分到多卡上,减少单卡显存压力。
- OprojTP:对 Attention 中输出投影矩阵 O 单独做 TP 切分,在小数据场景进一步优化性能。
并行组合建议如下:
- 机内(同一节点内):推荐使用 TP 或 DP
- 机间(跨节点):推荐使用 DP 进行横向扩展
3.1.3 MoE模块支持的并行策略
MoE 模块目前支持以下两类并行方式:
- EP(Expert Parallel):V3的核心并行方式,将专家拆分到不同设备。
- TP(Tensor Parallel):对每个专家内部继续使用张量并行(注意:当前仅
allgatherEP
模式支持 EP + TP 的混合并行。all2allEP
模式下尚未支持 TP 嵌套)。
EP目前有两种实现方式:
模式 | 特点 | 推荐场景 |
---|---|---|
allgatherEP | Attention 输出先通过 AllGather 汇总,各卡只计算本地专家对应的激活token,最后经 ReduceScatter 聚合输出结果。 | 适用于小规模集群(16~32卡) |
all2allEP | token通过AllToAll 派发,专家分布式处理。 | 适用于中~大规模集群(16卡以上) |
配置方式说明:通过 MindIE模型仓的config.json
中设置 ep_level
参数进行选择:
ep_level = 1
→ 启用allgatherEP
ep_level = 2
→ 启用all2allE
3.1.4 其他模块
- WordEmbedding:支持TP/DP并行
- MLP:支持TP/DP并行
- LMHead:支持TP/DP并行
3.2 并行策略快速选择示例
以下为典型昇腾硬件环境下,不同业务场景(中短序列、长序列、低时延、高吞吐)下的推荐并行策略配置。
3.2.1两机 A2 配置示例
配置说明:共 2 节点,每节点 8 张 A2 卡,共 16 卡。
中短序列场景(输入长度 ≤16K):
- Attention 层:DP=4, TP=4;在显存足够情况下,有效降低 Attention 通信压力,提升单卡计算效率;
- MoE 层:TP=4, EP=4, EP模式=allgatherEP;减轻专家负载不均(降低长尾问题),同时提升计算亲和性与整体吞吐性能。
长序列场景(输入长度可达 64K):
- Attention 层:DP=2, TP=8, SP=8;SP 与 TP 联合使用,有效分摊长序列计算与权重显存压力,避免单卡爆显存,DP=2 降低多机间通信开销;
- MoE 层:TP=1, EP=16, EP模式=all2allEP;通过all2allEP的分布式模式,降低激活在单卡的堆积,减小内存瓶颈。
3.2.2 八机 A2 配置示例
配置说明:共 8 节点,每节点 8 张 A2 卡,共 64 卡。
机制低时延场景(小 batch 处理):
- Attention 层:TP=8, DP=8;DP=8 降低并行度,避免小 batch 情况下计算资源浪费(DP 数量应 ≤ batch size);TP=8 保持并行效率,在 batch 小的情况下提升带宽利用率与计算速度;
- MoE 层:TP=1, EP=64, EP模式=all2allEP;使用 all2allEP,适配 64 卡大集群,避免 allgatherEP 带来的高通信开销。
高吞吐场景(大 batch 推理):
方案 A: 标准高吞吐配置(纯 DP 提升吞吐)
- Attention 层:TP=1, DP=64
- MoE 层:TP=1, EP=64, EP模式=all2allEP
方案 B:增强版配置(开启 O 投影并行,减少显存占用,进一步扩展bs上限)
- Attention 层:TP=1, DP=64, OprojTP=8
- MoE 层:TP=1, EP=64, EP模式=all2allEP
3.2.3 总结与建议
- 小规模集群建议使用 allgatherEP,减少通信复杂度;大规模集群使用 all2allEP 提升并行效率。
- TP 与 SP 的选择需结合序列长度与显存容量权衡,长序列场景建议开启 SP。
- 对于小 batch 低延迟场景,TP并行可减少计算时间;高吞吐场景则更偏向 DP 主导。
3.3 关键实现与调优点
本节介绍 DeepSeek 在并行部署中的关键优化策略与常见性能瓶颈排查方案,帮助在实际应用中高效定位与调优。
3.3.1关键优化点介绍
(1)OProjTP:输出投影矩阵并行优化
适用场景:推理/Decode阶段显存紧张、带宽受限场景
原理说明:在 Attention 模块中,仅对输出投影矩阵 O 单独进行 Tensor Parallel 拆分
优点:
减带宽:O矩阵是Attention模块中最大的权重矩阵,在小数据计算时为带宽受限,可以通过TP切分时减轻加载开销
免复制:由于仅O矩阵为TP,KVCache仍处于DP域,无需做TP相关的KV复制
缺点:
需要额外 2 次通信:AllToAllT(前)、ReduceScatter(后)
数据量大时,通信成本 > TP带来的计算加速收益
(2)EPLB:基于热度的专家负载均衡
适用场景:All2AllEP存在卡间负载不均,出现快慢卡现象
问题现象:All2AllEP 在专家域较大(如 EP=64、 EP=256)时,部分卡聚集了热点专家,推理阶段出现快慢卡,降低整体吞吐。
优化策略:
收集专家热度(TopK激活频率)
采用静态副本 + 分散部署策略(EPLB),将热点专家做冗余并均匀部署
热门专家与冷门专家混布,平均各卡计算负载
3.3.2常见性能瓶颈与应对策略
(1)显存瓶颈(长序列或大 batch 场景)
原因:Attention KVCache + 激活值均占用大量显存
解决方案:
开启 split_fuse 特性,预填充(Prefill)阶段按 bs 切分,降低峰值显存占用
将 Attention 的 DP 模式部分替换为 TP2/TP4 或 OProjTP8
对于长序列,开启 SP 并结合 TP,将序列和权重分别并行拆分
(2)性能波动 / 吞吐不稳定(All2AllEP场景)
原因:专家分布不均或热度动态变化,导致卡间快慢拖尾
解决方案:
重新采集专家热度(使用真实业务数据)
更新 EPLB 映射策略,生成新的专家部署方案
4. DeepSeek量化精度及性能调优
4.1 量化能力介绍
4.1.1 量化范围及其影响
W4/W8量化: 将权重量化到int4或int8类型,目的是为了减少显存占用和减少算子内存搬运量。
A8量化: 往往搭配W4/W8一起量化,此量化方式对权重和激活值同时进行量化,将高位浮点数转为8 bit,减少模型权重的体积。使用int8格式的数据进行计算,可以减少MatMul算子计算量,以提升推理性能。
C8量化: 当前只支持W8A8C8量化(FA3),Attention的Q,K,V都用int8计算,提高Attention运算速度,并且KV cache存入int8的数据,节省显存。
4.1.2 当前DeepSeek V3/R1已经支持的量化类型
W4A8; W8A8C8(FA3); W8A8; W8A16; W4A16
当前版本W4A16和W8A16功能支持,但并不确保精度在要求范围。
4.2 量化跑通步骤
第一步,跑通一次非量化的模型。
第二步,生成一版量化的权重。
同时,对于W8A8 dynamic和W8A16两种量化类型,在安装完msModelSlim工具后,模型仓提供快速生成量化权重的命令:
# 设置CANN包的环境变量
source /usr/local/Ascend/ascend-toolkit/set_env.sh
# 生成w8a16量化权重
bash examples/models/deepseekv2/generate_quant_weight.sh -src {浮点权重路径} -dst {量化权重路径} -type deepseekv2_w8a16 -trust_remote_code
# 生成w8a8 dynamic量化权重
bash examples/models/deepseekv2/generate_quant_weight.sh -src {浮点权重路径} -dst {量化权重路径} -type deepseekv2_w8a8_dynamic -trust_remote_code
MLA W8A16 + MoE W8A8 Dynamic混合精度量化, 生成w8a8 dynamic量化权重后,进行如下操作:
- 修改
config.py
文件,新增"mla_quantize": "w8a16"
- 修改
quant_model_description_w8a8_dynamic.json
文件,将包含self_attn
的字段中W8A8_DYNAMIC
修改为W8A16
第三步,根据不同的量化类型在权重config中写入不同的量化相关的参数。量化先关的参数主要有以下四个:
“quantize”: str, 必备参数,表示总体的量化类型
“moe_quantize”: str, MOE层的量化类型,如果没有则自动与 “quantize” 保持一致
“mla_quantize”: str, MLA的量化类型,如果没有则自动与 “quantize” 保持一致
“quantizetion_config”: dict, 一些量化的参数配置
W4A8的config如下:
"quantize":"w8a8 dynamic"
"mla quantize": "w8a8",
"quantization config":{
"group size":64 // per-group 量化
}
W8A8 dynamic 的配置如下:
"quantize":"w8a8 dynamic"
"mla quantize": "w8a8",
W8A8C8(FA3)的config如下:
"quantize":"w8a8 dynamic"
"mla quantize": "w8a8",
"quantization_config": {
"group_size": 0,
"kv_quant_type": null,
"fa_quant_type": "FAKQuant", // FA quant 开关
"w_bit": 8,
"a_bit": 8,
"dev_type": "npu",
"fraction": 0.01,
"act_method": 1,
"co_sparse": false,
"anti_method": "m1",
"disable_level": "L0",
"do_smooth": false,
"use_sigma": false,
"sigma_factor": 3.0,
"is_lowbit": false,
"mm_tensor": false,
"w_sym": true,
"open_outlier": true,
"is_dynamic": false
},
"nz_cache": true // FA3目前的kvcache只支持NZ格式
第四步,在atb-models/tests/modeltest/
目录下将权重路径换成量化后的权重跑,性能测试命令如下:
可以先将
bash run.sh pa_[data_type] performance [case_pair] [batch_size] ([prefill_batch_size]) (prefill_length [prefill_length]) (dataset [dataset_name]) (padding) ([batch_group]) [model_name] ([is_chat_model]) [weight_dir] ([trust_remote_code]) [rank_table_file] [world_size] [node_num] [rank_id_start] [master_address] ([max_position_embedding/max_sequence_length])
以双机为例,使用GSM8K数据集进行性能测试,命令如下:
bash run.sh pa_fp16 performance [[256,256]] 1 dataset gsm8k deepseekv2 weight_path ranktable_path 16 2 0 master_address [8,2,-1,4,4,-1,-1]
bash run.sh pa_fp16 performance [[256,256]] 1 dataset gsm8k deepseekv2 weight_path ranktable_path 16 2 8 master_address [8,2,-1,4,4,-1,-1]
精度测试命令如下:
bash run.sh pa_[data_type] [dataset] ([shots]) [batch_size] [model_name] ([is_chat_model]) [weight_dir] ([trust_remote_code]) [rank_table_file] [world_size] [node_num] [rank_id_start] [master_address](https://www.hiascend.com/developer/blog/details/[max_position_embedding/max_sequence_length])
以双机为例,测试CEval数据集命令如下:
bash run.sh pa_fp16 full_CEval 5 32 deepseekv2 weight_path ranktable_path 16 2 0 master_address [8,2,-1,4,4,-1,-1]
bash run.sh pa_fp16 full_CEval 5 32 deepseekv2 weight_path ranktable_path 16 2 0 master_address [8,2,-1,4,4,-1,-1]
4.3 量化精度调优
步骤一:调整离群值抑制算法
量化工具通过使用 AntiOutlierConfig 生成离群值抑制配置,启用离群值抑制功能。该 功能通过不同的算法对量化过程中的离群值进行抑制,进而提升量化模型的精度。
在AntiOutlierConfig配置中,可调整的参数为 anti_method
参数 | 算法名称 | 备注 |
---|---|---|
m1 | SmoothQuant 算法 | |
m2 | Outlier Suppression算法 | |
m3 | AWQ算法 | 仅权重量化算法 |
m4 | Iter Smooth Quant算法 | 对down层、o层异常值处理 |
m5 | CBQ 算法 | |
m6 | Flex Smooth 算法 | 支持自动搜索算法中的alpha/beta超参 |
在仅涉及权重量化的场景(如 W8A16 或 W4A16)下,选择 m3。 对于包含激活量化的场景,可根据场景需求在 m1、m2、m4、m5、m6 中尝试,以找到最适合的算法。
步骤二:激活量化算法选择
量化工具通过 QuantConfig 提供了量化配置的选择功能,其中激活量化算法是可优化的参数,对应字段为 act_method。该参数的默认值为 1,支持以下三种选项:
1:表示使用 min-max 量化方式。
2:表示使用 histogram 量化方式。
3:表示采用 min-max 和 histogram 自动混合量化方式。
步骤三:校准集调整
- 增大校准数据集规模:
- 当算法层面无法进一步提升精度时,可以尝试增大校准数据集的规模(通常建议在 10-50 条样本之间)。在正常情况下,增加数据量可以帮助提升模型精度,但当数据量达到一定规模后,继续增加数据对精度的影响将变得有限。
- 在某些特殊场景下(例如长文本数据场景),减少数据量反而可能带来精度的提升。
- 针对特定场景切换校准数据集: 中文模型、英文模型、代码生成模型、中英文兼顾的模型、数学场景可以使用对应场景的数据集作为校准数据集。
如果发现部分数据在校准后导致模型精度较低,可以尝试替换这些数据,选取更能代表模型分布的数据,以达到最优精度。当调优涉及多个数据集的精度时,可以从各数据集中抽取部分数据,混合组成一个新的校准数据集。这种方法可以帮助平衡不同数据分布的影响,从而提升整体精度。
步骤四:量化回退
某些网络层对于量化比较敏感,量化后会带来较大的精度损失,这些层并不适合进行量化,应该使用浮点权重进行计算,这个过程被称之为回退,量化工具支持自动回退和手动回退两种回退方式。
- 手动回退:量化工具通过 QuantConfig 提供了量化配置的选择功能,可通过设定disbale_name手动控制哪些层被回退。disable_names=[]:[]里添加回退层名称,如果不添加则为不回退。
- 自动回退:量化工具通过 Calibrator 类提供了自动回退选择功能,用户可通过设置参数 disable_level 来指定自动回退的层数。具体规则为:disable_level=‘LN’,N为自动回退的linear层数量,会在终端显示回退的层名称,disable_level='L0’即为不进行回退,若 N 的值超过模型总层数,则触发全部回退,且不会报错。(注:W8A16/W4A16不支持自动回退功能)
补充:
在W8A16/W4A16场景下,量化工具支持设置不同的权重量化方式,通过 QuantConfig中的w_method进行配置,可选值为 ‘MinMax’, ‘HQQ’, ‘GPTQ’。 W8A16场景下,大部分模型采用最简单的MinMax算法精度就能达到0.5%的精度损失。建议用户按照 MinMax → HQQ → GPTQ 的顺序逐步尝试,以找到最适合当前场景的权重量化方式。
目前msmodelslim仓库上为Deepseek配置了最佳实践参数组合:
W8A8量化:
anti_method=‘m4’
act_method=1,
校准集为预先配置好的混合校准集,以json形式体现
回退所有kv_b_proj层:
disable_names=[]
for ids in range(config.num_hidden_layers):
disable_names.append(“model.layers.” + str(ids) + “.self_attn.kv_b_proj”)
W8A8量化+FA3:
anti_method=‘m4’
act_method=1,
校准集为预先配置好的混合校准集,以json形式体现
回退所有self_attn.kv_b_proj层,另外R1和V3分别回退一些self_attn层;
5.常见问题链接
常见技术干货参见:昇腾MindIE 博客
开发者常见问题参见:昇腾MindIE 论坛