A12a_昇腾部署DeepSeek并行推理

昇腾部署DeepSeek并行推理

作者:Apricity

目 录

  1. DeepSeek模型推理在昇腾上的部署
  2. DeepSeek模型迁移适配
  3. DeepSeek模型并行策略及模型性能调优
  4. DeepSeek量化精度及性能调优
  5. 常见问题链接

前言

本文是昇腾开发者知识体系的配套材料,转载随意,如反馈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原始权重下载

Deepseek-R1

Deepseek-R1-Zero

目前提供模型权重下载脚本,支持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/
  1. 确认atb_models/build/weights_url.yaml文件中对应repo_id,当前已默认配置模型官方认可的下载地址,如您有其他信任来源的repo_id,可自行修改,默认配置如下:
HuggingFace: deepseek-ai/DeepSeek-R1
ModelScope: deepseek-ai/DeepSeek-R1
Modelers: None
  1. 执行下载脚本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模型权重:

huggingface

modelscope

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_listserver_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
组件版本
MindIE2.0.T3
CANN8.0.T63
Pytorch6.0.T700
MindStudioMsit: br_noncom_MindStudio_8.0.0_POC_20251231分支
Ascend HDK24.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])

参数说明:

  1. data_type:为数据类型,根据权重目录下config.json的data_type选择bf16或者fp16,例如:pa_bf16。

  2. dataset:可选full_BoolQ、full_CEval等,相关数据集可至魔乐社区MindIE下载,(下载之前,需要申请加入组织,下载之后拷贝到/usr/local/Ascend/atb-models/tests/modeltest/路径下)CEval与MMLU等数据集需要设置shots(通常设为5)。

  3. batch_size:为batch数

  4. model_name:为deepseekv2

  5. is_chat_model:为是否支持对话模式,若传入此参数,则进入对话模式

  6. weight_dir:为模型权重路径。

  7. rank_table_file:为“前置准备”中配置的rank_table_file.json路径。

  8. world_size:为总卡数。

  9. node_num:为当前节点编号,即rank_table_file.jsonserver_list中顺序确定。

  10. rank_id_start:为当前节点起始卡号,即rank_table_file.json中当前节点第一张卡的rank_id,Atlas 800I-A2双机场景下,主节点为0,副节点为8。

  11. master_address:为主节点ip地址,即rank_table_file.jsonserver_list中第一个节点的ip。

  12. 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])

参数说明:

  1. data_type:为数据类型,根据权重目录下config.json的data_type选择bf16或者fp16,例如:pa_bf16。

  2. case_pair:[最大输入长度,最大输出长度]。

  3. batch_size:为batch数

  4. prefill_batch_size:为可选参数,设置后会固定prefill的batch size。

  5. model_name:为deepseekv2

  6. is_chat_model:为是否支持对话模式,若传入此参数,则进入对话模式

  7. weight_dir:为模型权重路径。

  8. rank_table_file:为“前置准备”中配置的rank_table_file.json路径。

  9. world_size:为总卡数。

  10. node_num:为当前节点编号,即rank_table_file.jsonserver_list中顺序确定。

  11. rank_id_start:为当前节点起始卡号,即rank_table_file.json中当前节点第一张卡的rank_id,Atlas 800I-A2双机场景下,主节点为0,副节点为8。

  12. master_address:为主节点ip地址,即rank_table_file.jsonserver_list中第一个节点的ip。

  13. 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局部张量并行。

并行策略PrefillDecode
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 切分,在小数据场景进一步优化性能。

并行组合建议如下:

  1. 机内(同一节点内):推荐使用 TP 或 DP
  2. 机间(跨节点):推荐使用 DP 进行横向扩展

3.1.3 MoE模块支持的并行策略

MoE 模块目前支持以下两类并行方式:

  • EP(Expert Parallel):V3的核心并行方式,将专家拆分到不同设备。
  • TP(Tensor Parallel):对每个专家内部继续使用张量并行(注意:当前仅 allgatherEP 模式支持 EP + TP 的混合并行。all2allEP 模式下尚未支持 TP 嵌套)。

EP目前有两种实现方式:

模式特点推荐场景
allgatherEPAttention 输出先通过 AllGather 汇总,各卡只计算本地专家对应的激活token,最后经 ReduceScatter 聚合输出结果。适用于小规模集群(16~32卡)
all2allEPtoken通过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

参数算法名称备注
m1SmoothQuant 算法
m2Outlier Suppression算法
m3AWQ算法仅权重量化算法
m4Iter Smooth Quant算法对down层、o层异常值处理
m5CBQ 算法
m6Flex Smooth 算法支持自动搜索算法中的alpha/beta超参

在仅涉及权重量化的场景(如 W8A16 或 W4A16)下,选择 m3。 对于包含激活量化的场景,可根据场景需求在 m1、m2、m4、m5、m6 中尝试,以找到最适合的算法。

步骤二:激活量化算法选择

量化工具通过 QuantConfig 提供了量化配置的选择功能,其中激活量化算法是可优化的参数,对应字段为 act_method。该参数的默认值为 1,支持以下三种选项:

1:表示使用 min-max 量化方式。
2:表示使用 histogram 量化方式。
3:表示采用 min-max 和 histogram 自动混合量化方式。
步骤三:校准集调整
  1. 增大校准数据集规模:
  • 当算法层面无法进一步提升精度时,可以尝试增大校准数据集的规模(通常建议在 10-50 条样本之间)。在正常情况下,增加数据量可以帮助提升模型精度,但当数据量达到一定规模后,继续增加数据对精度的影响将变得有限。
  • 在某些特殊场景下(例如长文本数据场景),减少数据量反而可能带来精度的提升。
  1. 针对特定场景切换校准数据集: 中文模型、英文模型、代码生成模型、中英文兼顾的模型、数学场景可以使用对应场景的数据集作为校准数据集。

如果发现部分数据在校准后导致模型精度较低,可以尝试替换这些数据,选取更能代表模型分布的数据,以达到最优精度。当调优涉及多个数据集的精度时,可以从各数据集中抽取部分数据,混合组成一个新的校准数据集。这种方法可以帮助平衡不同数据分布的影响,从而提升整体精度。

步骤四:量化回退

某些网络层对于量化比较敏感,量化后会带来较大的精度损失,这些层并不适合进行量化,应该使用浮点权重进行计算,这个过程被称之为回退,量化工具支持自动回退和手动回退两种回退方式。

  1. 手动回退:量化工具通过 QuantConfig 提供了量化配置的选择功能,可通过设定disbale_name手动控制哪些层被回退。disable_names=[]:[]里添加回退层名称,如果不添加则为不回退。
  2. 自动回退:量化工具通过 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 论坛

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值