尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

大模型本地部署与量化实战:Ollama、transformers、llama.cpp对比与避坑指南

大模型本地部署与量化实战:Ollama、transformers、llama.cpp对比与避坑指南 折腾了一台24G显存的旧机器当大模型推理服务器前前后后把Ollama、transformers、llama.cpp三条路都走了个遍中间踩坑无数也解决了很多网上搜不到对应答案的怪问题。这篇不是官方文档的复读是我把大模型本地部署与量化从零到一完整趟完后的实操笔记。如果你手头有一张还可以的显卡或者只有一台普通CPU电脑想跑千问这类开源大模型想搞清楚量化是什么、怎么选工具、怎么落地那这篇文章应该能帮你少走不少弯路。先说结论大模型本地部署这件事工具不是越高级越好而是越匹配你的硬件和场景越好。Ollama负责让你五分钟跑起来transformers负责让你精细控制推理和量化过程llama.cpp负责让你在CPU老机器上也能凑合着用。三者不是互斥的很多时候是配合使用的。1. 本地部署大模型先算清楚这笔账1.1 放着免费的API不用图什么很多人问的第一个问题现在各种大模型API都能免费用为什么要费劲在本地部署我自己的理由很现实数据隐私和成本可控。公司内部做知识库问答的时候文档大概率涉及内部资料直接丢给云端API法务那边第一关就过不了。本地部署后所有推理都在内网完成数据不出机房这是硬需求。其次是成本团队高频调API一个月token费用轻松上千而一台24G显存二手卡机器的成本折算下来跑自家规模不大的业务场景几个月就能回本。还有个容易被忽略的好处是可控性——云端模型版本更新不受你控制今天还能用的prompt格式明天可能就变了自己部署想锁版本、想调参、想量化压缩全都自己说了算。当然如果你只是偶尔问几句话或者对模型能力要求极高比如最新旗舰模型那本地部署暂时不是最优解API方便得多。本地部署适合的是高频调用、数据敏感、想要深度定制这几类场景。1.2 需要什么样的硬件先看模型大小和显存本地部署最大的拦路虎不是软件是硬件。我见过太多人装好Ollama后一运行就爆显存然后就放弃了。其实只要提前算一笔账完全能避免这种挫败感。模型能跑多快、能不能跑起来核心就两个指标显存或内存容量和带宽。容量决定装不装得下带宽决定跑得多快。一张表先看清楚大概量级模型规模参数量FP16精度占用INT8占用INT4占用最低体验配置3B级别约6GB约3GB约1.8GB16GB内存纯CPU可跑速度慢7B级别约14GB约7GB约4GB8GB显存显卡或32GB内存纯CPU13B级别约26GB约13GB约7GB16GB显存显卡70B级别约140GB约70GB约35GB多卡或纯CPU基本告别实时交互这张表只是权重大小实际运行还要加上KV Cache后面细说、CUDA上下文、推理框架自身的开销。所以7B模型用4bit量化官方说权重只要4GB实际上整卡占用经常会到5GB到6GB这是正常的不用慌。1.3 三套工具分工别搞混了网上很多教程把Ollama、transformers、llama.cpp混在一起讲导致很多人以为它们是替代关系。实际上它们的定位非常不同Ollama面向最终使用者的开箱即用工具底层默认用llama.cpp做推理引擎在这个基础上封装了模型下载、服务启动、OpenAI兼容API。适合快速部署、日常使用。transformersHuggingFace家的标准模型库生态最全几乎所有开源模型都先发布在transformers格式。适合深入研究、微调、精细控制量化也能对接各种自定义代码。llama.cpp用C/C重写的推理引擎专注性能和低资源占用支持CPU推理、GPU加速、GGUF量化格式。Ollama底层就是它你把llama.cpp单独拎出来玩可以解锁更极致的性能调优。三者的关系可以类比成llama.cpp是发动机Ollama是整车transformers则是一套可以自己改装所有配件的工具箱。弄清楚这层关系后面所有选择都不纠结了。2. 量化到底在干什么FP16、INT8、INT4的参数账2.1 模型凭什么能从14GB压缩到4GB量化这个词听起来很高大上其实本质很简单模型里的权重参数原本用高精度浮点数保存我们用低精度数值去逼近它文件就变小了推理速度也快了代价是精度有些损失。具体到存储占用每个参数占用的字节数决定了模型文件大小FP3232位浮点4字节/参数训练时常用推理很少直接用FP1616位浮点2字节/参数推理默认精度效果最接近训练时状态BF16也是2字节/参数但动态范围和FP16不同主要在训练场景用INT88位整数1字节/参数量化后效果损失相对小INT44位整数0.5字节/参数压缩比最大速度最快效果开始有可感知下降所以一个70亿参数的模型7B用FP16存权重需要约14GB换成INT4只需要约3.5GB。这就是为什么8G显存的卡也能勉强跑7B模型——只要接受量化带来的效果折损。计算公式很直接权重显存占用GB≈ 参数量B× 每参数字节数 / 1024拿7B举例7 × 2 / 1024 ≈ 13.7GBFP167 × 0.5 / 1024 ≈ 3.4GBINT4。注意这里用的是GB和二进制换算厂商标称和实际系统识别会有差异预留10%余量比较稳。2.2 量化不是只砍权重KV Cache是另一个大头如果你只算权重显存就去跑模型大概率会OOM。因为模型推理时还有一个和上下文长度强相关的显存开销KV Cache。简单理解模型在生成每个token时都要参考之前所有token的信息框架会把历史token的Key和Value缓存下来避免重复计算。这个缓存的大小正比于上下文长度上下文越长显存占用越大。KV Cache的粗略估算公式KV Cache显存 ≈ 2K和V两个矩阵× 层数 × 注意力头数维度 × 序列长度 × 字节数拿7B模型、2K上下文、FP16计算通常要吃掉1GB到2GB显存如果把上下文拉到32K光这一项可能超过8GB。这就是为什么很多4bit量化模型能加载但一旦设了超长上下文就立刻OOM的原因。Ollama默认上下文常常只有2K或者4K如果你要处理长文档记得显式调大num_ctx同时要意识到显存开销会同步上涨。2.3 主流量化方案怎么选GPTQ、AWQ、GGUF、bitsandbytes量化工具这么多很容易看花眼。我按自己的使用经验整理一下GPTQ基于二阶信息的权重量化量化后的模型可以直接用GPU跑速度和精度平衡得不错尤其适合显存不够又想用transformers生态的人。4bit量化下效果损失较小。AWQ激活值感知量化思路是保护对输出影响大的那些权重量化效果通常和GPTQ持平甚至更好但生态相对年轻部分老代码兼容性一般。GGUFllama.cpp系使用的格式它不只是量化权重而是把整个模型打包成单一文件附带tokenizer、对话模板等元信息部署极其方便。模型文件直接放移动硬盘都能带走Ollama用的就是这种格式。bitsandbytestransformers里的动态量化方案不需要提前量化加载模型时直接传load_in_4bitTrue就行适合快速试验。缺点是没有专门的量化模型文件那么极致推理速度略慢。选型经验如果走Ollama路线直接用GGUF的q4_k_m或q5_k_m量化档位如果走transformers路线想省事用bitsandbytes想追求性能用GPTQ预量化模型如果要在老CPU上硬跑GGUF是唯一现实的选择。3. Ollama从安装到把模型跑起来的最短路径3.1 安装和模型存储位置一上来就改好两个默认值Ollama的安装本身没有难度官网下载对应系统安装包就行Linux一条命令的事情。但有两个默认值我强烈建议你提前改掉不然后面会很被动。第一是模型存储路径。Ollama默认把模型放在系统盘很多人的C盘空间本来就不宽裕一个7B模型4GB到8GB多拉几个模型C盘就爆了。改法是在环境变量里设置OLLAMA_MODELS指向一个大分区目录。以Windows为例在系统环境变量里新建变量变量名OLLAMA_MODELS变量值例如D:\ollama\models然后重启Ollama服务。Linux下就是export OLLAMA_MODELS/data/ollama/models写进/etc/profile.d/ollama.sh里保证持久化。第二是设置OLLAMA_HOST。如果想让局域网内其他机器也能访问这台推理服务器把它设为0.0.0.0这样别人就能通过http://你机器的IP:11434调用你的模型。注意设置后要确认防火墙放行11434端口。3.2 下载模型卡住两条可落地的解决思路ollama pull下载模型慢是绕不开的痛点尤其在下载动辄几个GB的权重文件时经常卡在进度条不动。我的经验是可以直接走模型社区中转的思路。先把模型权重从HuggingFace或者ModelScope魔搭社区下载好然后用Ollama从本地导入。具体做法是在魔搭社区搜索对应的GGUF量化版模型比如Qwen2.5-7B-Instruct-GGUF把模型文件下载到本地然后在模型文件旁边写一个Modelfile内容大概是FROM ./qwen2.5-7b-instruct-q4_k_m.gguf接着执行ollama create qwen2.5-7b -f Modelfile这样就能把本地GGUF文件注册成一个Ollama模型绕开ollama pull的下载瓶颈。这个方法在断网或内网环境下更是刚需我后来给内网服务器装模型全部走的这条链路稳定且可控。3.3 Modelfile调参温度和上下文长度必须自己控制Ollama拿来跑通很容易但跑得好需要调参数。Ollama每个模型背后有一个Modelfile你可以理解为模型启动参数清单常用参数包括temperature控制生成随机性太高容易胡说八道太低会变复读机默认0.8偏高我日常问答改成0.6左右。num_ctx上下文窗口长度默认只有2048。处理长文档必须调大但代价是显存占用上升。stop停止生成的自定义标记。实际修改时直接在交互命令里临时生效也行但更规范的是写进Modelfile再加载。比如创建一份自定义ModelfileFROM qwen2.5:7b PARAMETER temperature 0.6 PARAMETER num_ctx 8192然后重新创建模型ollama create qwen2.5-7b-ctx8k -f MyModelfile这样生成一个新模型原模型不受影响。3.4 API调用OpenAI兼容接口可以直接接现有代码Ollama启动后默认监听http://localhost:11434原生接口是/api/generate但更实用的其实是它的OpenAI兼容接口地址是http://localhost:11434/v1。这意味着你之前写的OpenAI SDK代码只需要改一下base_url和api_key就能切换到本地模型。比如Python里from openai import OpenAI client OpenAI( base_urlhttp://localhost:11434/v1, api_keyollama, # 随便填本地不校验 ) response client.chat.completions.create( modelqwen2.5:7b, messages[{role: user, content: 用一句话解释什么是量化}], ) print(response.choices[0].message.content)我公司内部的几个脚本就这么接过去的代码几乎没动。这也是Ollama作为通用入口最大的价值你让人人都学transformers不现实但给前端一个OpenAI兼容接口整个接入成本趋近于零。4. transformers路线用标准库做精细可控的量化推理4.1 环境版本匹配这块坑最多走transformers这条路第一个门槛不是代码是环境匹配。很多人在torch和CUDA的版本上栽跟头一跑就报错CUDA error: no kernel image is available或者undefined symbol。我的建议是不要追求把所有库都升到最新而是锁定一套经过验证的版本组合。以我目前稳定跑的一套为例pip install torch2.3.0 torchvision0.18.0 torchaudio2.3.0 --index-url https://download.pytorch.org/whl/cu121 pip install transformers4.42.4 accelerate0.32.0 bitsandbytes0.43.3注意几个关键点CUDA版本和PyTorch编译版本要对应比如cu121对应CUDA 12.1驱动驱动版本向下兼容老驱动要选老版本。bitsandbytes在Windows上的支持一直比较慢如果安装报错优先看官方issue很多情况下要用预编译whl包。transformers版本更新很快接口会变。我见过不少老代码在新transformers上跑不了的情况与其改代码不如直接锁版本。4.2 用BitsAndBytes实现4bit/8bit动态量化transformers里最省事的量化方式是bitsandbytes不需要提前量化模型加载时传几个参数就行。以4bit为例import torch from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig quant_config BitsAndBytesConfig( load_in_4bitTrue, bnb_4bit_compute_dtypetorch.float16, bnb_4bit_use_double_quantTrue, bnb_4bit_quant_typenf4, ) model AutoModelForCausalLM.from_pretrained( Qwen/Qwen2.5-7B-Instruct, quantization_configquant_config, device_mapauto, trust_remote_codeTrue, ) tokenizer AutoTokenizer.from_pretrained(Qwen/Qwen2.5-7B-Instruct)几个参数说明bnb_4bit_use_double_quantTrue是二次量化能再省一点显存推荐开启。bnb_4bit_quant_typenf4是bitsandbytes提出的normal float格式比fp4效果更好默认就是nf4不建议改。device_mapauto很重要它让模型自动分布到空闲显存、内存避免加载阶段就爆显存。这种方式的优点是真的零成本不需要预先找量化好的模型文件缺点是每次加载都要做一次量化启动慢一些推理速度也没专门量化模型文件快。但它特别适合在Jupyter Notebook里做实验对比不同模型的效果。4.3 加载GPTQ预量化模型性能更极致如果你想在transformers里跑GPTQ量化模型代码甚至比上面更简单因为量化工作在发布模型的人那里已经做完了你只需要加载成品。from transformers import AutoModelForCausalLM, AutoTokenizer model AutoModelForCausalLM.from_pretrained( TheBloke/Qwen2.5-7B-Instruct-GPTQ-Int4, device_mapauto, trust_remote_codeTrue, ) tokenizer AutoTokenizer.from_pretrained(TheBloke/Qwen2.5-7B-Instruct-GPTQ-Int4)GPTQ模型的仓库一般会说明量化用的是什么数据集、多少步校准挑选时可以关注一下。实际使用中GPTQ的4bit模型在速度和显存占用上都很稳我在7B级别上最常用的就是GPTQ Int4。用GPTQ要注意的是batch推理和长上下文的组合有时会有兼容问题如果你要做高并发服务建议先压测别直接上生产。4.4 显存不够时的三层兜底策略transformers的好处是应对设备不足的手段多按优先级排序device_mapauto框架自动尽量塞显存塞不下放内存代价是慢。torch_dtypetorch.float16不要用FP32加载显存直接翻倍降。降低上下文长度、改小batch size最朴素但从根本上解决问题。此外可以设置attn_implementationflash_attention_2如果显卡支持或sdpa降低显存开销并提速。显存这东西能省一分是一分尤其当你同时开多个模型试验的时候。5. llama.cppCPU老机器也能跑的GGUF方案5.1 GGUF格式好在哪llama.cpp是底层推理引擎它定义的GGUF格式在当前开源生态里占据绝对主导。GGUF最大的特点是一个文件装下所有权重、tokenizer、对话模板、特殊token等元信息并且支持多种量化等级。你不再需要分别下载模型权重和tokenizer也不用手动拼template一个文件就是完整模型。正因为这个特性GGUF特别适合分发和部署尤其配合Ollama这类工具模型管理变得非常简单。更关键的是llama.cpp对纯CPU推理做了大量SIMD优化AVX2、AVX512指令集都能吃到红利老机器即使没有NVIDIA显卡也能跑只是速度别抱期待。5.2 从HuggingFace原始权重自己转GGUF并量化很多人直接用别人量化好的GGUF文件但有时候你要的模型没人量化过或者你想自定义量化档位就需要自己动手。步骤不复杂只要原始HuggingFace模型下载到本地然后用llama.cpp自带的脚本转换# 1. 克隆代码并编译Linux/macOS下执行 git clone https://github.com/ggerganov/llama.cpp cd llama.cpp cmake -B build -DCMAKE_BUILD_TYPERelease cmake --build build --config Release -j $(nproc) # 2. 转成GGUFFP16原始格式 python3 convert_hf_to_gguf.py ~/models/Qwen2.5-7B-Instruct \ --outfile qwen2.5-7b-f16.gguf --outtype f16 # 3. 量化成4bit ./build/bin/llama-quantize qwen2.5-7b-f16.gguf qwen2.5-7b-q4_k_m.gguf q4_k_m转换过程需要一些时间主要花在读取原始权重上7B模型大概几分钟。量化档位选择我一般看两个q4_k_m综合性价比最高文件小、速度快、质量损失可接受日常首选。q5_k_m比q4质量略好文件大约大1GB显存富余时用。q8_0几乎无损文件接近FP16的一半但显存占用明显上升。如果你的机器连转换都觉得吃力直接用别人发布好的GGUF文件就行HuggingFace上TheBloke等账号长期维护主流模型的量化版本搜模型名 GGUF即可。5.3 llama-server一个命令起一个OpenAI兼容服务llama.cpp编出来后日常使用不需要自己写代码调用直接用自带的llama-server即可./build/bin/llama-server -m qwen2.5-7b-q4_k_m.gguf \ --host 0.0.0.0 --port 8080 \ --n-gpu-layers 99 \ --ctx-size 8192--n-gpu-layers是GPU卸载层数。设为99表示尽可能把层都扔到GPU上显存不够就降设为0就是纯CPU运行。这个参数是llama.cpp系CPU/GPU混合调度的核心我一般先跑个8B模型目测显存余量再动态调。启动后访问http://localhost:8080/v1同样是OpenAI兼容接口用上节的openai SDK改个base_url就能接。5.4 CPU纯跑到底什么体验直说结论体验能用但谈不上好。一台主流桌面CPU比如i5-12400跑7B q4模型约2到3 token/s能打字聊天但明显有等待感。如果是13B模型大概1 token/s左右每句话都要等很久。但如果你的场景是不需要实时交互的批量任务——比如离线处理FAQ匹配、文本分类、批量生成摘要CPU推理反而很划算毕竟不用买显卡功耗也低。我在一台无GPU的旧服务器上挂了llama-server跑文本分类稳得很。所以选llama.cpp前先问自己是要交互体验还是离线吞吐别对CPU速度抱不切实际期望。6. 同一台机器三条路实测对比6.1 我自己的测试环境和口径为了给一个直观参考我把Ollama、transformers、llama.cpp在同环境下的效果记了下来。机器配置是RTX 3090 24GB、128GB内存、Intel i7-12700模型统一用Qwen2.5-7B-Instruct量化均对应4bit级别。测试prompt是一段300字短文总结指标包括首次token延迟、生成速度token/s、峰值显存和加载时间。6.2 实测数据对比方案加载时间生成速度峰值显存备注Ollamaq4_k_m约3秒约55 token/s约6.2GB开箱即用参数调整空间有限transformers BitsAndBytes 4bit约20秒约38 token/s约5.5GB每次动态量化启动慢transformers GPTQ Int4约8秒约45 token/s约5.8GB预量化文件启动和推理都不错llama.cpp q4_k_m GPU约2秒约60 token/s约6GB纯命令行灵活可控llama.cpp q4_k_m CPU纯跑约1秒约2.6 token/s内存约5GB能跑但交互体验差这个数据只是我这一台机器上的抽样结果不同CUDA版本、驱动、模型版本都会带来差异。但相对趋势是稳定一致的llama.cpp系Ollama和原版llama.cpp速度最快transformers的bitsandbytes动态量化最慢GPTQ介于中间。6.3 我的选型心法综合这些数据和我日常用法我的选型逻辑很简单只是想尽快用起来不想折腾代码无脑Ollama。它底层就是llama.cpp性能不会差太多。需要精细控制、做实验对比多模型transformers搭配GPTQ预量化模型兼顾速度和灵活性。老机器只有CPU或者追求极致压榨GPU直接用llama.cpp自己按显存量化一个命令起步。跑服务给别人用优先Ollama或者llama-server两者都能挂OpenAI兼容接口稳占用小好维护。7. 本地部署避坑手册下载、显存、版本的各种意外7.1 模型下载慢/中断Ollama拉取大模型时经常卡住最常见原因是网络问题。绕开官方下载通道从ModelScope或国内可用镜像站下载GGUF文件再用ollama create导入是我试过最稳的办法。transformers下载HuggingFace权重同理可以把HF_ENDPOINT环境变量指向合适的镜像站或者直接用ModelScope的Python SDK拉模型from modelscope import snapshot_download model_dir snapshot_download(Qwen/Qwen2.5-7B-Instruct)下载动辄几个GB的文件建议配合终端工具断点续传别用浏览器来回重下。7.2 加载即OOM其实不一定是显存真不够有次跑一个7B量化模型12G显存的卡加载直接报CUDA out of memory我一度以为模型太大跑不了。后来排查发现是device_map没设对模型默认全部往GPU塞再加上bitsandbytes加载时临时占用了额外显存当场爆炸。改成device_mapauto后权重自动分了一部分到内存问题就解决了。另一个容易忽略的是显存碎片化。如果之前加载过其他模型没释放干净再加载新模型就容易OOM重启进程或者调整PYTORCH_CUDA_ALLOC_CONFexpandable_segments:True都可能解决问题。7.3 版本兼容性transformers老项目移植的大坑热搜里提到transformers3.4.0和PyTorch/CUDA的兼容问题我太理解这种痛了。transformers 3.x是非常老的版本压根没有支持最新的量化接口很多现有教程里的BitsAndBytesConfig、device_map这些参数它都不认识。如果你维护的老项目锁了transformers 3.4.0又想在本地跑大模型我的建议是不要硬升级整个项目而是在独立虚拟环境里装一套新transformers比如4.42.x做推理服务老项目通过API调用它。这个方案我实际操作过规避了依赖冲突也把新老生态都能用起来。7.4 量化模型乱回答先检查这四件事模型部署成功后出现胡言乱语先别怪量化从这四个方向排查对话模板有没有传对同一个模型在ollama里直接run没问题但一旦走OpenAI兼容API如果模板缺失或格式不对输出质量断崖式下降。上下文溢出长文中模型如果只看到开头没看到结尾答非所问很正常。把num_ctx调大就好。温度过高temperature0.8以上在开放问答时会话比较散技术类问题建议0.2到0.6之间。量化档位太低如果q2_k这类极端量化档位模型理解能力明显下降是正常的换q4_k_m或q5_k_m会有质的改善。7.5 一定量的精度换性能是值得的最后说点心态上的体会。很多人对量化有心理洁癖觉得INT4必然垃圾。实际体验下来7B模型从FP16降到q4_k_m日常问答、总结、代码生成的质量下降远没有想象中严重至少对于一个7B模型来说原本的上限就在那里量化去掉的只是尾部的精度。换取的是显存占用从14GB降到5GB左右加载速度和生成速度都明显变快。如果你的显卡本来跑不了FP16那量化不是“妥协方案”而是“可行方案”。我在实际部署多个模型后的习惯是先跑q4_k_m验证效果和速度如果质量不满足需求再往q5、q8升级始终用最小的资源达成可接受的目标。这比一上来就追求高精度要高效得多。另一个小技巧是给每套部署写一个版本清单记录模型版本、量化档位、上下文字段的配置不然过两周你就忘了这个模型当时为什么这么设参数。本地部署这件事折腾一次不可怕可怕的是每次换模型都把之前的坑重新踩一遍。
返回列表