ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

从Keras到vLLM:大模型推理部署的完整实践指南

从Keras到vLLM:大模型推理部署的完整实践指南 在实际的大模型推理部署场景中我们经常面临一个核心矛盾如何平衡开发效率与推理性能。使用 Keras 这样的高级 API 可以快速构建和训练模型但到了生产部署阶段尤其是在处理大语言模型LLM时原生的推理框架往往难以满足高并发、低延迟的需求。vLLMVectorized Large Language Model inference engine的出现正是为了解决这一痛点。它是一个专注于 LLM 服务的高性能推理引擎通过其核心的 PagedAttention 算法显著优化了显存利用率和吞吐量。本文将以一个实际的工程场景为例详细讲解如何将一个使用 Keras或 TensorFlow训练或保存的模型集成到 vLLM 推理服务中。我们将从理解 vLLM 的核心优势开始逐步完成环境准备、模型转换、服务部署、客户端调用以及常见问题的排查。无论你是希望将已有的 Keras 模型投入生产还是正在评估 vLLM 作为推理后端这篇文章都将提供一条清晰的实践路径。1. 理解 vLLM 的核心价值与集成前提在开始动手集成之前我们需要明确 vLLM 解决了什么问题以及它与 Keras/TensorFlow 生态的关系。这决定了我们集成工作的边界和预期收益。1.1 vLLM 为何能提升大模型推理性能vLLM 并非一个通用的深度学习推理框架它的设计目标非常明确高效服务自回归式的大语言模型。其性能提升主要源于两大创新PagedAttention这是 vLLM 的核心算法。它借鉴了操作系统虚拟内存中“分页”的思想将模型运行所需的 KV Cache键值缓存在显存中进行精细化管理。传统方式中每个请求的 KV Cache 是连续分配的一块内存由于不同序列长度差异巨大容易产生显存碎片导致显存利用率低下。PagedAttention 将 KV Cache 划分为固定大小的“块”允许多个请求的缓存块非连续地存储在显存中从而极大减少了内存浪费使得单张 GPU 能够同时服务更多的并发请求。Continuous Batching也称为迭代级调度。传统的批处理Static Batching需要等待一批请求全部完成后才能开始处理下一批如果请求间处理时间差异大会造成 GPU 空闲等待。Continuous Batching 则动态地将新到达的请求加入正在运行的批次中并让已完成的请求及时退出使得 GPU 利用率始终保持在高位。对于从 Keras 或 TensorFlow 过来的开发者可以这样理解我们习惯用model.predict进行批量推理但这在服务可变长度、流式输出的 LLM 请求时效率不高。vLLM 相当于为 LLM 量身定制了一套高性能的predict后端。1.2 Keras 模型与 vLLM 的集成模式vLLM 主要支持 Hugging Face Transformers 格式的模型。因此将 Keras/TensorFlow 模型集成到 vLLM核心步骤是模型格式转换。常见的路径有以下几种SavedModel - Hugging Face 格式如果你有一个 TensorFlow SavedModelKeras 保存的模型默认格式之一需要将其转换为 Hugging Face 支持的 PyTorch 格式.bin权重文件 config.json或 Safetensors 格式。这通常涉及权重映射和转换脚本。Keras.h5或.keras- Hugging Face 格式与上述类似需要先加载 Keras 模型然后提取权重再按照 Hugging Face 模型的结构进行重组和保存。直接使用 TensorFlow 实现的 Hugging Face 模型少数模型在 Hugging Face 上提供了 TensorFlow 实现如TFBertForCausalLM。vLLM 目前对原生 TensorFlow 模型的支持尚在完善中最稳妥的路线仍是转换为 PyTorch 格式。本文将重点介绍第一种情况即从TensorFlow SavedModel到Hugging Face PyTorch 格式再部署到 vLLM 的完整流程。这是目前最通用和稳定的路径。2. 环境准备与依赖配置一个清晰且隔离的环境是成功的第一步。我们将使用 Conda 创建 Python 虚拟环境并安装特定版本的依赖以避免版本冲突。2.1 创建并激活 Conda 环境# 创建名为 vllm_integration 的 Python 3.10 环境 conda create -n vllm_integration python3.10 -y conda activate vllm_integration选择 Python 3.10 是因为它在 vLLM 和主流深度学习框架中拥有较好的兼容性。2.2 安装基础深度学习框架我们需要安装 TensorFlow用于加载原始 Keras 模型和 PyTorch作为 vLLM 和模型转换的底层引擎。# 安装 TensorFlow。请根据你的 CUDA 版本选择对应的版本。 # 例如对于 CUDA 12.x可以安装 tensorflow2.15.0 pip install tensorflow2.15.0 # 安装 PyTorch。请务必访问 https://pytorch.org/get-started/locally/ 获取适合你系统的安装命令。 # 例如对于 CUDA 12.1 和 Linux 系统 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 # 安装 Hugging Face Transformers 和 Accelerate用于模型转换和加载 pip install transformers accelerate2.3 安装 vLLM 及其依赖vLLM 的安装方式有多种为了获得最佳性能和特性支持推荐从源码安装。# 克隆 vLLM 仓库 git clone https://github.com/vllm-project/vllm.git cd vllm # 从源码安装这会编译一些 C/CUDA 扩展 pip install -e .如果从源码安装遇到困难也可以直接安装预编译的 PyPI 包但可能无法包含最新的优化或对特定硬件的支持。pip install vllm关键依赖检查安装完成后运行以下命令验证关键库是否就位并检查 CUDA 是否可用。python -c import torch; print(fPyTorch version: {torch.__version__}); print(fCUDA available: {torch.cuda.is_available()}) python -c import tensorflow as tf; print(fTensorFlow version: {tf.__version__}); print(fGPU available: {len(tf.config.list_physical_devices(\GPU\)) 0}) python -c import vllm; print(fvLLM version: {vllm.__version__})3. 模型转换从 TensorFlow SavedModel 到 Hugging Face 格式这是集成过程中最具挑战性的一步。我们假设你已有一个用于文本生成的 TensorFlow LLM并保存为 SavedModel 格式一个包含saved_model.pb和variables文件夹的目录。3.1 理解权重映射关系不同的模型架构如 GPT、LLaMA、Qwen其层命名和结构不同。你需要找到或编写一个权重映射字典将 TensorFlow 变量名映射到 Hugging Face 模型对应的参数名。例如一个简化的 GPT-2 映射关系可能如下# 这是一个示例映射实际模型需要更完整的对应关系 tf_to_hf_map { “transformer/wte:0”: “transformer.wte.weight”, “transformer/wpe:0”: “transformer.wpe.weight”, “transformer/h0/attn/c_attn/w:0”: “transformer.h.0.attn.c_attn.weight”, “transformer/h0/attn/c_attn/b:0”: “transformer.h.0.attn.c_attn.bias”, # ... 其他层 }对于热门模型如 LLaMA, QwenHugging Face 社区或模型原作者通常提供了转换脚本。你的首要任务是在模型的官方仓库或 Hugging Face 页面寻找convert_tf_to_pt.py或类似的脚本。3.2 编写模型转换脚本如果找不到现成脚本你需要基于模型结构自行编写。以下是一个概念性的转换流程脚本import tensorflow as tf import torch from transformers import AutoConfig, AutoModelForCausalLM import numpy as np import os def convert_tf_savedmodel_to_hf(tf_model_path, hf_model_save_path, model_name_or_type“gpt2”): ”“” 将 TensorFlow SavedModel 转换为 Hugging Face PyTorch 格式。 参数 tf_model_path: SavedModel 目录路径。 hf_model_save_path: 转换后保存的路径。 model_name_or_type: Hugging Face 模型标识用于加载对应的 config。 ”“” # 1. 加载 TensorFlow 模型 print(f“Loading TensorFlow model from {tf_model_path}...”) tf_model tf.saved_model.load(tf_model_path) # 注意这里需要知道如何从 tf_model 中获取具体的推理函数和变量。 # 通常 SavedModel 会有一个签名例如 serving_default。 # 这里假设我们通过一个已知的变量列表来获取权重。 # 实际情况可能需要tf_model.variables 或 tf_model.signatures[‘serving_default’] # 2. 获取所有 TensorFlow 变量权重和偏置 # 这步需要根据你的模型具体实现调整以下为示例 tf_variables {} # 假设我们有一个方法能获取所有可训练变量 # for var in tf_model.trainable_variables: # tf_variables[var.name] var.numpy() # 3. 加载对应的 Hugging Face 模型配置和空模型 print(f“Loading Hugging Face config for {model_name_or_type}...”) config AutoConfig.from_pretrained(model_name_or_type) hf_model AutoModelForCausalLM.from_config(config) hf_model.eval() # 设置为评估模式 # 4. 执行权重映射和复制 print(“Starting weight conversion...”) state_dict hf_model.state_dict() for hf_param_name in state_dict.keys(): if hf_param_name in tf_to_hf_map: # 使用你定义的映射字典 tf_var_name tf_to_hf_map[hf_param_name] if tf_var_name in tf_variables: tf_value tf_variables[tf_var_name] # 将 numpy array 转换为 torch tensor并注意维度顺序 # 某些层如卷积或注意力层的权重可能需要转置 torch_value torch.from_numpy(tf_value) # 示例如果维度需要调整 # if ‘weight’ in hf_param_name and len(torch_value.shape) 2: # torch_value torch_value.T state_dict[hf_param_name].copy_(torch_value) print(f“ Mapped {tf_var_name} - {hf_param_name}”) else: print(f“ Warning: TF variable {tf_var_name} not found for HF param {hf_param_name}”) else: print(f“ Warning: HF parameter {hf_param_name} not in mapping dictionary.”) # 5. 保存转换后的模型 print(f“Saving converted model to {hf_model_save_path}...”) hf_model.save_pretrained(hf_model_save_path) # 同时保存 tokenizer如果你的 SavedModel 不包含需要单独从 Hugging Face 下载 from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(model_name_or_type) # 如果 tokenizer 有特殊配置如 pad_token需要设置 if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token tokenizer.save_pretrained(hf_model_save_path) print(“Conversion completed!”) if __name__ “__main__”: # 使用示例 convert_tf_savedmodel_to_hf( tf_model_path“./my_tf_llm_savedmodel”, hf_model_save_path“./converted_hf_model”, model_name_or_type“gpt2” # 根据你的模型类型更改 )重要提示这个脚本是一个高度简化的框架。实际转换中你需要精确知道 TensorFlow 模型变量的名称和形状并与 Hugging Face 模型的状态字典一一对应。对于复杂模型这可能需要深入阅读两者的模型实现代码。3.3 验证转换结果转换完成后使用 Hugging Face 的 API 加载模型并进行一次前向传播以验证转换是否正确。from transformers import AutoModelForCausalLM, AutoTokenizer import torch model_path “./converted_hf_model” tokenizer AutoTokenizer.from_pretrained(model_path) model AutoModelForCausalLM.from_pretrained(model_path, torch_dtypetorch.float16).cuda() # 使用半精度节省显存 # 测试推理 input_text “Hello, how are you?” inputs tokenizer(input_text, return_tensors“pt”).to(“cuda”) with torch.no_grad(): outputs model.generate(**inputs, max_new_tokens20) print(tokenizer.decode(outputs[0], skip_special_tokensTrue))如果这一步能成功运行并产生合理输出说明模型转换基本成功。4. 使用 vLLM 部署转换后的模型模型转换为 Hugging Face 格式后就可以享受 vLLM 带来的高性能推理服务了。vLLM 提供了两种主要使用方式离线批量推理和在线 API 服务。4.1 离线批量推理LLM 类对于一次性处理大量提示词可以使用vllm.LLM类。from vllm import LLM, SamplingParams # 指定转换后的模型路径 model_path “./converted_hf_model” # 初始化 LLM 引擎 # tensor_parallel_size 用于张量并行如果你的模型太大单卡放不下可以尝试设置为 2 或 4需要多 GPU llm LLM(modelmodel_path, trust_remote_codeTrue, tensor_parallel_size1) # 定义采样参数 sampling_params SamplingParams(temperature0.8, top_p0.95, max_tokens100) # 准备提示词列表 prompts [ “The future of artificial intelligence is”, “To solve climate change, we need to”, ] # 执行推理 outputs llm.generate(prompts, sampling_params) # 打印结果 for output in outputs: prompt output.prompt generated_text output.outputs[0].text print(f“Prompt: {prompt!r}\nGenerated text: {generated_text!r}\n---”)LLM类在初始化时会加载模型并准备好推理引擎后续的generate调用会利用 Continuous Batching 高效处理。4.2 启动在线 API 服务vLLM 服务器对于需要持续提供服务的场景vLLM 内置了一个高性能的 OpenAI 兼容 API 服务器。# 在终端中运行以下命令 python -m vllm.entrypoints.openai.api_server \ --model ./converted_hf_model \ --served-model-name my-llm \ --trust-remote-code \ --port 8000 \ --host 0.0.0.0参数解释--model: 转换后的 Hugging Face 模型路径。--served-model-name: 服务暴露的模型名称客户端调用时使用。--trust-remote-code: 如果模型定义不在 Hugging Face 官方库中例如自定义模型需要此参数。--port和--host: 指定服务器监听的端口和地址。服务器启动后会提供两个主要端点http://localhost:8000/v1/completions: 用于文本补全。http://localhost:8000/v1/chat/completions: 用于对话补全如果模型是对话模型。4.3 编写客户端调用代码你可以使用任何 HTTP 客户端或 OpenAI SDK 来调用该服务。# 使用 openai 包需要安装pip install openai from openai import OpenAI # 指向本地 vLLM 服务器 client OpenAI( api_key“token-abc123”, # vLLM 服务器默认不需要密钥但需要提供一个非空值 base_url“http://localhost:8000/v1 ) # 调用 completions 接口 response client.completions.create( model“my-llm”, # 与 --served-model-name 一致 prompt“What is the capital of France?”, max_tokens50, temperature0.7, ) print(response.choices[0].text) # 如果模型支持对话调用 chat.completions 接口 chat_response client.chat.completions.create( model“my-llm”, messages[{“role”: “user”, “content”: “Explain quantum computing in simple terms.”}], max_tokens150, ) print(chat_response.choices[0].message.content)5. 关键配置、参数调优与生产考量直接使用默认参数部署可能无法发挥最佳性能或满足生产要求。以下是一些关键配置项。5.1 vLLM 服务器关键启动参数参数类型默认值说明--modelstring(必填)模型路径或 Hugging Face 仓库 ID。--tokenizerstring(同 model)可指定独立的 tokenizer 路径。--tokenizer-modestringautoTokenizer 加载模式auto或slow。--trust-remote-codeflagFalse信任并执行模型仓库中的自定义代码。--download-dirstringNone模型下载缓存目录。--tensor-parallel-sizeint1张量并行度用于单机多卡拆分大模型。--block-sizeint16PagedAttention 的块大小影响内存碎片和性能。通常 16 或 32。--swap-spaceint4GPU 显存不足时使用多少 GiB 的系统内存作为交换空间。--gpu-memory-utilizationfloat0.9GPU 显存利用率目标0~1 之间。--max-num-batched-tokensint2560一次前向传播中最大批处理的 token 数。影响吞吐和延迟。--max-num-seqsint256引擎中同时处理的最大请求数序列数。--served-model-namestring(同 model)API 中使用的模型名称。--portint8000API 服务器端口。--hoststringlocalhost绑定地址。生产环境若需外部访问可设为 0.0.0.0。5.2 生产环境部署建议使用 Docker 容器化将模型、vLLM 代码和依赖打包成 Docker 镜像确保环境一致性。vLLM 官方提供了基础镜像vllm/vllm-openai。# 示例 Dockerfile FROM vllm/vllm-openai:latest COPY ./converted_hf_model /app/model CMD [“python”, “-m”, “vllm.entrypoints.openai.api_server”, \ “--model”, “/app/model”, \ “--served-model-name”, “my-llm”, \ “--trust-remote-code”, \ “--host”, “0.0.0.0”, \ “--port”, “8000”]配置资源限制与健康检查在 Kubernetes 或 Docker Compose 中配置 GPU 资源限制、存活探针和就绪探针。启用日志与监控vLLM 服务器日志会输出到标准输出。确保有日志收集系统如 ELK、Loki。同时可以暴露 Prometheus 指标vLLM 支持监控 GPU 使用率、请求队列长度、吞吐量、延迟等。前置反向代理与负载均衡使用 Nginx 或 Traefik 作为反向代理处理 TLS 终止、限流、负载均衡到多个 vLLM 实例。模型版本管理建立清晰的模型目录结构如/models/{model_name}/{version}并在 API 请求或服务器启动参数中指定版本便于滚动更新和回滚。6. 常见问题排查与性能调优在集成和运行过程中你可能会遇到以下典型问题。6.1 模型加载失败问题现象可能原因检查与解决方案ValueError: Unknown model or unable to parse: ./converted_hf_model1. 模型路径错误。2. 目录下缺少config.json。3.config.json中的architectures字段 vLLM 不支持。1. 检查路径是否正确、绝对。2. 确认目录包含config.json,pytorch_model.bin(或.safetensors) 等文件。3. 查看config.json确保模型架构如“LlamaForCausalLM”是 vLLM 支持的。RuntimeError: Failed to load model weights ...1. 权重文件损坏或格式不对。2. 权重文件与config.json不匹配如层数、维度。1. 用from_pretrained在纯 Transformers 环境中测试能否加载。2. 重新运行转换脚本确保映射正确。ModuleNotFoundError: No module named ‘xxx’模型代码依赖自定义模块trust_remote_codeTrue时。1. 确保自定义模块在 Python 路径中。2. 将模型相关源码复制到 vLLM 能访问的目录。6.2 推理时 GPU 内存不足OOM问题现象可能原因检查与解决方案torch.cuda.OutOfMemoryError1. 模型本身太大超过单卡显存。2.--max-num-batched-tokens或--max-num-seqs设置过高。3. PagedAttention 交换空间不足。1. 使用--tensor-parallel-size进行模型并行需要多 GPU。2. 使用量化如 AWQ, GPTQ。在LLM初始化时传入quantization“awq”。3. 调低--max-num-batched-tokens和--max-num-seqs。4. 增大--swap-space牺牲速度保稳定。5. 降低--gpu-memory-utilization。6.3 请求超时或吞吐量低问题现象可能原因检查与解决方案客户端请求长时间无响应或报超时错误。1. 请求队列过长。2. 单个请求生成长度过大max_tokens。3. GPU 计算资源成为瓶颈。4. 输入预处理Tokenizer或输出后处理慢。1. 监控vllm_engine_running和vllm_engine_swapped队列长度。2. 在客户端设置合理的超时时间并考虑对长文本进行分段或限制生成长度。3. 使用性能分析工具如nvtop,nsys查看 GPU 利用率。如果已饱和需考虑更强大的 GPU 或增加推理实例。4. 确保使用的是快速 Tokenizer--tokenizer-mode auto通常会选择 fast。6.4 生成结果质量差或乱码问题现象可能原因检查与解决方案生成的文本不连贯、重复或出现乱码。1. 模型转换过程中权重映射错误导致模型损坏。2. Tokenizer 不匹配。3. 采样参数temperature,top_p设置极端。1.首要检查用纯 Hugging Facegenerate方法如第 3.3 节测试如果问题依旧则是模型转换问题需复查权重映射。2. 确认 vLLM 使用的 tokenizer 与模型训练时一致。检查tokenizer.json或tokenizer_config.json是否正确。3. 调整SamplingParams。temperature接近 0 时确定性高但可能枯燥过高则随机性大top_p用于核采样。7. 进阶集成自定义模型与优化对于更复杂的场景你可能需要深入 vLLM 的内部。7.1 支持新的模型架构如果你的模型架构不在 vLLM 默认支持列表中如LLAMA,GPT2,QWEN等你需要编写一个自定义模型类。在vllm/model_executor/models目录下创建新文件例如my_model.py。定义一个继承自vllm.model_executor.models.Model的类。实现__init__方法加载权重以及forward方法定义计算逻辑。在vllm/model_executor/model_loader.py中注册你的模型类将其与config.json中的architectures字段关联。这个过程需要对模型架构和 vLLM 的底层执行器有较深理解通常适用于公司内部自研的 LLM。7.2 使用 vLLM 的异步 API 和批处理接口对于需要极高吞吐的应用可以绕过 OpenAI API 格式直接使用 vLLM 的底层异步引擎AsyncLLMEngine。from vllm.engine.arg_utils import AsyncEngineArgs from vllm.engine.async_llm_engine import AsyncLLMEngine from vllm.sampling_params import SamplingParams import asyncio async def main(): engine_args AsyncEngineArgs(model“./converted_hf_model”, trust_remote_codeTrue) engine AsyncLLMEngine.from_engine_args(engine_args) sampling_params SamplingParams(temperature0.8, top_p0.95, max_tokens100) request_id “test-request-1” prompt “The future of AI is” # 提交生成请求 results_generator engine.generate(prompt, sampling_params, request_id) # 异步流式获取结果 async for request_output in results_generator: # request_output 包含部分生成结果 pass # 或者使用 await engine.add_request(...) 进行更细粒度的控制 asyncio.run(main())这种方式提供了最大的灵活性但需要自行管理请求生命周期和结果流。将 Keras/TensorFlow 模型通过 vLLM 部署核心在于完成从 SavedModel 到 Hugging Face 格式的准确转换。一旦模型格式对齐vLLM 就能凭借其 PagedAttention 和 Continuous Batching 技术为你提供生产级的推理性能。在实际操作中务必仔细验证转换后模型的正确性这是后续所有工作的基石。在生产部署时结合 Docker 容器化、细致的资源监控和参数调优才能构建出稳定、高效的大模型服务。如果遇到性能瓶颈首先从量化、模型并行和 vLLM 引擎参数入手进行优化。
返回列表