经济实惠地自托管 LLaMA 3.1 70B(或任何约 70B 的大型语言模型)

如果您正在阅读本指南,那么 Meta 的 Llama 3 系列模型无需介绍。它们于 2024 年 4 月 发布,是目前最好、最可靠的开源大型语言模型,可用于生产环境,直接与 OpenAI 的 GPT-4o 和 Anthropic 的 Claude 3.5 Sonnet 等闭源替代方案竞争。人们经常问我如何托管这些模型用于个人用途、创建合成数据集以及用于私有数据的 RAG。不幸的是,我家里没有强大的 GPU(或多个 GPU)来运行 70B 这样的大型模型,所以我只能求助于使用云计算并积极寻找降低成本的方法。如果您也面临同样的情况,或者只是想知道如何实现,那么本文就是为您准备的。
作为一个有趣的福利,我还会展示如何在本地运行一个类似 ChatGPT 的用户界面来与您的私有模型进行交互。
友情提示:这将是一个直接明了的指南,所以不要指望我详细解释每个步骤。我的简短回答是“阅读文档”
简而言之
- 云服务:Runpod(我将在另一个教程中介绍 GCP)
- 推理引擎:vLLM(我将在未来的教程中介绍 TGI)
- 监控与代理:LiteLLM
- 数据库:PostgreSQL 容器 或 Supabase
- GPU:4x A40 或 2x A100
- Runpod 模板:vLLM 最新版
我创建了 Runpod 模板,请使用它。它也能帮我获得一些积分。
我们应该部署在哪里?
在尝试了几种选择之后,我发现最经济实惠的方法是将模型托管在 Runpod 上。它是一个专为 AI 和机器学习应用程序设计的云计算平台,允许用户通过其 Pod 和无服务器计算选项执行 GPU 和 CPU 资源的代码。以下是我对 Runpod 的看法:
- 非常容易上手
- 极其经济实惠
- 灵活使用我们自己的 Docker 镜像,实现开发环境的无缝迁移(这是我使用它的一个重要原因)
- 提供各种规格的 GPU
在本文中,首先,在决定我们需要什么 GPU 之前,我建议遵循以下粗略指南。
1. 模型大小:
既然我们讨论的是 70B 参数模型,要以 16 位浮点精度部署,我们需要约 140GB 的内存。这足够大,无法在市场上任何单个 GPU 中运行。但对于 4 位(INT4)模型,我们只需要约 45GB 的内存,但这也会导致质量略有下降,请注意这一点。在本指南中,我将向您展示如何部署一个 70B 模型,以:
- FP16/BF16
- INT8 - Bitsandbytes
- INT4 - AWQ
现在我们已经知道了这些模型的大致内存/磁盘需求,最好还是查看模型在 Huggingface 上的页面,以获取权重的确切大小,因为一个 70B 模型通常不完全是 70B,例如 LLaMA 3.1 70B 模型是 70.6B。
因此,16 位精度大约需要 148GB(高估了),8 位精度大约是其一半,而对于 4 位精度,由于我们使用的是 AWQ,最好也查看一下 -> hugging-quants/Meta-Llama-3.1-70B-Instruct-AWQ-INT4,它大约是 45GB。
2. 选择 GPU:技术考量
选择用于托管 LLaMA 3.1 70B 等大型语言模型的 GPU 时,需要考虑几个技术因素:
注意:如果您已经了解这些内容,只是将本文作为部署指南,请直接跳到 2.8。
2.1 显存容量
主要考虑因素是 GPU 的显存(视频内存)容量。LLaMA 3.1 70B,顾名思义,有 700 亿个参数。在 FP16 精度下,这需要大约 148GB 的内存来存储模型权重。但是,还需要额外的内存用于:
- 上下文窗口
- KV 缓存
根据经验,您需要至少模型大小的 1.2 倍到 1.5 倍的显存。但对于更长的上下文,您需要的远不止经验法则,一个 70B 模型,如果上下文长度为 32k,大约需要 14GB 的显存,并且它会随着上下文长度线性增加。
2.2 计算能力 (FLOPS)
FLOPS(每秒浮点运算次数)衡量 GPU 的原始计算能力。对于大型语言模型 (LLM),我们特别关注张量 FLOPS,它表示 GPU 高效执行矩阵乘法运算的能力。
几种不同 GPU 的比较(前两种是目前最划算的!)
GPU 型号 | 内存 | TF32 (TFLOPS) | FP16/BF16 (TFLOPS) | INT8 (TOPS) | FP8 (FLOPS) |
---|---|---|---|---|---|
A100 | 80GB | 156 | 312 | 624 | 不适用 |
H100 | 80GB | 989 | 1979 | 3958 | 3958 |
A40 | 48GB | 37.4 | 149.7 | 299.4 | 不适用 |
更高的 FLOPS 通常意味着更快的推理时间(每秒更多令牌)。约 300 TFLOPS 意味着每秒 300 万亿次操作。
顺便说一句,在大多数 GPU 中,BF16 比 FP16 快得多...如果您使用的是 Ampere 系列或更高版本的 GPU,请随意将 torch_dtype
属性设置为 bfloat16
。
2.3 内存带宽
内存带宽对大型模型至关重要,因为它决定了数据在显存和 GPU 核心之间移动的速度。它以 GB/s 为单位衡量。
- A100:最高 1935 GB/s
- H100:最高 3350 GB/s
- A40:696 GB/s
更高的内存带宽减少了等待数据的时间,从而提高了整体性能。
2.4 Tensor 核心
现代 NVIDIA GPU 包含 Tensor 核心,这是用于矩阵乘法和 AI 工作负载的专用单元。Tensor 核心的数量和效率显著影响 LLM 的性能。
2.5 精度支持
考虑您将运行模型的精度:
- FP32(32 位浮点):最高精度,但内存占用最大
- FP16(16 位浮点):精度和内存效率之间的良好平衡
- FP8(8 位浮点):精度降低,但仍优于 INT8,但并非所有 GPU 都支持此功能。(据我所知,只有 Nvidia Hopper 系列 GPU 支持此功能)
- INT8(8 位整数量化):精度降低,但内存占用显著减少
一些 GPU(例如 A100)提供混合精度功能,可优化性能。
2.6 多 GPU 设置
对于像 LLaMA 3.1 70B 这样大的模型,通常需要多 GPU 设置。考虑:
- NVLink 支持高带宽 GPU 到 GPU 通信
- PCIe 带宽用于 GPU 和 CPU 之间的数据传输
2.7 成本-性能权衡
在寻求经济实惠的托管方案时:
- 考虑使用多个消费级 GPU(例如 RTX 4090),而不是单个高端数据中心 GPU。
- 探索量化技术以减少内存需求。
- 寻找为 AI 工作负载提供有竞争力的定价的 GPU 云服务商。(因此选择了 Runpod,JarvisLabs.ai 也是我的最爱之一)
通过平衡这些因素,您可以找到最具成本效益的 GPU 解决方案来托管 LLaMA 3.1 70B,同时保持可接受的性能。
2.8 GPU 的选择
考虑到这些因素,以及之前使用这些 GPU 的经验,确定我的个人需求,并查看 Runpod 上 GPU 的成本(可以在这里找到),我决定为每种部署类型选择以下 GPU Pod:
- Llama 3.1 70B FP16:4x A40 或 2x A100
- Llama 3.1 70B INT8:1x A100 或 2x A40
- Llama 3.1 70B INT4:1x A40
此外,在撰写本文时,A40 的价格仅为每小时 0.35 美元,非常经济实惠。
如果您的预算充足,我推荐选择 H100 等 Hopper 系列显卡。如果预算有限,A100、A6000、A6000-Ada 或 A40 应该足够好。如果您仍想进一步降低成本(假设 A40 pod 的价格上涨),可以尝试使用 8x 3090。
推理引擎
vLLM 是目前在自定义硬件上托管大型语言模型的热门选择。这是因为它包含了许多已被发现的优化:
- 使用分页注意力机制实现高效的内存管理
- CUDA/HIP 图形执行
- Flash Attention
- 以及更多。
这也允许我们公开一个遵循 OpenAI API 格式的 API,这使得与使用相同格式的预编写工作流程集成变得更容易。
创建 Runpod 实例
在 Runpod 上创建实例相当简单,如果您遇到任何问题,请参阅他们的官方文档。
- 在控制面板上,进入
Pods -> Deploy
- 在这里,我们将不得不选择我们需要的 GPU 实例,我将选择 4x A40 用于 16 位模型。
- 您还需要选择正确的模板,然后编辑环境变量,并检查是否正确设置了
HF_TOKEN
密钥。 - 同时,请确保 TCP 端口 8000 已代理,否则 API 将无法对外暴露。
- 编辑存储(卷磁盘),将其设置为 180GB,这对于 16 位模型应该足够了。
但这还不是全部,您还需要编辑容器启动命令 (CMD),它会告诉 vLLM 要拉取哪个模型并进行推理设置。您可以通过点击 Edit Template
(编辑模板)然后编辑 Container Start Command
(容器启动命令)来完成此操作。
LLaMA 3.1 70B 16 位配置:
--host 0.0.0.0 --port 8000 --model meta-llama/Meta-Llama-3.1-70B-Instruct --dtype bfloat16 --enforce-eager --gpu-memory-utilization 0.95 --api-key sk-IrR7Bwxtin0haWagUnPrBgq5PurnUz86 --max-model-len 8128 --tensor-parallel-size 4
这里重要的参数有(嗯……所有)
- 模型:您当然要选择正确的模型
- 数据类型 (dtype):如果您使用的是 Ampere 系列 GPU 或更高版本(我们正在使用),请使用
bfloat16
;否则,请使用float16
。 - 强制即时执行 (enforce-eager):我曾遇到过一些 AsyncEngineDead 问题,如果没有此设置。目前 vLLM 似乎没有针对此问题的修复,因此您必须启用即时模式。
- GPU 内存利用率 (gpu-memory-utilization):这取决于您希望有多少余量,我通常将其设置为
0.9
或0.95
。 - API 密钥 (api-key):我提供了一个示例 API 密钥,您可以随意编辑。
- 最大模型长度 (max-model-len):这是模型的最大上下文长度(输入 + 输出),这再次取决于内存和您的用例。
- 张量并行大小 (tensor-parallel-size):这是您用于分布式推理的 GPU 数量。
LLaMA 3.1 70B 8 位配置:
--host 0.0.0.0 --port 8000 --model meta-llama/Meta-Llama-3.1-70B-Instruct --dtype bfloat16 --enforce-eager --gpu-memory-utilization 0.95 --api-key sk-IrR7Bwxtin0haWagUnPrBgq5PurnUz86 --max-model-len 8128 --tensor-parallel-size 2 --quantization bitsandbytes --load-format bitsandbytes
变更点
- 量化:我们将其设置为
bitsandbytes
- 加载格式:我们也将此设置为
bitsandbytes
。 - 张量并行大小:通过使用 8 位,我们将内存需求减半。
注意:我在 vLLM 中使用 8 位模型时遇到过问题,如果您遇到任何问题,请参阅文档或他们的 GitHub issues 线程。
LLaMA 3.1 70B 4 位配置:
--host 0.0.0.0 --port 8000 --model hugging-quants/Meta-Llama-3.1-70B-Instruct-AWQ-INT4 --enforce-eager --gpu-memory-utilization 0.98 --api-key sk-IrR7Bwxtin0haWagUnPrBgq5PurnUz86 --max-model-len 8128 --quantization awq
变更点
- 模型:我们使用的是来自 HuggingFace 的预量化模型,采用 AWQ 格式。
- 量化:我们将其设置为
awq
,因为我们的源模型使用了这种量化方法。 - 张量并行大小:这不再需要,因为 4 位模型可以放入单个 A40 GPU 的内存中。
现在,我们终于完成了所有配置步骤。您可以启动实例了。
注意:根据模型的不同,vLLM 可能需要一些时间来下载模型并提供服务。您可以在 Runpod 的日志选项卡中查看日志。
使用自托管模型
您可以选择直接使用您的自托管端点,或者使用 LiteLLM 设置代理,您可以在其中拥有多个部署实例、用于不同用例的多个模型等……此步骤是完全可选的,但它可以为您的 API 提供良好的可追溯性和治理。如果您打算以团队形式使用这些 API,它会特别有用。
直接使用 API
要查找 API 的 URL,请点击实例上的“连接”,然后点击端口 8000,您将获得一个 {"detail": "Not Found"}
响应,这是因为 API 实际上存在于 /v1/
路由中。所以复制 URL 并在末尾添加 /v1
。
之后使用 API 应该就相当简单了
import openai
OPENAI_BASE_URL = "https://runpod-instance-id-8000.proxy.runpod.net/v1" # Note the /v1 at the end
OPENAI_API_KEY = "sk-ABCDEFGHIJKLMNOPQRSTUVWZ" # Make sure to replace with the right one
SYSTEM_PROMPT = "You are a helpful AI assistant"
TEST_PROMPT = "What is Entropy?"
client = openai.OpenAI(
api_key=OPENAI_API_KEY,
base_url=OPENAI_BASE_URL,
)
response = client.chat.completions.create(
model="meta-llama/Meta-Llama-3.1-70B-Instruct",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": TEST_PROMPT}
],
)
通过 LiteLLM Proxy 使用
根据我的经验,使用 LiteLLM 有以下优点(即使是个人使用,我也推荐):
- 统一接口:通过单个 API 简化与多个 LLM 提供商的集成。
- 效率:优化架构降低了计算需求,使其更易于访问。
- 可扩展性:良好地适应各种硬件配置,而不会损失性能。
- 强大的功能:支持文本生成和图像创建等多种任务。
- 错误处理:自动重试和回退机制确保连续性。
- 成本效益:通过最大限度地减少对高端资源的需求来降低运营成本。
LiteLLM 是一个强大、易于访问的工具,可以高效地利用多个语言模型。
您可以将 LiteLLM 部署到任何您想部署的地方。我将在我的一个 Linux 服务器上以 Docker 方式运行它。我建议您查阅 LiteLLM 的文档以获取更多详细信息。
首先,我们必须创建一个包含所有模型端点的 yaml 配置文件。我的配置如下所示:
model_list:
- model_name: vllm-llama3.1-8b
litellm_params:
model: openai/meta-llama/Meta-Llama-3.1-8B-Instruct
api_base: https://runpod-instance-id-8000.proxy.runpod.net/v1 # Make sure to use the right URL
api_key: "os.environ/VLLM_API_KEY"
- model_name: vllm-llama3.1-70b
litellm_params:
model: openai/meta-llama/Meta-Llama-3.1-70B-Instruct
api_base: https://runpod-instance-id-8000.proxy.runpod.net/v1 # Make sure to use the right URL
api_key: "os.environ/VLLM_API_KEY"
- model_name: vllm-llama3.1-70b-4bit
litellm_params:
model: openai/hugging-quants/Meta-Llama-3.1-70B-Instruct-AWQ-INT4
api_base: https://runpod-instance-id-8000.proxy.runpod.net/v1 # Make sure to use the right URL
api_key: "os.environ/VLLM_API_KEY"
而且,我们还需要一个 Docker Compose 文件(docker-compose.yaml
)来创建在本地运行的 LiteLLM 服务,并使用 Postgres 数据库。(当然,请确保您的机器上已安装 Docker)
version: '3.8'
services:
litellm-database:
image: ghcr.io/berriai/litellm-database:main-latest
container_name: litellm-database
ports:
- "4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
environment:
LITELLM_MASTER_KEY: sk-YOUR-KEY-HERE # This is the key with which you can access all your models
DATABASE_URL: postgres://postgres:yourpassword@postgres:5432/litellmdb
GROQ_API_KEY: gsk_yougrokapikeyhere
VLLM_API_KEY: sk-yourvllmapikeyhere
depends_on:
- postgres
command: ["--config", "/app/config.yaml", "--detailed_debug"]
postgres:
image: postgres:15
container_name: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: yourpassword
POSTGRES_DB: litellmdb
volumes:
- litellm_postgres_data:/var/lib/postgresql/data
volumes:
litellm_postgres_data:
如果您不想使用本地数据库,您随时可以用 Supabase 替换它。
现在您已经创建了 compose 文件和配置文件,是时候运行它了。
sudo docker compose up -d
然后,检查容器日志,看看一切是否顺利。如果一切正常,您可以通过 http://0.0.0.0:4000
访问代理,并通过 http://0.0.0.0:4000/ui
访问用户界面。您可以在用户界面中做很多事情,请查阅文档。
现在您可以通过代理使用您的 API 了
import openai
OPENAI_BASE_URL = "http://0.0.0.0:4000/v1" # If you've hosted it on a cloud server use that IP/DNS here
OPENAI_API_KEY = "sk-ABCDEFGHIJKLMNOPQRSTUVWZ" # Make sure to replace with the right one
SYSTEM_PROMPT = "You are a helpful AI assistant"
TEST_PROMPT = "What is Entropy?"
client = openai.OpenAI(
api_key=OPENAI_API_KEY,
base_url=OPENAI_BASE_URL,
)
response = client.chat.completions.create(
model="meta-llama/Meta-Llama-3.1-8B-Instruct",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": TEST_PROMPT}
],
# Here you can add tags like these for monitoring API usage
extra_body={
"metadata": {
"tags": ["taskName:simple_api_test", "provider:vllm_runpod"]
}
}
)
福利:通过聊天界面使用 API
我们将使用 OpenWebUI 来实现这一点,步骤非常简单。您需要再次为 UI 设置一个 Docker 容器。这是我的 docker-compose.yaml
文件:
version: '3'
volumes:
open-webui:
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
environment:
- OPENAI_API_KEY=sk_ABCDEFGHIJKLMNOPQRSTUVWXYZ # This is our LiteLLM / Hosted server API key
- OPENAI_API_BASE_URL=https://api.together.xyz/v1 # This is our LiteLLM / Hosted server's base URL
- DATABASE_URL=postgres://YOURPOSTGRESURLHERE:5432/postgres
ports:
- "3000:8080"
volumes:
- open-webui:/app/backend/data
restart: always
基本上就是这样,您可以在自己的用户界面上与您的模型进行聊天了。
结论
恭喜!您现在已经设置好自己的 LLaMA 3.1 70B(或任何大约 70B 的大型语言模型)实例,并学习了如何高效地与其交互。让我们回顾一下我们所取得的成就:
- 我们探讨了托管大型语言模型的技术考虑因素,重点关注 GPU 选择和内存需求。
- 我们使用 Runpod 建立了经济高效的云部署,利用其 GPU 实例支持不同的量化级别(FP16、INT8 和 INT4)。
- 我们配置了 vLLM 作为我们的推理引擎,利用其对大型语言模型的优化。
- 我们实现了 LiteLLM 代理,以更好地进行 API 管理、可扩展性和监控。
通过遵循本指南,您现在拥有一个强大、可定制且相对经济实惠的设置,可用于运行最先进的语言模型。这为个人项目、研究甚至小规模生产部署开辟了无限可能。
请记住,人工智能领域发展迅速,因此请密切关注可能进一步提高性能或降低成本的新优化、量化技术和硬件选项。
祝您在您新部署的 LLM 上愉快地进行实验!无论您是将其用于创意写作、代码生成,还是构建您的下一个大型人工智能驱动应用程序,您现在都拥有了按照自己的方式和基础设施实现这些目标的工具。