从 `.pt` 到 `.gguf`:彻底理解大模型权重格式与推理框架的关系

很多人刚接触大模型都会有一个疑问:
模型权重不是
.pt、.pth吗?为什么现在又冒出来.safetensors、.gguf、.engine?为什么同一个模型,必须使用不同的组件(Transformers、vLLM、Ollama、llama.cpp)来启动?底层不都是 PyTorch 吗?
本文将从 训练 → 导出 → 推理 的完整生命周期,带你彻底理解这些问题。
一个最大的误区
很多人认为:
模型 = PyTorch 权重
其实这是错误的。
真正应该理解为:
模型(Model) = 神经网络结构 + 参数(Weights)
PyTorch 只是训练模型的一种框架,而不是模型本身。
可以把它理解成:
1 | PyTorch |
真正重要的是:
模型和运行框架是分离的。
大模型的完整生命周期
整个流程其实非常简单。
1 | 训练阶段 |
可以发现:
训练格式和推理格式本来就是两个世界。
第一阶段:训练
目前几乎所有主流大模型:
- Qwen
- Llama
- DeepSeek
- Gemma
- Mistral
都是使用:
- PyTorch
- JAX
- Megatron-LM
- DeepSpeed
- FSDP
训练出来的。
训练结束以后,通常得到的是:
1 | pytorch_model.bin |
或者
1 | model.safetensors |
早几年最常见的是:
1 | pytorch_model.bin |
实际上就是:
1 | torch.save(model.state_dict()) |
保存出来的。
后来因为:
- pickle 不安全
- 加载速度较慢
- 不支持 mmap
于是大家开始统一使用:
1 | .safetensors |
例如 Hugging Face 下载的模型:
1 | Qwen3/ |
.pt、.pth、.bin、.safetensors 有什么区别?
很多新人会觉得这些都是不同格式。
其实并不是。
.pt / .pth
一般都是:
1 | torch.save(...) |
保存出来的。
可以保存:
- 整个模型
- state_dict
- optimizer
- scheduler
- checkpoint
例如:
1 | torch.save({ |
所以:
.pt并不一定只是模型权重。
pytorch_model.bin
Hugging Face 以前默认使用:
1 | pytorch_model.bin |
本质也是:
1 | torch.save(state_dict) |
只是名字叫:
1 | pytorch_model.bin |
实际上依旧是 pickle。
safetensors
现在已经成为 Hugging Face 主流格式。
优点:
- 安全(没有 pickle)
- mmap 加载
- 更快
- 更稳定
里面保存的依然是:
1 | layers.0.attn.q_proj.weight |
这些 Tensor。
所以:
.safetensors本质上依旧只是 Tensor 集合。
第二阶段:推理
真正开始出现区别的是这里。
很多人认为:
推理是不是就是 PyTorch Forward 一下?
其实不是。
例如:
Transformers:
1 | Transformers |
但是:
很多推理框架根本不用 PyTorch。
例如:
1 | llama.cpp |
里面没有:
1 | torch.nn.Linear |
没有:
1 | torch.matmul |
甚至:
1 | Attention |
全部都是自己写的 C++ 实现。
因此:
它不能直接读取 PyTorch 的权重格式。
为什么需要 GGUF?
GGUF 可以理解成:
llama.cpp 专用模型格式。
GGUF 不只是保存权重。
它还保存:
- Tokenizer
- Vocabulary
- Rope 参数
- 特殊 Token
- 模型配置
- Metadata
- Tensor 排布
- 对齐方式
- 量化方式
例如:
1 | Qwen3-32B-Q4_K_M.gguf |
实际上已经是:
一个完整模型。
不像 Hugging Face:
1 | config.json |
需要很多文件。
GGUF 一个文件全部解决。
GGUF 最大特点:已经量化好了
例如:
Hugging Face:
1 | float16 |
可能:
1 | 2GB |
转换以后:
1 | Q4_K_M.gguf |
可能:
1 | 500MB |
为什么?
因为 Tensor 已经变成:
1 | 4bit |
例如:
原来:
1 | 0.315 |
float16。
转换以后:
1 | 01001010 |
已经不是 float16。
而是:
1 | Q4_K_M |
编码后的数据。
因此:
llama.cpp 加载的时候:
1 | 不用再量化 |
为什么 Transformers 不能直接读取 GGUF?
原因很简单。
Transformers 期待:
1 | float16 Tensor |
例如:
1 | torch.Tensor |
但是:
GGUF 里面已经变成:
1 | Q4_K_M |
这些编码。
PyTorch 根本不知道如何解释。
因此:
1 | GGUF |
或者:
1 | GGUF |
因为它们实现了对应的解码器。
Ollama 为什么可以一句话运行?
很多人觉得:
1 | ollama run qwen3 |
非常神奇。
实际上:
底层就是:
1 | Ollama |
例如:
1 | ollama run qwen3:32b |
实际上就是:
1 | 下载 GGUF |
所以用户感觉非常简单。
为什么 vLLM 不支持 GGUF?
因为:
vLLM 和 llama.cpp 的目标完全不同。
llama.cpp 追求:
- CPU
- Mac
- Metal
- 边缘设备
- 极低内存
而:
vLLM 追求:
- GPU 最大吞吐
- Tensor Parallel
- Pipeline Parallel
- Continuous Batching
- Prefix Cache
- PagedAttention
因此:
它更喜欢:
1 | float16 |
这些 GPU 可以高速计算的数据。
GGUF 更多是:
1 | CPU 优化 |
方向不同。
为什么不同框架不能互相读取?
可以想象:
Windows:
1 | .exe |
Linux:
1 | ELF |
Mac:
1 | Mach-O |
都是:
1 | 可执行程序 |
但是:
互相不能直接运行。
原因就是:
底层格式不同。
模型格式也是一样。
例如:
1 | Transformers |
而:
1 | GGUF |
因此:
必须使用不同加载器。
为什么很多模型都有多个版本?
例如:
Qwen3-32B
你可能看到:
1 | Qwen3-32B |
同时还有:
1 | Qwen3-32B-Q4_K_M.gguf |
还有:
1 | TensorRT Engine |
还有:
1 | MLX |
其实:
它们都是:
同一个模型。
只是:
采用了不同运行时。
各种格式之间是什么关系?
可以画成一张图:
1 | PyTorch 训练 |
所以:
真正重要的是:
所有格式都来源于同一份训练权重。
只是为了适应不同推理引擎。
常见模型格式总结
| 格式 | 主要用途 | 是否可继续训练 | 常见推理框架 |
|---|---|---|---|
.pt / .pth |
PyTorch 保存对象 | ✅ | PyTorch |
.bin |
早期 Hugging Face 权重 | ✅ | Transformers |
.safetensors |
当前 Hugging Face 主流格式 | ✅ | Transformers、vLLM、SGLang |
.gguf |
llama.cpp 专用格式 | ❌(通常不可直接训练) | llama.cpp、Ollama、LM Studio |
.onnx |
跨框架推理格式 | ❌ | ONNX Runtime |
.engine |
TensorRT 编译结果 | ❌ | TensorRT |
.mlpackage |
Apple CoreML | ❌ | CoreML |
底层真的都是 PyTorch 吗?
这是本文最重要的一点。
答案是:
训练阶段几乎都是 PyTorch。
但是:
推理阶段未必。
目前主流框架:
| 推理框架 | 是否依赖 PyTorch |
|---|---|
| Transformers | ✅ 完全依赖 |
| vLLM | ✅ 模型定义依赖 PyTorch,但核心算子大量自定义 CUDA 实现 |
| SGLang | ✅ 基于 PyTorch + Triton 等优化 |
| TensorRT-LLM | ❌ 不依赖 PyTorch Runtime |
| llama.cpp | ❌ 完全 C/C++ 实现 |
| Ollama | ❌ 底层基于 llama.cpp |
| MLX | ❌ 使用 Apple MLX |
因此:
很多推理框架甚至连:
1 | torch.nn.Linear |
都不会调用。
它们直接运行自己实现的:
- MatMul
- Attention
- KV Cache
- Sampling
- CUDA Kernel
- Metal Kernel
所以:
训练可以依赖 PyTorch,而推理完全可以摆脱 PyTorch。
总结
理解大模型权重格式,可以记住下面这张图:
1 | 训练 |
一句话概括全文:
.pt、.pth、.bin、.safetensors更多是训练和通用权重格式;.gguf、.engine、.mlpackage等则是针对特定推理引擎和硬件优化后的部署格式。模型本身没有变化,变化的是它的“打包方式”和“运行时”。真正决定模型能否运行的,不仅是权重文件,更是与之匹配的推理框架和底层执行引擎。