
PicoLM量化反量化完全解析Q4_K 4位权重如何恢复成FP32【免费下载链接】picolmRun a 1-billion parameter LLM on a $10 board with 256MB RAM项目地址: https://gitcode.com/gh_mirrors/pi/picolmPicoLM 是一个用纯 C 编写的极简 LLM 推理引擎能在 $10 开发板256MB RAM上运行 10 亿参数大模型。它的核心秘密之一就是Q4_K 量化把 4.4GB 的 FP32 权重压缩到 638MB推理时再把 4 位整数反量化还原成浮点数参与计算。本文带你完整拆解这条压缩 → 解压流水线看看每 144 字节里藏着的 256 个权重是如何一步步恢复成 FP32 的。一、为什么需要量化4.4GB 如何变成 638MBTinyLlama 1.1B 有 11 亿个参数。如果每个参数用 FP324 字节存储光权重就要4.4GB——远超一块 $10 板子的全部内存。量化就是答案用更少的位来近似每个权重。PicoLM 支持的量化格式定义在 quant.h 中各格式每 256 个权重的字节数对比来自 gguf_type_quant_size格式256 个权重占用每权重位数特点Q2_K84 字节~2.6 bit最小质量损失较大Q3_K110 字节~3.4 bit偏小Q4_K144 字节~4.5 bit质量/体积最佳平衡推荐Q6_K210 字节~6.5 bit高质量Q8_032×34 字节8 bit接近无损可以看到Q4_K 下每个权重平均只用144/256 ≈ 0.56 字节不到 FP32 的 1/7。模型文件从 4.4GB 缩到 638MB就能放在 SD 卡里、通过mmap按层流式读入内存。二、Q4_K 块结构256 个权重如何塞进 144 字节Q4_K 的基本单位是一个块block每个块打包256 个 4 位量化值。它的内存布局定义在 quant.h 的 block_q4_K 结构体字段大小含义d2 字节FP16超级块缩放因子super-block scaledmin2 字节FP16超级块最小值因子super-block minscales[12]12 字节8 个子块的6 位缩放因子 6 位最小值位级打包qs[128]128 字节256 个 4 位量化值nibble两两打包进 1 字节设计思想是两级缩放256 个权重一个 Q4_K 块, 144 字节 ┌────────────────────────────────────────────────────┐ │ d(FP16) dmin(FP16) ← 超级块全局缩放/最小值 │ ├────────────────────────────────────────────────────┤ │ scales[12] ← 8 个子块 × (6bit scale 6bit min) │ ├────────────────────────────────────────────────────┤ │ 子块0(32个) 子块1(32个) … 子块7(32个) │ │ 每个子块内部再分 2 组 × 16 个 4 位 nibble │ └────────────────────────────────────────────────────┘为什么是两级因为 256 个权重的数值范围各不相同只用一个全局缩放因子会损失精度。Q4_K 把它们切成 8 个子块每 32 个一组每个子块再各带 1 个 6 位缩放因子sc和 1 个 6 位最小值mn——共 16 个 6 位参数巧妙挤进 12 个字节8×1296 bit 12 B刚好不浪费。三、反量化公式4 位数字如何变回浮点数反量化的核心公式极其简洁见 dequantize_row_q4_Ky (d × sc) × q − (dmin × mn)其中d、dmin块头两个 FP16 因子先经 fp16_to_fp32 软件位运算转成 FP32无需硬件 FP16 支持sc、mn该 32 权重子块的 6 位缩放/最小值q0~15 的 4 位无符号整数从qs字节中按低 4 位 / 高 4 位拆开q[l] 0xF与q[l] 4。也就是说每个权重被近似成缩放 × 4位整数 − 偏移。4 位整数只有 16 档精度但两级缩放让它能紧贴每个子块的真实数值范围因此精度损失很小。一个容易踩坑的细节8 个 6 位参数无法直接存进字节对齐的位置get_scale_min_k4 用位运算从scales[12]里抠出它们——前 4 个子块直接取 6 位q[j] 63后 4 个子块的高 2 位被借存在前面字节的最高 2 位里q[j-4] 6。这种位级借位是 K-Quant 格式紧凑的关键。四、融合点积反量化与乘法一次完成 ⚡既然推理只需要权重 × 输入向量的点积何必先把整行权重解压进内存再读出来PicoLM 的 vec_dot_q4_K_f32 采用融合fused策略按子块累加两个中间量Σ q·x量化值与输入的加权和与Σ x输入分段和最后一步才乘上d·sc和dmin·mn合并出结果。数学上等价但反量化后的 FP32 权重从不落地内存——直接省掉一半访存量。在 ARM 平台上该函数还有 NEON 向量化版本一次处理 8 个字节vmovl_u8 → vmovl_u16 → vcvtq_f32_u32x86 则有 SSE2 版本构建时自动检测quant.h 的 SIMD 宏。这条融合点积正是矩阵乘法matmul的热路径tensor.c 的 matmul 把输出行分给多个线程每行调用一次vec_dot在 4 核 Pi 上可近似线性加速。五、在推理流水线中的位置反量化并不只服务于矩阵乘法PicoLM 中有两类调用点场景入口说明矩阵乘法Q/K/V/FFN 投影tensor.c 的 matmul →vec_dot走融合路径不产生临时 FP32 缓冲嵌入查表 / Norm 权重model.c 中 dequantize_row启动时预解压 RMSNorm 权重每个 token 从token_embd解压一行嵌入统一的分发逻辑在 dequantize_row按 GGUF 头里声明的类型GGUF_TYPE_Q4_K等switch 到对应内核所以换个 Q2_K/Q6_K 的模型文件无需改任何代码。六、总结一张表看懂 Q4_K 反量化步骤做什么对应源码① 读块头FP16 的d、dmin软转 FP32fp16_to_fp32② 拆 6 位参数从scales[12]位运算解出 8 组 sc/mnget_scale_min_k4③ 拆 nibble每字节拆成 2 个 4 位量化值dequantize_row_q4_K④ 还原权重y d·sc·q − dmin·mn同上⑤ 融合计算边拆边乘不落地 FP32vec_dot_q4_K_f32核心要点Q4_K 用两级缩放 6 位打包参数 4 位量化值三板斧把 4 字节的 FP32 压进平均 0.56 字节反量化时只需几次数乘和一次位拆分就能在 $10 板子上实时恢复出参与矩阵运算的浮点权重——这正是 PicoLM 以 45MB 运行内存驱动 1B 模型的底层功臣。【免费下载链接】picolmRun a 1-billion parameter LLM on a $10 board with 256MB RAM项目地址: https://gitcode.com/gh_mirrors/pi/picolm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考