本文旨在比较不同的开源库,用于LLM推理和服务。我们将探索它们的关键特点和不足之处,并使用真实的部署示例来进行讨论。我们将研究vLLM、文本生成推理、OpenLLM、Ray Serve等框架。
“简短”摘要
尽管有很多LLM推理框架,但每个都有其特定的用途。以下是一些要考虑的关键要点:
1. 如果需要批量提示传递的最大速度,请使用vLLM。
2. 如果需要原生的HuggingFace支持并且不打算为核心模型使用多个适配器,请选择文本生成推理。
3. 如果速度对你很重要,并且打算在CPU上运行推理,请考虑CTranslate2。
4. 如果要连接适配器到核心模型并利用HuggingFace Agents,请选择OpenLLM,特别是如果你不仅仅依赖PyTorch。
5. 如果需要稳定的流水线和灵活的部署,请考虑Ray Serve。它最适合更成熟的项目。
6. 如果想要在客户端(边缘计算)上本地部署LLM模型,例如在Android或iPhone平台上,请使用MLC LLM。
7. 如果已经使用DeepSpeed库并希望继续使用它来部署LLM模型,请使用DeepSpeed-MII。
本文将不涵盖传统的用于服务深度学习模型的库,如TorchServe、KServe或Triton Inference Server。尽管你可以使用这些库来推理LLM模型,但我只专注于明确设计用于LLM的框架。
1. vLLM
vLLM是一个快速且易于使用的LLM推理和服务库。它的吞吐量比HuggingFace Transformers(HF)高14倍至24倍,比HuggingFace Text Generation Inference(TGI)高2.2倍至2.5倍。
用法
离线批处理推理:
# pip install vllm
from vllm import LLM, SamplingParams
prompts = [
"Funniest joke ever:",
"The capital of France is",
"The future of AI is",
]
sampling_params = SamplingParams(temperature=0.95, top_p=0.95, max_tokens=200)
llm = LLM(model="huggyllama/llama-13b")
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")
API服务器:
# Start the server:
python -m vllm.entrypoints.api_server --env MODEL_NAME=huggyllama/llama-13b
# Query the model in shell:
curl http://localhost:8000/generate \
-d '{
"prompt": "Funniest joke ever:",
"n": 1,
"temperature": 0.95,
"max_tokens": 200
}'
关键特点
1. 连续批处理—迭代级调度,每个迭代确定一批大小。通过批处理,vLLM可以在大量查询负载下良好地工作。
2. PagedAttention—注意力算法来自操作系统中虚拟内存和分页机制的经典思想启发的。这是模型加速的秘诀。
优势
1. 文本生成速度快—我对该库进行了几次实验,并对结果感到非常满意。到目前为止,使用vLLM进行推理是最快的选择。
2. 高吞吐量服务—包括并行采样、波束搜索等各种解码算法。
3. 兼容OpenAI API服务器—如果你使用了OpenAI API,你只需要替换端点的URL即可。
局限性
尽管该库提供了用户友好的功能和广泛的功能,但我发现了一些限制:
1. 添加自定义模型:虽然可以将自己的模型整合进来,但如果该模型与vLLM中的现有模型使用的架构不相似,该过程会变得更加复杂。
2. 缺乏适配器的支持(LoRA、QLoRA等):开源的LLM在针对特定任务进行微调时具有重要的价值。然而,在当前的实现中,没有将模型和适配器权重分开使用的选项,这限制了有效利用这些模型的灵活性。
3. 缺乏权重量化功能:有时,LLM模型的大小可能超出可用的GPU内存,因此减少内存消耗至关重要。
这是最快的LLM推理库。由于其内部优化,它在性能上明显优于竞争对手。然而,它在支持的模型范围有限方面存在一些弱点。
2.Text generation inference
文本生成推理是用于文本生成推理的Rust、Python和gRPC服务器。它在HuggingFace的生产中被用于提供LLM的API推理小部件。
用法
使用docker运行web服务器:
mkdir data
docker run --gpus all --shm-size 1g -p 8080:80 \
-v data:/data ghcr.io/huggingface/text-generation-inference:0.9 \
--model-id huggyllama/llama-13b \
--num-shard 1
查询:
# pip install text-generation
from text_generation import Client
client = Client("http://127.0.0.1:8080")
prompt = "Funniest joke ever:"
print(client.generate(prompt, max_new_tokens=17 temperature=0.95).generated_text)
关键特点
1. 内置的Prometheus指标 - 你可以监测服务器的负载并了解其性能。
2. 经过优化的transformers代码,使用flash-attention((和v2版本)和Paged Attention进行推理。
优势
1. Docker中安装了所有的依赖项 — 你立即获得一个在你的机器上完全可工作的现成环境。
2. 对HuggingFace模型的原生支持 — 轻松运行你自己的模型或使用HuggingFace模型库中的任何模型。
3. 对模型推理的控制:该框架提供了多种选项来管理模型推理,包括精度调整、量化、张量并行、重复惩罚等。
局限性
1. 缺少适配器支持 - 需要注意的是,尽管可以使用适配器部署LLM模型,但目前官方还没有为此提供支持或文档。
2. 需要从源代码编译(Rust + CUDA内核) - 不要误解,我很欣赏Rust,但并不是所有的数据科学团队都熟悉它,这可能会使将自定义更改合并到库中变得具有挑战性。
3. 文档不完整:所有的信息都在项目的README(自述文件)中。
我认为这是竞争中的领先者之一。这个库编写得很好,我在模型部署过程中面临的挑战很少。如果你希望与HuggingFace进行原生集成,这绝对值得考虑。需要注意的是,该库不再是完全开源的。
3.CTranslate2
CTranslate2是一个用于有效推理Transformer模型的C++和Python库。
用法
首先,转换模型:
pip install -qqq transformers ctranslate2
# The model should be first converted into the CTranslate2 model format:
ct2-transformers-converter --model huggyllama/llama-13b --output_dir llama-13b-ct2 --force
查询:
import ctranslate2
import transformers
generator = ctranslate2.Generator("llama-13b-ct2", device="cuda", compute_type="float16")
tokenizer = transformers.AutoTokenizer.from_pretrained("huggyllama/llama-13b")
prompt = "Funniest joke ever:"
tokens = tokenizer.convert_ids_to_tokens(tokenizer.encode(prompt))
results = generator.generate_batch(
[tokens],
sampling_topk=1,
max_length=200,
)
tokens = results[0].sequences_ids[0]
output = tokenizer.decode(tokens)
print(output)
关键特点
1. 在CPU和GPU上快速高效执行 - 由于内置的一系列优化(如层融合、去除填充、批次重新排序、原地操作、缓存机制等),推理LLM速度更快,内存需求更低。
2. 动态内存使用 - 内存使用量根据请求大小动态变化,同时仍满足性能要求,这要归功于在CPU和GPU上的缓存分配器。
3. 支持多种CPU架构 - 该项目支持x86–64和AArch64/ARM64处理器,并集成了多个针对这些平台进行优化的后端:Intel MKL、oneDNN、OpenBLAS、Ruy和Apple Accelerate。
优势
1. 并行和异步执行 - 多个批次可以使用多个GPU或CPU核心并行和异步处理。
2. 提示缓存 - 模型在静态提示上运行一次,模型状态将被缓存并重用于将来使用相同静态提示的调用。
3. 磁盘占用空间较小 - 量化可以使模型在磁盘上缩小4倍,同时将精度损失降至最低。
局限性
1. 没有内置的REST服务器 — 尽管你仍然可以运行一个REST服务器,但我错过了一个具备日志记录和监控功能的现成服务。
2. 缺乏对适配器(LoRA、QLoRA等)的支持。
从发布和提交来看,开发人员正在积极地进行开发。该库的许多优化令人印象深刻,它最主要的亮点是能够在CPU上进行LLM推理。
4. DeepSpeed-MII
MII借助DeepSpeed实现了低延迟和高吞吐量的推理能力。
用法
运行web服务器:
# DON'T INSTALL USING pip install deepspeed-mii
# git clone https://github.com/microsoft/DeepSpeed-MII.git
# git reset --hard 60a85dc3da5bac3bcefa8824175f8646a0f12203
# cd DeepSpeed-MII && pip install .
# pip3 install -U deepspeed
# ... and make sure that you have same CUDA versions:
# python -c "import torch;print(torch.version.cuda)" == nvcc --version
import mii
mii_configs = {
"dtype": "fp16",
'max_tokens': 200,
'tensor_parallel': 1,
"enable_load_balancing": False
}
mii.deploy(task="text-generation",
model="huggyllama/llama-13b",
deployment_name="llama_13b_deployment",
mii_config=mii_configs)
查询:
import mii
generator = mii.mii_query_handle("llama_13b_deployment")
result = generator.query(
{"query": ["Funniest joke ever:"]},
do_sample=True,
max_new_tokens=200
)
print(result)
关键特点
1. 多个副本的负载平衡 — 对于处理大量用户非常有用的工具。负载均衡器能够高效地在不同的副本之间分配传入请求,从而提高应用程序的响应时间。
2. 非持久化部署 — 这是一种不将更新永久应用于目标环境的部署方法。在资源效率、安全性、一致性和管理便捷性至关重要的场景中,这是一个有价值的选择。它可以实现更可控、标准化的环境,同时降低运营开销。
优势
1. 不同的模型仓库 — 通过多个开源模型仓库如Hugging Face、FairSeq、EluetherAI等进行提供。
2. 延迟量化和成本降低 — MII可以显著降低昂贵语言模型的推理成本。
3. 本地和Azure集成 — 由Microsoft开发的MII框架与其云系统之间具有良好的集成能力。
局限性
1. 缺乏官方版本发布 — 我花了几个小时才找到一个具有功能的应用的正确提交。部分文档已经过时,不再相关。
2. 模型数量有限 — 不支持Falcon、LLaMA 2和其他语言模型。你只能运行有限数量的模型。
3. 缺乏对适配器(LoRA、QLoRA等)的支持。
该项目基于可靠的DeepSpeed库,该库在社区中享有声誉。如果你寻求稳定性和经过验证的解决方案,MII将是一个很好的选择。根据我的实验,该库在处理单个提示时展现出最佳的速度。然而,在将其应用到系统中之前,我建议先在你的具体任务上对该框架进行测试。
5. OpenLLM
用于在生产环境中运行大型语言模型(LLM)的开放平台。
用法
运行web服务器:
pip install openllm scipy
openllm start llama --model-id huggyllama/llama-13b \
--max-new-tokens 200 \
--temperature 0.95 \
--api-workers 1 \
--workers-per-resource 1
查询:
import openllm
client = openllm.client.HTTPClient('http://localhost:3000')
print(client.query("Funniest joke ever:"))
关键特点
1. 适配器支持 — 将多个适配器连接到一个部署的LLM模型上。想象一下,你可以只使用一个模型来执行多个专门的任务。
2. 运行时实现 — 使用不同的实现:PyTorch (pt)、TensorFlow (tf)或Flax (flax)。
3. HuggingFace Agents — 将HuggingFace上的不同模型与LLM和自然语言一起连接和管理。
优势
1. 良好的社区支持 — 该库不断发展并添加新的功能。
2. 集成新模型 — 开发人员提供了一个指南,介绍如何添加自己的模型。
3. 量化 — OpenLLM支持bitsandbytes和GPTQ的量化。
4. LangChain集成 — 你可以使用LangChain与远程的OpenLLM服务器进行交互。
局限性
1. 缺乏批处理支持 — 对于大量消息流,这很可能会成为应用程序性能的瓶颈。
2. 缺乏内置的分布式推理 — 如果你想要在多个GPU设备上运行大型模型,你需要额外安装OpenLLM的服务组件Yatai。
这是一个功能广泛的框架。它使你能够以最小的开销创建一个灵活的应用程序。尽管文档可能没有完全覆盖所有方面,但在你深入了解这个库时,你可能会在它的附加功能中发现令人愉快的惊喜。
6.Ray Serve
Ray Serve是一个可扩展的模型服务库,用于构建在线推理API。Serve是与框架无关的,因此你可以使用一个工具包来提供从深度学习模型到各种其他模型的服务。
用法
运行web服务器:
# pip install ray[serve] accelerate>=0.16.0 transformers>=4.26.0 torch starlette pandas
# ray_serve.py
import pandas as pd
import ray
from ray import serve
from starlette.requests import Request
@serve.deployment(ray_actor_options={"num_gpus": 1})
class PredictDeployment:
def __init__(self, model_id: str):
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
self.model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float16,
device_map="auto",
)
self.tokenizer = AutoTokenizer.from_pretrained(model_id)
def generate(self, text: str) -> pd.DataFrame:
input_ids = self.tokenizer(text, return_tensors="pt").input_ids.to(
self.model.device
)
gen_tokens = self.model.generate(
input_ids,
temperature=0.9,
max_length=200,
)
return pd.DataFrame(
self.tokenizer.batch_decode(gen_tokens), columns=["responses"]
)
async def __call__(self, http_request: Request) -> str:
json_request: str = await http_request.json()
return self.generate(prompt["text"])
deployment = PredictDeployment.bind(model_id="huggyllama/llama-13b")
# then run from CLI command:
# serve run ray_serve:deployment
查询:
import requests
sample_input = {"text": "Funniest joke ever:"}
output = requests.post("http://localhost:8000/", json=[sample_input]).json()
print(output)
关键特点
1. 监控仪表板和Prometheus指标 — 你可以使用Ray仪表板来获得Ray集群和Ray Serve应用程序状态的高级概览。
2. 多个副本的自动缩放 — Ray通过观察队列大小并根据情况做出缩放决策,从而适应流量峰值。
3. 动态请求批处理 — 当你的模型使用成本较高且希望最大化硬件利用率时,这是必要的。
优势
1. 全面的文档 — 我很欣赏开发人员在这方面投入了时间,并认真对待了文档的编写。几乎每种用例都可以找到很多示例,这非常有帮助。
2. 用于生产环境的准备就绪 — 在我看来,这是这个列表中最成熟的框架。
3. 本地LangChain集成 — 你可以使用LangChian与远程的OpenLLM服务器进行交互。
局限性
1. 缺乏内置的模型优化 — Ray Serve不专注于LLM,它是一个更广泛的用于部署任何机器学习模型的框架。你需要自行进行优化。
2. 高的入门门槛 — 该库有时会过多的附加功能,这提高了入门门槛,对于新手来说很难导航和理解。
如果你需要最适合生产环境并且不仅仅涉及深度学习的解决方案,Ray Serve是一个很好的选择。它非常适合企业级应用,其中可用性、可扩展性和可观察性非常重要。此外,你还可以利用其庞大的生态系统进行数据处理、训练、微调和服务。最后,从OpenAI到Shopify和Instacart等公司都在使用它。
7. MLCLLM
机器学习编译(MLC LLM)是一种通用的部署解决方案,可以使LLM模型在消费设备上高效运行,利用本机硬件加速。
用法
运行web服务器:
# 1. Make sure that you have python >= 3.9
# 2. You have to run it using conda:
conda create -n mlc-chat-venv -c mlc-ai -c conda-forge mlc-chat-nightly
conda activate mlc-chat-venv
# 3. Then install package:
pip install --pre --force-reinstall mlc-ai-nightly-cu118 \
mlc-chat-nightly-cu118 \
-f https://mlc.ai/wheels
# 4. Download the model weights from HuggingFace and binary libraries:
git lfs install && mkdir -p dist/prebuilt && \
git clone https://github.com/mlc-ai/binary-mlc-llm-libs.git dist/prebuilt/lib && \
cd dist/prebuilt && \
git clone https://huggingface.co/huggyllama/llama-13b dist/ && \
cd ../..
# 5. Run server:
python -m mlc_chat.rest --device-name cuda --artifact-path dist
查询:
import requests
payload = {
"model": "lama-30b",
"messages": [{"role": "user", "content": "Funniest joke ever:"}],
"stream": False
}
r = requests.post("http://127.0.0.1:8000/v1/chat/completions", json=payload)
print(r.json()['choices'][0]['message']['content'])
关键特点
1. 平台原生运行时 — 在用户设备的原生环境中部署,这些环境可能没有Python或其他必要的依赖项。应用开发人员只需要熟悉平台原生运行时,就可以将经过MLC编译的LLM模型集成到他们的项目中。
2. 内存优化 — 你可以使用不同的技术对模型进行编译、压缩和优化,从而能够在不同的设备上部署模型。
优势
1. 所有设置都在JSON配置中 — 你可以在单个配置文件中为每个编译模型定义运行时配置。
2. 预构建应用程序 — 你可以将模型编译为不同的平台:用于命令行的C++,用于Web的JavaScript,用于iOS的Swift以及用于Android的Java/Kotlin。
局限性
1. 使用LLM模型的功能有限:不支持适配器,无法更改精度,没有令牌流,等等。该库主要专注于为不同设备编译模型。
2. 仅支持分组量化 — 尽管这种方法显示出良好的结果,但在社区中,使用“bitsandbytes”和“GPTQ”等其他量化方法更为流行。
3. 安装复杂 — 我花了几个小时才正确安装该库。很可能它不适合初学者开发人员使用。
如果你需要在iOS或Android设备上部署应用程序,这个库正是你所需要的。它将使你能够快速而本地地编译和部署模型到设备上。然而,如果你需要一个高负载的服务器,我不建议选择这个框架。
总结
每个库都有其独特的优点和缺点。LLM模型的发展仍处于早期阶段,因此目前还没有单一的标准可供遵循。
来源:https://medium.com/better-programming/frameworks-for-serving-llms-60b7f7b23407