
FP32/FP16/BF16浮点数介绍normal value 公式sign位宽度/exp位宽度/fraction位宽度FP32 1/8/23FP16 1/5/10BF16 1/8/7normal value 公式不包含 subnormal/NaN/Infvalue (-1)^s✖️ (1.fraction) ✖️2^(exp - bias)0.15625 0.125 0.03125 2^(-3)2^(-5)0.00101_21.01_2 * 2^(-3)这里 _2 表示 2 进制带入(-1)^s✖️ (1.fraction) ✖️2^(exp - bias)公式FP32fraction 01exp - bias-3bias127exp 12401111100FP16fraction 01exp - bias-3bias15 exp 1201100BF16fraction 01exp - bias-3bias127exp 12401111100为什么浮点数要加 bias偏移为了让指数可以用无符号整数比较大小硬件电路做排序、比较的时候更简单指数真值有负数浮点数规格化的真实指数 e_true 可正可负。比如 FP32e_true in [-126, 127]如果内存里直接存有符号补码硬件比较两个数大小时要单独处理符号位电路复杂、慢补码比较正数、负数规则不一样要额外判断符号Bias 思路平移把全部指数变成非负整数e_storage e_true bias 把整个指数区间向右平移全部变成 ≥0 的无符号数FP32bias 127e_true -126 e_storage -126 127 1e_true 127 e_storage 127127254现在 e_storage in [1,254]是无符号 8 位整数特殊位置指数存储值全 0 → 非规格化数指数存储值全 1 → Inf / NaN这两个编码被预留出来不用于普通规格化数字为什么 bias 取2^(k-1)-1k 是指数位数指数位 k82^7-1127平移之后指数范围对称负指数和正指数的区间尽量均衡1127-12601282541127刚好把 0 真值指数映射到 e_storage biase_true 0 e_storagebias即1.0 * 2^0 1.0FP16 k5bias2^4-115BF16 k8bias127遵循同一个公式Q4量化处理的是一组权重的数值分布不是把每个浮点数的存储砍短一点统一affine的教学模型min和scale每组共享注意这不是 Q4_K的字节复刻Q4_KGGUF是保存张量和元数据的文件容器Q4表示主要权重使用 4bit 量化编码注意这里是主要权重不是所有权重K指向 llama.cpp 量化家族Q4_K_M 是 llama.cpp 生态 GGUF 模型最推荐的默认量化档位兼顾显存占用和模型能力Ollama / LM Studio 大量默认使用它老式 Q4_032 个权重一个 block块全局一组 scaleK-quant256 个权重为一个 super-block超块再拆成 8 个子块每个子块带独立 scale/min每组的局部元数据MMedium 混合策略不是全部张量统一 4bitQ4_K_M 是混合量化大部分张量用 Q4_K注意力等敏感张量自动升到更高精度Q5_K/Q6_K保证推理质量Q4_K_SSmall全部尽量 4bit文件更小质量略差Q4_K_MMedium平衡社区首选Q4_K_LLarge更多张量用高位质量更好体积更大神经网络权重大部分是正负混合Q4_0 用 uint4只能表达 0~15要把负数塞进去只能把整个值域平移会压缩有效精度Q4_0 是对称量化没有独立 min 偏移K-quant 每个子块带独立 min属于非对称量化K-quant 的min就是专门用来做这个平移每个子块独立设置 min4bit 的动态范围利用率高很多同等 bit 数量化误差明显下降Q4_0 和 Q4_K 都是32 个权重一组每组拥有自己的局部缩放因子Q4_0 的 scale 是完整 FP16K-quant 子块的 scale/min 本身是被二次量化的6bit还要乘以超块顶层的全局 FP16 系数是两级分层缩放1 super-block 256 权重拆成 8 个子块1 sub-block32 权重Q4_K 的参数存储超块顶层2 个 FP16d(super-scale)、dmin(super-min)8 个子块每个子块保存量化后的子 scale、子 min6bit不是 FP16反量化公式w_i d * s_b * q_i - dmin * m_bd,dmin超块顶层 FP16s_b,m_b子块的 scale/min从 6bit 解包出来为什么 Q4_K 要这么设计呢Q4_0简单粗暴每个 32 权重独立硬对称映射scale 用 FP16遇到非对称权重分布就浪费比特Q4_0的定义q4bit 无符号整数只能取 0,1,2,…,15 一共 16 个值16 个编码格子公式w scale * (q - 8)固定偏移-8是 Q4_0 对称量化的硬编码规则不能改在当前 block 内遍历 32 个权重算出 w_max max(|w_1|,|w_2|,…,|w_32|)。注意取绝对值的最大值令7 * scale w_max则scale w_max/7以 block 权重 [0.1 ~ 2.0] 为例scale0.2857看每个 q 对应的 w16 个 q 对应 16 个 w 点范围[-2.2856 , 2.0]量化后多出来一截不用的区间 [-2.2856, 0.1)8 个编码点完全闲置没用q815剩下 8 个编码点对应 w0 ~ 2.0。但这个例子真实起点是 0.1不是 0现在只用 8 个点去覆盖区间 [0.1, 2.0]区间长度 2.0 - 0.1 1.9即 8 个点相邻两点间隔 ≈ 1.9/7 ≈ 0.27量化步长≈0.27。意思真实权重落在两个编码点中间时最多误差接近 0.135K-quant 设计者观察到两件事子块内权重的最小值 min很重要不能硬编码scale/min 这类统计参数不需要 FP16可用低比特6bit相对值表达由一个超块顶层系数d 和 dminFP16统一缩放于是设计成大超块做全局值域内部 32 权重子块带独立 min 压缩后的 scale用微小的计算代价显著降低量化误差