-
步骤二:非sharegpt格式数据集转换(可选) 如果数据集json文件不是sharegpt格式,而是常见的 { "prefix": "AAA" "input": "BBB", "output": "CCC" } 格式,则需要执行convert_to_sharegpt.py 文件将数据集转换为share gpt格式。 python convert_to_sharegpt.py \
--input_file_path data_test.json \
--out_file_name ./data_for_sharegpt.json \
--prefix_name instruction \
--input_name input \
--output_name output \
--code_type utf-8
其中: input_file_path:预训练json文件地址。 out_file_name:输出的sharegpt格式文件地址。 prefix_name:预训练json文件的前缀 字段名称 (可设置为None,此时预训练数据集只有 input output 两段)输入前缀,(例如:您是一个xxx专家,您需要回答下面问题) input_name:预训练json文件的指令输入 字段名称(例如:请问苹果是什么颜色) output_name output:预训练json文件的output字段名称,例如:苹果是红色的。 code_type:预训练json文件编码 默认utf-8 当转换为share gpt格式时,prefix和 input会拼接成一段文字,作为human字段,提出问题,而output字段会作为gpt字段,做出回答。
-
步骤四:执行训练 安装完成后,执行: accelerate launch -m --mixed_precision=bf16 eagle.train.main \
--tmpdir [path of data] \
--cpdir [path of checkpoints] \
--configpath [path of config file] \
--basepath [path of base_model]
--bs [batch size] tmpdir:即为步骤三中的outdir,训练data地址 cpdir:为训练生成权重的地址 configpath:为模型config文件的地址 basepath:为大模型权重地址 bs:为batch大小 其中,要获取模型config文件, 首先到https://github.com/SafeAILab/EAGLE/页找到对应eagle模型地址。 图1 EAGLE Weights 以llama2-chat-7B为例,单击进入后 ,如下图所示config文件,即为对应模型的eagle config文件。
-
步骤三:sharegpt格式数据生成为训练data数据集 若使用开源数据集,推荐使用原论文代码仓数据集,下载地址:https://huggingface.co/datasets/Aeala/ShareGPT_Vicuna_unfiltered/blob/main/ShareGPT_V4.3_unfiltered_cleaned_split.json 否则使用第二步生成的开源数据集。 python allocation.py \
--outdir outdir0/sharegpt_0_99_mufp16 \
--end_num 100 \
--used_npus "0,1,2,3,4,5,6,7" \
--model_type llama \
--model_name ./llama-7B \
--data_path data_for_sharegpt.json \
--seed 42 \
--max_length 2048 \
--dtype bfloat16 其中 outdir:生成的训练data 地址 end_num:生成的data总条数 used_npus:使用哪些NPU model_type:使用模型类型 目前支持 qwen2 llama1 llama2 及 llama3,其中llama1、2及chat都填写llama model_name:模型地址 data_path:预训练数据集地址 即一中生成的文件地址 seed:生成训练data所使用的seed(此处42为开源训练设定参数) max_length:模型的max_length dtype:为模型dtype 默认为bfloat16
-
步骤五:训练生成权重转换成可以支持vLLM推理的格式 将训练完成后的权重文件(.bin文件或. safetensors文件),移动到下载好的开源权重目录下(即步骤4中,config文件所在目录)。 然后在llm_tools/spec_decode/EAGLE文件夹,执行 python convert_eagle_ckpt_to_vllm_compatible.py --base-path 大模型权重地址 --draft-path 小模型权重地址 --base-weight-name 大模型包含lm_head的权重文件名 --draft-weight-name 小模型权重文件名 --base-path:为大模型权重地址,例如 ./llama2-7b-chat --draft-path:小模型权重地址 即步骤四中config文件所在目录,例如 ./eagle_llama2-7b-chat --base-weight-name:为大模型包含lm_head的权重文件名,可以在 base-path 目录下的 model.safetensors.index.json 文件获取,例如llama2-7b-chat 的权重名为pytorch_model-00001-of-00002.bin --draft-weight-name 为小模型权重文件名,即刚才移动的.bin文件或者.safetensors 文件
-
Step2 配置pod 在节点自定义目录${node_path}下创建config.yaml文件 apiVersion: apps/v1
kind: Deployment
metadata:
name: yourapp
labels:
app: infers
spec:
replicas: 1
selector:
matchLabels:
app: infers
template:
metadata:
labels:
app: infers
spec:
schedulerName: volcano
nodeSelector:
accelerator/huawei-npu: ascend-1980
containers:
- image: ${image_name} # 推理镜像名称
imagePullPolicy: IfNotPresent
name: ${container_name}
securityContext:
runAsUser: 0
ports:
- containerPort: 8080
command: ["/bin/bash", "-c"]
args: ["${node-path}/run_vllm.sh"] # 节点自定义目录,该目录下包含pod配置文件config.yaml和推理服务启动脚本run_vllm.sh
resources:
requests:
huawei.com/ascend-1980: "8" # 需求卡数,key保持不变。
limits:
huawei.com/ascend-1980: "8" # 限制卡数,key保持不变。
volumeMounts: # 容器内部映射路径
- name: ascend-driver #驱动挂载,保持不动
mountPath: /usr/local/Ascend/driver
- name: ascend-add-ons #驱动挂载,保持不动
mountPath: /usr/local/Ascend/add-ons
- name: hccn #驱动hccn配置,保持不动
mountPath: /etc/hccn.conf
- name: localtime
mountPath: /etc/localtime
- name: npu-smi # npu-smi
mountPath: /usr/local/sbin/npu-smi
- name: model-path # 模型权重路径
mountPath: ${model-path}
- name: node-path
mountPath: ${node-path}
volumes: # 物理机外部路径
- name: ascend-driver
hostPath:
path: /usr/local/Ascend/driver
- name: ascend-add-ons
hostPath:
path: /usr/local/Ascend/add-ons
- name: hccn
hostPath:
path: /etc/hccn.conf
- name: localtime
hostPath:
path: /etc/localtime
- name: npu-smi
hostPath:
path: /usr/local/sbin/npu-smi
- name: model-path
hostPath:
path: ${model-path}
- name: node-path
hostPath:
path: ${node-path} 参数说明: ${container_name}:容器名称,此处可以自己定义一个容器名称,例如ascend-vllm。 ${image_name}:Step3 制作推理镜像构建的推理镜像名称。 ${node-path}:节点自定义目录,该目录下包含pod配置文件config.yaml和推理服务启动脚本run_vllm.sh,run_vllm.sh内容见Step3 创建服务启动脚本。 ${model-path}:Step1 上传权重文件中上传的模型权重路径。
-
Step4 创建pod 在节点自定义目录${node_path}下执行如下命令创建pod。 kubectl apply -f config.yaml 检查pod启动情况,执行下述命令。如果显示“1/1 running”状态代表启动成功。 kubectl get pod -A 图1 启动pod成功 执行如下命令查看pod日志,如果打印类似下图信息表示服务启动成功。 kubectl logs -f ${pod_name} 参数说明: ${pod_name}:pod名,例如图1${pod_name}为yourapp-87d9b5b46-c46bk。 图2 启动服务成功
-
附录:大模型推理常见问题 问题1:在推理预测过程中遇到NPU out of memory。 解决方法:调整推理服务启动时的显存利用率,将--gpu-memory-utilization的值调小。 问题2:在推理预测过程中遇到ValueError:User-specified max_model_len is greater than the drived max_model_len。 解决方法:修改config.json文件中的"seq_length"的值,"seq_length"需要大于等于 --max-model-len的值。config.json存在模型对应的路径下,例如:/data/nfs/benchmark/tokenizer/chatglm3-6b/config.json 问题3:使用离线推理时,性能较差或精度异常。 解决方法:将block_size大小设置为128。 from vllm import LLM, SamplingParams
llm = LLM(model="facebook/opt-125m", block_size=128) 问题4:使用llama3.1系模型进行推理时,报错:ValueError: 'rope_scaling' must be a dictionary with two fields, 'type' and 'factor', got {'factor': 8.0, 'low_freq_factor': 1.0, 'high_freq_factor': 4.0, 'original_max_position_embeddings': 8192, 'rope_type': 'llama3'} 解决方法:升级transformers版本到4.43.1:pip install transformers --upgrade 问题5:使用SmoothQuant进行W8A8进行模型量化时,报错:AttributeError: type object 'LlamaAttention' has no attribute '_init_rope' 解决方法:降低transformers版本到4.42:pip install transformers==4.42 --upgrade 问题6:使用AWQ转换llama3.1系列模型权重出现报错ValueError: `rope_scaling` must be a dictionary with two fields, `type` and `factor`, 解决方法:将transformers升级到4.44.0,修改对应transformers中的transformers/models/llama/modeling_llama.py,在class LlamaRotaryEmbedding中的forward函数中增加self.inv_freq = self.inv_freq.npu() 问题7:使用Qwen2-7B、Qwen2-72B模型有精度问题,重复输出感叹号 检查【配置环境变量】章节中,高精度模式的环境变量是否开启 父主题: 主流开源大模型基于Lite Cluster适配PyTorch NPU推理指导(6.3.910)
-
benchmark方法介绍 性能benchmark包括两部分。 静态性能测试:评估在固定输入、固定输出和固定并发下,模型的吞吐与首token延迟。该方式实现简单,能比较清楚的看出模型的性能和输入输出长度、以及并发的关系。 动态性能测试:评估在请求并发在一定范围内波动,且输入输出长度也在一定范围内变化时,模型的延迟和吞吐。该场景能模拟实际业务下动态的发送不同长度请求,能评估推理框架在实际业务中能支持的并发数。 性能benchmark验证使用到的脚本存放在代码包AscendCloud-LLM-xxx.zip的llm_tools/llm_evaluation目录下。 代码目录如下: benchmark_tools
├── benchmark_parallel.py # 评测静态性能脚本
├── benchmark_serving.py # 评测动态性能脚本
├── generate_dataset.py # 生成自定义数据集的脚本
├── benchmark_utils.py # 工具函数集
├── benchmark.py # 执行静态、动态性能评测脚本
├── requirements.txt # 第三方依赖
-
静态benchmark验证 本章节介绍如何进行静态benchmark验证。 已经上传benchmark验证脚本到推理容器中。如果在Step3 制作推理镜像步骤中已经上传过AscendCloud-LLM-x.x.x.zip并解压,无需重复执行。 执行如下命令进入容器。 kubectl exec -it {pod_name} bash ${pod_name}:pod名,例如图1${pod_name}为yourapp-87d9b5b46-c46bk。 进入benchmark_tools目录下,切换conda环境并安装依赖。 cd /home/ma-user/AscendCloud/AscendCloud-LLM/llm_tools/llm_evaluation/benchmark_tools
conda activate python-3.9.10
pip install -r requirements.txt 运行静态benchmark验证脚本benchmark_parallel.py,具体操作命令如下,可以根据参数说明修改参数。 python benchmark_parallel.py --backend openai --host 127.0.0.1 --port 8080 --tokenizer /path/to/tokenizer --epochs 5 \
--parallel-num 1 4 8 16 32 --prompt-tokens 1024 2048 --output-tokens 128 256 --num-scheduler-steps 8 --benchmark-csv benchmark_parallel.csv 参数说明 --backend:服务类型,支持tgi、vllm、mindspore、openai等。本文档使用的推理接口是vllm。 --host:服务部署的IP。 --port:推理服务端口8080。 --tokenizer:tokenizer路径,HuggingFace的权重路径。 --epochs:测试轮数,默认取值为5 --parallel-num:每轮并发数,支持多个,如 1 4 8 16 32。 --prompt-tokens:输入长度,支持多个,如 128 128 2048 2048,数量需和--output-tokens的数量对应。 --output-tokens:输出长度,支持多个,如 128 2048 128 2048,数量需和--prompt-tokens的数量对应。 --benchmark-csv:结果保存文件,如benchmark_parallel.csv。 --served-model-name: 选择性添加,在接口中使用的模型名;如果没有配置,则默认为tokenizer。 --num-scheduler-steps: 需和服务启动时配置的num-scheduler-steps一致。默认为1 --enable-prefix-caching:服务端是否启用enable-prefix-caching特性,默认为false。 --prefix-caching-num:构造的prompt的公共前缀的序列长度,prefix-caching-num值需小于prompt-tokens。 --use-spec-decode:是否使用投机推理进行输出统计,不输入默认为false。当使用投机推理时必须开启,否则会导致输出token数量统计不正确。注:由于投机推理的性能测试使用随机输入意义不大,建议开启--dataset-type、--dataset-path,并选择性开启--use-real-dataset-output-tokens使用真实数据集进行测试。 --dataset-type:当使用投机推理时开启,benchmark使用的数据类型,当前支持random、sharegpt、human-eval三种输入。random表示构造随机token的数据集进行测试;sharegpt表示使用sharegpt数据集进行测试;human-eval数据集表示使用human-eval数据集进行测试。注意:当输入为sharegpt或human-eval时,测试数据的输入长度为数据集的真实长度,--prompt-tokens的值会被忽略。 --dataset-path:数据集的路径,仅当--dataset-type为sharegpt或者human-eval的时候生效。 --use-real-dataset-output-tokens:当使用投机推理时开启,设置输出长度是否使用数据集的真实长度,不输入默认为false。当使用该选项时,测试数据的输出长度为数据集的真实长度,--output-tokens的值会被忽略。 --num-speculative-tokens:仅当开启--use-spec-decode时生效,需和服务启动时配置的--num-speculative-tokens一致。默认为-1。当该值大于等于0时,会基于该值计算投机推理的接受率指标。 脚本运行完成后,测试结果保存在benchmark_parallel.csv中,示例如下图所示。 图1 静态benchmark测试结果(示意图)
-
动态benchmark 本章节介绍如何进行动态benchmark验证。 执行如下命令进入容器。 kubectl exec -it {pod_name} bash ${pod_name}:pod名,例如图1${pod_name}为yourapp-87d9b5b46-c46bk。 进入benchmark_tools目录下,切换conda环境。 cd /home/ma-user/AscendCloud/AscendCloud-LLM/llm_tools/llm_evaluation/benchmark_tools
conda activate python-3.9.10 获取数据集。动态benchmark需要使用数据集进行测试,可以使用公开数据集,例如Alpaca、ShareGPT。也可以根据业务实际情况,使用generate_datasets.py脚本生成和业务数据分布接近的数据集。 方法一:使用公开数据集 ShareGPT下载地址: https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json Alpaca下载地址: https://github.com/tatsu-lab/stanford_alpaca/blob/main/alpaca_data.json 方法二:使用generate_dataset.py脚本生成数据集方法: generate_dataset.py脚本通过指定输入输出长度的均值和标准差,生成一定数量的正态分布的数据。具体操作命令如下,可以根据参数说明修改参数。 python generate_dataset.py --dataset custom_datasets.json --tokenizer /path/to/tokenizer \
--min-input 100 --max-input 3600 --avg-input 1800 --std-input 500 \
--min-output 40 --max-output 256 --avg-output 160 --std-output 30 --num-requests 1000 generate_dataset.py脚本执行参数说明如下: --dataset:数据集保存路径,如custom_datasets.json。 --tokenizer:tokenizer路径,可以是HuggingFace的权重路径。backend取值是openai时,tokenizer路径需要和推理服务启动时--model路径保持一致,比如--model /data/nfs/model/llama_7b, --tokenizer也需要为/data/nfs/model/llama_7b,两者要完全一致。 --min-input:输入tokens最小长度,可以根据实际需求设置。 --max-input:输入tokens最大长度,可以根据实际需求设置。 --avg-input:输入tokens长度平均值,可以根据实际需求设置。 --std-input:输入tokens长度方差,可以根据实际需求设置。 --min-output:最小输出tokens长度,可以根据实际需求设置。 --max-output:最大输出tokens长度,可以根据实际需求设置。 --avg-output:输出tokens长度平均值,可以根据实际需求设置。 --std-output:输出tokens长度标准差,可以根据实际需求设置。 --num-requests:输出数据集的数量,可以根据实际需求设置。 执行脚本benchmark_serving.py测试动态benchmark。具体操作命令如下,可以根据参数说明修改参数。 python benchmark_serving.py --backend openai --host 127.0.0.1 --port 8080 --dataset custom_datasets.json --dataset-type custom \
--tokenizer /path/to/tokenizer --request-rate 0.01 1 2 4 8 10 20 --num-prompts 10 1000 1000 1000 1000 1000 1000 \
--max-tokens 4096 --max-prompt-tokens 3768 --num-scheduler-steps 8 --benchmark-csv benchmark_serving.csv --backend:服务类型,如tgi,vllm,mindspore、openai。 --host ${docker_ip}:服务部署的IP地址,${docker_ip}替换为宿主机实际的IP地址。 --port:推理服务端口。 --dataset:数据集路径。 --dataset-type:支持三种 "alpaca","sharegpt","custom"。custom为自定义数据集。 --tokenizer:tokenizer路径,可以是HuggingFace的权重路径,backend取值是openai时,tokenizer路径需要和推理服务启动时--model路径保持一致,比如--model /data/nfs/model/llama_7b, --tokenizer也需要为/data/nfs/model/llama_7b,两者要完全一致。 --request-rate:请求频率,支持多个,如 0.1 1 2。实际测试时,会根据request-rate为均值的指数分布来发送请求以模拟真实业务场景。 --num-prompts:某个频率下请求数,支持多个,如 10 100 100,数量需和--request-rate的数量对应。 --max-tokens:输入+输出限制的最大长度,模型启动参数--max-input-length值需要大于该值。 --max-prompt-tokens:输入限制的最大长度,推理时最大输入tokens数量,模型启动参数--max-total-tokens值需要大于该值,tokenizer建议带tokenizer.json的FastTokenizer。 --benchmark-csv:结果保存路径,如benchmark_serving.csv。 --served-model-name: 选择性添加, 选择性添加,在接口中使用的模型名;如果没有配置,则默认为tokenizer。 --num-scheduler-steps: 需和服务启动时配置的num-scheduler-steps一致。默认为1 脚本运行完后,测试结果保存在benchmark_serving.csv中,示例如下图所示。 图2 动态benchmark测试结果(示意图)