目录

  1. 概述
  2. 权重文件基础概念
  3. 常见权重文件格式
  4. 格式对比
  5. 选择建议
  6. 转换工具
  7. 最佳实践
  8. 常见问题

概述

大模型权重文件是训练完成后保存的模型参数文件,包含了神经网络的所有可学习参数(权重、偏置等)。不同的深度学习框架和部署场景衍生出了多种权重文件格式,每种格式都有其特定的优势和适用场景。

随着大模型技术的快速发展,权重格式也在不断演进,从最初的框架原生格式到如今的通用格式,安全性和加载效率成为重要的考量因素。


权重文件基础概念

什么是模型权重

模型权重是神经网络中可学习的参数,主要包括:

参数类型说明示例
权重矩阵 (Weight)层与层之间的连接参数全连接层的权重矩阵
偏置 (Bias)每个神经元的偏移量卷积层的偏置项
归一化参数批归一化层的参数BN层的 γ 和 β
嵌入矩阵词嵌入层的参数Word Embedding
位置编码位置编码参数Transformer的位置编码

权重的数据结构

# 典型的权重字典结构示例
state_dict = {
    'model.encoder.layer.0.attention.self.query.weight': tensor([...]),
    'model.encoder.layer.0.attention.self.query.bias': tensor([...]),
    'model.encoder.layer.0.attention.self.key.weight': tensor([...]),
    # ... 更多层
    'model.pooler.dense.weight': tensor([...]),
    'model.pooler.dense.bias': tensor([...]),
}

精度与存储大小

不同精度对模型大小和性能的影响:

精度字节/参数7B模型大小13B模型大小70B模型大小质量影响
FP324字节28GB52GB280GB无损
FP162字节14GB26GB140GB极小
BF162字节14GB26GB140GB极小
INT81字节7GB13GB70GB轻微
INT40.5字节3.5GB6.5GB35GB可察觉
INT20.25字节1.75GB3.25GB17.5GB明显

常见权重文件格式

PyTorch 格式 (.pt/.pth/.bin)

描述:PyTorch 框架的原生权重格式,使用 Python 的 pickle 模块进行序列化。

文件结构

  • 使用 Python pickle 序列化字典
  • 包含键值对,键为参数名称,值为张量数据
  • 可保存模型权重、优化器状态、学习率调度器等

特点

  • ✅ 与 PyTorch 生态完全兼容
  • ✅ 支持保存完整的模型结构和优化器状态
  • ✅ 使用简单,保存和加载方便
  • ✅ 支持动态计算图
  • ❌ 存在安全风险(pickle 可能执行恶意代码)
  • ❌ 文件体积较大
  • ❌ 加载速度相对较慢
  • ❌ 跨框架兼容性差

适用场景

  • PyTorch 模型的训练和推理
  • 需要保存训练中间状态(如优化器状态、学习率调度器)
  • 研究和开发环境
  • 模型微调和断点续训

文件内部结构

PyTorch 文件 (.pt/.pth)
├── 版本信息 (version)
├── 数据源 (source)
├── 数据 (data)
│   ├── 键值对 1 (key1: tensor)
│   ├── 键值对 2 (key2: tensor)
│   └── ...
└── 其他元数据

示例代码

import torch

# 保存模型权重(仅保存参数)
torch.save(model.state_dict(), 'model.pth')

# 保存完整模型(包含结构)
torch.save(model, 'model_full.pt')

# 保存训练状态(包含优化器、学习率调度器等)
checkpoint = {
    'epoch': epoch,
    'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
    'loss': loss,
    'lr_scheduler_state_dict': scheduler.state_dict(),
}
torch.save(checkpoint, 'checkpoint.pth')

# 加载模型权重
model.load_state_dict(torch.load('model.pth', map_location='cpu'))

# 加载完整模型
model = torch.load('model_full.pt')

# 加载训练状态
checkpoint = torch.load('checkpoint.pth')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])

安全警告

# 不安全的加载方式(可能执行恶意代码)
state_dict = torch.load('untrusted_model.pth')

# 推荐的安全加载方式(仅加载数据,不执行代码)
state_dict = torch.load('model.pth', weights_only=True)

SafeTensors 格式 (.safetensors)

描述:由 Hugging Face 推出的安全、快速的模型权重格式,旨在替代 pickle 格式。

设计目标

  1. 安全性:不涉及代码执行,防止恶意代码注入
  2. 速度:零拷贝反序列化,加载速度更快
  3. 简单性:文件格式简单,易于解析
  4. 兼容性:跨框架、跨平台支持

文件结构

SafeTensors 文件 (.safetensors)
├── 头部 (Header) - 8字节长度 + JSON 元数据
│   ├── 张量信息(名称、形状、数据类型、偏移量)
│   └── 元数据(可选)
├── 数据区 (Data) - 原始张量数据
│   ├── tensor1_data
│   ├── tensor2_data
│   └── ...
└── 填充区 (Padding) - 对齐用

头部 JSON 示例

{
  "__metadata__": { "format": "pt" },
  "model.layers.0.self_attn.q_proj.weight": {
    "dtype": "bfloat16",
    "shape": [4096, 4096],
    "data_offsets": [0, 33554432]
  },
  "model.layers.0.self_attn.k_proj.weight": {
    "dtype": "bfloat16",
    "shape": [1024, 4096],
    "data_offsets": [33554432, 41943040]
  }
}

特点

  • ✅ 安全性高(不涉及代码执行)
  • ✅ 加载速度快(零拷贝反序列化,比 PyTorch 快 3-10 倍)
  • ✅ 文件体积相对较小(无 pickle 开销)
  • ✅ 支持懒加载(lazy loading),可部分读取
  • ✅ 跨框架兼容性好
  • ✅ 内存映射(mmap)支持
  • ❌ 相对较新,部分旧工具可能不支持
  • ❌ 不支持保存优化器状态
  • ❌ 不支持动态计算图

性能对比

操作PyTorch (.pth)SafeTensors (.safetensors)提升
加载 7B 模型~60秒~15秒4x
加载 70B 模型~600秒~120秒5x
内存占用较高较低-20%

适用场景

  • 模型分发和共享
  • 生产环境部署
  • 需要快速加载模型的场景
  • 安全敏感的应用
  • Hugging Face Hub 上的模型发布

示例代码

from safetensors.torch import save_file, load_file
import torch

# 保存模型权重
tensors = {key: value.contiguous() for key, value in model.state_dict().items()}
save_file(tensors, 'model.safetensors')

# 加载模型权重(完整加载)
state_dict = load_file('model.safetensors', device='cpu')
model.load_state_dict(state_dict)

# 懒加载(部分加载)
from safetensors import safe_open

with safe_open('model.safetensors', framework='pt', device='cpu') as f:
    # 只读取特定张量
    tensor_names = f.keys()
    specific_tensor = f.get_tensor('model.layers.0.self_attn.q_proj.weight')

多文件分片

model.safetensors.index.json    # 索引文件,记录每个张量在哪个分片
model-00001-of-00004.safetensors # 分片 1
model-00002-of-00004.safetensors # 分片 2
model-00003-of-00004.safetensors # 分片 3
model-00004-of-00004.safetensors # 分片 4

ONNX 格式 (.onnx)

描述:Open Neural Network Exchange 格式,是一种开放的模型表示格式,支持跨框架模型转换。

设计目标

  1. 跨框架兼容:PyTorch、TensorFlow、Caffe2 等框架互转
  2. 优化部署:支持模型优化和量化
  3. 硬件加速:支持各种硬件加速器

文件结构

ONNX 文件 (.onnx)
├── 模型结构 (Model)
│   ├── 图信息 (Graph)
│   │   ├── 输入节点 (Inputs)
│   │   ├── 输出节点 (Outputs)
│   │   ├── 节点列表 (Nodes) - 算子
│   │   ├── 初始化器 (Initializers) - 权重
│   │   └── 值信息 (Value Info)
│   ├── 算子集 (Opset)
│   └── 元数据 (Metadata)
└── 序列化的 Protocol Buffer 数据

支持的数据类型

ONNX 类型NumPy 类型说明
FLOATfloat3232位浮点
UINT8uint88位无符号整数
INT8int88位有符号整数
UINT16uint1616位无符号整数
INT16int1616位有符号整数
INT32int3232位有符号整数
INT64int6464位有符号整数
STRINGstr字符串
BOOLbool布尔值
FLOAT16float1616位浮点
DOUBLEfloat6464位浮点
UINT32uint3232位无符号整数
UINT64uint6464位无符号整数
COMPLEX64complex6464位复数
COMPLEX128complex128128位复数

特点

  • ✅ 跨框架兼容(PyTorch、TensorFlow、Caffe2 等)
  • ✅ 支持模型优化和量化
  • ✅ 推理性能优秀
  • ✅ 支持硬件加速(如 TensorRT、OpenVINO)
  • ✅ 静态计算图,推理效率高
  • ❌ 可能丢失部分训练时的元数据
  • ❌ 转换过程可能遇到算子不兼容问题
  • ❌ 不支持保存优化器状态
  • ❌ 动态控制流支持有限

算子集 (Opset)

  • ONNX 定义了多个算子集版本
  • 新版本支持更多算子,但兼容性可能降低
  • 常用版本:opset 11, 13, 17, 18

适用场景

  • 跨平台模型部署
  • 边缘设备和移动端部署
  • 需要高性能推理的场景
  • 模型优化和量化
  • 与各种推理引擎集成

示例代码

import torch
import torch.onnx

# 准备模型和数据
model.eval()
dummy_input = torch.randn(1, 3, 224, 224)

# 导出为 ONNX 格式
torch.onnx.export(
    model,                          # PyTorch 模型
    dummy_input,                    # 示例输入
    'model.onnx',                   # 输出文件名
    export_params=True,             # 导出训练参数
    opset_version=17,               # ONNX 算子集版本
    do_constant_folding=True,       # 常量折叠优化
    input_names=['input'],          # 输入节点名称
    output_names=['output'],        # 输出节点名称
    dynamic_axes={                  # 动态维度
        'input': {0: 'batch_size', 2: 'height', 3: 'width'},
        'output': {0: 'batch_size'}
    }
)

# 验证导出的模型
import onnx
onnx_model = onnx.load('model.onnx')
onnx.checker.check_model(onnx_model)

# 使用 ONNX Runtime 推理
import onnxruntime as ort
session = ort.InferenceSession('model.onnx')
outputs = session.run(None, {'input': input_data.numpy()})

量化支持

from onnxruntime.quantization import quantize_dynamic, quantize_static

# 动态量化(INT8)
quantize_dynamic('model.onnx', 'model_int8.onnx', weight_type=QuantType.QInt8)

# 静态量化(需要校准数据)
quantize_static('model.onnx', 'model_int8_static.onnx', calibration_data_reader)

TensorFlow 格式 (.h5/.pb/.ckpt)

描述:TensorFlow 框架的权重格式,包括 HDF5 格式(.h5)、SavedModel 格式(.pb)和检查点格式(.ckpt)。

HDF5 格式 (.h5)

文件结构

HDF5 文件 (.h5)
├── 模型结构 (model_weights)
│   ├── 层1 (layer1)
│   │   ├── 权重 (weights)
│   │   └── 偏置 (bias)
│   ├── 层2 (layer2)
│   └── ...
├── 训练配置 (training_config)
└── 优化器状态 (optimizer_weights) [可选]

特点

  • ✅ 单文件存储,便于分发
  • ✅ 支持保存完整模型结构
  • ✅ 支持保存优化器状态
  • ❌ 不支持自定义模型结构
  • ❌ 跨框架兼容性差
SavedModel 格式 (.pb)

文件结构

SavedModel 目录
├── saved_model.pb          # 模型图定义
├── variables/              # 变量(权重)
│   ├── variables.data-00000-of-00001
│   └── variables.index
└── assets/                 # 资源文件(如词汇表)
    └── assets.txt

特点

  • ✅ TensorFlow Serving 标准格式
  • ✅ 支持模型签名 (Signature)
  • ✅ 支持多种计算图
  • ✅ 支持 Asset 文件
  • ❌ 格式较为复杂
  • ❌ 跨框架兼容性差
Checkpoint 格式 (.ckpt)

文件结构

Checkpoint 目录
├── checkpoint              # 索引文件,记录检查点状态
├── ckpt-00001.data-00000-of-00001  # 权重数据
├── ckpt-00001.index       # 索引数据
└── ckpt-00001.meta        # 元数据(图结构)

特点

  • ✅ 支持增量保存
  • ✅ 可恢复训练
  • ✅ 支持分布式训练
  • ✅ 包含优化器状态
  • ❌ 格式因框架版本而异
  • ❌ 文件体积较大

示例代码

import tensorflow as tf

# ===== HDF5 格式 =====
# 保存模型
model.save('model.h5')

# 加载模型
model = tf.keras.models.load_model('model.h5')

# ===== SavedModel 格式 =====
# 保存模型
tf.saved_model.save(model, 'saved_model/')

# 加载模型
loaded_model = tf.saved_model.load('saved_model/')

# 使用签名推理
infer = loaded_model.signatures['serving_default']
output = infer(input_tensor)

# ===== Checkpoint 格式 =====
# 创建检查点回调
checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath='checkpoints/ckpt-{epoch:04d}',
    save_weights_only=True,
    save_freq='epoch'
)

# 保存检查点
model.save_weights('checkpoints/ckpt')

# 加载检查点
model.load_weights('checkpoints/ckpt')

GGUF 格式 (.gguf)

描述:GPT-Generated Unified Format,专为 llama.cpp 和本地 LLM 部署设计的格式。

设计目标

  1. 统一格式:整合模型配置、 tokenizer、权重数据
  2. 量化支持:内置多种量化方案
  3. 本地优化:专为 CPU 推理优化
  4. 元数据嵌入:支持丰富的模型元数据

文件结构

GGUF 文件 (.gguf)
├── 文件头 (Header)
│   ├── 魔数 (Magic): 0x46554747 ("GGUF")
│   ├── 版本号 (Version): 3
│   ├── 张量数量 (Tensor Count)
│   └── 元数据数量 (KV Count)
├── 元数据区 (Metadata) - 键值对
│   ├── 模型架构信息
│   ├── 量化信息
│   ├── Tokenizer 配置
│   └── 其他自定义元数据
├── 张量信息区 (Tensor Info)
│   ├── 张量名称
│   ├── 张量形状
│   ├── 张量类型
│   └── 偏移量
└── 张量数据区 (Tensor Data)
    ├── tensor1_data (可能已量化)
    ├── tensor2_data
    └── ...

元数据示例

{
  "general.architecture": "llama",
  "general.name": "Llama 2 7B",
  "llama.context_length": 4096,
  "llama.embedding_length": 4096,
  "llama.block_count": 32,
  "llama.attention.head_count": 32,
  "llama.attention.layer_norm_rms_epsilon": 1e-05,
  "general.file_type": 15,
  "general.quantize_version": 2
}

量化类型详解

类型比特数块大小7B模型大小质量推理速度说明
F3232-28GB★★★★★★☆☆☆☆无损
F1616-14GB★★★★★★★☆☆☆几乎无损
Q8_08327.5GB★★★★☆★★★☆☆高质量
Q6_K62565.5GB★★★★☆★★★☆☆高质量
Q5_K_M52564.8GB★★★☆☆★★★★☆平衡
Q5_K_S52564.6GB★★★☆☆★★★★☆轻量
Q4_K_M42564.1GB★★★☆☆★★★★☆推荐
Q4_K_S42563.9GB★★★☆☆★★★★☆轻量
Q4_04323.8GB★★☆☆☆★★★★★快速
Q3_K_M32563.3GB★★☆☆☆★★★★☆紧凑
Q3_K_S32563.1GB★★☆☆☆★★★★☆轻量
Q3_K_L32563.6GB★★☆☆☆★★★★☆大型
Q2_K22562.7GB★☆☆☆☆★★★★☆最紧凑
Q2_K_S22562.5GB★☆☆☆☆★★★★☆超轻量
IQ1_S12561.8GB☆☆☆☆☆★★★☆☆实验性
IQ1_M12562.0GB☆☆☆☆☆★★★☆☆实验性

量化命名规则

  • Q:Quantized(量化)
  • 数字:每个元素占用的比特数
  • _K:使用块量化(K-quant),块大小为 256
  • _M:Medium(中等质量),使用重要性矩阵
  • _S:Small(轻量),质量略低但体积更小
  • _L:Large(大型),质量更高但体积更大
  • IQ:Integer Quantization(整数量化),实验性

量化原理详解

1. 基础量化(如 Q4_0)

原始 FP16 权重: [-0.1234, 0.5678, -0.9012, 0.3456, ...]

量化为 Q4_0:
1. 将权重分成 32 个元素的块
2. 计算每个块的 scale 和 min 值
3. 将每个值映射到 [-8, 7] 范围
4. 存储 scale、min 和量化后的值

量化后: scale=0.0025, min=-0.95, values=[-8, 7, -8, 7, ...]

2. K-Quant 量化(如 Q4_K_M)

K-Quant 量化过程:
1. 将权重分成 256 个元素的块
2. 识别"重要"和"非重要"权重
3. 对重要权重使用更高的精度
4. 对非重要权重使用更低的精度
5. 存储 scale、min 和量化后的值

优势:在相同比特数下,保留更多关键信息

3. 重要性矩阵(Importance Matrix)

重要性矩阵的作用:
- 识别模型中对输出影响较大的权重
- 对重要权重分配更多比特
- 对非重要权重分配更少比特
- 在保持质量的同时减少体积

M(Medium)vs S(Small):
- Q4_K_M: 使用重要性矩阵,质量更高
- Q4_K_S: 不使用重要性矩阵,体积更小

4. 量化类型选择指南

需求场景推荐类型备选类型说明
高质量生成Q8_0Q6_K适合需要高质量输出的场景
平衡选择Q4_K_MQ5_K_M推荐大多数用户使用
资源受限Q3_K_MQ4_K_S适合内存有限的环境
极致压缩Q2_KQ2_K_S适合存储受限的环境
实验性IQ1_MIQ1_S正在研究中,质量较低

量化注意事项

  1. 精度损失

    • 量化会导致模型质量下降
    • 下降程度取决于量化级别和模型类型
    • 建议在实际任务上测试量化后的模型
  2. 硬件兼容性

    • 不同量化类型对硬件要求不同
    • Q4_0 和 Q8_0 兼容性最好
    • Q2_K 和 IQ1 可能需要特定硬件支持
  3. 内存占用

    • 量化后的模型仍需加载到内存
    • 运行时内存占用约为模型大小的 1.5-2 倍
    • 需预留足够的内存空间
  4. 推理速度

    • 量化级别越低,推理速度越快
    • 但质量也会相应下降
    • 需根据实际需求权衡
  5. GGUF 文件类型

    • general.file_type 元数据类型表示量化类型
    • 常见值:1 (F32), 2 (F16), 7 (Q8_0), 8 (Q4_K_M), 15 (Q2_K)
  6. 量化版本

    • general.quantize_version 表示量化版本
    • 版本 2 是当前推荐的版本
    • 新版本可能包含量化算法改进
  7. 混合量化(Mixed Quantization)

    基本概念

    • 混合量化是指对模型中不同的层或张量使用不同的量化类型
    • 核心思想:对模型输出影响大的层使用高精度,影响小的层使用低精度
    • 优势:在保持模型质量的同时,进一步减小模型体积

    为什么需要混合量化

    • 不同层对模型质量的贡献不同
    • 例如:embedding 层直接影响词汇理解,需要更高精度
    • 中间层可能对质量影响相对较小,可以使用更低精度
    • 全局统一量化无法平衡质量和体积

    常见的混合量化策略

    策略名称高精度层低精度层适用场景
    嵌入层优先Embedding (Q8_0)其他层 (Q4_K_M)通用场景
    输出层优先Output/Embedding (Q8_0)中间层 (Q4_K_M)需要高质量输出
    关键层优先Attention (Q6_K)FFN (Q4_K_M)需要保持推理能力
    分层量化前几层 (Q6_K)后几层 (Q4_K_M)长文本生成

    混合量化命令示例

    # 指定 embedding 层使用 Q8_0,其他层使用 Q4_K_M
    ./quantize --embedding-qtype q8_0 input.gguf output.gguf q4_K_M
    
    # 指定 output 张量使用 Q8_0,其他层使用 Q4_K_M
    ./quantize --output-tensor q8_0 input.gguf output.gguf q4_K_M
    
    # 同时指定 embedding 和 output 使用高精度
    ./quantize --embedding-qtype q8_0 --output-tensor q8_0 input.gguf output.gguf q4_K_M
    
    # 指定特定层范围使用不同精度
    ./quantize --layer-range 0-10 q6_k --layer-range 11-31 q4_k input.gguf output.gguf q4_K_M
    

    混合量化的工作原理

    原始模型 (FP16):
    ├── Embedding Layer (重要) → 量化为 Q8_0
    ├── Attention Layer 0-15 (关键) → 量化为 Q6_K
    ├── FFN Layer 0-15 (一般) → 量化为 Q4_K_M
    ├── Attention Layer 16-31 (关键) → 量化为 Q6_K
    ├── FFN Layer 16-31 (一般) → 量化为 Q4_K_M
    └── Output Layer (重要) → 量化为 Q8_0
    
    混合量化后:
    - 关键层保持高质量 (Q8_0, Q6_K)
    - 非关键层大幅压缩 (Q4_K_M)
    - 整体体积比全局 Q4_K_M 略大,但质量更好
    

    混合量化的效果对比

    量化方式7B模型大小困惑度 (PPL)质量评价
    全局 Q4_K_M4.1GB6.5★★★☆☆
    全局 Q6_K5.5GB5.8★★★★☆
    混合量化 (Embedding+Output Q8_0)4.5GB6.0★★★★☆
    混合量化 (关键层 Q6_K)5.0GB5.9★★★★☆

    选择建议

    • 内存充足:使用全局 Q6_K 或关键层 Q6_K 的混合量化
    • 内存受限:使用全局 Q4_K_M 或 Embedding Q8_0 + 其他 Q4_K_M
    • 存储受限:使用全局 Q3_K 或更低精度
    • 最佳平衡:Embedding/Output Q8_0 + 其他 Q4_K_M
  8. 量化效果评估

    • 使用 perplexity(困惑度)评估量化效果
    • 困惑度越低,量化效果越好
    • 建议在标准数据集上进行评估

量化命令示例

# 基本量化
./quantize input.gguf output.gguf q4_K_M

# 指定量化类型
./quantize input.gguf output-Q8_0.gguf q8_0
./quantize input.gguf output-Q4_K_M.gguf q4_K_M
./quantize input.gguf output-Q2_K.gguf q2_k

# 带混合量化的量化
./quantize --embedding-qtype q8_0 --output-tensor q4_K_M input.gguf output.gguf q4_K_M

特点

  • ✅ 专为大语言模型优化
  • ✅ 支持多种量化级别(Q2_K 到 F32)
  • ✅ 适合 CPU 推理
  • ✅ 文件体积可大幅压缩
  • ✅ 支持元数据嵌入
  • ✅ 单文件包含所有信息
  • ❌ 主要用于推理,不支持训练
  • ❌ 生态系统相对较小

适用场景

  • 本地大语言模型部署
  • 资源受限环境(如个人电脑)
  • 使用 llama.cpp、Ollama 等工具
  • 需要量化模型的场景
  • 边缘设备部署

示例代码

# 使用 llama.cpp 加载 GGUF 模型
from llama_cpp import Llama

# 加载模型
llm = Llama(
    model_path="model-q4_K_M.gguf",
    n_ctx=4096,          # 上下文长度
    n_threads=8,         # 线程数
    n_gpu_layers=0,      # GPU 层数(0表示纯CPU)
)

# 生成文本
output = llm(
    "Hello, how are you?",
    max_tokens=128,
    temperature=0.7,
    top_p=0.9,
)
print(output)

支持的推理框架

  • llama.cpp(原生支持)
  • Ollama(封装 llama.cpp)
  • LM Studio(GUI 工具)
  • text-generation-webui(Web UI)
  • ctransformers(Python 绑定)
  • llama-cpp-python(Python 绑定)

GGML 格式 (.ggml)

描述:llama.cpp 早期使用的模型格式,现已被 GGUF 格式取代。

历史背景

  • 2023年初:GGML 格式首次发布
  • 2023年中:GGUF 格式发布,逐步取代 GGML
  • 2024年:GGML 格式停止维护

特点

  • ✅ 专为 CPU 推理优化
  • ✅ 支持量化
  • ❌ 已被 GGUF 格式取代
  • ❌ 功能相对有限
  • ❌ 不再推荐使用

适用场景

  • 旧版 llama.cpp 项目
  • 历史项目维护

迁移建议

# 使用 llama.cpp 将 GGML 转换为 GGUF
./main --model.ggml-model.bin --convert ggml-to-gguf

Checkpoint 格式 (.ckpt)

描述:通用的模型检查点格式,用于保存训练过程中的模型状态。

文件结构(以 PyTorch Lightning 为例):

Checkpoint 文件 (.ckpt)
├── epoch                    # 当前 epoch
├── global_step              # 全局步数
├── pytorch-lightning_version # PyTorch Lightning 版本
├── callbacks                 # 回调函数状态
├── lr_schedulers            # 学习率调度器状态
├── optimizer_states         # 优化器状态
│   ├── optimizer_0
│   │   ├── state
│   │   └── param_groups
│   └── ...
├── model_state_dict         # 模型权重
├── hyperparameters          # 超参数
└── 其他训练状态

特点

  • ✅ 支持增量保存
  • ✅ 可恢复训练
  • ✅ 支持分布式训练
  • ✅ 包含优化器状态
  • ✅ 保存完整的训练状态
  • ❌ 格式因框架而异
  • ❌ 文件体积较大
  • ❌ 主要用于训练,不推荐用于部署

适用场景

  • 模型训练过程中的状态保存
  • 断点续训
  • 模型微调
  • 模型评估

示例代码

import torch
import pytorch_lightning as pl

# ===== 保存检查点 =====
# 手动保存
checkpoint = {
    'epoch': epoch,
    'global_step': global_step,
    'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
    'lr_scheduler_state_dict': scheduler.state_dict(),
    'loss': loss,
}
torch.save(checkpoint, 'manual_checkpoint.ckpt')

# 使用 PyTorch Lightning 自动保存
trainer = pl.Trainer(
    callbacks=[
        pl.callbacks.ModelCheckpoint(
            dirpath='checkpoints/',
            filename='{epoch}-{val_loss:.2f}',
            save_top_k=3,
            monitor='val_loss',
            save_last=True,
        )
    ]
)

# ===== 加载检查点 =====
# 手动加载
checkpoint = torch.load('manual_checkpoint.ckpt')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
start_epoch = checkpoint['epoch'] + 1

# 使用 PyTorch Lightning 加载
model = MyLightningModule.load_from_checkpoint('checkpoint.ckpt')

Hugging Face 格式

描述:Hugging Face Hub 使用的模型存储格式,通常包含多个文件。

典型文件结构

model-name/
├── .gitattributes           # Git LFS 配置
├── config.json              # 模型配置
├── model.safetensors        # SafeTensors 权重(新版)
├── pytorch_model.bin        # PyTorch 权重(旧版)
├── generation_config.json   # 生成配置
├── tokenizer.json           # 分词器配置
├── tokenizer_config.json    # 分词器设置
├── special_tokens_map.json  # 特殊 token 映射
├── tokenizer.model          # SentencePiece 模型
├── vocab.json               # 词汇表
├── merges.txt               # BPE 合并规则
├── preprocessor_config.json # 预处理器配置
├── feature_extractor_config.json
├── README.md                # 模型卡片
└── LICENSE                  # 许可证

config.json 示例

{
  "architectures": ["LlamaForCausalLM"],
  "hidden_size": 4096,
  "intermediate_size": 11008,
  "max_position_embeddings": 4096,
  "model_type": "llama",
  "num_attention_heads": 32,
  "num_hidden_layers": 32,
  "num_key_value_heads": 32,
  "vocab_size": 32000,
  "torch_dtype": "bfloat16",
  "transformers_version": "4.31.0",
  "hidden_act": "silu",
  "rms_norm_eps": 1e-06,
  "rope_theta": 10000.0,
  "tie_word_embeddings": false
}

特点

  • ✅ 标准化的模型仓库结构
  • ✅ 支持版本控制和共享
  • ✅ 包含模型配置和分词器
  • ✅ 支持 SafeTensors 格式
  • ✅ 社区支持广泛
  • ✅ 自动模型加载
  • ❌ 依赖 Hugging Face 生态
  • ❌ 文件大小限制(单文件 50GB)

示例代码

from transformers import AutoModel, AutoTokenizer

# 加载模型和分词器
model = AutoModel.from_pretrained("meta-llama/Llama-2-7b-hf")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")

# 保存模型(使用 SafeTensors 格式)
model.save_pretrained("./local-model", safe_serialization=True)
tokenizer.save_pretrained("./local-model")

# 从本地加载
model = AutoModel.from_pretrained("./local-model")
tokenizer = AutoTokenizer.from_pretrained("./local-model")

# 推送到 Hub
model.push_to_hub("my-model-name")

PaddlePaddle 格式 (.pdparams)

描述:PaddlePaddle 深度学习框架的原生权重格式。

特点

  • ✅ 与 PaddlePaddle 生态完全兼容
  • ✅ 支持分布式训练
  • ✅ 支持模型压缩
  • ❌ 跨框架兼容性差
  • ❌ 生态系统相对较小

示例代码

import paddle

# 保存模型权重
paddle.save(model.state_dict(), 'model.pdparams')

# 加载模型权重
state_dict = paddle.load('model.pdparams')
model.set_state_dict(state_dict)

CoreML 格式 (.mlmodel/.mlpackage)

描述:Apple 的机器学习框架格式,专为 iOS/macOS 优化。

文件结构

ML Package 目录
├── Model.mlpackage
│   ├── Data/
│   │   ├── model.mlmodel    # 模型描述
│   │   ├── weights/        # 权重数据
│   │   │   ├── weight_0.bin
│   │   │   └── ...
│   │   └── metadata.json   # 元数据
│   └── Manifest.json
└── ...

特点

  • ✅ Apple 设备原生支持
  • ✅ 支持 Neural Engine 加速
  • ✅ 支持模型加密
  • ✅ 支持隐私保护
  • ❌ 仅限 Apple 生态
  • ❌ 转换过程复杂

示例代码

import coremltools as ct

# 将 PyTorch 模型转换为 CoreML
mlmodel = ct.convert(
    model,
    inputs=[ct.ImageType(name="input", shape=(1, 3, 224, 224))],
)
mlmodel.save("model.mlpackage")

TensorRT 格式 (.engine/.plan)

描述:NVIDIA TensorRT 的高性能推理格式,专为 NVIDIA GPU 优化。

特点

  • ✅ NVIDIA GPU 最优性能
  • ✅ 支持 FP16/INT8 推理
  • ✅ 自动内核调优
  • ✅ 支持动态形状
  • ❌ 仅限 NVIDIA GPU
  • ❌ 转换过程耗时
  • ❌ 与硬件绑定

示例代码

import tensorrt as trt

# 从 ONNX 构建 TensorRT 引擎
logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)
network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
parser = trt.OnnxParser(network, logger)

# 解析 ONNX 文件
with open('model.onnx', 'rb') as f:
    parser.parse(f.read())

# 构建引擎
config = builder.create_builder_config()
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30)  # 1GB
engine = builder.build_serialized_network(network, config)

# 保存引擎
with open('model.engine', 'wb') as f:
    f.write(engine)

格式对比

综合对比表

格式扩展名安全性加载速度文件大小跨框架量化支持主要用途
PyTorch.pt/.pth⚠️ 低训练/推理
SafeTensors.safetensors✅ 高分发/推理
ONNX.onnx✅ 高部署/推理
TensorFlow.h5/.pb✅ 高训练/推理
GGUF.gguf✅ 高小-大本地推理
GGML.ggml✅ 高小-大已废弃
Checkpoint.ckpt⚠️ 低训练
PaddlePaddle.pdparams⚠️ 低训练/推理
CoreML.mlpackage✅ 高Apple 生态
TensorRT.engine✅ 高最快小-中NVIDIA GPU

场景对比表

使用场景推荐格式备选格式原因
模型训练PyTorch / CheckpointTensorFlow支持优化器状态保存
模型分发SafeTensorsGGUF安全、快速、标准化
生产部署ONNXSafeTensors推理性能优秀
本地 LLMGGUFSafeTensors量化支持好
移动端CoreML (iOS) / TFLite (Android)ONNX平台原生支持
NVIDIA GPUTensorRTONNXGPU 最优性能
边缘设备ONNX + INT8GGUF体积小、速度快
模型微调PyTorchCheckpoint支持断点续训
模型共享SafeTensors (Hugging Face)-社区标准

选择建议

训练阶段

  • 推荐:PyTorch (.pt/.pth) 或 Checkpoint (.ckpt)
  • 原因:支持保存优化器状态,便于断点续训
  • 注意事项
    • 定期保存检查点,防止训练中断
    • 保存完整的训练状态(模型、优化器、学习率调度器)
    • 使用框架提供的自动保存机制

模型分发

  • 推荐:SafeTensors (.safetensors)
  • 原因:安全、快速、文件适中
  • 注意事项
    • 单文件模型:直接使用 model.safetensors
    • 大模型分片:使用 model-00001-of-0000X.safetensors + 索引文件
    • 包含完整的模型配置和 tokenizer

生产部署

  • 推荐:ONNX (.onnx) 或 SafeTensors (.safetensors)
  • 原因:推理性能好,支持优化和量化
  • 注意事项
    • 使用 ONNX Runtime 或 TensorRT 进行推理
    • 考虑量化以提升性能
    • 使用模型优化工具(如 onnx-simplifier)

本地 LLM 部署

  • 推荐:GGUF (.gguf)
  • 原因:专为本地推理优化,支持多种量化级别
  • 注意事项
    • 根据硬件选择合适的量化级别
    • Q4_K_M 是平衡性能和质量的推荐选择
    • 使用 llama.cpp 或 Ollama 加载模型

跨平台部署

  • 推荐:ONNX (.onnx)
  • 原因:跨框架兼容性最好
  • 注意事项
    • 注意算子集版本兼容性
    • 验证目标平台的 ONNX Runtime 支持
    • 使用 onnx-simplifier 简化模型

资源受限环境

  • 推荐:GGUF (.gguf) 配合量化
  • 原因:可大幅压缩模型体积
  • 注意事项
    • 根据设备性能选择量化级别
    • 考虑内存占用和推理速度
    • 测试量化后的模型质量

Apple 生态

  • 推荐:CoreML (.mlpackage)
  • 原因:Apple 设备原生支持,性能最优
  • 注意事项
    • 使用 coremltools 转换模型
    • 支持 Neural Engine 加速
    • 注意模型大小限制

转换工具

1. PyTorch ↔ SafeTensors

pip install safetensors
from safetensors.torch import load_file, save_file
import torch

# PyTorch → SafeTensors
def pth_to_safetensors(input_path, output_path):
    state_dict = torch.load(input_path, map_location='cpu', weights_only=True)
    save_file(state_dict, output_path)
    print(f"转换完成: {output_path}")

# SafeTensors → PyTorch
def safetensors_to_pth(input_path, output_path):
    state_dict = load_file(input_path, device='cpu')
    torch.save(state_dict, output_path)
    print(f"转换完成: {output_path}")

# 使用示例
pth_to_safetensors('model.pth', 'model.safetensors')
safetensors_to_pth('model.safetensors', 'model.pth')

2. PyTorch → ONNX

pip install onnx onnxruntime onnx-simplifier
import torch
import torch.onnx

def export_to_onnx(model, dummy_input, output_path, opset_version=17):
    model.eval()
    torch.onnx.export(
        model,
        dummy_input,
        output_path,
        export_params=True,
        opset_version=opset_version,
        do_constant_folding=True,
        input_names=['input'],
        output_names=['output'],
        dynamic_axes={
            'input': {0: 'batch_size'},
            'output': {0: 'batch_size'}
        }
    )
    
    # 验证模型
    import onnx
    onnx_model = onnx.load(output_path)
    onnx.checker.check_model(onnx_model)
    
    # 简化模型
    from onnxsim import simplify
    model_simp, check = simplify(onnx_model)
    assert check, "简化失败"
    onnx.save(model_simp, output_path)
    print(f"转换完成: {output_path}")

# 使用示例
dummy_input = torch.randn(1, 3, 224, 224)
export_to_onnx(model, dummy_input, 'model.onnx')

3. Hugging Face 模型转换

from transformers import AutoModel, AutoTokenizer

def convert_hf_model(model_name, output_dir, format='safetensors'):
    # 下载模型
    model = AutoModel.from_pretrained(model_name)
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    
    # 保存模型
    if format == 'safetensors':
        model.save_pretrained(output_dir, safe_serialization=True)
    else:
        model.save_pretrained(output_dir, safe_serialization=False)
    
    tokenizer.save_pretrained(output_dir)
    print(f"模型已保存到: {output_dir}")

# 使用示例
convert_hf_model('meta-llama/Llama-2-7b-hf', './local-model')

4. GGUF 转换(使用 llama.cpp)

# 克隆 llama.cpp
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
pip install -r requirements.txt

# 转换 HF 模型为 GGUF
python convert-hf-to-gguf.py ../model-name \
    --outfile model-f16.gguf \
    --outtype f16

# 量化模型
./quantize model-f16.gguf model-q4_K_M.gguf q4_K_M

# 验证模型
./main -m model-q4_K_M.gguf -p "Hello, how are you?" -n 128

5. 使用 Optimum(Hugging Face)

pip install optimum[onnxruntime]
# 导出为 ONNX
optimum-cli export onnx --model model-name ./onnx-model/

# 量化 ONNX 模型
optimum-cli export onnx --model model-name --quantize int8 ./onnx-model-int8/

6. ONNX ↔ TensorRT

pip install tensorrt
# 使用 trtexec 转换
trtexec --onnx=model.onnx --saveEngine=model.engine --fp16

# 使用 Python API
import tensorrt as trt

def onnx_to_tensorrt(onnx_path, engine_path, fp16=True):
    logger = trt.Logger(trt.Logger.WARNING)
    builder = trt.Builder(logger)
    network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
    parser = trt.OnnxParser(network, logger)
    
    with open(onnx_path, 'rb') as f:
        parser.parse(f.read())
    
    config = builder.create_builder_config()
    config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30)
    
    if fp16 and builder.platform_has_fast_fp16:
        config.set_flag(trt.BuilderFlag.FP16)
    
    engine = builder.build_serialized_network(network, config)
    
    with open(engine_path, 'wb') as f:
        f.write(engine)
    print(f"转换完成: {engine_path}")

最佳实践

1. 训练阶段

# 定期保存检查点
checkpoint_callback = pl.callbacks.ModelCheckpoint(
    dirpath='checkpoints/',
    filename='{epoch}-{val_loss:.2f}',
    save_top_k=3,           # 保留最好的3个检查点
    monitor='val_loss',
    save_last=True,         # 保存最后一个检查点
    save_on_train_epoch_end=True,
)

# 保存模型时包含完整状态
checkpoint = {
    'epoch': epoch,
    'global_step': global_step,
    'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
    'lr_scheduler_state_dict': scheduler.state_dict(),
    'best_metric': best_metric,
}
torch.save(checkpoint, f'checkpoints/checkpoint-{epoch}.pth')

2. 模型分发

# 使用 SafeTensors 格式分发
model.save_pretrained(
    output_dir,
    safe_serialization=True,  # 使用 SafeTensors 格式
    max_shard_size='5GB',     # 分片大小限制
)

# 创建模型卡片
from huggingface_hf_api import HfApi
api = HfApi()
api.upload_folder(
    folder_path=output_dir,
    repo_id="username/model-name",
    repo_type="model",
)

3. 模型优化

# ONNX 模型优化
import onnx
from onnxsim import simplify

# 简化模型
model = onnx.load('model.onnx')
model_simp, check = simplify(model)
assert check, "简化失败"
onnx.save(model_simp, 'model_simplified.onnx')

# 量化模型
from onnxruntime.quantization import quantize_dynamic, QuantType
quantize_dynamic(
    'model_simplified.onnx',
    'model_int8.onnx',
    weight_type=QuantType.QInt8
)

4. 版本控制

# 使用 DVC (Data Version Control) 管理大模型
pip install dvc

# 初始化 DVC
dvc init

# 添加模型文件
dvc add models/model.safetensors

# 提交更改
git add models/model.safetensors.dvc .gitignore
git commit -m "Add model v1.0"

# 存储到远程
dvc remote add -d myremote s3://my-bucket/models
dvc push

常见问题

Q1: SafeTensors 和 PyTorch 格式有什么区别?

A:

  • 安全性:SafeTensors 不使用 pickle,避免了代码执行风险
  • 速度:SafeTensors 加载速度比 PyTorch 快 3-10 倍
  • 大小:SafeTensors 文件通常比 PyTorch 小
  • 兼容性:SafeTensors 支持懒加载,PyTorch 不支持

Q2: 如何选择 GGUF 的量化级别?

A:

  • 高质量需求:Q8_0 或 F16
  • 平衡选择:Q4_K_M(推荐)
  • 资源受限:Q2_K 或 Q3_K_M
  • 测试建议:从 Q4_K_M 开始,根据质量和性能调整

Q3: ONNX 模型转换失败怎么办?

A:

  • 检查 PyTorch 版本和 ONNX 版本兼容性
  • 尝试降低 opset_version
  • 使用 torch.onnx.exportverbose=True 查看详细错误
  • 检查是否有不支持的算子
  • 使用 onnx-simplifier 简化模型

Q4: 如何验证模型转换的正确性?

A:

import torch
import numpy as np

# 比较原始模型和转换模型的输出
def verify_conversion(original_model, converted_model, input_data):
    original_model.eval()
    converted_model.eval()
    
    with torch.no_grad():
        original_output = original_model(input_data)
        converted_output = converted_model(input_data)
    
    # 计算差异
    diff = torch.abs(original_output - converted_output)
    max_diff = diff.max().item()
    mean_diff = diff.mean().item()
    
    print(f"最大差异: {max_diff}")
    print(f"平均差异: {mean_diff}")
    
    # 判断是否在可接受范围内
    assert max_diff < 1e-3, "转换验证失败"
    print("转换验证通过")

Q5: 如何处理大模型的分片文件?

A:

from safetensors import safe_open
import torch

def load_sharded_model(model_dir, index_file='model.safetensors.index.json'):
    import json
    
    # 读取索引文件
    with open(f'{model_dir}/{index_file}', 'r') as f:
        index = json.load(f)
    
    # 获取所有分片文件
    shard_files = set(index['weight_map'].values())
    
    # 加载所有分片
    state_dict = {}
    for shard_file in shard_files:
        with safe_open(f'{model_dir}/{shard_file}', framework='pt', device='cpu') as f:
            for key in f.keys():
                state_dict[key] = f.get_tensor(key)
    
    return state_dict

Q6: 如何加密模型权重文件?

A:

from cryptography.fernet import Fernet
import pickle

# 生成密钥
key = Fernet.generate_key()
cipher = Fernet(key)

# 加密模型
def encrypt_model(model_path, encrypted_path, key):
    with open(model_path, 'rb') as f:
        data = f.read()
    
    encrypted_data = cipher.encrypt(data)
    
    with open(encrypted_path, 'wb') as f:
        f.write(encrypted_data)

# 解密模型
def decrypt_model(encrypted_path, key):
    cipher = Fernet(key)
    
    with open(encrypted_path, 'rb') as f:
        encrypted_data = f.read()
    
    decrypted_data = cipher.decrypt(encrypted_data)
    state_dict = pickle.loads(decrypted_data)
    
    return state_dict

文档生成时间:2026-06-11

更多推荐