本地部署大模型,你需要知道哪些相关知识?
从模型下载、量化参数到推理框架的一次扫盲
前言
最近两年的时间,大模型这个话题越来越热。作为一个从Java开发转到大模型开发赛道的人,我也经常在想一个问题:
如果不依赖云厂商提供的API,自己在电脑或者服务器上部署一个大模型,到底需要准备些什么?
这个问题看起来不复杂,真正动手的时候却很容易被一堆名词绕进去。打开Hugging Face的模型仓库,除了模型名称,还会看到7B、Instruct、BF16、AWQ、GPTQ、GGUF、Q4_K_M等各种参数。
以前我们部署一个Java服务,通常关注JDK版本、依赖包、配置文件和JVM参数。现在换成大模型,虽然整体思路没有变,但需要关注的对象完全不一样了:
Java服务:代码包 + 配置文件 + JVM + Web容器
大模型:模型权重 + Tokenizer + 推理框架 + 硬件
这些名称有的描述模型大小,有的描述参数精度,有的描述量化算法,还有的描述文件格式。如果没有接触过大模型,很容易把它们混在一起。
更麻烦的是,模型并不是下载下来就一定能运行。权重文件、Tokenizer、配置文件、推理框架和硬件,只要其中一个环节没有匹配好,就可能出现模型加载失败,或者模型虽然能说话,但回答质量明显不对的问题。
所以,这篇文章就作为大模型专题的第一篇,不深入复杂的数学原理,也不急着上源码,先从一个Java开发者最容易理解的角度,把本地部署模型这件事涉及到的基本概念梳理清楚。
下面我们就从“下载一个模型之前,需要先看懂什么”开始,一点一点来看。
看完这篇文章,至少要能够回答下面几个问题:
- 我应该下载Base模型还是Instruct模型?
BF16、INT4、AWQ、GPTQ和GGUF分别是什么?- 为什么模型文件能放进显存,运行时还是可能内存不够?
- 为什么下载了权重文件,还需要Tokenizer和配置文件?
- 我的电脑或服务器应该选择什么模型版本和推理框架?
一、先建立一个整体认识
先不要急着打开下载链接,我们先把本地部署模型这件事拆开看一下。
本地部署模型,大致可以拆成下面几个环节:
选择模型
│
├── 看模型用途、版本、许可证
│
├── 选择权重精度和量化版本
│
├── 下载权重、配置、Tokenizer
│
├── 选择推理框架
│
├── 根据显存和上下文长度估算内存
│
└── 调整生成参数并启动服务
这里最重要的是:模型不是一个单独的权重文件。
很多初学者第一次部署失败,问题往往不在模型本身,而在于只下载了权重,或者下载的模型格式和推理框架不匹配。
一个完整的本地部署,至少需要同时考虑下面四类内容:
| 类别 | 常见内容 | 主要解决的问题 |
|---|---|---|
| 模型本身 | Base、Instruct、Dense、MoE | 这个模型适合做什么 |
| 模型文件 | safetensors、GGUF | 权重如何保存和加载 |
| 数值与量化 | BF16、FP16、INT4、AWQ、GPTQ | 模型占用多少内存、效果损失多少 |
| 运行环境 | Transformers、vLLM、llama.cpp、Ollama | 使用什么程序和硬件运行 |
二、下载模型前,先看懂模型卡片
Hugging Face上的模型仓库一般都有一个README.md,也叫Model Card。这里通常会介绍模型用途、训练信息、评测结果、限制和许可证。[1]
模型卡片可以理解成项目的README。不要看到模型名字里有一个熟悉的品牌就直接下载,建议先看下面几个信息。
1. Base模型还是Instruct模型?
这是最容易选错的地方。
Qwen-7B // Base基础模型
Qwen-7B-Instruct // 指令微调模型
Base模型更适合继续训练、微调或者做底层能力研究;Instruct模型经过指令微调,更适合直接进行问答和聊天。
如果只是想在本地运行一个聊天机器人,通常优先选择Instruct、Chat或类似名称的版本。
这里可以先记住一句话:Base模型偏底座,Instruct模型偏使用。选错了并不一定会报错,但实际对话效果可能完全不是预期。
2. 7B、14B、32B表示什么?
这里的B是Billion,表示十亿,7B大约代表70亿个参数。
参数量越大,通常模型能力越强,但需要的内存也越多。可以先用下面这个经验进行判断:
参数量越大 → 模型通常越强 → 需要的内存越多 → 推理速度可能越慢
不过这不是绝对的。同等参数量下,模型架构、训练数据和训练方法也会影响最终效果。
如果是MoE模型,还需要区分:
- 总参数量:模型一共包含多少参数
- 激活参数量:每次推理真正参与计算的参数量
所以,MoE模型的“总参数量”和“运行时计算量”不一定是同一个概念。
第一次接触MoE时,不需要马上研究专家路由的细节。先知道它不是简单地把所有参数每次都算一遍,就够用了。
3. 是否支持中文、视觉和工具调用?
还需要看模型的能力范围:
- 是否支持中文
- 是否是纯文本模型
- 是否支持图片或视频输入
- 是否支持函数调用和工具调用
- 是否适合代码、数学或长文本任务
比如,视觉模型除了语言模型权重,还可能需要视觉编码器、图片处理器等额外文件,不能完全按照纯文本模型的方式部署。
4. 许可证是否允许使用?
模型不一定都可以随意商用。下载前要重点确认:
- 是否允许商业使用
- 是否要求署名
- 是否有用户数量或收入限制
- 是否为研究用途限定
- 是否需要单独申请访问权限
部分模型是gated model,需要先在网页上申请权限,再使用hf auth login登录后下载。[2]
也就是说,模型能不能下载下来,不只取决于磁盘和网络,有时还取决于模型协议以及当前账号是否有访问权限。
三、下载的模型文件都是什么?
模型选好了,接下来就要看仓库里的文件。以Transformers加载的模型为例,目录通常类似下面这样:
config.json
generation_config.json
tokenizer.json
tokenizer_config.json
special_tokens_map.json
model-00001-of-00003.safetensors
model-00002-of-00003.safetensors
model-00003-of-00003.safetensors
model.safetensors.index.json
1. config.json
config.json可以理解为模型的结构配置文件,里面会记录:
- 模型类型
- 层数
- 隐藏层大小
- 注意力头数量
- 词表大小
- 最大上下文长度等
推理框架会根据它知道“应该如何组装这个模型”。
2. safetensors
模型权重常见的格式有:
model.safetensors
model-00001-of-00003.safetensors
pytorch_model.bin
一般优先选择safetensors。它是专门用于保存张量的格式,加载时不会执行Python pickle中的任意对象,相比传统.bin文件更加安全,也适合快速读取。[4]
如果模型被拆成多个safetensors文件,需要把所有分片和索引文件下载完整,不能只下载第一个文件。
这有点像一个被拆成多个JAR包的应用,只下载其中一个分片,当然无法正常启动。
3. Tokenizer
Tokenizer负责把文本转换成模型能够识别的Token,也负责把模型输出的Token转换回文本。
常见文件包括:
tokenizer.json
tokenizer_config.json
special_tokens_map.json
没有Tokenizer,模型就无法正确处理输入文本。所以,下载模型时不要只盯着几个GB甚至几十GB的权重文件。
4. Chat Template
不同模型训练时使用的对话格式可能不同,例如:
<|user|>你好
<|assistant|>
也可能是其他特殊Token组合。这个格式通常保存在Tokenizer的chat_template中。
如果使用了错误的对话模板,模型可能仍然能够运行,但回答质量会明显下降。使用Transformers时,建议优先调用模型自带的apply_chat_template()。[3]
这也是一个比较隐蔽的问题:程序没有报错,但模型的回答变差了。遇到这种情况,除了检查Prompt,也要检查Chat Template是不是用对了。
简单示例:
messages = [
{"role": "user", "content": "请介绍一下Redis"}
]
inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_tensors="pt"
)
四、BF16、FP16、INT4:参数到底如何存储?
前面提到的模型文件,解决的是“权重保存在哪里”;下面这些参数,解决的是“每个权重使用多少空间保存”。
先把几个概念放在一张表里。Hugging Face也将BF16、FP16等半精度格式和INT8、INT4等低比特整数表示区分开来。[6]
| 名称 | 本质 | 每个参数占用 | 大致特点 |
|---|---|---|---|
| FP32 | 32位浮点数 | 32 bit | 精度高,但体积大 |
| FP16 | 16位浮点数 | 16 bit | 体积较小,GPU支持较好 |
| BF16 | 16位浮点数 | 16 bit | 数值范围接近FP32,精度低于FP32 |
| INT8 | 8位整数 | 8 bit | 进一步压缩,常用于推理 |
| INT4 | 4位整数 | 4 bit | 体积很小,可能有一定效果损失 |
1. BF16和FP16
BF16全称是Brain Floating Point 16,是一种16位浮点数格式。它的结构是:
1 bit 符号位 + 8 bit 指数位 + 7 bit 小数位 = 16 bit
BF16和FP32拥有相同数量的指数位,因此可表示的数值范围比较接近;但小数位更少,所以精度低于FP32。[5]
BF16和FP16都属于浮点数格式,常见于模型的高精度版本。它们的优点是模型效果损失小,缺点是占用内存较大,而且需要硬件和推理框架支持。
2. INT4
INT4中的4表示每个参数使用4 bit存储。4 bit理论上只能表示16种状态,所以不可能精确保存原始浮点数。
量化时,通常会把一组浮点权重映射成较小的整数,并额外保存缩放因子scale,可以简单理解为:
原始浮点权重 ≈ 量化后的整数 × scale
实际过程还会涉及分组大小、零点、对称量化等概念。因为还要保存这些辅助信息,所以模型实际大小会比理论值略大。
看到这里,可以先得到一个很直观的结论:量化的主要目的,是用更少的存储空间保存模型,让原本放不下的模型有机会在本地运行。
以一个70亿参数的模型为例,简单估算权重占用:
BF16:7B × 16 bit ÷ 8 ≈ 14 GB
INT4:7B × 4 bit ÷ 8 ≈ 3.5 GB
这只是模型权重的理论估算,没有计算Tokenizer、运行时、激活值和KV Cache。
另外,很多4 bit模型实际采用的是W4A16:
W4:模型权重使用4 bit
A16:激活值在计算时仍使用16 bit浮点数
所以,“4 bit模型”并不代表整个推理过程都只使用4 bit。
五、AWQ和GPTQ:它们是量化方法
AWQ和GPTQ经常出现在模型名称中:
Qwen-7B-AWQ
Llama-3-8B-GPTQ-Int4
它们描述的是“如何把高精度模型转换成低比特模型”,不是文件后缀。
那么问题来了,同样都是4 bit,为什么还要分AWQ和GPTQ?下面简单看一下它们的区别。
1. AWQ
AWQ全称是Activation-aware Weight Quantization,即“激活感知的权重量化”。
它的核心思想是:模型中的权重并不是同等重要的,有一小部分权重对模型效果更加敏感。AWQ会通过校准数据观察激活值分布,找到重要通道,再通过缩放等方式降低量化误差。[7]
简单总结一下:
- 通常用于4 bit权重量化
- 会参考模型运行时的激活值
- 不需要重新训练整个模型
- 对支持相关算子的GPU比较友好
- 具体能否运行,取决于推理框架和硬件
2. GPTQ
GPTQ是一种典型的训练后量化方法,全称是Accurate Post-Training Quantization for Generative Pre-trained Transformers。
它使用少量校准数据,逐层寻找更合适的量化结果,并使用近似的二阶信息降低量化误差。在3 bit、4 bit等低比特场景中,GPTQ通常能够在模型大小和效果之间取得不错的平衡。[8]
简单总结一下:
- 常见于3 bit、4 bit权重量化
- 需要校准数据
- 量化过程相对复杂
- GPU推理生态中使用较多
- 需要匹配对应的加载器和推理框架
AWQ和GPTQ的目标比较接近,区别主要在于量化时处理误差的思路不同。普通使用者不需要自己实现算法,重点是选择和推理框架匹配的模型版本。
所以,下载模型时不要只看“4 bit”这几个字,还要看它是AWQ还是GPTQ,以及当前使用的推理框架是否支持。
六、GGUF和Q4_K_M:模型文件怎么保存?
前面讲的AWQ和GPTQ是量化方法,接下来再看一个经常和它们混淆的概念:模型文件格式。
1. GGUF是什么?
GGUF是一种模型文件格式,经常和llama.cpp、Ollama等本地推理工具一起出现。
它可以保存模型张量、模型配置和其他元数据,目标是让模型更容易被基于GGML的推理程序加载。[9]
所以:
AWQ / GPTQ:量化方法
GGUF:模型文件格式
GGUF不等于INT4。GGUF文件中可以保存F16、BF16、Q4_0、Q4_K_M、Q8_0等不同类型的张量。
2. Q4_K_M是什么?
经常会看到下面这样的文件名:
模型名称-Q4_K_M.gguf
可以先这样理解:
| 名称部分 | 大致含义 |
|---|---|
Q4 |
主要权重使用4 bit量化 |
K |
使用K-quant分块量化方案 |
M |
通常表示混合配置,部分层使用更高精度 |
.gguf |
使用GGUF文件格式 |
Q4_K_M不是最简单的INT4,而是GGUF生态中的一种具体量化类型,通常在模型体积和效果之间做折中。不同版本的工具实现可能会有差异,最终应以模型说明和GGUF元数据为准。[10]
这里不要把Q4_K_M、INT4和GGUF当成同一类东西。一个描述量化配置,一个描述位宽,一个描述文件格式,它们处在不同的层次。
常见的经验是:
Q4_K_M:体积小,效果和体积比较均衡Q5_K_M:占用更多内存,通常可以换来更好的效果Q8_0:体积更大,但更接近高精度模型
七、上下文长度和KV Cache
模型权重能够加载,只能说明模型“基本跑起来了”,还不代表实际请求一定不会OOM。接下来这个概念,和运行时内存关系比较大。
模型名称中经常会出现:
32K
128K
Long Context
这些通常表示模型支持的上下文长度。
相关配置可能出现在:
max_position_embeddings
rope_scaling
rope_theta
上下文长度越长,推理时需要保存的历史信息越多,KV Cache占用的内存也会增加。
所以,本地推理所需的内存不能只看模型文件大小,还要考虑:
总内存
≈ 模型权重
+ KV Cache
+ 激活值
+ 推理框架运行时开销
上下文越长、并发越高,KV Cache占用通常越大。模型文件能够放进显存,不代表一定能够支持很长的上下文。
这和Java服务中的堆内存有点类似:程序包本身可能不大,但运行时对象、缓存和并发请求也会持续占用内存。
八、如何根据硬件选择推理框架?
模型和硬件选好了,还要选择一个能够加载它的“运行容器”。在Java领域,我们不会拿一个Tomcat应用直接交给JVM运行;大模型也一样,需要匹配对应的推理框架。
不同推理框架支持的模型格式不同,不能只看模型名称下载。
| 运行环境或目标 | 可以优先了解 | 常见模型格式 |
|---|---|---|
| Python研究、简单调用 | Transformers | safetensors(含AWQ/GPTQ量化权重) |
| GPU高吞吐服务 | vLLM等服务框架 | safetensors、部分AWQ/GPTQ |
| CPU或希望轻量运行 | llama.cpp | GGUF |
| 使用Ollama快速体验 | Ollama | GGUF生态 |
上表只能作为入门参考,具体支持情况还要查看当前框架版本的官方文档。
通常可以这样选择:
显存充足,优先保证效果
→ BF16 / FP16
NVIDIA GPU,使用支持量化的推理框架
→ AWQ / GPTQ 4 bit
CPU、Mac或使用llama.cpp生态
→ GGUF,优先Q4_K_M
如果只是第一次体验本地模型,可以先选择简单的工具把模型跑起来;如果后面要提供多人并发服务,再重点关注吞吐量、批处理、显存管理和服务接口。
量化后的模型也不一定更快。量化最直接的收益是减少权重占用,让模型能够运行起来;速度是否提升,还要看硬件是否支持对应的低比特算子、推理框架是否做了优化,以及批量大小和上下文长度等因素。
九、从Hugging Face下载模型时,还要看哪些参数?
模型版本选择好了,接下来就是下载。手动点击文件当然可以,但如果以后要在服务器、测试环境和生产环境重复部署,最好把下载版本和文件范围固定下来。
如果只是手动下载,直接点击文件列表也可以。但如果希望部署过程可重复,建议了解下面几个参数:
hf download ORG/MODEL --revision COMMIT_HASH --include "*.safetensors" --exclude "*.bin" --local-dir ./models/model
| 参数 | 作用 |
|---|---|
revision |
固定分支、Tag或Commit版本 |
--include |
只下载匹配的文件 |
--exclude |
排除不需要的文件 |
--local-dir |
指定本地保存目录 |
例如,模型仓库同时提供safetensors和.bin时,可以只下载safetensors,避免浪费磁盘空间。Hugging Face的下载工具支持通过revision固定版本,也支持使用包含或排除规则筛选文件。[11]
另外,如果加载模型时需要设置:
trust_remote_code=True
说明模型使用了仓库中的自定义代码。只有确认仓库可信时才建议开启,并且最好固定到具体的Commit版本。[2]
十、生成参数:模型能跑起来之后怎么调?
模型成功加载只是第一步。接下来还会遇到一个问题:同一个模型,为什么有时回答很稳定,有时又比较发散?这就和生成参数有关了。
这类参数不决定模型能不能加载,但会影响模型的输出:
| 参数 | 作用 |
|---|---|
temperature |
控制输出随机性 |
top_p |
控制候选Token范围 |
top_k |
只从概率最高的K个Token中选择 |
max_new_tokens |
限制最多生成多少Token |
repetition_penalty |
降低重复输出 |
stop |
指定停止生成的字符串 |
简单理解:
temperature低一些 → 输出更稳定
temperature高一些 → 输出更多样
max_new_tokens越大 → 最长输出越长
不要把这些参数和模型量化参数混在一起。量化参数主要影响模型的大小、内存和效果;生成参数主要影响一次推理的输出风格。
十一、下载前的最小检查清单
好了,前面的概念比较多,我们最后把它们收敛成一张清单。
如果要把这篇文章的内容压缩成一张清单,下载模型前至少确认下面这些内容:
1. 是Base模型还是Instruct模型
2. 模型参数量是否满足机器配置
3. 是Dense模型还是MoE模型
4. 选择的是BF16、FP16、AWQ、GPTQ还是GGUF版本
5. 推理框架是否支持该模型格式
6. config、Tokenizer和Chat Template是否完整
7. 上下文长度是否满足业务需求
8. KV Cache是否有足够的内存
9. 模型许可证是否允许当前用途
10. 是否需要申请gated model权限
11. 是否固定了revision,保证部署可复现
12. 是否确认了生成参数和停止Token
结语
OK,看到这里,相信大家对本地部署大模型已经有了一个整体认识。刚开始接触时,模型仓库里的参数确实比较多,但把它们按层次拆开之后,其实并没有想象中那么复杂。
以前我们部署Java服务,需要理解JAR包、配置文件、JVM和Web容器。换到大模型领域,虽然名词变了,但本质上还是一个“程序如何在指定环境中运行起来”的问题。
如果用Java开发者熟悉的方式来类比:
模型卡片:类似项目README,说明模型能做什么、怎么使用
模型权重:类似JAR包,是真正参与运行的核心内容
Tokenizer:类似输入输出的编解码协议
推理框架:类似运行容器,负责把模型加载并运行起来
显存和内存:类似服务运行时需要准备的机器资源
这几个概念可以简单记成:
Base / Instruct:模型适合做什么
7B / 14B / 32B:模型有多少参数
BF16 / FP16 / INT4:参数使用什么精度保存
AWQ / GPTQ:参数通过什么方法量化
GGUF:模型使用什么文件格式保存
Q4_K_M:GGUF生态中的一种具体量化类型
32K / 128K:模型支持多长的上下文
Tokenizer:文本如何转换成Token
Chat Template:对话如何组织成模型认识的格式
本地部署大模型并不只是“下载一个模型文件然后启动”。先看懂模型卡片,再根据硬件选择合适的精度、量化版本和推理框架,最后补齐Tokenizer、上下文长度和生成参数,基本就可以把模型顺利跑起来。
对于Java开发者来说,转型到大模型开发并不意味着一开始就要研究复杂的模型结构和量化算法。先把模型下载、加载、推理这一条链路跑通,知道每个组件是做什么的,后面再继续学习Prompt、RAG、LoRA、模型微调和服务化部署,理解起来就会顺畅很多。
这也是本篇文章想解决的问题:先把本地部署大模型的基础概念弄明白,后面遇到各种模型名称和参数时,至少不会再一头雾水。
当然,本文只是做了一次入门扫盲,很多内容还没有展开,比如推理服务如何接入Java应用、RAG到底怎么落地、LoRA微调是怎么回事,以及如何通过并发、批处理和KV Cache优化服务性能。
不过学习一件新技术,我一直觉得不需要一上来就把所有细节研究透。先把模型下载下来,选择合适的版本,在本地真正跑通,再带着问题继续往下学习,往往会更容易一些。
后面我们再针对这些内容继续展开,敬请期待。
参考资料
[2] Hugging Face,Gated Models与Loading Models、Loading Models
[3] Hugging Face,Chat Templates
[5] PyTorch Documentation,Tensor Attributes
[6] Hugging Face,Quantization Overview
[7] Ji Lin 等,AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration
[8] Elias Frantar 等,GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers