Mindie推理服务化调度方案(服务化性能调优可参考)

mindie实现的continuous batching方案基本原理如下(调度:合理地分配和协调任务或作业的执行顺序,以优化系统的性能、效率和公平性。)

动图封面

特点:

同一时刻只有prefill或者decode;随推理进行,轮流调度prefill和decode

prefill和decode的bs分开设置

优先prefill or decode:

优先prefill:防止新进入请求在队列等待,降低首token时延

设置support_select_batch = 0 

动图封面

优先decode:降低新进入请求对推理影响,提高吞吐量(吞吐量:时间单位内能完成的任务数量)

设置support_select_batch=1

动图封面

LLM推理性能指标

首token时延(prefill时延)TTFT:越小越好

非首token时延(decode时延)TPOT(time per output token):越小越好

E2E吞吐:

1. token吞吐:Tokens总数/推理总耗时 or (输入+输出token总数)/推理总耗时:越大越好

2. request吞吐:单位时间内能处理的请求数,越大越好

可用性:一定约束条件(一般是时延)满足推理性能要求的请求总数占总请求数的比例(首token时延<1s,模型推理p99 TTFT = 1s,大约99%请求满足首token时延要求 可用性99%)

不同场景指标叫法不同

静态推理性能测试(纯模型)

固定输入,输出长度,batch size下测试模型推理性能

主要目的:

1. 性能摸底,与版本基线数据对齐,和友商性能数据比对,如果不和预期进一步分析模型本身性能差距和瓶颈

2. 为动态性能测试提供性能参考

3. 通过静态了解prefill时延,decode时延随着bs 序列长度的变化规律

4. 固定输入输出长度下,最大bs和吞吐性能摸高(摸高:通过变化输入输出长度和bs找最大吞吐性)

在输入输出长度不变的情况下,如果batchsize增加,时延增加,同时吞吐量也增加(大batch size需要更多内存,在NPU内存够时候,基本呈线性增长)

batch size改变或者改变输入输出长度,时延,吞吐量变化

动态推理性能测试(服务化)

测试模型在序列长度不同,bs也是动态变化情况下的推理性能,使用continuous batching

测试方法:

1.使用客户提供的压测脚本在贴近客户业务场景的数据集进行,压测脚本内进行请求构造,mindie service restful api调用,推理结果收集,推理性能统计

压测是指通过mindie-service restful API接口向服务端发送请求获取结果,统计输出,本质上客户压测和benchmark压测是基本一致,就是客户压测是客户自己写的,benchmark压测是昇腾写的,还有一个工具evalscope也是可以压测,基本是一样就是输出统计的信息可能有差别,但是核心功能都是发请求、获取结果、统计耗时(首token、非首Token)

2.benchmark:

通过部署昇腾服务化配套包后,以调用终端命令的方式测试llm在不同配置参数下推理性能和精度,通过表格的形式展示模型在各个阶段的推理耗时(例如FirstTokenTime、DecodeTime等),以及对应时延的平均值、最小值、最大值、75分位(P75)和99分位(P99)概率统计值,最后将计算结果保存到本地csv文件中。

两种推理模式

clients

文本模式:输入输出都是文本,支持全量文本和流式文本生成,用的接口分别是MindIE Client的.generate().generate_stream()接口对应Mindie server的兼容trition的文本推理接口和trition的流式推理接口

全量文本直接所有一起输出,流式文本一个一个token输出

engine

MindIE Benchmark支持通过直接调用北向接口提供的InferenceEngine Python API进行流式推理

支持tokenid到tokenid的异步推理和文本到文本的异步推理

从modeltest上面安装数据集:examples/atb_models/tests/modeltest/README_NEW.md · Ascend/MindIE-LLM - 码云 - 开源中国

LLM推理性能测试&调优

模型并行方案确认

llm内存来自两方面:kv cache和模型权重

模型放不下单卡时,就会考虑量化,多卡推理方案

llm涉及并行方案:TP,PP,DP,不同类型不同参数的模型用不同并行方案效果不完全相同

对于稠密LLM模型用tp并行(模型切分)的推理方案:tp size越大,相同bs输入,模型推理时延会下降,但是引入通信开销越大,所以根据模型规模权衡tp size值

启动容器

写在docker_start.sh脚本里:

IMAGES_ID=$1

NAME=$2

if [ $# -ne 2 ]; then

echo "error: need one argument describing your container name."

exit 1

fi

docker run --name ${NAME} -it -d --net=host --shm-size=500g \

--privileged=true \

-w /home \

--device=/dev/davinci_manager \

--device=/dev/hisi_hdc \

--device=/dev/devmm_svm \

--entrypoint=bash \

-v /data:/data \

-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \

-v /usr/local/dcmi:/usr/local/dcmi \

-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \

-v /usr/local/sbin:/usr/local/sbin \

-v /home:/home \

-v /tmp:/tmp \

-v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \

-e http_proxy=$http_proxy \

-e https_proxy=$https_proxy \

${IMAGES_ID}

启动命令:

动图封面

--privileged=true \ 不需要在写八张卡 因为这里已经有privilege

紫色:挂载驱动固件

-v /home:/home \ 代码挂载

-e http_proxy=$http_proxy \

-e https_proxy=$https_proxy \自动配置proxy环境

Qwen跑推理的权重下载

在宿主机上操作

Qwen2-7B: Mirror of https://huggingface.co/Qwen/Qwen2-7B

1.用git clone下载

export http_proxy="http://141.4.154.206:3128"

export https_proxy="http://141.4.154.206:3128"

export no_proxy=127.0.0.1,*.huawei.com,localhost,local,.local

export GIT_SSL_NO_VERIFY=true

unset HTTP_PROXY

unset HTTPS_PROXY

git config --global http.sslverify false

git config --global https.sslverify false

git config --global --unset http.proxy

git config --global --unset https.proxy

git config --global http.proxy "http://141.4.154.206:3128"

git config --global https.proxy "http://141.4.154.206:3128"

在容器外下载

git lfs pull 因为这里大文件可能会变小 文件不全

2.用scp从别的机器放到自己路径下

scp -r root@141.61.33.111:/home/c00925825/Qwen2-7B /home/c00925825

scp -r root@90.90.81.26:/data/Qwen2-7B /home/c00925825

Qwen中python包版本下载(requirements)

cd /usr/local/Ascend/atb-models/requirements/models/ 

cd usr/local/Ascend/atb-models/

env | grep ASCEND 这条命令用于查看当前环境中所有与 Ascend 相关的环境变量

动图封面

需要配置环境变量但是不在里面的从这里看(一般都已经配好环境)

cd ..

ls并且source所有的set_env.sh

动图封面

source nnal/atb/set_env.sh nnal实在里面atb的set env

driver挂在了不需要

env| grep ATB_SPEED可以看atb-models在什么路径内,如果出容器再进来还是一样有

推理

bash examples/models/qwen/run_pa.sh -m "/home/c00925825/Qwen2-7B/" --trust_remote_code true

这个命令跑模型推理采用qwen2-7b权重

性能测试

卡的选择

性能测试如果要改使用的卡的位置,可以选择:

export ASCEND_RT_VISIBLE_DEVICES=4,5,6,7

如果要跑的卡是双卡 那就会默认选前两张

跑并发:多个输入一起跑,那多卡就会比单卡运行速度快很多,如果oom就代表没有容量,因为每个输入需要kv cache 多个并发就会需要大的容量 那如果单卡容量小 那速度就会慢

并且并发量越多显存过大会导致报runtime error

batch size不变 输入输出长度改变大小

输入输出长度增加,perfill时延变长,吞吐量减小

Prefill 计算量∝Batch Size×输入长度

batch size变大 输入输出长度不变

时延越长 吞吐量越大

· Prefill 时延增加:更大的 batch size表示一次 需要处理更多的 tokens,Prefill 时延线性增加。

· 吞吐量增加:更大的 batch size 可以更好地利用硬件资源(如 GPU/NPU 的并行计算能力),提高单位时间内处理的 tokens 数量

mindie-service服务化推理

服务化拉起

拉起通过修改conf路径的config.json,按照

配置参数:在mindie-service路径下cd conf/找config。json

设置文件权限和属主的命令:

chmod -R 640 /modelpath

chown -R root:root /modelpath 

modelpath是权重路径

出现报错:

动图封面

动图封面

权重中:max prefill batch_size是可以和decode部分不一样,max prefill tokens是一共所有batchsize的输入tokens加起来总数最长长度 一般不能超过这两个其中一个(max prefill batch_size和max prefill tokens)

服务化推理

推理过程中出现报错:Wiki: 容器内无法使用curl/yum/dnf

因为进容器一开始是配了代理:

export http_proxy="http://141.4.154.206:3128"

export https_proxy="http://141.4.154.206:3128"

然后在curl这边解决就是 按照上面wiki

后来在服务化过程中因为代理导致报错:

动图封面

需要unset代理:

unset http_proxy

unset https_proxy

服务化命令从客户端输入 服务端接受命令进行推理任务

大模型在推理过程中top-k和top-p同时设置的时候该怎么采样,详细介绍这个过程 - 知乎

https://blog.csdn.net/qq_35971258/article/details/143753893

1. 客户端封装请求

在这种模式下,客户端负责将用户的命令封装成服务端可以理解的请求格式,然后发送给服务端。服务端直接处理封装好的请求,无需进一步解析。

1.1 流程

· 客户端接收用户输入的命令。

· 客户端将命令封装成标准化的请求(如 JSON、Protobuf 等格式)。

· 客户端将请求发送到服务端。

· 服务端接收请求并直接执行任务。

· 服务端将结果返回给客户端。

动图封面

动图封面

2. 服务端解析命令

在这种模式下,客户端直接将用户的原始命令发送给服务端,服务端负责解析命令并封装成内部请求格式。

2.1 流程

· 客户端接收用户输入的命令。

· 客户端将原始命令发送到服务端。

· 服务端解析命令并封装成内部请求格式。

· 服务端执行任务。

· 服务端将结果返回给客户端。

动图封面

动图封面

有代理访问不到这个服务化接口:

unset http_proxy

unset https_proxy

推理接口

· Python API:用于在 Python 中配置和运行模型。

· 配置文件:用于设置模型推理的参数(如 max prefill batch size 和 max prefill tokens)。

· 命令行工具:用于启动和管理推理任务。

接口配置的参数:

文本推理接口-兼容TGI 0.9.4版本接口-EndPoint业务面RESTful接口-服务化接口-MindIE Service开发指南-服务化集成部署-MindIE1.0.0开发文档-昇腾社区

接口post

使用兼容TGI 0.9.4版本的接口-接口调用-快速开始-MindIE Service开发指南-服务化集成部署-MindIE1.0.0开发文档-昇腾社区

curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{

"inputs": "My name is Olivier and I",

"parameters": {

"details": true,

"do_sample": true,

"max_new_tokens": 30,

"repetition_penalty": 1.03,

"return_full_text": false,

"seed": null,

"temperature": 0.5,

"top_k": 10,

"top_p": 0.95,

"truncate": null,

"typical_p": 0.5,

"watermark": false

}

}' http://127.0.0.1:1025/generate_stream

流式推理:输出结果如下

动图封面

get接口

动图封面

参考如下:

健康检查-兼容TGI 0.9.4版本接口-EndPoint业务面RESTful接口-服务化接口-MindIE Service开发指南-服务化集成部署-MindIE1.0.0开发文档-昇腾社区

一般正常的话就没有输出

查询TGI Endpoint信息

动图封面

服务化推理性能测试--client 文字请求

数据集下载:

examples/atb_models/tests/modeltest/README_NEW.md · Ascend/MindIE-LLM - 码云 - 开源中国

下载方法如上

mkdir -p /usr/local/Ascend/atb-models/tests/modeltest/temp_data/humaneval

cp "/home/c00925825/human-eval-v2-20210705.jsonl" /usr/local/Ascend/atb-models/tests/modeltest/temp_data/humaneval/

ls /usr/local/Ascend/atb-models/tests/modeltest/temp_data/humaneval/

python3 scripts/data_prepare.py --dataset_name humaneval #数据集转换格式

跑benchmark里client

SMPL_PARAM="{\"temperature\":0.5,\"top_k\":10,\"top_p\":0.9,\"typical_p\":0.9,\"seed\":1234,\"repetition_penalty\":1,\"watermark\":true,\"truncate\":10}"

benchmark \

--DatasetPath "/usr/local/Ascend/atb-models/tests/modeltest/temp_data/humaneval" \

--DatasetType "humaneval" \

--ModelName "Qwen2-7B" \

--ModelPath "/home/c00925825/Qwen2-7B" \

--TestType client \

--Http https://127.0.0.1:1025 \

--Concurrency 128 \

--TaskKind stream \

--Tokenizer True \

--MaxOutputLen 512 \

--DoSampling True \

--SamplingParams $SMPL_PARAM

会报错:

动图封面

后续继续报错:

动图封面

要改成如下:

SMPL_PARAM="{\"temperature\":0.5,\"top_k\":10,\"top_p\":0.9,\"typical_p\":0.9,\"seed\":1234,\"repetition_penalty\":1,\"watermark\":true,\"truncate\":10}"

benchmark \

--DatasetPath "/usr/local/Ascend/atb-models/tests/modeltest/temp_data/humaneval" \

--DatasetType "humaneval" \

--ModelName "Qwen2-7B" \

--ModelPath "/home/c00925825/Qwen2-7B" \

--TestType client \

--Http http://127.0.0.1:1025 \

--Concurrency 128 \

--TaskKind stream \

--Tokenizer True \

--MaxOutputLen 512 \

--DoSampling True \

--SamplingParams $SMPL_PARAM

并且:

export MINDIE_LOG_TO_STDOUT="benchmark:1; client:1"

动图封面

first token time:perfill时延

decode time:decode时延

generate time平均一条请求输出的时延(总时延)

input tokens和generate tokens:一句话的输入输出token数量

throughput:请求的吞吐量

generatespeed:生成token吞吐量

p99:生成的百分之99都是小于某个值

服务化推理性能测试--client tokenid请求

通过:数据集使用-附录-MindIE Service开发指南-服务化集成部署-MindIE1.0.0开发文档-昇腾社区

和上面的数据集下载

可以把数据转成token id,然后后处理测试样例

同样的:

SMPL_PARAM='{"temperature":0.5,"top_k":10,"top_p":0.9,"seed":1234,"repetition_penalty":1}'

benchmark \

--DatasetPath "/usr/local/Ascend/atb-models/tests/modeltest/temp_data/gsm8k/token_gsm8k_model.csv" \

--DatasetType gsm8k \

--ModelName "Qwen2-7B" \

--ModelPath "/home/c00925825/Qwen2-7B" \

--TestType client \

--Http http://127.0.0.1:1025 \

--ManagementHttp http://127.0.0.2:1026 \

--Concurrency 128 \

--TaskKind stream_token \

--Tokenizer False \

--MaxOutputLen 512 \

--DoSampling True \

--SamplingParams $SMPL_PARAM

这里报了一个错:

动图封面

这一行数据单独去纯模型推理看看问题:

在atb-models路径下看:

examples/run_pa.py

找到input

动图封面

接着找到parse_argument

动图封面

因为是id所以在这里加上一行数据

bash examples/models/qwen/run_pa.sh -m "/home/c00925825/Qwen2-7B/" --trust_remote_code true

没问题 

curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{

"id": "42",

"inputs": [{

"name": "input0",

"shape": [

1,

75

],

"datatype": "UINT32",

"data": [

25300,482,21051,1059,6930,2205,23971,2326,3039,264,1042,13,576,2783,315,825,3947,374,400,17,13,4636,220,20,1635,11,279,2783,315,825,3947,702,7172,553,220,16,20,15,13384,714,6898,482,6635,537,311,2968,705,894,3947,323,8570,311,728,311,279,23971,369,220,18,803,1635,13,2585,1753,1521,6898,482,8329,389,678,21051,311,279,23971,30

]

}],

"outputs": [{

"name": "output0"

}],

"parameters": {

"temperature":0.5,"top_k":10,"top_p":0.9,"seed":1234,"repetition_penalty":1, "max_new_tokens": 20

}

}' http://127.0.0.1:1025/v2/models/Qwen2-7B/infer

也没问题

LLM推理PD分离

在 PD 分离式架构中:

· Prefill Instance 专注于 Prefill 阶段的计算。

· Decode Instance 专注于 Decode 阶段的生成任务。

当 Prefill Instance 完成 KV Cache 的计算后,会将其传输给 Decode Instance,后者接续生成结果。这种架构独立优化了两个阶段的性能,因此又被简称为 PD 分离。

为什么需要 Prefill-Decode 分离?

在大模型推理中,常用以下两项指标评估性能:

· TTFT(Time-To-First-Token):首 token 的生成时间,主要衡量 Prefill 阶段性能。

· TPOT(Time-Per-Output-Token):生成每个 token 的时间,主要衡量 Decode 阶段性能。

当 Prefill 和 Decode 在同一块 GPU 上运行时,由于两阶段的计算特性差异(Prefill 是计算密集型,而 Decode 是存储密集型),资源争抢会导致 TTFT 和 TPOT 之间的权衡。例如:

· 若优先处理 Prefill 阶段以降低 TTFT,Decode 阶段的性能(TPOT)可能下降。

· 若尽量提升 TPOT,则会增加 Prefill 请求的等待时间,导致 TTFT 上升。

PD 分离式架构的提出正是为了打破这一矛盾。通过将 Prefill 和 Decode 分离运行,可以针对不同阶段的特性独立优化资源分配,从而在降低首 token 延迟的同时提高整体吞吐量。

分离式推理架构的优化方向

1. 算力与存储的独立优化

在 PD 分离架构中,Prefill 和 Decode 阶段的资源需求不同,分别体现为:

· Prefill 阶段:计算密集型(compute-bound)。在流量较大或用户提示长度较长时,Prefill 的计算压力更大。完成 KV Cache 的生成后,Prefill 阶段本身无需继续保留这些缓存。

· Decode 阶段:存储密集型(memory-bound)。由于逐 token 生成的特性,Decode 阶段需频繁访问 KV Cache,因此需要尽可能多地保留缓存数据以保障推理效率。

因此,在 PD 分离架构下,可以分别针对计算和存储瓶颈进行优化。

2. Batching 策略的独立优化

在 DistServe 的实验中,Batching 策略对两阶段的性能影响显著,但趋势相反:

· Prefill 阶段:吞吐量随 batch size 增加逐渐趋于平稳。这是因为 Prefill 的计算受限特性(compute-bound),当 batch 中的总 token 数超过某个阈值时,计算资源成为瓶颈。

· Decode 阶段:吞吐量随 batch size 增加显著提升。由于 Decode 阶段的存储受限特性(memory-bound),增大 batch size 可提高计算效率,从而显著增加吞吐量。

Logo

昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链

更多推荐