Misc. bug: Data corruption for Q8_0 quantization for larger models under numpy 1.*

这个报错通常出现在使用 numpy 1.* 并通过 llama.cpp 的 convert_hf_to_gguf.py 把较大模型转换为 Q8_0(以及 TQ1_0、TQ2_0)时,权重符号被静默破坏;优先检查 numpy 版本与 gguf/quants.py 中的 np_roundf 实现。

快速结论:这个报错通常出现在使用 numpy 1.* 并通过 llama.cpp 的 convert_hf_to_gguf.py 把较大模型转换为 Q8_0(以及 TQ1_0、TQ2_0)时,权重符号被静默破坏;优先检查 numpy 版本与 gguf/quants.py 中的 np_roundf 实现。

适用环境:Issue 中确认的环境为 Linux、llama.cpp build 10819(commit 6a1a922d2,GNU 13.3.0),受影响模块为 llama-quantize 相关的转换流程;numpy 1.26.4 可复现,numpy 2.x 未触发。评论中提到为维持 Ubuntu 22.04 / Python 3.10 支持曾降到 numpy 2.2.6,但该版本是否修复尚未确认。

最快修复方案:暂无确认的一步修复方案;Issue 中给出的是代码层修改建议——在 np_roundf 开头加入 s = np.sign(n),并把 return np.sign(n) * b 改为 return s * b,同时补充一个能触发大临时张量路径的测试。

注意事项:该修改建议尚未在 Issue 中确认为已合并方案,属于可优先尝试的修复方向;真正验证需要同时覆盖 numpy 1.* 和评论中提到的 numpy 2.2.6 环境,并确认 Q8_0 之外的 TQ1_0、TQ2_0 转换路径也一并检查。

问题场景

用户使用 llama.cpp 提供的 convert_hf_to_gguf.py,在 Linux 上把 Hugging Face 格式的较大模型转换为 Q8_0 GGUF,随后再量化到 IQ4_XS。触发问题的具体命令为:

python ~/workspace/llama.cpp/convert_hf_to_gguf.py Abliterated/ --outfile Abliterated/glm5.3-Flash-q8_0.gguf --fp8-as-q8

报告者在 GLM-5.3-Flash 的 FP8 微调转换中直接遇到 Q8_0 数据损坏;该问题也与 Q8_0TQ1_0TQ2_0 共用的 np_roundf 函数有关。

报错原文

Misc. bug: Data corruption for Q8_0 quantization for larger models under numpy 1.*

(16, 2048) 0.501251220703125 0.498077392578125
(16, 4096) 0.5001068115234375 0.0

其中 (16, 4096) 一行显示反量化后负值比例从约 50% 变为 0.0,即符号信息已丢失。

原因分析

Issue 给出的原因指向 numpy 1.* 的原地运算行为。当张量超过 NPY_MIN_ELIDE_BYTES(默认 256KB)时,numpy 1.* 对临时数组执行数学运算可能采用 in-place 方式,从而静默修改输入值。具体到 quants.pynp_roundf,由于 return np.sign(n) * b 中的 np.sign(n) 先被计算,随后 * b 可能触发对临时数组的原地修改,导致 n 中原本为负的元素被强制为正,权重张量符号因此丢失。

该问题在 numpy 2.x 下不触发,因为 numpy 2 不再执行这种 ELIDE 行为;较小模型或较小张量也不会触发。可能原因还包括:转换路径只在使用该函数的量化类型(Q8_0、TQ1_0、TQ2_0)中暴露,因此整体表现较隐蔽。

环境排查

  • 确认 numpy 版本:numpy 1.*(包括 requirements 中的 numpy~=1.26.4)可复现,numpy 2.x 未触发;评论中提到的 numpy 2.2.6 需额外确认。
  • 确认 llama.cpp 版本:Issue 中为 version: 0.4.0-dev (build 10819, commit 6a1a922d2)
  • 确认操作系统与构建环境:Linux x86_64,GNU 13.3.0。
  • 确认受影响模块:llama-quantize 相关转换流程,重点检查 gguf/quants.pynp_roundf,以及 Q8_0、TQ1_0、TQ2_0 的量化路径。
  • 确认是否在转换较大模型:当张量超过 256KB 时更容易触发。
  • Issue 未提供 CUDA、PyTorch、显卡等信息,无需据此推断。

解决步骤

  1. 先用 Issue 中的最小验证脚本确认当前环境是否复现:用 numpy 1.26.4 对 shape 为 (16, 2048)(16, 4096) 的随机矩阵执行 Q8_0 量化与反量化,观察 (d < 0).mean() 是否异常变为 0.0。
  2. 如果复现,检查 gguf/quants.py 中的 np_roundf:确认是否存在 return np.sign(n) * b 这类写法。
  3. 可优先尝试按 Issue 建议修改:在 np_roundf 开头增加 s = np.sign(n),并把返回语句改为 return s * b,使符号只在运算前提取一次,避免后续原地操作改写原数据。
  4. test_quants.py 中补充一个能触发大临时张量路径的测试;Issue 指出当前测试使用 r = np.random.randn(8, 1024, 1024).astype(np.float32, copy=False) 仍不足以触发该问题。
  5. 若需要维持 Ubuntu 22.04 / Python 3.10 的兼容性,按评论建议在 numpy 2.2.6 下重跑上述验证;但该版本是否真正修复尚未在 Issue 中确认,需要实际测试后再下结论。
  6. 重新执行转换命令,确认生成的 Q8_0 GGUF 不再出现负值比例归零的现象。

验证方法

用 numpy 1.26.4 运行 Issue 中的验证脚本,两个 shape 的反量化结果负值比例都应接近 50%,其中 (16, 4096) 不应再输出 0.0。同时用修复前后的 np_roundf 对比 Q8_0 转换结果,并确认 TQ1_0、TQ2_0 路径未被符号丢失影响。若在 numpy 2.2.6 下测试,需单独记录该版本的结果,不能直接套用 numpy 2.x 已通过的说法。

参考来源

ggml-org/llama.cpp #28438

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 22661

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注