
ik_llama.cpp 排查实录llama-perplexity 对 unsloth Q8_0 量化模型输出全 NaN 的根因分析与修复【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp导读本文完整还原 ik_llama.cpp 仓库 issue #285 的排查全过程同一份 unsloth 出品的 DeepSeek-R1-Q8_0 GGUF 模型文件mainline llama.cpp 能跑出正常的困惑度PPL ≈ 3.3490而 ik_llama.cpp 无论怎样组合参数都输出全 NaN。文章将带你掌握llama-perplexity的完整命令行参数、分步定位 NaN 的排查方法论并从源码层面理解Q8_1激活量化的fp16块累加和溢出是导致数值崩溃的根因以及 issue #291 对应的修复方向。问题现象同一模型文件mainline 正常、fork 全 NaN2025-03-24用户ubergarm在 ik_llama.cpp 仓库提交 issue #285关联自 issue #271 的后续讨论使用 unsloth 发布的DeepSeek-R1-Q8_0GGUF V3 格式、15 个分片、671B 参数、约 664 GiB运行llama-perplexity时mainline llama.cpp 可以顺利完成而 ik_llama.cpp 从第一个 chunk 起就输出[1]nan,[2]nan,[3]nan,...无法得到任何有效评估结果。关键疑点有两个模型文件本身没问题同样的 GGUF 文件在 mainline 上得到干净结果不是量化损坏用户使用 ik_llama.cpp 的-rtr实时 repack和ik/offline_repack分支产出的Q8_0_R8重打包模型依然全 NaN。从日志结构看加载阶段出现了 ik_llama.cpp 特有的张量处理流程 llm_load_tensors: need to compute 61 wk_b tensors Computed blk.0.attn_v_b.weight as 128 x 512 x 128 and stored in buffer CPU Computed blk.1.attn_v_b.weight as 128 x 512 x 128 and stored in buffer CPU ... Repacked 663 tensors也就是说DeepSeek-V3/R1 这类 MLAMulti-head Latent Attention架构的attn_v_b.weight等张量并不会直接从 GGUF 中读入而是由加载器根据压缩表示**实时计算compute**得到然后再按 ik_llama.cpp 的行交错量化row-interleaved quant规则重打包repack为 663 个张量。NaN 正是在这一整套非标准张量装载与后续计算流程中产生的。对照实验mainline llama.cpp 的干净基准为了证明模型文件无误用户给出了 mainlinellama.cppb1b132ef的完整命令与输出节选关键部分$ git rev-parse --short head b1b132ef $ numactl -N 0 -m 0 \ ./build/bin/llama-perplexity \ --model /mnt/ai/models/unsloth/DeepSeek-R1-GGUF/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00001-of-00015.gguf \ -ctk f16 -ctv f16 \ --ctx-size 512 \ --ubatch-size 512 \ -f wiki.test.raw \ --numa numactl \ --threads 80关键运行信息模型deepseek2架构61 层Q8_0文件类型8.50 BPW文件大小 664.29 GiB张量构成f32361 个 q8_0664 个上下文n_ctx 2048每序列 512ubatch 512结果共计算 561 个 chunkFinal estimate: PPL 3.3490 /- 0.01849全流程无 NaN性能参考prompt eval 约 34.52 tokens/s80 线程、AMX/AVX512 环境下。这一组干净数据成为判断问题出在 ik_llama.cpp 侧的基准锚点。ik_llama.cpp 侧的参数组合尝试无论怎么配都 NaN用户随后在 ik_llama.cppf2fb15de上尝试了多组参数包括显式启用 fork 的特性开关$ numactl -N 0 -m 0 \ ./build/bin/llama-perplexity \ --model /mnt/ai/models/unsloth/DeepSeek-R1-GGUF/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00001-of-00015.gguf \ -rtr \ -ctk f16 -ctv f16 \ -mla 2 -fa \ -amb 2048 \ -fmoe \ --ctx-size 512 \ --ubatch-size 512 \ -f wiki.test.raw \ --numa numactl \ --threads 80输出同样是[1]nan,[2]nan,...。期间上下文初始化确认了这些开关全部生效llama_new_context_with_model: flash_attn 1 llama_new_context_with_model: mla_attn 2 llama_new_context_with_model: attn_max_b 2048 llama_new_context_with_model: fused_moe 1第二轮尝试offline repack 的 Q8_0_R8 模型用户切换到ik/offline_repack分支ik_llama.cpp9fe6fc37使用离线重打包后的DeepSeek-R1-Q8_0_R8.gguf并把 KV cache 也换成q8_0$ git checkout ik/offline_repack $ git rev-parse --short HEAD 9fe6fc37 $ numactl -N 0 -m 0 \ ./build/bin/llama-perplexity \ --model /mnt/ai/models/unsloth/repack/DeepSeek-R1-Q8_0_R8.gguf \ -ctk q8_0 \ -mla 2 -fa \ -amb 512 \ -fmoe \ --ctx-size 512 \ --ubatch-size 512 \ -f wiki.test.raw \ --seed 1337 \ --numa numactl \ --threads 128此时张量构成变为f32361 个 q8_01 个 q8_0_r8663 个模型 ftype 显示为Q8_0_R8 - 8.5 bpw说明重打包成功。但结果依旧[1]nan,[2]nan,...。第三轮尝试去掉所有优化开关的 vanilla 配置作者 ikawrakow 在 2025-03-25 回应因为用户在其他模型上用Q8_0做注意力张量没有问题问题大概率出在expert 张量上请用户用完全不带优化开关的最小配置复现./bin/llama-perplexity -m /mnt/ai/models/unsloth/repack/DeepSeek-R1-Q8_0_R8.gguf -f wiki.test.raw -t 128 -b 512用户照做main98a264a2此时上下文初始化为llama_new_context_with_model: flash_attn 0 llama_new_context_with_model: mla_attn 0 llama_new_context_with_model: attn_max_b 0 llama_new_context_with_model: fused_moe 0即 MLA、FlashAttention、fused MoE、attention max batch全部关闭的纯 CPU vanilla 路径。结果仍然是[1]nan,[2]nan,...且n_seq1、ubatch512。这说明 NaN 与-mla、-fa、-fmoe、-amb等加速开关没有因果关系——问题存在于这些优化之外的更底层路径。根因定位Q8_1 块累加和的 fp16 溢出2025-03-26ikawrakow 给出了最终假设我的当前假设是NaN 由Q8_1的 block sum块累加和溢出导致该累加和以fp16存储。这一假设在仓库源码中得到直接印证。查看 ggml/src/ggml-common.h 中Q8_1量化块的定义#define QK8_1 32 typedef struct { GGML_SCALE_TYPE1(s, ds); // d 与 s 均以 ggml_halffp16存储 int8_t qs[QK8_1]; // 32 个 int8 量化值 } block_q8_1; static_assert(sizeof(block_q8_1) 2*sizeof(ggml_half) QK8_1, wrong q8_1 block size/padding);其中ssum即块内量化值的累加和和ddelta缩放因子都只有fp16的表示精度。Q8_1在推理路径中主要用于激活activation量化——矩阵乘法时把 fp32/fp16 激活张量临时量化成Q8_1参与计算仓库中Q8_1也出现在 ggml/src/ggml-cuda/mmq.cuh 等 MMQ 内核中。当激活值动态范围较大、块内 32 个 int8 量化值的绝对值累加和超过fp16可表示的最大值约 65504时s溢出为inf后续乘法自然得到NaN。DeepSeek-R1 这种 671B 参数、61 层、256 个 expert 的巨型 MoE 模型其中间激活在层间传播时完全可能触发该溢出。这也解释了为什么其他较小模型用Q8_0注意力张量不出现 NaNmainline 的相同路径或不同精度处理没有触发问题无论-mla/-fa/-fmoe是否开启都会复现——因为激活量化是更底层的通用路径。仓库中的 issue #196 - Refactor: remove usage of Q8_1 for activation quantization 也从侧面印证了这一关注点该重构议题明确提出用bf16替换Q8_1中fp16的 block scale 与 block sum以规避此类精度问题。修复验证issue #291基于上述假设ikawrakow 在 2025-03-26 请用户用包含修复的#291重新测试Q8_0和Q8_0_R8模型验证 NaN 是否消除。issue #285 在 2025-03-27 关闭修复方向即落在Q8_1累加和的表示精度上。排查方法论沉淀遇到 perplexity 全 NaN 该怎么查从这次实战中可以提炼出一套可复用的排查清单步骤操作本次案例结论1. 锚定基准用 mainline 跑同一模型文件mainline PPL 3.3490模型文件健康2. 最小化复现去掉-mla -fa -fmoe -amb -rtr等所有 fork 增强开关vanilla 路径依然全 NaN排除加速开关嫌疑3. 交叉验证模型用 offline repack 的Q8_0_R8再测仍 NaN排除 repack/实时计算张量路径单独作恶4. 定位差异层对比两侧日志中张量装载与量化类型的差异Q8_1激活量化 fp16块和进入嫌疑范围5. 源码验证查看block_q8_1结构体定义s与d均为ggml_half溢出条件成立6. 修复与回归应用 #291 修复后重新跑 perplexity 与 imatrix确认 NaN 消除此外本次排查还揭示了两点对 DeepSeek 系模型用户重要的实操信息-ububatch-size会显著影响数值稳定性相关 issue #245IQ4_KSS 量化同样触发 NaN中用户观察到-ub 8/32/64/128能跑完而-ub 256/512必现 NaN且大上下文4096下用-ub 64也会在 8 个 chunk 后开始 NaN。降低 ubatch 能暂时规避但不是根因IQ_K 家族量化类型不适合注意力张量issue #245 中 ikawrakow 明确指出IQ4_K/IQ4_KSS以及IQ2_KS, IQ2_K, IQ3_K, IQ4_KS, IQ5_K, IQ6_K没有实现量化矩阵乘内核MMQ在 CUDA 上会先转成fp16再走 cuBLAS GEMM数值上不稳定不能用于注意力张量——这也是 #245 里用户最终把attn_*全部设成q8_0的原因。相关量化命令与--custom-q规则可参考 examples/quantize/quantize.cpp 及 issue #245 中的完整参数清单。相关源码与文档索引Q8_1块结构定义ggml/src/ggml-common.hs/d均为ggml_halfqs为 32 个 int8Q8_1激活量化相关内核ggml/src/ggml-cuda/mmq.cuh相关重构讨论github-data/issues/196 - Refactor: remove usage of Q8_1 for activation quantization同类 NaN 问题IQ4_KSS 量化github-data/issues/245 - Bug: Perplexity returns NaN with IQ4_KSS quantisation复现与排查使用的工具examples/perplexity/perplexity.cpp、examples/quantize/quantize.cpp结语issue #285 是一次典型的fork 特有路径数值回归排查模型文件本身健康、mainline 结果干净、所有 fork 加速开关均非诱因最终通过源码结构反推 修复验证定位到Q8_1块累加和以fp16存储导致的溢出并通过 issue #291 修复。对 DeepSeek-R1/V3 这类超大规模 MoE 模型的量化用户而言它同时也是一份宝贵的参数选择与排查清单评估前务必检查量化类型与注意力张量的匹配关系遇到 NaN 时优先考虑激活量化精度与 ubatch 规模两个变量。【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考