人工智能

大型语言模型的优化部署:vLLM 的 PagedAttention 和高效 AI 服务的未来

mm
Deploy the vLLM Inference Engine to Run Large Language Models

大型语言模型(LLMs)在现实世界应用中存在独特的挑战,特别是在计算资源、延迟和成本效益方面。在本综合指南中,我们将探索 LLM 服务的格局,重点关注 vLLM(向量语言模型),一种改变我们部署和交互这些强大模型方式的解决方案。

大型语言模型服务的挑战

在深入探讨具体解决方案之前,让我们检查一下使 LLM 服务成为复杂任务的关键挑战:

计算资源

LLMs 以其巨大的参数数量而闻名,范围从数十亿到数百亿。例如,GPT-3 拥有 175 亿参数,而更 recent 的模型,如 GPT-4,估计拥有更多参数。这种庞大的规模转化为显著的计算需求。

示例:
考虑一个相对较小的 LLM,具有 13 亿参数,例如 LLaMA-13B。即使这个模型需要:

– 大约 26 GB 的内存来存储模型参数(假设 16 位精度)
– 额外的内存用于激活、注意力机制和中间计算
– 实时推理所需的显著 GPU 计算能力

延迟

在许多应用中,例如聊天机器人或实时内容生成,低延迟对于良好的用户体验至关重要。然而,LLMs 的复杂性可能导致显著的处理时间,尤其是对于更长的序列。

示例:
想象一个由 LLM 驱动的客户服务聊天机器人。如果每个响应需要几秒钟来生成,会话将感觉不自然且令人沮丧。

成本

运行 LLMs 的硬件可能非常昂贵。高端 GPU 或 TPU 通常是必要的,这些系统的能耗也很大。

示例:
在云计算中运行一组 NVIDIA A100 GPU(通常用于 LLM 推理)每天的成本可能达到数千美元。

传统的 LLM 服务方法

在探索更高级的解决方案之前,让我们简要回顾一下传统的 LLM 服务方法:

使用 Hugging Face Transformers 的简单部署

Hugging Face Transformers 库提供了一种直接的方式来部署 LLMs,但它不针对高吞吐量服务进行优化。

示例代码:

“`python
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_name = “meta-llama/Llama-2-13b-hf”
model = AutoModelForCausalLM.from_pretrained(model_name, device_map=”auto”)
tokenizer = AutoTokenizer.from_pretrained(model_name)

def generate_text(prompt, max_length=100):
inputs = tokenizer(prompt, return_tensors=”pt”).to(model.device)
outputs = model.generate(**inputs, max_length=max_length)
return tokenizer.decode(outputs[0], skip_special_tokens=True)

print(generate_text(“The future of AI is”))
“`

虽然这种方法有效,但它不适合高流量应用程序,因为它的资源利用效率低下且缺乏服务优化。

使用 TorchServe 或类似框架

像 TorchServe 这样的框架提供了更强大的服务功能,包括负载均衡和模型版本控制。然而,它们仍然没有解决 LLM 服务的特定挑战,例如大型模型的高效内存管理。

了解 LLM 服务中的内存管理

高效的内存管理对于服务大型语言模型(LLMs)至关重要,因为需要大量的计算资源。以下图像说明了内存管理的各个方面,这些方面对于优化 LLM 性能至关重要。

分段内存与分页内存

操作系统与 vLLM 的内存管理

操作系统与 vLLM 的内存管理

 

操作系统与 vLLM 的内存管理

操作系统与 vLLM 的内存管理

这些图表比较了分段内存和分页内存管理技术,这些技术通常用于操作系统(OS)。

  • 分段内存:此技术将内存划分为不同的段,每个段对应一个不同的程序或进程。在 LLM 服务的背景下,不同的段可能分配给模型的各个组件,例如标记化、嵌入和注意力机制。每个段可以独立增长或缩小,提供灵活性,但如果段不正确管理,可能会导致碎片化。
  • 分页内存:这里,内存被划分为固定大小的页,这些页被映射到物理内存。页可以根据需要交换进出,从而实现内存资源的高效使用。在 LLM 服务中,这对于管理存储模型权重和中间计算所需的大量内存至关重要。

操作系统与 vLLM 的内存管理

此图比较了传统操作系统的内存管理与 vLLM 使用的内存管理方法。

  • 操作系统内存管理:在传统操作系统中,进程(例如进程 A 和进程 B)在物理内存中分配页(例如页 0、页 1 等)。这种分配可能会随着时间的推移导致碎片化,因为进程请求和释放内存。
  • vLLM 内存管理:vLLM 框架使用键值(KV)缓存来更高效地管理内存。请求(例如请求 A 和请求 B)分配 KV 缓存的块(例如 KV 块 0、KV 块 1 等)。这种方法有助于最小化碎片化并优化内存使用,从而实现更快、更高效的模型服务。

LLMs 中的注意力机制

LLMs 中的注意力机制

LLMs 中的注意力机制

注意力机制是变换器模型的基本组成部分,变换器模型通常用于 LLMs。该图说明了注意力公式及其组成部分:

  • 查询(Q):解码器步骤中的新标记或模型看到的最后一个标记。
  • 键(K):模型应该关注的前一个上下文。
  • 值(V):对前一个上下文的加权和。

公式通过计算查询与键的点积、按键维度的平方根缩放、应用 softmax 函数以及计算值的点积来计算注意力得分。该过程允许模型在生成每个标记时关注输入序列的相关部分。

服务吞吐量比较

vLLM:使用 PagedAttention 的易用、快速、廉价的 LLM 服务

vLLM:使用 PagedAttention 的易用、快速、廉价的 LLM 服务

该图显示了不同框架(HF、TGI 和 vLLM)在不同硬件设置上使用 LLaMA 模型的服务吞吐量比较。

  • LLaMA-13B,A100-40GB:vLLM 的吞吐量比 Hugging Face Transformers(HF)高 14 倍至 24 倍,比 Hugging Face Text Generation Inference(TGI)高 2.2 倍至 2.5 倍。
  • LLaMA-7B,A10G:观察到类似的趋势,vLLM 的性能明显优于 HF 和 TGI。

vLLM:一种新的 LLM 服务架构

vLLM 由 UC Berkeley 的研究人员开发,代表了 LLM 服务技术的一大飞跃。让我们探索其关键功能和创新:

PagedAttention

vLLM 的核心是 PagedAttention,一种受操作系统虚拟内存管理启发的新型注意力算法。以下是其工作原理:

键值(KV)缓存分区:与其将整个 KV 缓存连续存储在内存中,PagedAttention 将其划分为固定大小的块。

非连续存储:这些块可以存储在内存中,不需要连续的存储,从而实现更灵活的内存管理。

按需分配:只有在需要时才分配块,减少内存浪费。

高效共享:多个序列可以共享块,从而实现并行采样和束搜索等技术的优化。

示例:

“`
传统 KV 缓存:
[Token 1 KV][Token 2 KV][Token 3 KV]…[Token N KV]
(连续内存分配)

PagedAttention KV 缓存:
[块 1] -> 物理地址 A
[块 2] -> 物理地址 C
[块 3] -> 物理地址 B

(非连续内存分配)
“`

这种方法显著减少了内存碎片化,并允许更高效地使用 GPU 内存。

连续批处理

vLLM 实现了连续批处理,动态处理随时间到达的请求,而不是等待形成固定大小的批次。这导致延迟降低,吞吐量提高。

示例:

“`
时间 0ms:请求 A 到达
时间 10ms:开始处理请求 A
时间 15ms:请求 B 到达
时间 20ms:开始处理请求 B(与 A 并行)
时间 25ms:请求 C 到达

“`

使用连续批处理,vLLM 可以立即开始处理每个请求,而不是等待将它们分组到预定义的批次中。

高效并行采样

对于需要每个提示多个输出样本的应用程序(例如创意写作助手),vLLM 的内存共享功能非常突出。它可以生成多个输出,同时重用 KV 缓存以共享前缀。

使用 vLLM 的示例代码:

“`python
from vllm import LLM, SamplingParams

llm = LLM(model=”meta-llama/Llama-2-13b-hf”)
prompts = [“The future of AI is”]

# 生成每个提示 3 个样本
sampling_params = SamplingParams(n=3, temperature=0.8, max_tokens=100)
outputs = llm.generate(prompts, sampling_params)

for output in outputs:
print(f”Prompt:{output.prompt}”)
for i, out in enumerate(output.outputs):
print(f”Sample {i + 1}:{out.text}”)
“`

此代码利用 vLLM 的优化高效地为给定提示生成多个样本。

基准测试 vLLM 性能

为了真正欣赏 vLLM 的影响,让我们看一下一些性能比较:

吞吐量比较

基于提供的信息,vLLM 的性能明显优于其他服务解决方案:

– 与 Hugging Face Transformers 相比,吞吐量提高了多达 24 倍

– 与 Hugging Face Text Generation Inference(TGI)相比,吞吐量提高了 2.2 倍至 3.5 倍

示例:

“`
吞吐量(令牌/秒)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`

内存效率

vLLM 的 PagedAttention 结果显示出几乎最优的内存使用:

– 内存浪费仅约 4%,而传统系统中为 60-80%
– 这种效率允许使用相同的硬件服务更大的模型或处理更多的并发请求

开始使用 vLLM

现在我们已经探索了 vLLM 的好处,让我们一步一步地介绍如何设置和在项目中使用它。

6.1 安装

使用 pip 安装 vLLM 非常简单:

“`python
!pip install vllm
“`

6.2 离线推理的基本用法

以下是使用 vLLM 进行离线文本生成的简单示例:

“`python
from vllm import LLM, SamplingParams

# 初始化模型
llm = LLM(model=”meta-llama/Llama-2-13b-hf”)

# 准备提示
prompts = [
“写一首关于人工智能的短诗:”,
“用简单的语言解释量子计算:”
]

# 设置采样参数
sampling_params = SamplingParams(temperature=0.8, max_tokens=100)

# 生成响应
outputs = llm.generate(prompts, sampling_params)

# 打印结果
for output in outputs:
print(f”Prompt:{output.prompt}”)
print(f”生成文本:{output.outputs[0].text}\n”)
“`

此脚本演示如何加载模型、设置采样参数并为多个提示生成文本。

6.3 设置 vLLM 服务器

对于在线服务,vLLM 提供了一个与 OpenAI 兼容的 API 服务器。以下是如何设置它:

1. 启动服务器:

“`bash
python -m vllm.entrypoints.openai.api_server –model meta-llama/Llama-2-13b-hf
“`

2. 使用 curl 查询服务器:

“`bash
curl http://localhost:8000/v1/completions \
-H “Content-Type: application/json” \
-d ‘{
“model”: “meta-llama/Llama-2-13b-hf”,
“prompt”: “人工智能的好处包括:”,
“max_tokens”: 100,
“temperature”: 0.7
}’
“`

此设置允许您使用与 OpenAI API 兼容的接口提供 LLM 服务,使其易于集成到现有应用程序中。

vLLM 的高级主题

虽然 vLLM 提供了显著的 LLM 服务改进,但仍有其他需要探讨的考虑和高级主题:

7.1 模型量化

为了实现更高效的服务,特别是在内存有限的硬件上,量化技术可以被采用。虽然 vLLM 本身不支持量化,但可以与量化模型一起使用:

“`python
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# 加载量化模型
model_name = “meta-llama/Llama-2-13b-hf”
model = AutoModelForCausalLM.from_pretrained(model_name, device_map=”auto”, load_in_8bit=True)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# 将量化模型与 vLLM 一起使用
from vllm import LLM

llm = LLM(model=model, tokenizer=tokenizer)
“`

7.2 分布式推理

对于非常大的模型或高流量应用程序,可能需要在多个 GPU 或机器上进行分布式推理。虽然 vLLM 本身不支持此功能,但可以使用像 Ray 这样的框架将其集成到分布式系统中:

“`python
import ray
from vllm import LLM

@ray.remote(num_gpus=1)
class DistributedLLM:
def __init__(self, model_name):
self.llm = LLM(model=model_name)

def generate(self, prompt, params):
return self.llm.generate(prompt, params)

# 初始化分布式 LLMs
llm1 = DistributedLLM.remote(“meta-llama/Llama-2-13b-hf”)
llm2 = DistributedLLM.remote(“meta-llama/Llama-2-13b-hf”)

# 并行使用它们
result1 = llm1.generate.remote(“Prompt 1”, sampling_params)
result2 = llm2.generate.remote(“Prompt 2”, sampling_params)

# 检索结果
print(ray.get([result1, result2]))
“`

7.3 监控和可观察性

在生产环境中提供 LLMs 时,监控至关重要。虽然 vLLM 没有内置监控,但可以将其与 Prometheus 和 Grafana 等工具集成:

“`python
from prometheus_client import start_http_server, Summary
from vllm import LLM

# 定义指标
REQUEST_TIME = Summary(‘request_processing_seconds’, ‘处理请求所花费的时间’)

# 初始化 vLLM
llm = LLM(model=”meta-llama/Llama-2-13b-hf”)

# 公开指标
start_http_server(8000)

# 使用带有监控的模型
@REQUEST_TIME.time()
def process_request(prompt):
return llm.generate(prompt)

# 您的服务循环在这里
“`

此设置允许您跟踪指标,例如请求处理时间,可以在 Grafana 仪表板中可视化。

结论

高效地服务大型语言模型是一项复杂但至关重要的任务,尤其是在人工智能时代。vLLM 通过其创新的 PagedAttention 算法和优化的实现,代表了 LLM 部署的一个重大飞跃。

通过显著提高吞吐量、减少内存浪费和提供更灵活的服务选项,vLLM 为将强大的语言模型集成到广泛的应用程序中开启了新的可能性。不论您是构建聊天机器人、内容生成系统还是任何其他 NLP 驱动的应用程序,了解和利用像 vLLM 这样的工具对于成功至关重要。

我已经沉浸在了令人着迷的机器学习和深度学习世界中五年了。我的热情和专业知识让我为超过50个不同的软件工程项目做出了贡献,特别关注AI/ML。我的持续的好奇心也让我对自然语言处理产生了兴趣,这是一个我渴望进一步探索的领域。