
ik_llama.cpp BF16_R16 量化格式深度解析16 行交错 bf16 布局如何加速 CPU 推理【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp本篇技术指南聚焦 ik_llama.cpp 仓库中的BF16_R16行交错 bf16 格式源自 PR #142「BF16_R16 - 16 interleaved bf16 rows」讲解其设计动机、内存布局原理、CPU 矩阵乘法内核实现与实测性能表现并给出完整的量化使用方式。读完本文你将理解行交错row-interleaved重排格式为什么能提升 bf16 模型的 Prompt ProcessingPP与 Token GenerationTG速度以及如何在当前仓库中把模型转换/重排为BF16_R16并验证其收益。一、背景从 8-bit 世界纪录到 bf16 提速尝试ik_llama.cpp 的核心特色之一是其iqk内核体系见 ggml/src/iqk以及一系列行交错重排量化格式R4/R8/R16后缀。在 PR #141 中作者ikawrakow借助Q8_K_R88-bit 量化矩阵乘法取得了极具竞争力的性能表现紧接着在 2024 年 12 月 14 日提交的 PR #142 中作者将同样的「行交错」思路应用到bf16Brain Float 16格式上尝试进一步加速 bf16 的 CPU 推理这就是BF16_R16的由来。需要特别说明的是BF16_R16并不是一种新的压缩量化——它不改变数值精度、不减小模型体积7B 模型下同为 14.00G而是对 bf16 权重做16 行交错重排目标是让 CPU 在计算矩阵乘法时获得更好的内存访问局部性与 SIMD 寄存器复用从而提升吞吐。PR 状态为Closed作者自评结果有些令人失望因为 PP 提升幅度有限但其 TG 收益与后续 row-interleaved 格式家族的发展脉络仍然值得深入剖析。二、性能实测PR #142 公布的 Ryzen-7950X 基准数据PR #142 在 Ryzen-7950X 上对 LLaMA-3.1-8BBF16_R16格式14.96 GiB8.03 B 参数纯 CPU 后端公布了以下基准结果模型大小参数后端线程测试t/sllama 8B BF16_R1614.96 GiB8.03 BCPU16pp512263.15 ± 0.19llama 8B BF16_R1614.96 GiB8.03 BCPU1tg1283.12 ± 0.00llama 8B BF16_R1614.96 GiB8.03 BCPU2tg1284.25 ± 0.00llama 8B BF16_R1614.96 GiB8.03 BCPU4tg1284.14 ± 0.00pp512 表示 512 token 的 prompt processing 吞吐tg128 表示 128 token 的文本生成速度数据均来自 PR #142 描述测试环境为单机 Ryzen-7950X。作者给出的关键结论是PP 速度BF16_R16相比iqk_mul_mat中原生 bf16 实现仅提升约11%——但请注意iqk 的原生 bf16 实现本身已比主线 llama.cpp 快约3 倍因此是优等生上的再优化。TG 速度LLaMA-3.1-8B 单线程下从 2.5 t/s 提升到3.12 t/s双线程下从 3.9 t/s 提升到4.25 t/s。有趣的是2 线程时BF16_R16已经完全饱和内存带宽4 线程反而回落至 4.14 t/s说明在双线程配置下瓶颈已从计算转移到内存。三、内存布局原理16 行如何交错BF16_R16的核心是repack_bf16模板函数实现在 ggml/src/iqk/iqk_quantize.cpptemplate typename T void repack_bf16(int nrows, int n_per_row, const T * x, ggml_bf16_t * y, [[maybe_unused]] bool online) { GGML_ASSERT(nrows%16 0); GGML_ASSERT(n_per_row%2 0); for (int row 0; row nrows; row 16) { for (int k 0; k 16; k) { auto x8 x k*n_per_row; for (int ib 0; ib n_per_row/2; ib) { y[32*ib 2*k 0] to_bf16(x8[2*ib0]); y[32*ib 2*k 1] to_bf16(x8[2*ib1]); } } x 16*n_per_row; y 16*n_per_row; } }布局规则非常清晰可拆解为三层以 16 行为一个超级块nrows % 16 0是前置条件超级块内按「块索引ib」组织每个块对应 16 行各取2 个连续元素即y[32*ib .. 32*ib31]内连续存放 16 行 × 2 个 bf16第k行0..15的 2 个元素被放置在偏移2*k与2*k1处从而把 16 行的数据交织在相邻内存中。换句话说BF16_R16的读取模式是16 行共享一段连续的内存区间读取一行时可以顺带把其余 15 行的对应数据一起加载进 cache/寄存器。这与Q8_K_R8、Q8_K_R16等格式的R系列思路一脉相承R4 4 行交错、R8 8 行交错、R16 16 行交错。PR 作者在描述中提到他试验了 4、8、16 行三种交错宽度16 行最快但也只是比 8 行略快因此最终选择了R16。对应的两个 repack 入口定义在 ggml/src/iqk/iqk_quantize.cpprepack_f32_bf16_r16将 f32 权重转换为 bf16 并交错重排repack_bf16_bf16_r16将已有 bf16 权重直接重排为交错布局。在 ggml/src/iqk/iqk_quantize.cpp 的 repack 注册表中可以看到GGML_TYPE_BF16与GGML_TYPE_F16都能直接重排为BF16_R16{ GGML_TYPE_BF16, { GGML_TYPE_BF16_R16, 16, (Repack::repack_func)repack_bf16ggml_bf16_t}}, { GGML_TYPE_F16, { GGML_TYPE_BF16_R16, 16, (Repack::repack_func)repack_bf16ggml_half} },四、源码级实现类型定义、调度路径与 AVX512 内核4.1 类型与文件类型定义BF16_R16在 ggml 类型系统中是正式成员定义于 ggml/include/ggml.hGGML_TYPE_BF16_R16 230,对应模型文件类型ftype为GGML_FTYPE_MOSTLY_BF16_R16 224见 ggml/include/ggml.h类型名称为bf16_r16见 ggml/src/ggml.c。从 ggml/src/ggml.c 可看到GGML_FTYPE_MOSTLY_BF16_R16与GGML_TYPE_BF16_R16的映射关系。此外ggml 将BF16_R16与Q8_K_R16一同识别为 16 行交错类型ggml/src/ggml.c。4.2 乘法内核mul_mat_bf16_r16_bf16BF16_R16的矩阵乘法走的是 float 系内核核心实现在 ggml/src/iqk/iqk_gemm_floats.cpp函数名为mul_mat_bf16_r16_bf16并以#ifdef __AVX512BF16__保护——即依赖支持 AVX512 BF16 指令_mm512_dpbf16_ps单指令完成 bf16 点积累加的 CPUtemplate int nrc_y static void mul_mat_bf16_r16_bf16(int n, const void * vx, size_t bx, const DataInfo info, int nrc_x) { GGML_ASSERT(nrc_x%16 0); const ggml_bf16_t * y[nrc_y]; ... for (int ix 0; ix nrc_x/32; ix) { __m512 acc[2*nrc_y] {}; __m512bh qx[8]; ... acc[2*iy0] _mm512_dpbf16_ps(acc[2*iy0], qx[0], ...); ... } }实现要点与推断如下一次处理 32 行 xnrc_x/32外层循环通过_mm512_loadu_si512以 512-bit 宽度加载 bf16 数据到__m512bh向量qx中被加载的权重数据会被多个y行nrc_y个输出行反复复用这正是行交错布局的核心收益16 行交错的权重连续驻留在寄存器中减少重复内存加载函数模板按nrc_y 1..8实例化set_mul_mat_bf16_r16见 ggml/src/iqk/iqk_gemm_floats.cpp覆盖常见的输出行数。从内核的GGML_ASSERT(nrc_x%16 0)可以看出BF16_R16的乘法要求 x 侧行数为 16 的倍数这与 repack 阶段的nrows%16 0约束保持一致。4.3 调度路径在 x86-64 上MulMat::prepare会把GGML_TYPE_BF16_R16归入 float 系内核选择分支与F16/F32/BF16并列调用iqk_set_kernels_float见 ggml/src/iqk/iqk_mul_mat.cpp。若权重不是预重排的BF16_R16还可以在加载/推理时在线 repack——ggml/src/ggml.c 中存在调用repack_f32_bf16_r16的路径配合 docs/development/on-demand-tensor-reload.md 中描述的按需张量重载机制使用。五、如何生成与使用 BF16_R16 模型BF16_R16已作为正式量化选项注册在 examples/quantize/quantize.cpp 的QUANT_OPTIONS表中{ BF16_R16, LLAMA_FTYPE_MOSTLY_BF16_R16, 14.00G, -0.0050 ppl Mistral-7B, },这意味着你可以直接用仓库自带的llama-quantize工具把模型转换为该格式# 将 F16/F32/BF16 模型转换重排为 BF16_R16 ./llama-quantize input-model.gguf output-model.gguf BF16_R16要点说明选项名大小写不敏感try_parse_ftype内部会转大写后匹配见 examples/quantize/quantize.cpp工具标注的模型体积为 7B 模型约 14.00G与BF16/F16一致印证其无损重排、不压缩的属性其困惑度增量-0.0050 ppl Mistral-7B与BF16完全相同即数值质量与普通 bf16 完全等价转换完成后用llama-cliexamples/main、llama-serverexamples/server等工具正常加载推理即可模型加载器会自动识别GGML_FTYPE_MOSTLY_BF16_R16见 src/llama-model-loader.cpp 与 src/llama-quantize.cpp 中对相关类型的处理。六、适用前提与收益边界结合 PR 描述与源码实现BF16_R16的收益有明显边界务必理性看待指令集前提核心内核受__AVX512BF16__宏保护只有在支持 AVX512 BF16 的 CPU如 Sapphire Rapids 等上才能发挥_mm512_dpbf16_ps的点积优势无此指令集的平台会走其他路径收益大打折扣。PP 增益有限PR 作者实测仅比 iqk 原生 bf16 快约 11%——但 iqk 的 bf16 本身已比主线快约 3 倍因此BF16_R16属于最后一公里优化。TG 对线程数敏感实测 2 线程即饱和内存带宽4.25 t/s4 线程反而回落4.14 t/s单线程也有约 25% 提升2.5 → 3.12 t/s。在内存带宽受限的 TG 场景盲目加线程无益。PR 状态为 Closed该 PR 最终未合入作者称之为somewhat disappointing result。从仓库现状看16 行交错的思路后来以Q8_K_R16等形式继续演进ggml/include/ggml.hBF16_R16本身则保留了作为 bf16 重排格式的独立价值。七、总结BF16_R16是 ik_llama.cpp 行交错格式家族在 bf16 精度上的尝试通过将 16 行权重交织存储配合 AVX512 BF16 点积指令的寄存器复用在已有高水准的 iqk bf16 内核之上再获得约 11% 的 PP 提升与约 25%单线程的 TG 提升且不损失任何数值质量。对追求 bf16 精度又希望榨干现代 x86 CPU 性能的用户而言BF16_R16是一个值得一试的选项而对想深入理解行交错布局原理的读者ggml/src/iqk/iqk_quantize.cpp 的repack_bf16与 ggml/src/iqk/iqk_gemm_floats.cpp 的mul_mat_bf16_r16_bf16是两段最直接的参考实现。关联文件速查PR 原文github-data/pull_requests/142 - BF16_R16 - 16 interleaved bf16 rows.md类型定义ggml/include/ggml.h重排实现ggml/src/iqk/iqk_quantize.cpp乘法内核ggml/src/iqk/iqk_gemm_floats.cpp调度入口ggml/src/iqk/iqk_mul_mat.cpp量化选项examples/quantize/quantize.cpp相关讨论github-data/discussions/548 - Poor performance with bf16 model on Qwen3 30B-A3B.md【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考