
为 ik_llama.cpp 的 gguf-py 工具链补齐新量化类型常量从 KeyError 到 GGML_QUANT_SIZES 修复全记录【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cppik_llama.cpp 持续引入新的量化格式如IQ1_S_R4、IQ1_M_R4、IQ2_K_R4、IQ4_K_R4、IQ5_K_R4但 Python 侧的 gguf-py/gguf/constants.py 若未同步更新gguf_dump.py、gguf_reader.py等工具在解析新格式模型时就会因查不到块尺寸而崩溃。本文以仓库内 PR #298「Update gguf-py constants」的完整修复过程为线索讲解错误链路、GGML_QUANT_SIZES与GGML_ROW_META_SIZES的正确补法、从 C 源码获取权威尺寸的方法以及验证手段帮助你在自定义量化格式出现时快速为 Python 工具链打补丁。问题现场解析 DeepSeek-V3 IQ4_K_R4 模型时的 KeyErrorPR #298 的起因是 issue #297「Update gguf-py scripts to support new quant types」中报告的崩溃当使用gguf_dump.py以 Markdown 模式导出一个DeepSeek-V3-0324-IQ4_K_R4.gguf模型时命令直接抛出KeyErrorpython gguf-py/scripts/gguf_dump.py --markdown /mnt/sda/DeepSeek-V3-0324-IQ4_K_R4.ggufTraceback (most recent call last): File .../gguf-py/scripts/gguf_dump.py, line 454, in module main() File .../gguf-py/scripts/gguf_dump.py, line 439, in main reader GGUFReader(args.model, r) File .../gguf-py/gguf/gguf_reader.py, line 130, in __init__ self._build_tensors(offs, tensors_fields) File .../gguf-py/gguf/gguf_reader.py, line 278, in _build_tensors block_size, type_size GGML_QUANT_SIZES[ggml_type] KeyError: GGMLQuantizationType.IQ5_K_R4: 340注意报错的关键信息GGMLQuantizationType.IQ5_K_R4: 340。也就是说模型的张量元数据里写的是量化类型 340而当时constants.py的GGML_QUANT_SIZES字典里并没有登记这个类型于是在_build_tensors执行到GGML_QUANT_SIZES[ggml_type]时发生KeyError。错误链路gguf_dump 为什么会走到 GGML_QUANT_SIZES要理解这个错误需要顺着调用链往下看入口gguf-py/scripts/gguf_dump.py 的main()调用GGUFReader(args.model, r)打开模型文件构造器GGUFReader.__init__解析元数据字段后调用self._build_tensors(offs, tensors_fields)张量构建gguf-py/gguf/gguf_reader.py 的_build_tensors从每个张量字段中取出raw_dtype转换为ggml_type GGMLQuantizationType(raw_dtype[0])然后执行block_size, type_size GGML_QUANT_SIZES[ggml_type] n_rows n_elems // int(dims[0]) if n_elems 0 else 0 n_bytes n_elems * type_size // block_size n_rows * GGML_ROW_META_SIZES.get(ggml_type, 0)block_size块内元素数与type_size每块字节数是计算张量在文件中的字节长度n_bytes、定位数据偏移所必需的。只要GGML_QUANT_SIZES缺少某个类型整个解析流程就无法继续。同理gguf-py/gguf/quants.py 中的dequantize/quantize也会用同一张表计算block_size与type_size见quants.py第 15、23 行因此这张表是 Python 侧所有量化操作的基石。修复方法如何拿到缺失类型的权威尺寸PR #298 的维护者 ikawrakow 在对话中给出了两条明确的查找路径这也是任何新量化类型合入后补constants.py的标准做法路径一从 ggml-common.h 的 static_assert 读取块大小在 ggml/src/ggml-common.h 中搜索缺失的量化类型每个block_*结构体下方都有static_assert直接声明其字节大小。例如 PR 修复涉及的几个 R4 类型结构体static_assert 内容块大小字节block_iq1_s_r4sizeof(block_iq1_s_r4) 2424block_iq1_m_r4sizeof(block_iq1_m_r4) 2828block_iq2_k_r4sizeof(block_iq2_k_r4) 4*sizeof(block_iq2_k)4 × 76 304block_iq4_k_r4sizeof(block_iq4_k_r4) 4*sizeof(block_iq4_k)4 × 144 576block_iq5_k_r4sizeof(block_iq5_k_r4) 4*sizeof(block_iq5_k)4 × 176 704以block_iq2_k76 字节/256 元素为参照可以推得IQ2_K_R4的type_size / block_size 76 / 256。这种按块元素数归一的写法在GGML_QUANT_SIZES中体现为(256, 76)这种(block_size, type_size)二元组。路径二从 ggml.c 的 type_traits 一次性读取全部信息ggml.c中的type_traits结构体把每个类型所需的全部元信息集中在一处定义类型、块大小、类型大小、行元数据等例如 ggml/src/ggml.c 中[GGML_TYPE_IQ5_K_R4] {...}的条目。维护者原话是「Thetype_traitsstructure inggml.cdefines everything needed inconstants.pyin one place」建议直接对照它生成 Python 侧常量避免逐个 static_assert 换算。修复后的 constants.py 实际内容PR 最终将 gguf-py/gguf/constants.py 中的GGML_QUANT_SIZES补齐为包含全部 R4 系列类型的完整字典第 2187 行起。以下是本次修复涉及的关键条目(block_size, type_size)格式GGMLQuantizationType.IQ1_S_R4 : ( 32, 6), GGMLQuantizationType.IQ1_M_R4 : ( 32, 7), GGMLQuantizationType.IQ2_BN_R4 : ( 64, 16), GGMLQuantizationType.IQ2_K_R4 : ( 256, 76), GGMLQuantizationType.IQ3_K_R4 : ( 256, 110), GGMLQuantizationType.IQ4_K_R4 : ( 256, 144), GGMLQuantizationType.IQ5_K_R4 : ( 256, 176), GGMLQuantizationType.IQ4_KS_R4 : ( 256, 136), GGMLQuantizationType.IQ5_KS_R4 : ( 256, 168), GGMLQuantizationType.Q8_KV_R8 : ( 32, 32), GGMLQuantizationType.Q8_K_R8 : ( 256, 258),同时GGML_ROW_META_SIZES第 2280 行起也需要补充每行额外元数据的类型。这一点在_build_tensors的n_bytes计算公式中与GGML_QUANT_SIZES配合使用缺了它同样会导致字节数计算错误GGML_ROW_META_SIZES: dict[GGMLQuantizationType, int] { GGMLQuantizationType.IQ1_BN : 2, GGMLQuantizationType.IQ2_BN : 4, GGMLQuantizationType.IQ2_BN_R4 : 4, GGMLQuantizationType.IQ1_S_R4 : 2, GGMLQuantizationType.IQ1_M_R4 : 2, GGMLQuantizationType.IQ2_KS : 2, ... GGMLQuantizationType.Q8_KV : 8, GGMLQuantizationType.Q8_KV_R8 : 4, ... }此外GGMLQuantizationType枚举第 20162043 行与LlamaFileType第 2057 行起也必须与新类型一一对应例如IQ1_S_R4 219、IQ1_M_R4 229、IQ2_K_R4 337、IQ4_K_R4 339、IQ5_K_R4 340以及对应的MOSTLY_IQ5_K_R4 341等文件级类型。枚举值与 C 侧ggml.h的定义必须严格一致因为 GGUF 文件里存的就是这个整数。验证让 gguf_dump 恢复正常修复完成后PR 提交者在原命令上重新验证python gguf-py/scripts/gguf_dump.py --markdown /mnt/sda/DeepSeek-V3-0324-IQ4_K_R4.gguf此时命令可正常跑通并输出 Markdown 格式的完整模型信息元数据键值对 张量列表随后 PR 获得维护者 ✅ APPROVED。--markdown之外的输出格式纯文本、JSON走的是同一套GGUFReader解析路径因此同样受益。此外仓库内还有一套量化自检测试 gguf-py/tests/test_quants.py它会遍历GGML_QUANT_SIZES中注册的所有类型做dequantize(quantize(x))的往返一致性验证block_size, type_size gguf.GGML_QUANT_SIZES[qtype] gguf.dequantize(np.zeros((gguf.GGML_QUANT_SIZES[qtype][1]), dtypenp.uint8), qtype) gguf.quantize(np.zeros((gguf.GGML_QUANT_SIZES[qtype][0]), dtypenp.float32), qtype)因此补完constants.py后跑一遍该测试是比单纯跑gguf_dump更全面的回归验证手段——它同时覆盖了quants.py的量化/反量化路径能发现尺寸写错导致的越界或形状不匹配问题。维护启示Python 工具链与 C 侧保持同步PR 对话中还有一段值得留意的维护经验ikawrakow 坦言 Python 侧脚本与主线的同步一直是个痛点——差异积累过大后难以自动合并而本项目在 Python 侧的定制主要是围绕 Bitnet 模型以及 DeepSeek 模型 MLA 相关的张量处理且提到该部分后续可能被移除因为相关张量可以在模型加载时按需生成。这意味着新增量化类型时GGMLQuantizationType、LlamaFileType、GGML_QUANT_SIZES、GGML_ROW_META_SIZES四处必须同时更新缺一不可尺寸来源必须回查 C 代码ggml-common.h的 static_assert 或ggml.c的type_traits不能靠猜测或从模型文件反推否则一旦写错gguf_dump虽然能过但quants.py的量化/反量化会静默产生错误结果合并上游 Python 改动时要小心直接整体覆盖会丢掉本项目的定制逻辑逐个甄别又会随差异增大而越来越难需在两者之间做取舍。小结PR #298 看似只是往字典里加了几行但它完整展示了 ik_llama.cpp 生态中 C/C 量化核心与 Python 工具链之间的契约关系GGML_QUANT_SIZES和GGML_ROW_META_SIZES是 Python 侧解析、量化、反量化所有 GGUF 模型的元数据基准其权威来源始终是 ggml/src/ggml-common.h 与 ggml/src/ggml.c。掌握了报错 → 定位缺失类型 → 回查 C 源码尺寸 → 补全四处常量 → 用 gguf_dump 与 test_quants 验证这一完整闭环你就能在任何新量化格式包括未来的 R8/R16 系列出现时第一时间让整个 Python 工具链保持可用。【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考