OpenPPL-LLM实战
OpenPPL-LLM
OpenPPL-LLM 是商汤高性能计算团队基于原有的推理引擎 OpenPPL,开发的一款专为大语言模型设计的自研高性能推理系统。
OpenPPL-LLM实战
安装与使用(Llama-hf)
软件:
```
Linux ai-gpu 5.4.0-67-generic #75-Ubuntu SMP Fri Feb 19 18:03:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
GCC:9.4.0
CMake:3.27.7
#snap info cmake
Git:2.25.1
CUDA Toolkit:11.7
mpich:3.3.2
#更新软件包列表和系统
sudo apt update
sudo apt upgrade
#选择安装特定版本的mpich,可以使用以下命令查询可用版本:
apt-cache policy mpich
#安装mpich
apt install mpich
#查看mpich版本
mpiexec --version
mpichversion
```
硬件
```
V100S-PCIE-32GB 2卡;Volta架构
```
模型准备
```
llama2 7b chat:huggingface格式
```
模型转换(hf->自定义pmx算子格式)
```
#获取pmx转模型工具
git clone ****s://github.com/openppl-public/ppl.pmx.git
cd ppl.pmx/model_zoo/llama/huggingface
#安装依赖
pip install -r requirements.txt -i ****s://pypi.tuna.tsinghua.edu.cn/simple
#由于与huggingface的RotaryPositionEmbedding功能的实现不一致,需要转换权重参数为pmx格式。
#激活conda环境
source activate /root/miniconda3
#转换格式
python ConvertWeightToPmx.py --input_dir <hf_model_dir> --output_dir <pmx_model_dir>
#split model,将PMX模型的权重拆分为多个碎片,并将其划分为指定的碎片,为每个碎片创建单独的模型。
cd ../modeling/
python SplitModel.py --input_dir <pmx_model_dir> --num_shards <number_of_shards> --output_dir <pmx_shards_split_out>
#merge model,将一个分片模型的权重合并到一个模型中。从模型的多个碎片中读取权重,并创建具有组合权重的合并模型。
python MergeModel.py --input_dir <pmx_shards_split_out> --num_shards <number_of_shards> --output_dir <output_directory_path>
#导出前模型的正确性验证
cd ../huggingface/
#OMP_NUM_THREADS:此参数确定OpenMP线程的数量。它被设置为1,以防止过度使用CPU核心。每个PyTorch进程都会打开一个OpenMP线程池,将其设置为1可以避免占用过多的CPU核心。
OMP_NUM_THREADS=1 torchrun --nproc_per_node $num_gpu Demo.py --ckpt_dir <pmx_shards_split_out/pmx_model_dir> --tokenizer_path <llama_tokenizer_dir>/tokenizer.model --fused_qkv 1 --fused_kvcache 1 --auto_causal 1 --quantized_cache 1 --dynamic_batching 1
```
pmx_model_dir
pmx_shards_split_out
验证
模型导出
```shell
# 有2个GPU的7B模型的示例命令:
OMP_NUM_THREADS=1 torchrun --nproc_per_node 2 Export.py --ckpt_dir <pmx_shards_split_out> --tokenizer_path <llama_tokenizer_dir>/tokenizer.model --fused_qkv 1 --fused_kvcache 1 --auto_causal 1 --quantized_cache 1 --dynamic_batching 1 --export_path <export_dir>
#参数解释
--fused_qkv 1:启用融合的 Query-Key-Value(QKV)操作,通过融合三个操作来提高效率。
--fused_kvcache 1:启用融合的 Key-Value 缓存操作,通过融合缓存操作来提高效率。
--auto_causal 1:启用自动因果性(Auto Causal)模式,该模式允许模型只使用已生成的标记进行下一步预测,加快推理速度。
--quantized_cache 1:启用量化缓存操作,通过量化缓存操作来减少内存占用。
--dynamic_batching 1:启用动态批处理,根据序列长度动态调整批处理大小,以提高内存利用率和训练效率。
#可选参数
ckpt_dir:模型的检查点目录,即LLAMA模型的路径。
tokenizer_path:LLAMA模型的tokenizer文件路径。
temperature:生成文本的温度参数,控制生成的随机性。较大的值会使生成文本更加随机,较小的值会使生成文本更加确定。
top_p:生成文本时的top-p参数,控制生成文本的多样性。较大的值会生成更多的词汇选择,较小的值会生成更少的词汇选择。
batch:生成文本的批量大小。
seqlen_scale_up:将输入序列进行重复以扩大长度的倍数。
unaligned_batch:是否使用不对齐的批次生成文本。
max_gen_len:生成文本的最大长度限制。
friendly_gqa:用重复键和值进行gqa操作来模拟解码。
fused_qkv:是否融合查询、键和值的线性层。
fused_kvcache:是否融合键值缓存和多头注意力。
auto_causal:是否由注意力操作自动完成因果遮罩,无需额外的遮罩传递给模型。
quantized_cache:是否对8位键值缓存进行量化。
cache_layout:更改键值缓存布局以提高硬件性能。
cache_mode:更改键值缓存索引模式以提供更友好的内存管理,仅在dynamic_batching == True时有效。
dynamic_batching:是否使用动态批处理调度。
dump_tensor_path:将中间张量数据保存到指定路径。
dump_steps:保存中间张量数据的步骤列表。
```
导出后的模型目录
model_slice_0模型的权重信息和模型结构model.onnx
生成测试数据
```shell
#使用指定的命令在步骤0、1和255生成测试数据。
OMP_NUM_THREADS=1 torchrun --nproc_per_node $num_gpu Demo.py --ckpt_dir <pmx_shards_split_out/pmx_model_dir> --tokenizer_path <llama_tokenizer_dir>/tokenizer.model --fused_qkv 1 --fused_kvcache 1 --auto_causal 1 --quantized_cache 1 --dynamic_batching 1 --seqlen_scale_up 1 --max_gen_len 256 --dump_steps 0,1,255 --dump_tensor_path <dump_dir> --batch 1
#参数解释
seqlen_scale_up:输入字节大小的比例因子(序列长度按8放大)。
max_gen_len:指定生成的最大输出长度(以字节为单位)。
dump_tensor_path:存储转储的测试数据的路径。
batch:指定数据处理的批大小。
```
测试结果
0,1,255步测试数据
编译-科学上网
```shell
git clone ****s://github.com/openppl-public/ppl.llm.serving.git
cd ppl.llm.serving
./build.sh -DPPLNN_USE_LLM_CUDA=ON -DPPLNN_CUDA_ENABLE_NCCL=ON -DPPLNN_ENABLE_CUDA_JIT=OFF -DPPLNN_CUDA_ARCHITECTURES="'80;86;87'" -DPPLCOMMON_CUDA_ARCHITECTURES="'80;86;87'"
#使用的是V100
sudo apt-get install pkg-config
./build.sh -DPPLNN_USE_LLM_CUDA=ON -DPPLNN_CUDA_ENABLE_NCCL=ON -DPPLNN_ENABLE_CUDA_JIT=OFF -DPPLNN_CUDA_ARCHITECTURES="'70'" -DPPLCOMMON_CUDA_ARCHITECTURES="'70'"
#消除cmake警告
vi deps/grpc/third_party/zlib/CMakeLists.txt
vi deps/grpc/third_party/cares/cares/CMakeLists.txt
deps/rapidjson/CMakeLists.txt
cmake_minimum_required(VERSION 3.5...3.28)
sudo apt-get update
sudo apt-get upgrade cmake
#zlib错误
wget ****s://***.zlib.net/zlib-1.3.tar.gz
tar -xzvf zlib-1.3.tar.gz
cd zlib-1.3
./configure --prefix=/usr/local/zlib
make
sudo make install
ls /usr/local/zlib/lib
sudo ldconfig
```
**单卡/多卡模型**部署
服务器端Server
```
#配置文件llama_7b_config_example.json:运行前需要设置server的配置文件,以llama2 7b chat为例
{
"model_type": "llama",
"model_dir": "export_path[_split]/",
"model_param_path": "export_path/params.json",
"tokenizer_path": "llama_model/tokenizer.model",
"tensor_parallel_size": 1,
"top_p": 0.0,
"top_k": 1,
"max_tokens_scale": 0.94,
"max_tokens_per_request": 4096,
"max_running_batch": 1024,
"max_tokens_per_step": 8192,
"host": "0.0.0.0",
"port": 23333
}
```
客户端请求
在线请求
```
#运行client_sample:prompt定义在源文件中,支持多batch发送和流式接收。
#prompt:"Building a website can be done in 10 simple steps:\n"
./ppl-build/client_sample 127.0.0.1:23333
```
prompt和生成的answer
**进行 QPS benchmark 测试**
QPS benchmark 测试是指对系统或应用程序的性能进行评估和测试,特别是在高并发负载下的性能表现。QPS(Queries Per Second,每秒查询数)是衡量系统处理能力的重要指标之一。
```
./ppl-build/client_qps_measure --target=127.0.0.1:23333 --tokenizer=/model_data/llama_fb/tokenizer.model --dataset=tools/samples_1024.json --request_rate=inf
#参数解释
--target 是server的ip和端口;
--tokenizer是tokenizer的路径;
--dataset是测试的数据集,此处测试集数量为1024,tools/目录下另有其他大小的数据集;
--request_rate是每秒发送的请求数,此处inf表示无间隙发送所有请求。
```
```
#输出解释
benchmark time: 性能测试的总时间,以秒为单位。在这个例子中,测试总时间为 119.52 秒。
request count: 请求的总数。这里是 1024 个请求。
avg input len: 平均输入长度。这里是 113,表示平均每个请求的输入文本长度为 113 个字符。
total input len: 输入文本的总长度。这里是 115860,表示所有请求的输入文本总长度为 115860 个字符。
avg gen len: 平均生成长度。这里是 321,表示平均每个回复的生成文本长度为 321 个字符。
total gen len: 生成文本的总长度。这里是 328942,表示所有回复的生成文本总长度为 328942 个字符。
time per token: 每个生成文本标记的平均处理时间,以毫秒为单位。这里是 0.36 毫秒。
avg latency prefill: 平均填充延迟。这里是 37471.37 毫秒,表示平均每个请求的填充延迟为 37471.37 毫秒。
avg latency decoding: 平均解码延迟。这里是 80.91 毫秒,表示平均每个请求的解码延迟为 80.91 毫秒。
avg latency per prompt: 平均每个提示的延迟。这里是 60579.34 毫秒,表示平均每个请求的提示延迟为 60579.34 毫秒。
tokens out per sec: 每秒生成的标记数量。这里是 2752.19 标记。
tokens inout per sec: 每秒输入和生成的标记总数。这里是 3721.57 标记。
requests per sec: 每秒请求数量。这里是 8.57 个请求。
#如果想要获取更精确的测量结果,可以在进行benchmark测试前,调用几次client sample来warm up机器。
```
总结
首先进行了llama2 7b chat的huggingface模型转换和导出微pmx算子格式, 接着进行了pmx模型的部署和client推理测试。
目前支持llama、internlm和baichuan模型,后续会支持更多模型。