当前位置: 首页 > news >正文

GGUF 文件格式全解析

在机器学习领域,模型的存储和部署一直是关键环节。随着大语言模型 (LLM) 的广泛应用,如何高效地存储和加载这些复杂的模型成为一个亟待解决的问题。GGUF(GGML Universal Format)作为一种新兴的二进制文件格式,旨在解决传统 GGML 及其衍生格式(如 GGMF 和 GGJT)的局限性,为模型推理提供更高效、更灵活的解决方案。

官方介绍:https://github.com/ggml-org/ggml/blob/master/docs/gguf.md

GGUF 文件格式全解析

  • 一、关于 GGUF
  • 二、GGUF 规范
  • 三、GGUF 命名约定
  • 四、GGUF 文件结构

一、关于 GGUF

GGUF 是一种用于存储模型以便与 GGML 及其基于 GGML 的执行器进行推理的文件格式。GGUF 是一种二进制格式,设计目的是为了快速加载和保存模型,并便于读取。模型通常使用 PyTorch 或其他框架开发,然后转换为 GGUF 以在 GGML 中使用。

它是 GGML、GGMF 和 GGJT 的后继文件格式,旨在通过包含加载模型所需的所有信息来消除歧义,同时设计为可扩展,以便在不破坏兼容性的情况下为模型添加新信息。

二、GGUF 规范

GGUF 是一种基于现有 GGJT 格式的格式,但对其进行了一些更改,使其更具扩展性和易用性。以下是期望的功能:

  • 单文件部署:易于分发和加载,不需要额外的外部文件提供附加信息。
  • 可扩展性:可以在不破坏现有模型兼容性的情况下,为基于 GGML 的执行器添加新功能或为 GGUF 模型添加新信息。
  • mmap 兼容性:模型可以使用 mmap 加载,以实现快速加载和保存。
  • 易于使用:通过少量代码即可轻松加载和保存模型,无需外部库,且不受所用语言限制。
  • 完整信息:加载模型所需的所有信息都包含在模型文件中,用户无需提供额外信息。

GGJT 与 GGUF 的关键区别在于,超参数(现称为元数据)使用了键值结构,而不是无类型的数值列表。这允许在不破坏现有模型兼容性的情况下添加新元数据,并为模型添加可能对推理或识别模型有用的附加信息。

三、GGUF 命名约定

GGUF 遵循 .gguf 的命名约定,其中每个组件如果存在则由 - 分隔。最终目的是让人类能够一目了然地了解模型的最重要细节。由于现有 GGUF 文件名的多样性,这一命名约定并非旨在实现完美的字段解析。

组件包括:

  1. BaseName:模型基础类型或架构的描述性名称。
    • 可从 GGUF 元数据 general.basename 派生,将空格替换为短划线。
  2. SizeLabel:参数权重类别(适用于排行榜),表示为 x。
    • 可从 GGUF 元数据 general.size_label 派生(若存在),或在缺失时计算。
    • 支持带单个字母比例前缀的四舍五入小数点计数,以辅助显示浮点指数,如下所示:
      • Q:千万亿参数。
      • T:万亿参数。
      • B:十亿参数。
      • M:百万参数。
      • K:千参数。
    • 可根据需要附加额外的 - 来表示其他感兴趣的属性。
  3. FineTune:模型微调目标的描述性名称(例如 Chat、Instruct 等)。
    • 可从 GGUF 元数据 general.finetune 派生,将空格替换为短划线。
  4. Version:(可选)表示模型版本号,格式为 v.。
    • 如果模型缺少版本号,则假定为 v1.0(首次公开发布)。
    • 可从 GGUF 元数据 general.version 派生。
  5. Encoding:表示应用于模型的权重编码方案。内容、类型混合和排列由用户代码决定,可能因项目需求而异。
  6. Type:表示 GGUF 文件的类型及其预期用途。
    • 如果缺失,则文件默认是一个典型的 GGUF 张量模型文件。
    • LoRA:GGUF 文件是一个 LoRA 适配器。
    • vocab:仅包含词汇表数据和元数据的 GGUF 文件。
  7. Shard:(可选)表示模型已被分成多个分片,格式为 -of-。
    • ShardNum:此模型中的分片位置,必须为 5 位数字,用零填充。
      • 分片编号始终从 00001 开始(例如,第一个分片始终为 00001-of-XXXXX,而不是 00000-of-XXXXX)。
    • ShardTotal:此模型中的分片总数,必须为 5 位数字,用零填充。

验证上述命名约定

至少,所有模型文件应包含 BaseName、SizeLabel 和 Version,以便轻松验证其是否符合 GGUF 命名约定。例如,如果省略 Version,则 Encoding 可能被误认为是 FineTune。

可以使用以下正则表达式进行验证:^(?<BaseName>[A-Za-z0-9\s]*(?:(?:-(?:(?:[A-Za-z\s][A-Za-z0-9\s]*)|(?:[0-9\s]*)))*))-(?:(?<SizeLabel>(?:\d+x)?(?:\d+\.)?\d+[A-Za-z](?:-[A-Za-z]+(\d+\.)?\d+[A-Za-z]+)?)(?:-(?<FineTune>[A-Za-z0-9\s-]+))?)?-(?:(?<Version>v\d+(?:\.\d+)*))(?:-(?<Encoding>(?!LoRA|vocab)[\w_]+))?(?:-(?<Type>LoRA|vocab))?(?:-(?<Shard>\d{5}-of-\d{5}))?\.gguf$,它将检查 BaseName、SizeLabel 和 Version 是否按照正确顺序存在。

例如:

  • Mixtral-8x7B-v0.1-KQ2.gguf:
    • 模型名称:Mixtral
    • 专家数量:8
    • 参数数量:7B
    • 版本号:v0.1
    • 权重编码方案:KQ2
  • Hermes-2-Pro-Llama-3-8B-F16.gguf:
    • 模型名称:Hermes 2 Pro Llama 3
    • 专家数量:0
    • 参数数量:8B
    • 版本号:v1.0
    • 权重编码方案:F16
    • 分片:无
  • Grok-100B-v1.0-Q4_0-00003-of-00009.gguf:
    • 模型名称:Grok
    • 专家数量:0
    • 参数数量:100B
    • 版本号:v1.0
    • 权重编码方案:Q4_0
    • 分片:共 9 个分片中的第 3 个

四、GGUF 文件结构

在这里插入图片描述

GGUF 文件结构如下。它们使用由 general.alignment 元数据字段指定的全局对齐(下文称为 ALIGNMENT)。必要时,文件会用 0x00 字节填充至 general.alignment 的下一个倍数。

字段(包括数组)按顺序写入,除非另有说明,否则不进行对齐。

模型默认使用小端序(little-endian)。它们也可以使用大端序(big-endian)以适应大端序计算机;在这种情况下,所有值(包括元数据值和张量)也将是大端序。目前无法确定模型是否为大端序,这一问题可能在未来版本中得到修正。如果未提供额外信息,则假定模型为小端序。

enum ggml_type: uint32_t {
    GGML_TYPE_F32     = 0,
    GGML_TYPE_F16     = 1,
    GGML_TYPE_Q4_0    = 2,
    GGML_TYPE_Q4_1    = 3,
    // GGML_TYPE_Q4_2 = 4, 支持已移除
    // GGML_TYPE_Q4_3 = 5, 支持已移除
    GGML_TYPE_Q5_0    = 6,
    GGML_TYPE_Q5_1    = 7,
    GGML_TYPE_Q8_0    = 8,
    GGML_TYPE_Q8_1    = 9,
    GGML_TYPE_Q2_K    = 10,
    GGML_TYPE_Q3_K    = 11,
    GGML_TYPE_Q4_K    = 12,
    GGML_TYPE_Q5_K    = 13,
    GGML_TYPE_Q6_K    = 14,
    GGML_TYPE_Q8_K    = 15,
    GGML_TYPE_IQ2_XXS = 16,
    GGML_TYPE_IQ2_XS  = 17,
    GGML_TYPE_IQ3_XXS = 18,
    GGML_TYPE_IQ1_S   = 19,
    GGML_TYPE_IQ4_NL  = 20,
    GGML_TYPE_IQ3_S   = 21,
    GGML_TYPE_IQ2_S   = 22,
    GGML_TYPE_IQ4_XS  = 23,
    GGML_TYPE_I8      = 24,
    GGML_TYPE_I16     = 25,
    GGML_TYPE_I32     = 26,
    GGML_TYPE_I64     = 27,
    GGML_TYPE_F64     = 28,
    GGML_TYPE_IQ1_M   = 29,
    GGML_TYPE_COUNT,
};

enum gguf_metadata_value_type: uint32_t {
    // 值是 8 位无符号整数。
    GGUF_METADATA_VALUE_TYPE_UINT8 = 0,
    // 值是 8 位有符号整数。
    GGUF_METADATA_VALUE_TYPE_INT8 = 1,
    // 值是 16 位无符号小端整数。
    GGUF_METADATA_VALUE_TYPE_UINT16 = 2,
    // 值是 16 位有符号小端整数。
    GGUF_METADATA_VALUE_TYPE_INT16 = 3,
    // 值是 32 位无符号小端整数。
    GGUF_METADATA_VALUE_TYPE_UINT32 = 4,
    // 值是 32 位有符号小端整数。
    GGUF_METADATA_VALUE_TYPE_INT32 = 5,
    // 值是 32 位 IEEE754 浮点数。
    GGUF_METADATA_VALUE_TYPE_FLOAT32 = 6,
    // 值是布尔值。
    // 1 字节值,其中 0 表示假,1 表示真。
    // 其他任何值均无效,应视为模型无效或读取器有错误。
    GGUF_METADATA_VALUE_TYPE_BOOL = 7,
    // 值是 UTF-8 非空终止字符串,前置长度。
    GGUF_METADATA_VALUE_TYPE_STRING = 8,
    // 值是其他值的数组,前置长度和类型。
    // 数组可以嵌套,数组长度是元素数量而非字节数。
    GGUF_METADATA_VALUE_TYPE_ARRAY = 9,
    // 值是 64 位无符号小端整数。
    GGUF_METADATA_VALUE_TYPE_UINT64 = 10,
    // 值是 64 位有符号小端整数。
    GGUF_METADATA_VALUE_TYPE_INT64 = 11,
    // 值是 64 位 IEEE754 浮点数。
    GGUF_METADATA_VALUE_TYPE_FLOAT64 = 12,
};

// GGUF 中的字符串。
struct gguf_string_t {
    // 字符串的字节长度。
    uint64_t len;
    // UTF-8 非空终止字符串。
    char string[len];
};

union gguf_metadata_value_t {
    uint8_t uint8;
    int8_t int8;
    uint16_t uint16;
    int16_t int16;
    uint32_t uint32;
    int32_t int32;
    float float32;
    uint64_t uint64;
    int64_t int64;
    double float64;
    bool bool_;
    gguf_string_t string;
    struct {
        // 任何值类型均有效,包括数组。
        gguf_metadata_value_type type;
        // 元素数量而非字节数
        uint64_t len;
        // 值数组。
        gguf_metadata_value_t array[len];
    } array;
};

struct gguf_metadata_kv_t {
    // 元数据的键。它是一个标准的 GGUF 字符串,但有以下限制:
    // - 必须是有效的 ASCII 字符串。
    // - 必须是层次键,每段为 `lower_snake_case`,由 `.` 分隔。
    // - 长度最多为 2^16-1/65535 字节。
    // 不遵循这些规则的键均无效。
    gguf_string_t key;

    // 值的类型。
    // 必须是 `gguf_metadata_value_type` 中的一个值。
    gguf_metadata_value_type value_type;
    // 值。
    gguf_metadata_value_t value;
};

struct gguf_header_t {
    // 魔数,表明这是一个 GGUF 文件。
    // 在字节级别必须是 `GGUF`:`0x47` `0x47` `0x55` `0x46`。
    // 您的执行器可能使用小端字节序,因此可能需要检查 0x46554747 并让字节序抵消。
    // 在此建议非常明确地指定字节序。
    uint32_t magic;
    // 实现的格式版本。
    // 对于本规范中描述的版本必须为 `3`,该版本引入了大端序支持。
    // 仅在格式结构发生变化时才应增加此版本。
    // 不影响文件结构的变化应通过更新元数据来表示。
    uint32_t version;
    // 文件中的张量数量。
    // 明确包含此项,而不是将其放入元数据,以确保加载张量时始终存在。
    uint64_t tensor_count;
    // 元数据键值对的数量。
    uint64_t metadata_kv_count;
    // 元数据键值对。
    gguf_metadata_kv_t metadata_kv[metadata_kv_count];
};

uint64_t align_offset(uint64_t offset) {
    return offset + (ALIGNMENT - (offset % ALIGNMENT)) % ALIGNMENT;
}

struct gguf_tensor_info_t {
    // 张量的名称。它是一个标准的 GGUF 字符串,但限制最多为 64 字节长。
    gguf_string_t name;
    // 张量的维度数。
    // 当前最多为 4,但未来可能会改变。
    uint32_t n_dimensions;
    // 张量的维度。
    uint64_t dimensions[n_dimensions];
    // 张量的类型。
    ggml_type type;
    // 张量数据在此文件中的字节偏移量。
    //
    // 此偏移量相对于 `tensor_data`,而不是文件的开头,以方便写入器编写文件。
    // 读取器应考虑将此偏移量暴露为相对于文件开头的值,以方便读取数据。
    //
    // 必须是 `ALIGNMENT` 的倍数。即 `align_offset(offset) == offset`。
    uint64_t offset;
};

struct gguf_file_t {
    // 文件头部。
    gguf_header_t header;

    // 张量信息,可用于定位张量数据。
    gguf_tensor_info_t tensor_infos[header.tensor_count];

    // 填充至最接近的 `ALIGNMENT` 倍数。
    //
    // 即,如果 `sizeof(header) + sizeof(tensor_infos)` 不是 `ALIGNMENT` 的倍数,则添加此填充。
    //
    // 可计算为 `align_offset(position) - position`,其中 `position` 是 `tensor_infos` 末尾的位置(即 `sizeof(header) + sizeof(tensor_infos)`)。
    uint8_t _padding[];

    // 张量数据。
    //
    // 这是对应模型权重的任意二进制数据。这些数据应与原始模型文件中的数据接近或相同,但由于量化或其他推理优化可能有所不同。任何此类偏差应记录在元数据或架构定义中。
    //
    // 每个张量的数据必须存储在此数组中,并通过其 `tensor_infos` 条目定位。每个张量数据的偏移量必须是 `ALIGNMENT` 的倍数,张量之间的空间应填充至 `ALIGNMENT` 字节。
    uint8_t tensor_data[];
};

相关文章:

  • 问题:undefined reference to `pthread_mutexattr_init‘
  • Vue的父子组件通信问题
  • vsCode下载、安装、推荐插件
  • 90.奇妙货币交易问题|Marscode AI刷题
  • 在Linux、Windows和macOS上部署DeepSeek模型的最低配置要求
  • 大白话3Vuex 是什么,具体怎么用?
  • 349. 两个数组的交集
  • django:更新页面但未生效
  • 基于JavaWeb开发的高校食堂点餐系统
  • 国内访问Github的四种方法(2025版)
  • 【YOLOv3】 源码总体结构分析
  • Linux部署dnsmasq软件
  • 【前端】【面试】【功能函数】写一个JavaScript树形结构操作函数:`filter` 与 `forEach`
  • C++ QT 6.6.1 QCustomPlot的导入及使用注意事项和示例 | 关于高版本QT使用QCustomPlot报错问题解决的办法
  • vue+element ui 实现选择季度组件
  • Linux(CentOS)安装 Nginx
  • java23种设计模式-命令模式
  • 安全性质量属性场景
  • 策略模式结合SpringBoot
  • 银行信贷业务解析:运营与数据双视角下的业务本质与技术支撑
  • 不关闭网站备案/百度一下网页搜索
  • 厦门移动网站建设哪家专业/如何网站seo
  • 注册外贸网站有哪些问题/百度搜索热词排行榜
  • 做网站备案需要什么/网站超级外链
  • 制作网站软件哪个好/网站推广是干嘛的
  • 简单房地产网站/优化大师官方免费下载