记录在两台910B4服务器上运行 W8A8 量化的 DeepSeek-R1-0528 模型,并使用 EvalScope 做一个简单的推理性能测试,后面还有一些推理性能相关的参数介绍以及模型报错排查方法
一、环境信息
| 模型 | DeepSeek-R1-0528-W8A8-MindIE | 需要是W8A8量化过的模型,每台机器上都要存放模型权重文件 |
| 服务器型号 | Atlas 800I A2 | 2台 |
| 显卡 | 910B4 | 64G/张,2台共16张卡 |
| MindIE | >=2.1.RC1 | 低于这个版本会出现对话时模型输出异常的问题 |
| 驱动 | >=24.1.0 |
1.1 下载模型权重文件
模型权重文件大概660G,需要确保服务器磁盘空间足够
从 ModelScope 上下载模型文件需要使用到modelscope工具
# 1、下载 modelscope
pip install modelscope
# 2、下载模型
modelscope download --model 'TensorLake/DeepSeek-R1-0528-W8A8-MindIE' --local_dir '/model/DeepSeek-R1-0528-W8A8-MindIE'
Bash
二、运行模型
2.1 准备 rank table 文件
使用多机推理时,需要将包含设备ip,服务器ip等信息的json文件地址传递给底层通信算子。
参考如下格式,配置 /model/rank_table_file.json (后面会将/model目录挂载到 MindIE 容器内),参考:
-
server_count:总节点数 -
server_list:节点列表,第一个server为主节点 -
server_id:当前节点的ip地址 -
container_ip:容器ip地址(服务化部署时需要),若无特殊配置,则与server_id相同 -
device_id:当前卡的本机编号,取值范围[0, 本机卡数) -
device_ip:当前卡的ip地址,可通过hccn_tool命令获取,参考命令for i in {0..7};do hccn_tool -i $i -ip -g; done -
rank_id:当前卡的全局编号,取值范围[0, 总卡数){
"version": "1.0",
"server_count": "2",
"server_list": [
{
"server_id": "Master节点IP地址",
"container_ip": "Master节点容器IP地址",
"device": [
{ "device_id": "0", "device_ip": "10.20.0.2", "rank_id": "0" },
{ "device_id": "1", "device_ip": "10.20.0.3", "rank_id": "1" },
{ "device_id": "2", "device_ip": "10.20.0.4", "rank_id": "2" },
{ "device_id": "3", "device_ip": "10.20.0.5", "rank_id": "3" },
{ "device_id": "4", "device_ip": "10.20.0.6", "rank_id": "4" },
{ "device_id": "5", "device_ip": "10.20.0.7", "rank_id": "5" },
{ "device_id": "6", "device_ip": "10.20.0.8", "rank_id": "6" },
{ "device_id": "7", "device_ip": "10.20.0.9", "rank_id": "7" }
]
},
{
"server_id": "Slave节点IP地址",
"container_ip": "Slave节点容器IP地址",
"device": [
{ "device_id": "0", "device_ip": "10.20.0.10", "rank_id": "8" },
{ "device_id": "1", "device_ip": "10.20.0.11", "rank_id": "9" },
{ "device_id": "2", "device_ip": "10.20.0.12", "rank_id": "10" },
{ "device_id": "3", "device_ip": "10.20.0.13", "rank_id": "11" },
{ "device_id": "4", "device_ip": "10.20.0.14", "rank_id": "12" },
{ "device_id": "5", "device_ip": "10.20.0.15", "rank_id": "13" },
{ "device_id": "6", "device_ip": "10.20.0.16", "rank_id": "14" },
{ "device_id": "7", "device_ip": "10.20.0.17", "rank_id": "15" }
]
}
],
"status": "completed"
}
JSON
2.2 运行 MindIE 容器
需要在两个节点上运行这个容器,随后会运行容器之后进入到容器内修改 MindIE 相关配置
参数说明:
-
--device=/dev/davinciN:挂载显卡设备,这里将8张卡全部挂载到容器内 -
--net=host:使用网络模式为host -
-v /model:/model:挂载宿主机上的模型权重文件到容器内,需要自行修改CONTAINER_NAME="deepseek-r1-0528"
MINDIE_IMAGE="swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:2.1.RC1-800I-A2-py311-openeuler24.03-lts"docker run -itd --privileged --name={CONTAINER_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/devmm_svm \ --device=/dev/hisi_hdc \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ -v /usr/local/sbin/:/usr/local/sbin/ \ -v /etc/hccn.conf:/etc/hccn.conf \ -v /model:/model \ {MINDIE_IMAGE}
/bin/bash在容器内查看显卡信息
docker exec -it ${CONTAINER_NAME} npu-smi info
Bash
2.3 修改 MindIE 配置
修改两台机器上 MindIE 容器的配置,除ipAddress外其他配置都保持一致
# 进入 MindIE 容器
docker exec -it deepseek-r1-0528 bash
# 在容器内修改 MindIE 配置文件
vim /usr/local/Ascend/mindie/latest/mindie-service/conf/config.json
Bash
配置文件参考如下:
https://www.hiascend.com/document/detail/zh/mindie/21RC1/mindiellm/llmdev/mindie_llm0004.html
ServerConfig:ipAddress: 修改为容器/服务器IP地址(由于MindIE启动命令中指定了网络模式为 host,所以容器IP地址与服务器IP地址一致)httpsEnabled: 配置为falseinterCommTLSEnabled: 配置为false
BackendConfig:multiNodesInferEnabled: 配置为trueinterNodeTLSEnabled: 配置为falsenpuDeviceIds: 使用NPU卡的索引,多张卡的索引号使用逗号分隔,比如[[0,1]]。多机推理场景下该值无效,每个节点上使用的npuDeviceIds根据ranktable计算获得。modelName: 模型名称,比如deepseek-r4-0528,在后续调用模型需要在请求中填写该名称modelWeightPath: 模型权重路径,比如/model/DeepSeek-R1-0528-W8A8-MindIEworldSize: 模型参数中worldSize必须与使用的NPU数量相等。多机推理场景下该值无效,worldSize根据ranktable计算获得。dp/tp/sp/moe_tp/moe_ep: 如果配置文件中没有这几个配置,需要手动添加(参考下面的配置文件)
性能相关参数,可修改这些参数调整服务化性能:
BackendConfig:maxSeqLen: 最大序列长度maxInputTokenLen: 最大输入 Token 长度
ScheduleConfig:-
maxPrefillTokens: Prefill阶段,当前batch中所有input token总数。maxPrefillTokens和maxPrefillBatchSize谁先达到各自的取值就完成本次组batch。建议配置为maxInputTokenLen -
maxPrefillBatchSize: Prefill阶段,一个batch可以组的最大请求数量。maxPrefillBatchSize和maxPrefillTokens谁先达到各自的取值就完成本次组batch。 -
maxIterTimes: 模型全局最大输出长度。会影响每个用户请求得到的模型实际输出长度outputLen,规则为:outputLen = min(maxIterTimes, max_tokens, maxSeqLen - inputLen)或outputLen = min(maxIterTimes, max_new_tokens, maxSeqLen - inputLen){
"Version" : "1.0.0","ServerConfig" : { "ipAddress" : "10.1.2.10", "managementIpAddress" : "127.0.0.2", "port" : 1025, "managementPort" : 1026, "metricsPort" : 1027, "allowAllZeroIpListening" : true, "maxLinkNum" : 1000, "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", "tokenTimeout" : 600, "e2eTimeout" : 600, "distDPServerEnabled":false }, "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" : 13300, "maxInputTokenLen" : 8300, "truncation" : false, "ModelConfig" : [ { "modelInstanceType" : "Standard", "modelName" : "deepseek-r1-0528", "modelWeightPath" : "/model/DeepSeek-R1-0528-W8A8-MindIE", "worldSize" : 8, "cpuMemSize" : 5, "npuMemSize" : -1, "backendType" : "atb", "trustRemoteCode" : false, "async_scheduler_wait_time": 120, "kv_trans_timeout": 10, "kv_link_timeout": 1080, "dp": 2, "tp": 8, "sp": 1, "moe_tp": 4, "moe_ep": 4 } ] }, "ScheduleConfig" : { "templateType" : "Standard", "templateName" : "Standard_LLM", "cacheBlockSize" : 128, "maxPrefillBatchSize" : 50, "maxPrefillTokens" : 8300, "prefillTimeMsPerReq" : 150, "prefillPolicyType" : 0, "decodeTimeMsPerReq" : 50, "decodePolicyType" : 0, "maxBatchSize" : 4096, "maxIterTimes" : 5000, "maxPreemptCount" : 0, "supportSelectBatch" : false, "maxQueueDelayMicroseconds" : 5000 } }}
-
JSON
2.4 修改文件权限
需要修改两台机器上 MindIE 容器中一些文件的权限
# 进入 MindIE 容器
docker exec -it deepseek-r1-0528 bash
# 修改模型权重文件权限
chmod -R 750 /model/DeepSeek-R1-0528-W8A8-MindIE
# 修改 rank table 文件权限
chmod 640 /model/rank_table_file.json
# 修改配置文件权限
chmod 640 /usr/local/Ascend/mindie/latest/mindie-service/conf/config.json
Bash
2.5 运行 MindIE 服务
修改完配置之后就可以启动模型服务了,需要在两台节点上都要操作 ,注意修改MIES_CONTAINER_IP变量值为本机IP:
配置比较麻烦,可以自行修改成脚本自动拉起模型
# 进入 MindIE 容器
docker exec -it deepseek-r1-0528 bash
## 配置变量
export MIES_CONTAINER_IP=10.1.2.10 # 本机ip,两台机器不同
export WORLD_SIZE=16
export RANK_TABLE_FILE=/model/rank_table_file.json
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/mindie/set_env.sh
source /usr/local/Ascend/mindie/latest/mindie-service/set_env.sh
source /usr/local/Ascend/mindie/latest/mindie-llm/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh
# export MINDIE_LOG_LEVEL="info"
export MINDIE_LOG_TO_STDOUT=1
export ASDOPS_LOG_TO_STDOUT=1
export ASDOPS_LOG_LEVEL=ERROR
export ATB_LLM_HCCL_ENABLE=1
export ATB_LLM_COMM_BACKEND="hccl"
export HCCL_CONNECT_TIMEOUT=7200
export HCCL_EXEC_TIMEOUT=0
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
# 集合通信优化:AIV
export HCCL_OP_EXPANSION_MODE="AIV"
# 算子下发队列优化等级:2
export TASK_QUEUE_ENABLE=2
# CPU绑核:细粒度
export CPU_AFFINITY_CONF=2
# python高并发:10
export OMP_NUM_THREADS=10
# 内存最大使用比例:0.96,过大会有Failed to get engine response报错风险
export NPU_MEMORY_FRACTION=0.96
cd /usr/local/Ascend/mindie/latest/mindie-service
./bin/mindieservice_daemon
Bash
当两个 MindIE 服务都出现Daemon start success之后说明模型服务运行成功
2.6 验证模型服务
可以通过下面命令验证下模型服务是否可用,地址为主节点IP,如果可以正常获得结果,则说明模型运行成功
这里使用的IP是主节点 IP(也就是 rank table 中配置的第一个节点的 IP)
curl -X POST -H "Content-Type: application/json" -d '{
"model": "deepseek-r1-0528",
"messages": [{
"role": "user",
"content": "你好"
}],
"do_sample":true,
"temperature":0.6,
"top_p":0.95,
"max_tokens": 2000,
"stream": false
}' http://10.1.2.10:1025/v1/chat/completions
Bash
三、推理性能测试
测试工具选择 EvalScope,示例脚本如下:
EvalScope 支持命令行、Python两种执行方式,这两种方式对结果不会有影响,这里使用 Python 脚本的方式,再自行写脚本批量执行
# llm-bench.py
from evalscope.perf.main import run_perf_benchmark
from evalscope.perf.arguments import Arguments
task_cfg = Arguments(
parallel=[1],
number=[10],
model='deepseek-r1-0528',
url='http://127.0.0.1:1025/v1/chat/completions',
api='openai',
dataset='random',
min_tokens=256,
max_tokens=256,
prefix_length=0,
min_prompt_length=1024,
max_prompt_length=1024,
tokenizer_path='/model/DeepSeek-R1-0528-W8A8-MindIE',
extra_args={'ignore_eos': True}
)
results = run_perf_benchmark(task_cfg)
Bash
执行:
python3 llm-bench.py
Bash
结果:
| 输入Token数 | 输出Token数 | 并发数 | 请求数 | TTFT(s) | TPOT(s) | 吞吐(tokens/s) | 测试持续时间(s) |
|---|---|---|---|---|---|---|---|
| 1024 | 1024 | 1 | 10 | 0.2498 | 0.0795 | 27.8786 | 816.1595 |
| 1024 | 1024 | 16 | 50 | 1.0182 | 0.0847 | 295.8321 | 346.1467 |
| 1024 | 1024 | 32 | 64 | 1.9359 | 0.0909 | 688.9966 | 189.9679 |
| 1024 | 1024 | 64 | 128 | 3.0536 | 0.1021 | 1218.0585 | 215.0697 |
| 1024 | 1024 | 96 | 192 | 4.1496 | 0.1183 | 1567.1657 | 250.4576 |
| 1024 | 1024 | 128 | 256 | 5.3218 | 0.1345 | 1833.4286 | 285.8392 |
| 1024 | 1024 | 192 | 384 | 7.6181 | 0.1915 | 1664.9904 | 472.196 |
| 2048 | 2048 | 1 | 10 | 0.3615 | 0.0801 | 27.6764 | 1644.1845 |
| 2048 | 2048 | 16 | 50 | 1.8391 | 0.0844 | 296.3263 | 689.7419 |
| 2048 | 2048 | 32 | 64 | 3.1226 | 0.0916 | 687.6929 | 381.1939 |
| 2048 | 2048 | 64 | 128 | 5.436 | 0.1049 | 1189.3768 | 440.2723 |
| 2048 | 2048 | 96 | 192 | 8.0733 | 0.1459 | 1100.0131 | 724.744 |
| 2048 | 2048 | 128 | 256 | 49.8969 | 0.1691 | 1125.1326 | 931.6918 |
| 2048 | 2048 | 192 | 384 | 169.4648 | 0.1991 | 1233.4575 | 1200.5783 |
| 4096 | 1024 | 1 | 10 | 0.5861 | 0.0804 | 68.6732 | 828.2852 |
| 4096 | 1024 | 16 | 50 | 3.2289 | 0.087 | 708.3615 | 361.2423 |
| 4096 | 1024 | 32 | 64 | 5.7349 | 0.0946 | 1598.6378 | 204.9749 |
| 4096 | 1024 | 64 | 128 | 8.2758 | 0.1372 | 1880.7218 | 348.3938 |
| 4096 | 1024 | 96 | 192 | 61.966 | 0.1495 | 1955.4701 | 522.4232 |
| 4096 | 1024 | 128 | 256 | 123.954 | 0.1497 | 1918.4845 | 682.2142 |
| 4096 | 1024 | 192 | 384 | 260.5085 | 0.1581 | 1902.0598 | 1032.7816 |
四、性能调优相关
可以根据自身环境进行调整测试寻求符合自身需求的配置
4.1 相关参数介绍
性能调优相关参数:
-
maxSeqLen: 最大序列长度 -
maxInputTokenLen: 最大输入 Token 长度 -
maxIterTimes: 模型全局最大输出长度。会影响每个用户请求得到的模型实际输出长度outputLen,规则为:outputLen = min(maxIterTimes, max_tokens, maxSeqLen - inputLen)或outputLen = min(maxIterTimes, max_new_tokens, maxSeqLen - inputLen) -
maxPrefillTokens: Prefill阶段,当前batch中所有input token总数。maxPrefillTokens和maxPrefillBatchSize谁先达到各自的取值就完成本次组batch。建议配置为maxInputTokenLen -
maxPrefillBatchSize: Prefill阶段,一个batch可以组的最大请求数量。maxPrefillBatchSize和maxPrefillTokens谁先达到各自的取值就完成本次组batch。
一般配置为 maxSeqLen = maxInputTokenLen + maxIterTimes,并且 maxPrefillTokens = maxInputTokenLen
maxPrefillBatchSize与maxPrefillTokens共同作用,控制输入请求的序列总长度,由于最大输入的要求,maxPrefillTokens往往设置与最大输入相同,可以保证最长的请求也可以正常推理,若实际输入长度远低于最大输入长度,maxPrefillBatchSize会存在一定的调优空间
4.2 性能数据分析
在启动服务化启动前导入以下环境变量,可以开启调度日志的打印,以及对应耗时信息
export MINDIE_LLM_BENCHMARK_ENABLE=2
Bash
最终调度日志会存放在以下路径/usr/local/Ascend/mindie/latest/mindie-llm/logs/benchmark.jsonl
五、运行失败排查
运行模型时可能会经常发生启动失败等问题,整理了一些常用的排查方法
5.1 驱动版本较老
如果使用的 MindIE 版本比较新,服务器上装的驱动版本比较老的话,可能会出现不兼容的情况,可以尝试更新驱动和固件的版本
5.2 配置错误
常见配置错误为:
npuDeviceIds中配置的卡号的数量与worldSize不一致maxSeqLen等相关配置过大,超出显卡显存- MindIE 配置文件、Rank table 文件、模型文件权限错误
5.3 查看 MindIE 运行日志
模型启动时配置日志相关环境变量
注意:正式运行模型服务时不建议设置日志级别为debug(MINDIE_LOG_LEVEL="debug"),debug 级别输出的日志非常多而且不一定会有所帮助,在实际排查时可能还会更困难
# 修改日志级别(仅在排查时建议设置为 debug 级别)
export MINDIE_LOG_LEVEL="debug"
# 日志输出到标准输出
export MINDIE_LOG_TO_STDOUT=1
Bash
也可以在容器中的~/mindie/log中查看日志