配置类型 |
配置项 |
最优配置 |
---|---|---|
调度配置 |
maxPrefillBatchSize |
|
maxPrefillTokens |
|
|
maxBatchSize |
表6中根据公式计算出的最大值。 |
|
maxPreemptCount |
10。 |
|
supportSelectBatch |
true |
|
模型配置 |
npuDeviceIds |
[0, 1, 2, ..., worldSize-1] |
worldSize |
节点的最大可用卡数。 |
|
npuMemSize |
表5中根据公式计算出的最大值,单位GB。 |
|
资源配置 |
preAllocBlocks |
表1范围内适当调小。理论上为ceil(数据集平均输出长度/cacheBlockSize)最佳,但当前不开满可能会卡死。 |
在mindservice.log日志中,过滤测试时间段对应的“COMPLETED REQ ID”关键字如下:
...COMPLETED REQ ID: 363 , 5 , 593 , 81 , 512 , 12 , 60 , 1 ...COMPLETED REQ ID: 377 , 5 , 237 , 87 , 150 , 12 , 60 , 1
性能的最优值就是根据第7列的NpuBlock使用个数和Total Block Num个数之间的关系调整BatchSize,具体调整策略如下:
这里以llama-65b模型为例进行最优性能的配置,环境信息举例如下:
使用vim命令打开/usr/local/Ascend/mindie/latest/mindie-service/latest/bin/ibis目录中的model_inputs.py文件,注释第61-64行即可关闭后处理:
# elif input_tensor.name() == "SAMPLING": # has_sampling = True # if is_prefill: # sampling_param = np.array(input_tensor, copy=False)[0]
根据计算公式:Total Block Num = Floor[NPU显存/(模型网络层数*Block Size*模型注意力头数*注意力头大小*Cache类型字节数*Cache数)],公式中各参数的取值信息如表2所示。
参数 |
取值 |
---|---|
NPU显存 |
1中npuMemSize的值。 |
模型网络层数 |
模型网络层数是模型权重文件config.json中的hidden_layers值,取值为:80。 |
Block Size |
默认值:128。 |
模型注意力头数 |
“模型注意力头数*注意力头大小”的值为模型权重文件中config.json中的hidden_size值。 说明:
对于llama2模型,由于是GQA类模型(分组查询注意力类模型),需使用模型权重文件config.json中num_key_value_heads的值作为注意力头数,而不是num_attention_heads。所以每张卡上的“模型注意力头数*注意力头大小”的值不一定是用hidden_size/卡数。例如llama2-70b的“模型注意力头数*注意力头大小”的值应该为8*128=1024,而不是hidden_size中的值:8192。 |
注意力头大小 |
|
Cache类型字节数 |
由模型config.json文件中的torch.dtype决定,一般为float16类型,取值为:2。 |
Cache数 |
默认值:2。 |
将以上参数值代入公式,得到Total Block Num=Floor[34*1024*1024*1024/(80 * 128 * 128 * 64/8 * 2 * 2)] = 870。
注:以上算式中64/8是由于有8张NPU卡,所以注意头数需均分在8张卡上。
Total Block Num的值也可以通过跑一次性能后在python日志中的npuBlockNum获取,详情请参考•吞吐量最大化。
根据计算公式:Block Num = Ceil(输入Token数/Block Size)+Ceil(最大输出Token数/Block Size),公式中各参数的取值信息如表3所示。
参数 |
取值 |
---|---|
输入Token数 |
首次一般参考数据集的平均输入,取值100。 第二次则可以直接取返回结果中的average_input_length的值。 |
最大输出Token数 |
从config.json文件中的maxIterTimes参数获取,取值:512。 |
Block Size |
默认值:128。 |
将以上参数值代入公式,得到Block Num = Ceil(100/128)+Ceil(512/128) = 5。
“Ceil”表示计算结果向上取整。
maxBatchSize = 870/5 = 174。
preAllocBlocks的值根据ceil(数据集平均输出长度/cacheBlockSize) 进行计算,约为1。
数据集如需要转换请参见数据集使用章节。
watch npu-smi info
这时从性能返回结果可以看出来lpot会优于配置之前的值,并且generate speed也有很大的提升。
通过调整maxBatchSize的值使吞吐量最大化。首先根据结果日志(logs/mindservice.logs)使用以下命令查看最大Total Block Num的值,如图4所示。
grep "COMPLETED" mindservice*.log
从上图中查看Total Block Num的峰值为854,比计算得到的Total Block Num值小。即可适当调大maxBatchSize的值(同步调整对应的maxPrefillBatchSize、maxPrefillTokens和maxPreemptCount的值)再进行一次性能操作。
也可以通过将set_env.sh环境变量中打开Python日志(export MIES_PYTHON_LOG_TO_FILE=1),并在/workspace/log/pythonlog.log.xxxxx下对应日志中通过搜索npuBlockNum找到,如图5所示,值为896。
为了让非首token时延(lpot)最小化,则需要调小maxBatchSize来达到最优性能,暂时只能通过阶梯调整。
根据3对maxBatchSize进行调整,并调整对应的maxPrefillBatchSize、maxPrefillTokens和maxPreemptCount的值,对比哪个值可以达到要求。
maxPrefillTokens的值不能小于4096。
比如baichuan2-7b模型在Atlas 300I Duo 推理卡上进行的测试,lpot要求是小于80ms,这时maxBatchSize的值选择87时可以得到最小化的时延要求以及该时延下最优吞吐量。
maxBatchSize |
lpot(时延) |
generate speed(吞吐量) |
---|---|---|
200 |
160 |
1145 |
100 |
88 |
1074 |
90 |
81 |
1058 |
89 |
80.4 |
1058 |
88 |
80.4 |
1060 |
87 |
79.7 |
1032 |