# 1. 推理服务性能优化
# 1.1 推理服务的优化方向
随着LLM的不断发展和应用,如何提高模型推理性能成为了一个重要的研究方向。推理性能受到显存带宽而不是计算能力的限制,服务吞吐量受到推理batch_size的限制。针对推理性能和服务吞吐量的优化,可以从三个角度开展:推理引擎层、服务层优化以及量化技术。
推理引擎层主要是针对计算性能进行优化,例如KernelFusion、KV-Cache、FlashAttention、TP+PP、PagedAttention等技术;
服务层优化主要关注吞吐量的提升,包括Dynamic-Batching、Continous-Batching等技术。
此外,还有针对特定场景的优化技术,例如流式、交互式及持续生成,以及长序列推理等。
模型量化方面主要涉及Weight-Only、int8、int4以及KV-Cache量化等。
对于以上这些技术基础理论的介绍,详见这篇文章:大模型推理-2-推理引擎和服务性能优化 (opens new window)
# 1.2 基于vLLM加速大模型推理
# 1.2.1 vLLM项目简介
vLLM是一个大型语言模型推理加速工具,它通过优化内存管理、连续批处理、CUDA核心优化和分布式推理支持等技术手段,显著提高了大型语言模型的推理速度和效率。在官方实验中,vLLM 的吞吐量比 HF 高出 24 倍,比 TGI 高出 3.5 倍。
- 项目地址:https://github.com/vllm-project/vllm (opens new window)
- 论文地址:https://dl.acm.org/doi/pdf/10.1145/3600006.3613165 (opens new window)
- 官方博客:vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention (opens new window)
注:vLLM官方目前还不支持AutoGPTQ的量化模型,也不支持ChatGLM-1模型,也不支持LoRA微调后的adapters。
# 1.2.2 vLLM基本原理
vLLM是LLM推理和服务引擎,支持多种模型,具有极高的性能,PagedAttention是vLLM背后的核心技术。
作者发现大模型推理的性能瓶颈主要来自于内存。一是自回归过程中缓存的K和V张量非常大,在LLaMA-13B中,单个序列输入进来需要占用1.7GB内存。二是内存占用是动态的,取决于输入序列的长度。由于碎片化和过度预留,现有的系统浪费了60%-80%的内存。
PagedAttention灵感来自于操作系统中虚拟内存和分页的经典思想,它可以允许在非连续空间立存储连续的KV张量。具体来说,PagedAttention把每个序列的KV缓存进行了分块,每个块包含固定长度的token,而在计算attention时可以高效地找到并获取那些块。
每个固定长度的块可以看成虚拟内存中的页,token可以看成字节,序列可以看成进程。那么通过一个块表就可以将连续的逻辑块映射到非连续的物理块,而物理块可以根据新生成的token按需分配。
所以序列在分块之后,只有最后一个块可能会浪费内存(实际中浪费的内存低于4%)。高效利用内存的好处很明显:系统可以在一个batch中同时输入更多的序列,提升GPU的利用率,显著地提升吞吐量。
PagedAttention的另外一个好处是高效内存共享。例如,在并行采样的时候,一个prompt需要生成多个输出序列。这种情况下,对于这个prompt的计算和内存可以在输出序列之间共享。
通过块表可以自然地实现内存共享。类似进程之间共享物理页,在PagedAttention中的不同序列通过将逻辑块映射到一样的物理块上可以实现共享块。为了确保安全共享,PagedAttention跟踪物理块的引用计数,并实现了Copy-on-Write机制。内存共享减少了55%内存使用量,大大降低了采样算法的内存开销,同时提升了高达2.2倍的吞吐量。
# 1.2.3 vLLM基本用法
vLLM只是用来对prompts进行批处理,但它并不能独立使用,需要搭配 Dynamic-Batching 去使用,这里可以自己去实现,也可以使用开源实现,比如:triton-inference-server、mosecorg/mosec、ShannonAI/service-streamer等。
# 2. 需求分析及测试环境
# 2.1 需求与技术选型
# 2.1.1 需求场景
[1] 对并行处理做了优化,能够在较快响应速度的前提下支持较多的并发量。
[2] 支持目前主流的大模型(如ChatGLM、Baichuan、Qwen、LLaMA),支持流式输出。
[3] 在显存溢出时让它使用内存,这样只是推理变慢而不是爆显存导致挂掉。
# 2.1.2 技术选型
技术选型:调研了很多开源项目,发现还是LLaMA-Factory最合适。它是一个主要用于大模型微调的项目,里面自带推理服务,在2024.3.07的版本在推理服务里支持了vLLM技术,可用来部署高效的推理服务。
关于使用它进行大模型微调这里就不赘述了,详见我的另一篇博客:ChatGLM大模型的高效微调 (opens new window)
关于显存溢出时让它用内存,可参考:ZeRO-Inference: Democratizing massive model inference (opens new window) 文章。
vLLM的issues里有个人在自己的Fork仓库里进行了实现,还没合并到主分支,详见:https://github.com/vllm-project/vllm/issues/3563 (opens new window)
另外,调研时尝试过的其他开源项目如下所示,仅供参考:
- LightLLM:一个基于 Python 的 LLM推理和服务框架,以其轻量级设计、易于扩展和高速性能而著称 (opens new window)
- FastLLM:一个纯c++的全平台llm加速库,支持python调用 (opens new window)
- ServiceStreamer:将服务请求排队组成一个完整的batch,再送进GPU运算,极大提高GPU利用率 (opens new window)
- Mosec:一个高性能 ML 模型服务框架,提供动态批处理和 CPU/GPU 管道,以充分利用计算资源 (opens new window)
- triton-inference-server/vllm_backend:vLLM设计,旨在vLLM引擎上运行支持的模型 (opens new window)
- imitater:基于 vllm 和 infinity 构建的统一语言模型服务器 (opens new window)
# 2.2 服务器测试环境
实验环境:实体GPU服务器,NVIDIA RTX 4090 / 24GB,CentOS 7.9,Anaconda3-2019.03,CUDA 12.4
如果没有GPU服务器,可以租用AutoDL等平台的。服务器的租用及基础环节的安装这里就不赘述了,详见我的另一篇博客:常用深度学习平台的使用指南 (opens new window)
# 3. 部署高效推理服务
# 3.1 使用LLaMA-Factory部署推理服务
# 3.1.1 拉取项目并安装依赖
拉取项目并安装依赖,并准备模型文件(这里以 chatglm3-6b (opens new window) 为例)
$ git clone https://github.com/hiyouga/LLaMA-Factory.git
$ conda create -n llama_factory python=3.10
$ conda activate llama_factory
$ cd LLaMA-Factory
$ pip3 install -r requirements.txt
$ pip3 install vllm==0.3.3
2
3
4
5
6
# 3.1.2 启动支持vLLM的推理服务
启动支持vLLM的推理服务,官方支持多种方式,这里仅以 API Demo 为例:
$ CUDA_VISIBLE_DEVICES=0 python3 src/api_demo.py \
--model_name_or_path /root/llm_models/THUDM/chatglm3-6b/ \
--template default \
--infer_backend vllm
2
3
4
# 3.2 对部署的推理服务进行测试
# 3.2.1 查看接口文档
使用Chrome浏览器打开此地址:http://<your_server_ip>:8000/docs
,可以访问到接口文档。
先请求一下 /v1/models 接口,发现模型名叫做 gpt-3.5-turbo。
然后在 /v1/chat/completions 接口里请求推理服务,注意把 model 和 content 改了。
# 3.2.2 测试流式输出
在接口文档那里,可以看到 curl 命令,把 stream 改成 true 即可变成流式输出。
$ curl -X 'POST' \
'http://<your_server_ip>:8000/v1/chat/completions' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": "解释一下量子计算"
}
],
"tools": [],
"do_sample": true,
"temperature": 0,
"top_p": 0,
"n": 1,
"max_tokens": 0,
"stream": true
}'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 3.2.3 进行压力测试
这里不使用专业的压力测试工具了,直接写个 Python 脚本进行压力测试。
# -*- coding: utf-8 -*-
import threading
import requests
import json
def send_post_request(url, payload):
"""
向指定的URL发送POST请求。
"""
headers = {
"accept": "application/json",
"Content-Type": "application/json"
}
updated_payload = {
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": payload["prompt"]
}
],
"tools": [
{
"type": "function",
"function": {
"name": "string",
"description": "string",
"parameters": {}
}
}
],
"temperature": 0,
"top_p": 0,
"n": 1,
"max_tokens": 0,
"stream": False
}
response = requests.post(url, headers=headers, data=json.dumps(updated_payload))
try:
response_json = response.json()
print(response_json)
except ValueError:
print("Response could not be decoded as JSON:", response.text)
def threaded_requests(url, payload, num_threads, total_requests):
"""
创建并启动多线程以达到指定的请求总量。
"""
rounds = (total_requests + num_threads - 1) // num_threads # 计算需要的轮数
for _ in range(rounds):
threads = []
for _ in range(num_threads):
if total_requests <= 0:
break # 如果已经达到请求总量,停止创建新线程
thread = threading.Thread(target=send_post_request, args=(url, payload))
thread.start()
threads.append(thread)
total_requests -= 1
for thread in threads:
thread.join()
if __name__ == '__main__':
api_url = 'http://your_server_ip:8000/v1/chat/completions'
payload = {
"prompt": "解释一下量子计算"
}
num_threads = 50 # 线程数
total_requests = 100 # 总请求数
threaded_requests(api_url, payload, num_threads, total_requests)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
可以看到,哪怕只是在一张单卡4090显卡上,大模型的响应速度也是非常迅速的。
# 4. 参考资料
[1] vLLM是一个大型语言模型推理加速工具 from Github (opens new window)
[2] vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention from vLLM官方文档 (opens new window)
[3] vLLM:给大模型提提速,支持高并发吞吐量提高24倍,同时推理速度最少提高 8 倍 from CSDN (opens new window)
[4] vLLM Feature:Offload Model Weights to CPU from Github issues (opens new window)
[5] 如何让vLLM适配一个新模型 from 知乎 (opens new window)
[7] 如何解决LLM大语言模型的并发问题 from 知乎 (opens new window)
[8] 大模型的N种高效部署方法:以LLama2为例 from 美熙科技说 (opens new window)
[9] LightLLM:纯Python超轻量高性能LLM推理框架 from AI文摘 (opens new window)
[10] 大模型推理百倍加速之KV cache篇 from 知乎 (opens new window)
[11] 大模型推理-2-推理引擎和服务性能优化 from 知乎 (opens new window)
[12] 在 Triton 中部署 vLLM 模型 from Github (opens new window)
[13] VLLM推理加速与部署 from Github (opens new window)
[14] Triton Inference Server教程2 from CSDN (opens new window)
[15] 使用本地模型替代 OpenAI:多模型并发推理框架 from 知乎 (opens new window)
[16] 怎么在我们项目中使用vLLM推理 from Github issues (opens new window)
[17] LLaMA-Factory统一 100 多个 LLM 的高效微调 from Github (opens new window)
[18] ZeRO-Inference: Democratizing massive model inference from Deepspeed官方文档 (opens new window)
[19] 图解大模型计算加速系列:vLLM源码解析1,整体架构 from AINLP (opens new window)
[20] 量化模型能否用vllm部署 from Github issues (opens new window)
[21] Would it be possible to support LoRA fine-tuned models from Github issues (opens new window)
[22] Support LoRA adapter from Github issues (opens new window)