← 返回信息流
AI 资讯Hacker News·2 小时前

同一模型同一Q4_K_M标签,每权重比特数竟有差异

原标题:Same model, same Q4_K_M label: 5.02, 5.07 and 5.27 bits per weight

速览

发现同一模型在使用相同的Q4_K_M量化标记时,经过不同实现或版本所得的每权重比特数存在差异(5.02、5.07和5.27)。这表明量化标记可能未严格对应确切的比特精度,对模型部署的复现性和结果比较有影响。该现象提示开发者需警惕量化过程中的精度波动。

AI 深度解读

背景

本地大语言模型(LLM)的推理性能评估长期存在一个痛点:开发者通常只汇报一个“tok/s”数字,但这个数字可能正确却隐瞒了真实情况。同一模型、同一量化标签(如 Q4_K_M)下的实际比特数可以相差很大,GPU 加速可能因二进制构建问题而静默失效,而预填充(prefill)和解码(decode)的速度差异可达 20 倍以上。picchio 正是为解决这类诊断问题而诞生的一个轻量级 Python 工具,由开发者 logxio 发布在 GitHub 上。

核心内容

picchio 是一个单个 Python 文件,通过测量本地 LLM 的有效每权重比特数(effective bits per weight)、三个 tok/s 通道(预填充、解码、总耗时)以及静默 CPU 回退(silent CPU fallback),并提供 GPU 使用情况的客观验证。它不需要复杂安装,只需 Python3 和 llama.cpp 或 ollama 即可运行。以下是对原文功能的完整解读:

安装与运行

curl -fsSLO https://raw.githubusercontent.com/logxio/picchio/main/picchio.py
python3 picchio.py

无参数运行时,会自动查找模型(ollama 标签、当前文件夹、Hugging Face 和 LM Studio 缓存),并让用户选择运行的模型。如果传入 .gguf 路径,则执行完整的 llama.cpp 诊断;传入 ollama 标签则进入测量模式。三个 pass 使用固定 prompt,第一个为冷启动。

GPU 参与时大约一分钟完成,纯 CPU 则需几分钟。工具会在 ~/.cache/picchio 下写入一个缓存文件,不产生其他垃圾。

核心发现:同一量化标签的比特数差异

使用同一模型 Qwen3.5-9B,同样标为 Q4_K_M 的四个不同量化版本,实际测量得到的每权重比特数分别为 5.02、5.02、5.07 和 5.27 bits。这意味着“Q4_K_M”这个标签并不等同于 4 bits,它只是五种不同 ggml 类型张量的混合(范围从 4.50 到 32.00 bits),并且不同量化工具(quantizer)生成的张量集也可能不同——例如有一个量化器将 243M 参数的 MTP 头嵌入主文件并量化为 q8_0,另一个则将其作为独立仓库存放。KV 缓存的数据类型不在文件内,工具会记录最近一次运行的实际测量结果。对于 MoE 模型,picchio 会报告每个 token 激活的专家数(例如 34.7B 参数模型中每个 token 只激活约 3.5B 参数)。

三个“通道”(lanes)

  • 预填充(Prefill,又称 prompt processing 或 pp):模型读取 prompt 的速度,决定了长 prompt 下的首 token 延迟。Mac 上声称的 500 tok/s 几乎都是预填充速度。
  • 解码(Decode,又称 tg 或 eval):模型生成回答的速度。
  • 总耗时(Wallclock):生成的总 token 数除以总时间(包括加载和预热)。

这三个通道可能各自表现不同,例如预填充在 GPU 和 CPU 之间可差 22 倍,而解码只差不到 2 倍(同一模型、同一文件)。

静默 CPU 回退(Silent CPU Fallback)

开发者指出裸 llama.cpp 曾给出 36 tok/s,但通过同一个模型在应用里只得到 11.5 tok/s,这差距正是 picchio 诞生的原因。经过一个跨 CPU/GPU、冷/热启动的 32 格子矩阵测试,发现 36 tok/s 从未在任何一个格子中出现,说明那是另一个通道的速度被误记为生成速度,而实际运行中存在静默 CPU 回退——二进制构建问题导致 GPU 并未被使用,但工具不报错,用户浑然不知。

诊断机制:GPU 使用验证

在运行 pass 的同时,后台线程会读取操作系统自身的 GPU 计量器:

  • macOS:以 4Hz 频率读取 ioreg,加上 powermetrics 能量计数器(免 sudo)。
  • NVIDIA Linux:使用驱动 NVML。

结果以 os 行输出。如果模型宣称完全卸载到 GPU,但操作系统观察到 GPU 闲置,则给出 CONFLICTING EVIDENCE(退出码 5);如果二进制构建根本没有 GPU 证据,而计量器看到 GPU 空闲,则判定为 SILENT CPU FALLBACK(退出码 4)。缺失的信息源会标注“abstains”并说明剩余证据。

对比 llama-bench

llama-bench 回答的是稳态的 pp 和 tg 值,但不包含加载时间、冷/热启动区分、无 verdict 判断。picchio 提供更全面的诊断,包括 EXIT 码用于脚本化:

  • 0:健康或无证据
  • 2:无法运行
  • 3:部分卸载
  • 4:静默 CPU 回退
  • 5:冲突证据

watch 模式

用于实时观察正在运行的推理引擎,不启动新进程、不卸载任何东西。例如:

python3 picchio.py watch --engine ollama --for 8

指定采样窗口 8 秒,判定 GPU 是否在真正工作。

自测试

python3 picchio.py --selftest 会重放 examples/raw/ 中的引擎日志,必须逐行复现每个已提交的 verdict 块。CI 每次推送都会运行该测试。

输出示例(表格)

文中列举了两个真实运行结果:

  • Apple M5(32 GB,macOS 26.5.1,llama.cpp build 9430,ollama 0.31.1):约 730 prompt tokens + 128 生成 tokens,3 个 pass,首次冷。表格中的“lane”列为预热中位数。
  • 一台租赁的 Linux RTX 4090(CUDA)对比。

35B 参数的 MoE 模型(每 token 激活 3.5B)存在加载瓶颈:第一个 pass 的 19 秒中 13 秒用于读取 20.6 GiB 权重,但解码速度仍比稠密 9B 快 1.6 倍。

关键要点

  • 同一量化标签(如 Q4_K_M)在不同量化工具下实际每权重比特数差异可达 5% 以上(5.02 vs 5.27),且张量集合可能不同,导致文件大小和性能不可靠。
  • GPU 静默回退是常见但被忽视的陷阱:二进制构建错误或驱动问题可能导致模型实际在 CPU 上运行,但上层应用仍报告 GPU 卸载成功。picchio 通过对比 OS 计量器与引擎日志来判别。
  • 三个速度通道(预填充、解码、总耗时)需独立测量:一个数字无法反映真实体验,长 prompt 下预填充慢会导致首 token 延迟高,而解码快并不代表总用时短。
  • llama.cpp 开发者应使用 picchio 验证构建的正确性:工具可在没有硬件修改的情况下检测 GPU 是否真正参与工作。
  • MoE 模型的加载时间是性能瓶颈之一:虽然激活参数少,但读取全部权重的时间可能占主导。
  • Ollama 的限制:不暴露每层放置信息、设备初始化日志或线程配置,因此 picchio 对其只能通过内存分配推测放置,缺失时标记未知。
  • 暖启动数值有 5–8% 的漂移:建议增加 pass 数(如 --passes 5)以稳定单次读数。
  • 退出码设计:可脚本化判断 GPU 工作状态(0 正常,4 静默回退,5 证据冲突等)。

意义与影响

picchio 填补了 LLM 推理性能诊断的一个关键空白。以往开发者只能通过 tok/s 粗略评估,而不知道 GPU 是否真正参与、量化标签是否诚实、预填充与解码的分离表现如何。该工具通过三种机制(比特数测量、三通道分离、OS 级 GPU 计量)提供了可复现、可验证的诊断报告。它对

查看原文 →github.com