常见人工智能模型格式

社区文章 发布于 2025 年 2 月 27 日

cover

本文镜像自 https://blog.ngxson.com/common-ai-model-formats

📻 🎙️ 这是关于这篇博文的 AI 播客,欢迎收听!

此播客通过 ngxson/kokoro-podcast-generator 生成,使用了 DeepSeek-R1Kokoro-TTS

在过去的两年里,开源 AI 社区对新 AI 模型的开发充满热情。每天都有越来越多的模型在 Hugging Face 上发布,其中许多模型已用于生产应用。然而,开发者在使用这些模型时遇到的一个挑战是它们所采用的各种格式。

在本文中,我们将探讨当前常用的一些 AI 模型格式,包括 GGUF、PyTorch、Safetensors 和 ONNX。我们将讨论每种格式的优缺点,并提供何时使用它们的指导。

GGUF

GGUF 最初是为 llama.cpp 项目开发的。GGUF 是一种二进制格式,旨在实现快速模型加载和保存,并易于阅读。模型通常使用 PyTorch 或其他框架开发,然后转换为 GGUF 以与 GGML 配合使用。

随着时间的推移,GGUF 已成为开源社区中共享 AI 模型最流行的格式之一。它受到众多知名推理运行时的支持,包括 llama.cppollamavLLM

目前,GGUF 主要用于语言模型。虽然也可以将其用于其他类型的模型,例如通过 stable-diffusion.cpp 实现的扩散模型,但它不如其在语言模型中的应用常见。

GGUF 文件包括:

  • 一个以键值对形式组织的元数据部分。此部分包含模型的架构、版本和超参数等信息。
  • 一个用于张量元数据的部分。此部分包含模型中张量的详细信息,例如它们的形状、数据类型和名称。
  • 最后,是包含张量数据本身的部分。

diagram of GGUF format structure 图片来自 @mishig25 (GGUF v3)

GGUF 格式和 GGML 库还提供灵活的**量化方案**,可实现高效的模型存储,同时保持良好的准确性。一些最常见的量化方案有:

  • Q4_K_M:大多数张量被量化为 4 位,部分量化为 6 位。这是最常用的量化方案。
  • IQ4_XS:几乎所有张量都量化为 4 位,但借助**重要性矩阵**。此矩阵用于校准每个张量的量化,可能会在保持存储效率的同时提高准确性。
  • IQ2_M:与 IQ4_XS 类似,但采用 2 位量化。这是最具侵略性的量化方案,但仍能在某些模型上达到良好精度。适用于内存非常有限的硬件。
  • Q8_0:所有张量均量化为 8 位。这是侵略性最低的量化方案,精度几乎与原始模型相同。

Example of Llama-3.1 8B model in GGUF format Llama-3.1 8B 模型 GGUF 格式示例,链接在此

让我们回顾一下 GGUF 的优缺点:

  • 优点:
    • 简单:单文件格式易于共享和分发。
    • 快速:通过与 mmap() 的兼容性实现模型的快速加载和保存。
    • 高效:提供灵活的量化方案。
    • 可移植:作为二进制格式,无需特定库即可轻松读取。
  • 缺点:
    • 大多数模型需要从其他格式(PyTorch、Safetensors)转换为 GGUF。
    • 并非所有模型都可转换。有些模型不受 llama.cpp 支持。
    • 模型保存为 GGUF 后,修改或微调模型并不容易。

GGUF 主要用于在生产环境中**提供模型服务**,在这些环境中快速加载时间至关重要。它也用于在开源社区中**共享模型**,因为这种格式的简单性便于分发。

有用的资源

  • llama.cpp 项目,提供将 HF 模型转换为 GGUF 的脚本。
  • HF 上的 gguf-my-repo 空间允许将模型转换为 GGUF 格式,无需本地下载。
  • ollamaHF-ollama 集成允许通过 ollama run 命令从 HF Hub 运行任何 GGUF 模型。

PyTorch (.pt/.pth)

.pt/.pth 扩展名代表 PyTorch 的默认序列化格式,用于存储包含学习参数(权重、偏差)、优化器状态和训练元数据的模型状态字典。

PyTorch 模型可以保存为两种格式:

  • .pt:这种格式保存整个模型,包括其架构和学习参数。
  • .pth:这种格式只保存模型的状态字典,其中包含模型的学习参数和一些元数据。

PyTorch 格式基于 Python 的 pickle 模块,该模块用于序列化 Python 对象。为了理解 pickle 的工作原理,让我们看下面的例子:

import pickle
model_state_dict = { "layer1": "hello", "layer2": "world" }
pickle.dump(model_state_dict, open("model.pkl", "wb"))

pickle.dump() 函数序列化 model_state_dict 字典并将其保存到名为 model.pkl 的文件中。输出文件现在包含字典的二进制表示:

model.pkl hex view

要将序列化后的字典加载回 Python,我们可以使用 pickle.load() 函数:

import pickle
model_state_dict = pickle.load(open("model.pkl", "rb"))
print(model_state_dict)
# Output: {'layer1': 'hello', 'layer2': 'world'}

正如您所见,pickle 模块提供了一种简便的 Python 对象序列化方法。然而,它也存在一些局限性:

  • 安全性:任何东西都可以被 pickle,**包括恶意代码**。如果序列化数据未经验证,这可能导致安全漏洞。例如,Snyk 的这篇文章解释了如何对 pickle 文件进行后门攻击
  • 效率:它并非为延迟加载或部分数据加载而设计。这可能导致处理大型模型时加载缓慢内存使用率高
  • 可移植性:它特定于 Python,这使得与其他语言共享模型变得困难。

如果您只在 Python 和 PyTorch 环境中工作,PyTorch 格式可能是一个合适的选择。然而,近年来,AI 社区已转向更高效和安全的序列化格式,例如 GGUF 和 Safetensors。

有用的资源

  • PyTorch 文档关于保存和加载模型。
  • executorch 项目提供了一种将 PyTorch 模型转换为 .pte 的方法,该格式可在移动和边缘设备上运行。

Safetensors

由 Hugging Face 开发的 safetensors 解决了传统 Python 序列化方法(如 PyTorch 使用的 pickle)中存在的安全和效率限制。该格式使用受限的反序列化过程来防止代码执行漏洞。

一个 safetensors 文件包含:

  • 一个以 JSON 格式保存的元数据部分。此部分包含模型中所有张量的信息,例如它们的形状、数据类型和名称。它还可以选择包含自定义元数据。
  • 一个用于张量数据的部分。

Diagram of Safetensors format structure Safetensors 格式结构图

  • 优点:
    • 安全:Safetensors 采用受限的反序列化过程,以防止代码执行漏洞。
    • 快速:它专为延迟加载和部分数据加载而设计,可以缩短加载时间并降低内存使用量。这类似于 GGUF,您可以在其中 mmap() 文件。
    • 高效:支持量化张量。
    • 可移植:它旨在跨不同编程语言移植,从而便于与其他语言共享模型。
  • 缺点:
    • 量化方案不如 GGUF 灵活。这主要是由于 PyTorch 提供的量化支持。
    • 需要一个 JSON 解析器来读取元数据部分。当使用 C++ 等没有内置 JSON 支持的低级语言时,这可能会出现问题。

注:虽然理论上元数据可以保存在文件中,但实际上,模型元数据通常存储在单独的 JSON 文件中。这既有利也有弊,具体取决于用例。

Safetensors 格式是 Hugging Face 的 transformers 库使用的默认序列化格式。它在开源社区中广泛用于**共享、训练、微调和提供 AI 模型服务**。Hugging Face 上发布的新模型都以 safetensors 格式存储,包括 Llama、Gemma、Phi、Stable-Diffusion、Flux 等等。

有用的资源

  • transformers 库关于保存和加载模型的文档。
  • bitsandbytes 指南,介绍了如何量化模型并将其保存为 safetensors 格式。
  • HF 上的 mlx-community 组织提供与 MLX 框架(Apple Silicon)兼容的模型。

ONNX

开放神经网络交换(ONNX)格式提供了机器学习模型的供应商中立表示。它是 ONNX 生态系统的一部分,该生态系统包括用于 PyTorch、TensorFlow 和 MXNet 等不同框架之间互操作性的工具和库。

ONNX 模型以 .onnx 扩展名保存为单个文件。与 GGUF 或 Safetensors 不同,ONNX 不仅包含模型的张量和元数据,还包含模型的**计算图**。

将计算图包含在模型文件中,使得处理模型时具有更大的灵活性。例如,当发布新模型时,您可以轻松地将其转换为 ONNX 格式,而无需担心模型的架构或推理代码,因为计算图已保存在文件中。

Example for a compute graph in ONNX format ONNX 格式计算图示例,由 Netron 生成

  • 优点:
    • 灵活性:模型文件中包含计算图,在不同框架之间转换模型时提供更大的灵活性。
    • 可移植性:得益于 ONNX 生态系统,ONNX 格式可以轻松部署到各种平台和设备,包括移动设备和边缘设备。
  • 缺点:
    • 对量化张量的支持有限。ONNX 不原生支持量化张量,而是将其分解为整数张量和比例因子张量。这可能导致处理量化模型时质量下降。
    • 复杂的架构可能需要运算符回退或自定义实现来处理不受支持的层。这可能会导致将模型转换为 ONNX 格式时性能下降。

总的来说,如果您正在使用移动设备或进行浏览器内推理,ONNX 是一个不错的选择。

有用的资源

  • Hugging Face 上的 onnx-community 组织,提供 ONNX 格式模型以及转换指南。
  • transformer.js 项目,允许在浏览器中使用 WebGPU 或 WebAssembly 运行 ONNX 模型。
  • onnxruntime 项目提供了一个在各种平台和硬件上运行的高性能推理引擎。
  • netron 项目,允许在浏览器中可视化 ONNX 模型。

硬件支持

选择模型格式时,考虑模型将部署的硬件至关重要。下表显示了每种格式的硬件支持建议:

硬件 GGUF PyTorch Safetensors ONNX
CPU ✅ (最佳) 🟡 🟡
GPU
移动部署 🟡 (通过 executorch)
Apple 芯片 🟡 ✅ (通过 MLX 框架)

说明

  • ✅:完全支持
  • 🟡:部分支持或性能较低
  • ❌:不支持

结论

在本文中,我们探讨了目前常用的一些 AI 模型格式,包括 GGUF、PyTorch、Safetensors 和 ONNX。每种格式都有其自身的优缺点,因此根据您的具体用例和硬件要求选择正确的格式至关重要。

脚注

mmap:内存映射文件是一种操作系统功能,允许将文件映射到内存中。这对于读取和写入大型文件非常有利,而无需将整个文件加载到内存中。

延迟加载:延迟加载是一种技术,它将数据的加载推迟到实际需要时才进行。这有助于减少内存使用量并提高处理大型模型时的性能。

计算图:在机器学习的上下文中,计算图是一种流程图,它说明了数据如何流经模型以及如何在每个步骤执行不同的计算(例如加法、乘法或激活函数应用)。

社区

嗨,谢谢分享!您能否详细说明为什么很难微调或修改使用 GGUF 保存的模型?

·
文章作者

至于微调,社区曾一度尝试将此功能添加到 llama.cpp 中,但事实证明维护起来过于复杂。截至本文撰写之时,在 GPU 上对 llama.cpp 进行微调的功能尚不存在。

而对于修改,很明显所有元数据和张量都烘焙到一个文件中,这使得编辑变得困难。例如,对于 safetensors 模型,修改聊天模板很简单:它存储在 tokenizer_config.json 中。但对于 GGUF,您需要使用一个特殊脚本,该脚本不是修改,而是创建一个带有修改后的元数据的新 GGUF。

注册登录 以评论