ARTICLE DETAIL

资讯详情

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

LLM推理加速工具全解析:vLLM、TensorRT-LLM、Ollama与llama.cpp选型指南

LLM推理加速工具全解析:vLLM、TensorRT-LLM、Ollama与llama.cpp选型指南 大模型跑起来慢是很多人从“玩一玩”转向“真拿来干活”时撞上的第一堵墙。你本地部署了一个70亿参数的模型问一句话等十几秒才蹦出第一个字多轮对话下来显存直接爆掉或者你在服务器上部署了更大的模型单张卡吞吐量低得可怜并发一上来延迟就失控。这些问题不是模型本身不行而是推理引擎没选对、参数没调好。这篇内容就是围绕LLM加速工具这条线把目前主流方案的适用场景、核心原理、部署要点和踩坑经验一次讲透不管你是刚入门想跑通第一个本地模型还是已经在做应用开发需要优化线上服务都能从中找到可以直接上手的东西。1. 先搞清楚“加速”到底在加速什么很多人一提到LLM加速第一反应就是换更快的GPU。但实际做下来你会发现换硬件带来的提升往往不如换推理框架明显。原因在于大模型推理的性能瓶颈并不只在算力上更多时候卡在显存带宽、KV Cache管理、批处理调度这些环节。理解这些瓶颈在哪里才能选对工具。1.1 推理过程的两个阶段Prefill和Decode大模型生成一个token的过程可以拆成两个截然不同的阶段。第一个阶段叫Prefill也就是把你输入的prompt一次性喂给模型计算出所有输入token的KV Cache。这个阶段是计算密集型的GPU的算力利用率高矩阵乘法可以充分并行。第二个阶段叫Decode也就是逐个生成输出token每生成一个token都要和之前所有token的KV Cache做注意力计算。这个阶段是显存带宽密集型的算力反而用不满因为每次只处理一个token并行度极低。这两个阶段的性能特征完全不同所以优化手段也不一样。Prefill阶段可以通过Flash Attention、量化计算来加速Decode阶段则更依赖KV Cache的压缩、Paged Attention、连续批处理等技术。很多加速工具的核心卖点其实就是在Decode阶段做文章。提示如果你发现模型“首字延迟”很高但后续生成速度还行瓶颈大概率在Prefill如果首字很快但吐字慢瓶颈就在Decode。1.2 显存带宽才是Decode阶段的真正瓶颈举个具体的例子。一个70亿参数的模型如果用FP16精度加载权重大约占14GB显存。每生成一个token都需要把这14GB的权重从显存里读一遍。假设你的GPU显存带宽是600GB/s那么理论上每秒最多能读42次权重也就是每秒生成42个token。这就是为什么Decode阶段的速度上限很大程度上由显存带宽决定而不是由算力决定。理解了这一点你就能明白为什么量化技术对推理加速效果这么明显。把FP16换成INT8权重体积直接减半显存带宽压力也跟着减半生成速度理论上就能翻倍。换成INT4效果更显著。当然量化会带来精度损失但对于很多应用场景来说INT4量化的质量损失是可以接受的。1.3 批处理为什么能大幅提升吞吐量单次只处理一个请求的时候GPU的算力大量闲置。但如果把多个请求拼成一个batch一起推理Decode阶段就可以同时为多个请求生成token权重只需要读一次却服务了多个请求。这就是连续批处理的核心思想。不过传统的静态批处理有个问题一个batch里所有请求必须等最长的那个生成完才能释放短请求被长请求拖死。连续批处理则允许请求动态进出一个请求生成完了立刻腾出位置给新请求GPU利用率能维持在很高水平。vLLM、TensorRT-LLM这些框架的核心竞争力很大程度上就体现在批处理调度的效率上。2. 主流LLM推理加速工具横向对比目前市面上能用的推理加速工具不少但各有各的定位和适用场景。选错了工具可能折腾半天还不如直接用Transformers的generate方法。下面把几个主流方案拉出来对比一下。2.1 vLLM目前最流行的开源推理引擎vLLM的核心创新是PagedAttention它把KV Cache像操作系统管理内存页一样分成固定大小的块按需分配极大减少了显存碎片。配合连续批处理vLLM在高并发场景下的吞吐量比朴素实现能高出十几倍甚至几十倍。部署vLLM的基本流程很直接pip install vllm python -m vllm.entrypoints.openai.api_server \ --model /path/to/your/model \ --tensor-parallel-size 2 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192tensor-parallel-size指定用几张卡做张量并行gpu-memory-utilization控制显存占用比例max-model-len限制最大上下文长度。启动之后会暴露一个兼容OpenAI API的接口可以直接用openai的Python SDK调用。vLLM的优点是生态好、社区活跃、支持模型多缺点是启动时需要预分配显存冷启动较慢而且对某些自定义模型结构的支持需要改代码。2.2 TensorRT-LLM极致性能但上手门槛高TensorRT-LLM是NVIDIA官方推出的推理加速方案它会把模型编译成TensorRT引擎在NVIDIA GPU上能跑到接近硬件极限的性能。它支持FP8、INT4等多种量化精度在Decode阶段的优化非常激进。但它的缺点也很明显编译过程复杂需要先把模型转成TensorRT的checkpoint格式再根据具体GPU型号编译引擎。换一张卡就得重新编译部署灵活性差。而且它对模型结构的支持不如vLLM广泛新模型出来往往要等官方适配。# TensorRT-LLM的编译流程示意 python convert_checkpoint.py --model_dir ./llama-model --output_dir ./trt_ckpt trtllm-build --checkpoint_dir ./trt_ckpt --output_dir ./trt_engine --gemm_plugin float16如果你追求极致性能且GPU型号固定TensorRT-LLM值得投入时间如果追求部署灵活性和快速迭代vLLM更合适。2.3 Ollama本地部署最省心的选择Ollama的定位和前两者不同它主打的是开箱即用。一条命令就能拉取模型并启动服务底层用的是llama.cpp对消费级硬件友好Mac上也能跑。ollama run qwen2.5:7bOllama会自动下载模型、量化、加载你不需要关心任何推理参数。它适合个人开发者做本地实验、原型验证或者对延迟要求不高的桌面应用。但它的并发能力弱不适合做线上服务。2.4 llama.cppCPU和混合推理的利器llama.cpp是纯C实现的推理框架最大的特点是支持CPU推理和CPUGPU混合推理。它支持GGUF格式的量化模型从Q2到Q8有多种量化等级可选。在没有GPU的机器上或者GPU显存不够放下整个模型的时候llama.cpp是很好的选择。它的缺点是CPU推理速度受限于内存带宽生成速度通常只有个位数token每秒只适合对速度不敏感的场景。工具核心优势适用场景主要限制vLLMPagedAttention、高吞吐线上服务、高并发冷启动慢、需GPUTensorRT-LLM极致性能、低延迟固定硬件、追求极限编译复杂、适配慢Ollama开箱即用、跨平台本地实验、原型验证并发弱、优化少llama.cppCPU推理、混合推理无GPU环境、边缘设备速度慢、吞吐低3. 量化不换硬件也能提速的实用手段量化是LLM加速里性价比最高的手段之一。它通过降低模型权重的数值精度来减少显存占用和带宽压力从而提升推理速度。你不需要买新卡只需要换一个量化版本的模型速度可能就有明显提升。3.1 量化精度的选择INT8还是INT4INT8量化把FP16的16位权重压缩到8位模型体积减半速度通常能提升30%到50%精度损失很小大多数场景下几乎感知不到。INT4量化进一步压缩到4位体积只有FP16的四分之一速度提升更明显但精度损失开始变得可感知尤其是在需要精确推理的任务上。实际选择的时候可以遵循这个原则如果你的任务对准确性要求高比如代码生成、数学推理优先用INT8如果是通用对话、文本摘要这类容错率高的任务INT4完全够用。3.2 GPTQ和AWQ两种主流量化方案的区别GPTQ和AWQ是目前最常用的两种权重量化方法。GPTQ基于二阶信息做逐层量化量化速度快生态成熟支持INT4和INT8。AWQ则是基于激活值分布来保护重要权重通道在INT4精度下通常比GPTQ保留更好的模型质量。实测下来AWQ在INT4下的困惑度PPL通常比GPTQ低一些但GPTQ的推理速度在某些框架下更快。选哪个取决于你的推理框架支持情况vLLM对两种都支持TensorRT-LLM对AWQ的支持更好。3.3 GGUF格式llama.cpp生态的量化标准GGUF是llama.cpp使用的模型格式它把量化后的权重和模型元数据打包在一个文件里。GGUF支持从Q2_K到Q8_0的多种量化等级命名里的数字代表量化位数K代表使用了K-quant量化方法。# 用llama.cpp加载GGUF模型 ./llama-cli -m ./models/qwen2.5-7b-q4_k_m.gguf -p 你好 -n 128Q4_K_M是社区里最常用的量化等级在质量和体积之间取得了比较好的平衡。Q5_K_M质量更高但体积更大Q3_K_M体积更小但质量下降明显。我的经验是7B模型用Q4_K_M13B以上模型可以考虑Q5_K_M。注意量化模型的推理速度不仅取决于量化位数还和你的硬件有关。在某些GPU上INT4量化的实际加速比可能不如预期因为反量化操作本身也有开销。4. 部署实战从零跑通一个加速推理服务光看对比不够实际部署一遍才能踩到真正的坑。下面以vLLM为例走一遍完整的部署流程把每一步的意图和容易出问题的地方都讲清楚。4.1 环境准备与依赖安装首先确认你的CUDA版本和PyTorch版本匹配。vLLM对版本比较敏感CUDA 12.1以上、PyTorch 2.1以上是比较稳妥的组合。# 查看CUDA版本 nvcc --version # 创建虚拟环境 conda create -n vllm-env python3.10 conda activate vllm-env # 安装vLLM pip install vllm如果你的机器有多张卡还需要确认NCCL通信正常。可以用nvidia-smi topo -m查看卡之间的互联拓扑NVLink互联的卡做张量并行效率更高PCIe互联的卡通信开销会大一些。4.2 模型下载与格式确认vLLM支持HuggingFace格式的模型直接从HuggingFace Hub拉取或者本地加载都行。如果网络条件不好可以先用huggingface-cli download把模型拉到本地。huggingface-cli download Qwen/Qwen2.5-7B-Instruct --local-dir ./qwen2.5-7b下载完之后检查一下模型目录里有没有config.json、tokenizer.json和权重文件。有些模型需要trust_remote_codeTrue才能加载vLLM启动时加--trust-remote-code参数即可。4.3 启动参数调优的实操逻辑启动vLLM的时候几个关键参数直接决定了性能和稳定性--gpu-memory-utilization默认0.9意思是vLLM会预分配90%的显存用于KV Cache和模型权重。如果你的机器上还有其他进程占显存这个值要调低否则会OOM。--max-model-len最大上下文长度。设得越大KV Cache占用越多能同时处理的请求数就越少。根据你的实际需求设置不要盲目拉满。--max-num-seqs最大并发序列数。这个值影响批处理的大小设得太小GPU利用率上不去设得太大显存可能不够。--tensor-parallel-size张量并行度等于使用的GPU数量。注意这个值必须是2的幂次或者能被注意力头数整除。python -m vllm.entrypoints.openai.api_server \ --model ./qwen2.5-7b \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.85 \ --max-model-len 4096 \ --max-num-seqs 64 \ --port 8000启动之后看到Uvicorn running on http://0.0.0.0:8000就说明服务起来了。可以用curl测试一下curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: ./qwen2.5-7b, messages: [{role: user, content: 介绍一下你自己}], max_tokens: 128 }4.4 压测与性能观察服务跑起来之后别急着上线先做个简单的压测看看实际吞吐和延迟。可以用vllm自带的benchmark脚本也可以用locust、wrk这类工具。# 用vLLM自带的benchmark python -m vllm.entrypoints.benchmark_serving \ --backend openai \ --base-url http://localhost:8000 \ --model ./qwen2.5-7b \ --num-prompts 100 \ --request-rate 10重点关注两个指标TTFTTime To First Token首字延迟和TPOTTime Per Output Token每token生成时间。TTFT反映Prefill阶段的性能TPOT反映Decode阶段的性能。如果TTFT高考虑开Flash Attention或者减少prompt长度如果TPOT高考虑量化或者增加批处理大小。5. 那些文档里不会写的踩坑记录工具用起来之后真正让人头疼的往往不是核心功能而是各种边界情况和环境问题。下面这几个坑是我在实际部署中反复遇到的分享出来帮你省点时间。5.1 显存碎片导致的间歇性OOMvLLM的PagedAttention虽然能减少碎片但在长时间运行、请求长度差异很大的场景下仍然可能出现显存碎片。表现是服务跑了一段时间后突然OOM重启又好了。解决办法是适当降低--gpu-memory-utilization给系统留一点余量或者定期重启服务。另一个容易忽略的点是如果你的请求里有超长prompt它会一次性占用大量KV Cache块可能把其他请求挤掉。可以在入口层做prompt长度限制超过阈值的请求直接拒绝或者截断。5.2 模型加载时的trust_remote_code陷阱很多国产模型比如Qwen系列、ChatGLM系列需要trust_remote_codeTrue才能加载因为它们的模型结构定义在远程代码里。但有些模型的自定义代码和vLLM的版本不兼容加载时会报各种奇怪的错误。遇到这种情况先检查模型的config.json里auto_map字段指向的代码文件看看它依赖的transformers版本。如果版本冲突严重可以考虑用模型官方推荐的推理框架或者等vLLM社区适配。5.3 多卡张量并行的通信瓶颈用两张卡做张量并行理论上速度应该接近翻倍但实际可能只提升了30%到50%。原因在于卡之间的通信开销。如果两张卡是PCIe互联而不是NVLink每层推理都要做All-Reduce通信延迟会明显增加。# 查看GPU互联拓扑 nvidia-smi topo -m输出里如果显示NVLink说明互联带宽高张量并行效率好如果显示PHB或PXB说明走的是PCIe通信开销大。这种情况下与其做张量并行不如用流水线并行或者干脆用单卡加量化。5.4 量化模型在vLLM上的兼容性问题不是所有量化模型都能直接在vLLM上跑。GPTQ和AWQ格式的支持相对成熟但一些自定义量化格式比如GGUF在vLLM上支持有限。如果你从网上下载了一个GGUF模型想用vLLM加载大概率会失败。解决办法是确认模型格式vLLM主要支持HuggingFace格式的FP16、GPTQ、AWQ模型。GGUF模型请用llama.cpp或Ollama加载。下载模型前先看清楚格式说明能省很多折腾时间。5.5 请求排队与超时设置线上服务最怕的不是慢而是请求堆积导致雪崩。vLLM本身有请求队列但如果并发超过处理能力队列会越来越长客户端等不到响应就超时重试进一步加剧拥堵。建议在vLLM前面加一层网关设置合理的超时和限流。比如单个请求超过30秒没返回就主动断开同时限制每秒新建连接数。这样即使高峰期也能保证服务不崩。6. 不同场景下的工具选型建议说了这么多工具和参数最后落到实际选择上还是要看你的具体场景。下面按几种典型情况给出建议。6.1 个人开发者本地实验如果你只是想在本地跑个模型玩玩、做做实验Ollama是最省心的选择。一条命令拉模型不用管CUDA版本、不用管依赖冲突。Mac、Windows、Linux都支持。模型选Q4_K_M量化版本7B模型在16GB内存的机器上就能跑。如果机器有NVIDIA显卡且显存足够比如12GB以上可以试试vLLM体验一下高吞吐的感觉。但要做好折腾环境的心理准备。6.2 中小团队线上服务中小团队做线上服务vLLM是目前最平衡的选择。部署简单、社区活跃、性能足够。一张A100或者4090就能撑起不错的并发量。如果预算有限用两张3090做张量并行也比单卡强。关键是把监控做好盯住TTFT、TPOT、显存占用和请求队列长度。这些指标异常的时候能第一时间发现。6.3 追求极致性能的生产环境如果你的业务对延迟极其敏感且GPU型号固定TensorRT-LLM值得投入。它能把推理性能压榨到接近硬件极限尤其是在Decode阶段。但要做好模型适配和引擎编译的长期维护成本。一个折中方案是用vLLM做日常服务用TensorRT-LLM做关键路径的加速。两者可以共存通过网关做路由。6.4 无GPU或边缘设备场景没有GPU或者要在边缘设备上跑模型llama.cpp是唯一现实的选择。它支持纯CPU推理也支持CPUGPU混合推理。模型用GGUF格式量化等级根据设备内存选。树莓派、旧笔记本、工控机都能跑起来虽然速度不快但胜在能跑。我在实际使用中的体会是LLM加速这件事没有银弹。同一个工具在不同硬件、不同模型、不同请求模式下表现可能差很多。最好的办法是先明确自己的瓶颈在哪里然后有针对性地选工具、调参数。不要盲目追求最新最热的方案适合自己场景的才是最好的。另外量化虽然香但别一上来就上INT4先从INT8试起质量损失小速度提升也够用。如果INT8满足不了再往下压。
返回列表