
ik_llama.cpp 运行 BitNet b1.58 2B 模型实战从 bitnet-b1.58 架构兼容到 I2_S 量化转换【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp本文以 ik_llama.cpp 仓库中关于 BitNet 新架构的 issue #365 为核心脉络完整梳理微软 BitNet b1.58 2B 模型从「加载报错」到「量化转换、正常运行」的全过程包括bitnet-b1.58架构名兼容、微软私有量化类型I2_S的识别以及IQ2_BN/IQ2_BN_R4/IQ1_BN三种转换方案的选型。读完本文你将掌握在 ik_llama.cpp 中转换并运行 BitNet b1.58 系列模型的完整命令、量化类型取舍原则以及背后的源码级实现原理。一、背景BitNet 模型与架构命名的演进BitNet 是微软提出的 1-bit 大语言模型路线权重被限制在{-1, 0, 1}三个值即 1.58 bit因此在 CPU 上也能以极低的内存占用运行。ik_llama.cpp 最初通过 PR 337 支持了 2025 年初发布的 BitNet 模型其 GGUF 中标注的架构名为bitnet-25。2025 年 4 月 23 日微软在 Hugging Face 上替换了旧的 BitNet 模型发布新的 BitNet b1.58 2B 模型4T tokens 训练新版本 GGUF 的general.architecture字段改成了bitnet-b1.58。这看起来只是名称变化却导致了旧版本 ik_llama.cpp如 issue 中提到的98d1626469879d35faba9cb7e9d0b1ddaf853eee无法识别该模型。在当前的仓库源码中可以清楚看到 BitNet 家族共有三个架构条目见 src/llama-arch.cpp{ LLM_ARCH_BITNET, bitnet }, { LLM_ARCH_BITNET_25, bitnet-25 }, { LLM_ARCH_BITNET_B158, bitnet-b1.58 },对应枚举定义在 src/llama-arch.h 中LLM_ARCH_BITNET、LLM_ARCH_BITNET_25、LLM_ARCH_BITNET_B158。其中bitnet-b1.58正是 issue 中新增的架构名而它在计算图构建上复用了与bitnet-25相同的实现——src/llama-build-context.cpp 中case LLM_ARCH_BITNET: result llm.build_bitnet(); break; case LLM_ARCH_BITNET_B158: case LLM_ARCH_BITNET_25: result llm.build_bitnet_158(); break;同时bitnet-25与bitnet-b1.58的张量映射表token_embd、output_norm、output、rope_freqs、attn_norm、attn_q/k/v、attn_output、attn_rot_embd、ffn_gate_inp、ffn_norm、ffn_gate/down/up、MoE 专家张量、attn_sub_norm、ffn_sub_norm 等在 src/llama-model.cpp 中完全一致。这说明从模型结构角度两者本质上是同一套网络布局差异主要体现在架构标识上。二、问题现象新模型加载与量化直接报错issue 中用户 jdluzen 在 Windows arm64 上尝试运行新版 BitNet 模型时遇到两类典型错误架构无法识别llama-quantize报unknown model architecture: bitnet-b1.58直接导致量化失败张量类型无法处理模型加载器提示llama_model_loader: unknown type i2_s随后在ggml.c中因GGML_TYPE_I2_S类型号 36对应的vec_dot为 null 而崩溃。另一位用户 usatenko 在 macOS 上复现了同样的问题给出了完整的量化失败日志。模型元数据非常值得关注这里完整摘录该模型即微软官方发布的bitnet-b1.58-2B-4T-gguf./bin/llama-quantize --allow-requantize models/ggml-model-i2_s.gguf ggml-model-i2_s_bn.gguf iq2_bnmain: build 3657 (98d16264) main: built with Apple clang version 17.0.0 (clang-1700.0.13.3) for arm64-apple-darwin24.4.0 main: quantizing models/ggml-model-i2_s.gguf to ggml-model-i2_s_bn.gguf as IQ2_BN llama_model_loader: loaded meta data with 24 key-value pairs and 332 tensors from models/ggml-model-i2_s.gguf (version GGUF V3 (latest)) llama_model_loader: unknown type i2_s llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output. llama_model_loader: - kv 0: general.architecture str bitnet-b1.58 llama_model_loader: - kv 1: general.name str bitnet2b llama_model_loader: - kv 2: bitnet-b1.58.vocab_size u32 128256 llama_model_loader: - kv 3: bitnet-b1.58.context_length u32 4096 llama_model_loader: - kv 4: bitnet-b1.58.embedding_length u32 2560 llama_model_loader: - kv 5: bitnet-b1.58.block_count u32 30 llama_model_loader: - kv 6: bitnet-b1.58.feed_forward_length u32 6912 llama_model_loader: - kv 7: bitnet-b1.58.rope.dimension_count u32 128 llama_model_loader: - kv 8: bitnet-b1.58.attention.head_count u32 20 llama_model_loader: - kv 9: bitnet-b1.58.attention.head_count_kv u32 5 llama_model_loader: - kv 10: tokenizer.ggml.add_bos_token bool true llama_model_loader: - kv 11: bitnet-b1.58.attention.layer_norm_rms_epsilon f32 0.000010 llama_model_loader: - kv 12: bitnet-b1.58.rope.freq_base f32 500000.000000 llama_model_loader: - kv 13: general.file_type u32 40 llama_model_loader: - kv 14: tokenizer.ggml.model str gpt2 llama_model_loader: - kv 15: tokenizer.ggml.tokens arr[str,128256] [!, \, #, $, %, , , ... llama_model_loader: - kv 16: tokenizer.ggml.scores arr[f32,128256] [0.000000, 0.000000, 0.000000, 0.0000... llama_model_loader: - kv 17: tokenizer.ggml.token_type arr[i32,128256] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... llama_model_loader: - kv 18: tokenizer.ggml.merges arr[str,280147] [Ġ Ġ, Ġ ĠĠĠ, ĠĠ ĠĠ, ... llama_model_loader: - kv 19: tokenizer.ggml.bos_token_id u32 128000 llama_model_loader: - kv 20: tokenizer.ggml.eos_token_id u32 128001 llama_model_loader: - kv 21: tokenizer.ggml.padding_token_id u32 128001 llama_model_loader: - kv 22: tokenizer.chat_template str {% for message in messages %}{% if lo... llama_model_loader: - kv 23: general.quantization_version u32 2 llama_model_loader: - type f32: 121 tensors llama_model_loader: - type f16: 1 tensors llama_model_loader: - type i2_s: 210 tensors llama_model_quantize: failed to quantize: unknown model architecture: bitnet-b1.58 main: failed to quantize model from models/ggml-model-i2_s.gguf这段日志揭示了两个关键事实模型结构128256 词表gpt2 BPE 分词器、4096 上下文、2560 隐藏维度、30 层、6912 FFN 维度、20 个注意力头5 个 KV 头、RoPE 维度 128、freq_base 500000、RMS Norm epsilon 1e-5张量分布332 个张量中121 个 f32、1 个 f16、210 个 i2_s。i2_s 就是微软私有的I2_S量化类型占据了绝大多数权重张量。三、根因分析I2_S 是微软私有量化格式为什么老版本无法加载问题不在架构本身而在量化类型。微软发布的 BitNet GGUF 使用了自己的量化类型I2_S这是一种 2-bit 符号量化格式权重量化为{-1, 0, 1}三元值1.58 bit 的含义即来源于此。在 ik_llama.cpp 的 ggml/include/ggml.h 中GGML_TYPE_I2_S 36的注释写得很明确GGML_TYPE_I2_S 36, // So we are able to consume MS BitNet I2_S quants即该类型是为了「能够消费微软 BitNet 的 I2_S 量化权重」而加入的。但仅有类型定义还不够——量化权重要真正参与计算必须要有对应的vec_dot向量点积内核。issue 中的崩溃点vec_dot为 null 正是发生在GGML_TYPE_I2_S类型上旧版本代码里 I2_S 只有类型定义用于读取模型却没有可直接执行的计算内核因此直接运行原始 GGUF 会在矩阵乘环节崩溃。issue 中 jdluzen 用 debug 版llama-cli.exe -m ggml-model-i2_s.gguf直接运行原始模型时还遇到了另一个崩溃Assertion failed: ldb k, file A:\src\ik_llama.cpp\ggml\src\llamafile\sgemm.cpp, line 856这正是「拿一个只有存储格式、没有完整计算链的量化类型直接跑推理」的典型症状。四、解决方案一补充 bitnet-b1.58 架构名社区成员 saood06 很快定位到问题新版模型只是架构名从bitnet-25改成了bitnet-b1.58模型结构本身没有变化。验证方法很有说服力——对基于新旧模型分别转换出的 GGUF 运行gguf-hash.py得到完全一致的哈希值证明两个 GGUF 在内容层面除架构名外是等价的。随后提交的 PR 366 在架构名映射表中新增了bitnet-b1.58条目即当前仓库 src/llama-arch.cpp 中{ LLM_ARCH_BITNET_B158, bitnet-b1.58 }这行并使其与bitnet-25共用build_bitnet_158()计算图构建逻辑。用户 usatenko 确认「thank you, it works now」问题得以解决。这也解释了为什么说「这只是个名称变化」架构枚举、张量映射、计算图构建都是现成的缺的只是把字符串bitnet-b1.58解析到已有枚举LLM_ARCH_BITNET_B158的那一行映射。五、解决方案二将 I2_S 转换为 IQ2_BN / IQ1_BN推荐架构名修复只是让模型「能被识别」但要获得可用的推理性能还需要把微软的I2_S权重转换为 ik_llama.cpp 原生支持且带有完整计算内核的量化格式。项目作者 ikawrakow 在 issue 中给出了官方标准做法./bin/llama-quantize --allow-requantize $microsoft_model $converted_model iq2_bn即对微软原始 GGUF 执行**允许重新量化requantize**的转换目标格式为IQ2_BN。5.1 为什么需要 --allow-requantize常规量化是从 fp16/fp32 等未量化权重出发而微软模型本身已经是量化过的I2_S。要把I2_S再转成IQ2_BN属于「量化到量化」的转换必须显式传入--allow-requantize才能放行。在 src/llama-quantize.cpp 中可以看到对GGML_TYPE_I2_S张量有专门的处理分支——先通过qtype.to_float把整个张量反量化回 f32再做后续处理if (tensor-type GGML_TYPE_I2_S) { // we need to dequantize the entire tensor for I2_S qtype.to_float(tensor-data, f32_output, nelements); return; }也就是说转换链路是I2_S → f32 → IQ2_BN中间必须经过全精度反量化。这也意味着转换过程需要一定的内存与时间开销。5.2 三种目标格式的取舍ikawrakow 在 issue 回复中给出了完整的选型建议整理如下目标格式每权重比特数适用场景说明iq2_bn约 2 bit通用默认官方推荐的标准转换目标CPU / GPU 均可iq2_bn_r4约 2 bit仅 CPU且追求 prompt 处理速度采用行交错row-interleaved打包prompt processing 性能更好iq1_bn1.625 bit追求更小模型体积模型更小PP 性能低于 iq2_bn/iq2_bn_r4但在部分 CPU 上可能获得略高的 token 生成速度具体命令以iq2_bn_r4和iq1_bn为例# CPU-only 场景追求更好的 prompt processing 性能 ./bin/llama-quantize --allow-requantize $microsoft_model $converted_model iq2_bn_r4 # 追求更小体积1.625 bits/weight ./bin/llama-quantize --allow-requantize $microsoft_model $converted_model iq1_bn从源码看iq2_bn_r4是iq2_bn的 4 行交错变体映射关系定义在 src/llama-quantize.cpp{ GGML_TYPE_IQ2_BN_R4, { GGML_TYPE_IQ2_BN, 4} }即IQ2_BN_R4以 4 行为一组打包底层量化结构与IQ2_BN相同。这就是为什么两种格式可以自由互转、且 r4 变体在行连续的内存布局上对 CPU 更友好的原因。5.3 转换时的张量处理细节转换过程还有一些值得注意的细节对齐要求IQ1_BN/IQ2_BN/IQ2_BN_R4要求张量列数能被块大小整除nx % QK_IQ1BN 0其中QK_IQ1BN定义为 64见 ggml/src/ggml-common.h。若张量形状不满足量化器会自动回退为兼容类型见 src/llama-quantize.cpp特殊张量类型对于output_norm等归一化张量和token_embd.weight嵌入张量当目标为IQ1_BN/IQ2_BN/IQ2_BN_R4时默认类型会被调整为IQ4_NL见 src/llama-quantize.cpp 与 src/llama-quantize.cpp因为这些张量对精度更敏感不适合 1-2 bit 量化文件类型标识转换产物对应 GGUF 文件类型LLAMA_FTYPE_MOSTLY_IQ1_BN 136、LLAMA_FTYPE_MOSTLY_IQ2_BN 137、LLAMA_FTYPE_MOSTLY_IQ2_BN_R4 337见 include/llama.h对应的底层张量类型为GGML_TYPE_IQ1_BN 134、GGML_TYPE_IQ2_BN 135、GGML_TYPE_IQ2_BN_R4 335见 ggml/include/ggml.h。六、IQ1_BN / IQ2_BN 量化格式的源码级原理转换后的IQ1_BN/IQ2_BN是 ik_llama.cpp 为 BitNet 这类 1.58-bit 模型引入的特化格式。从 ggml/src/iqk/iqk_quantize.cpp 可以看到其核心实现void quantize_row_iq1_bn(const float * x, void * y, int64_t k) { quantize_iq1_bn(x, y, 1, k, nullptr, nullptr); } void dequantize_row_iq1_bn(const block_iq1_bn * x, float * y, int64_t k) { assert(k%QK_IQ1BN 0); int nblock k / QK_IQ1BN; ... } size_t quantize_iq2_bn(const float * src, void * dst, int64_t nrows, int64_t n_per_row, const float * imatrix, ...) { IQ1BNQuantizer iq1bn; ... iq1bn.quantize_one_row_2bn(src row*n_per_row, (block_iq2_bn *)qrow, n_per_row, imatrix); ... }反量化逻辑显示IQ1_BN以 64 个元素为一个 blockQK_IQ1BN 64每个 block 用极紧凑的位打包表示{-1, 0, 1}三元权重反量化时通过乘加移位还原出整数值。IQ2_BN则基于同一套IQ1BNQuantizer实现quantize_one_row_2bn在 1.58-bit 的基础上提供约 2 bit 的更高精度表示——这也解释了为什么iq2_bn是官方首推的转换目标它在模型质量与体积之间取得了更平衡的取舍。从仓库的模型支持公告看README.mdbitnet-b1.58-2B-4T的支持正是通过 PR 337 引入的与本次 issue 修复PR 366共同构成了该模型在 ik_llama.cpp 中的完整支持链路PR 337 加架构与 I2_S 读取支持 → PR 366 补架构名映射 → llama-quantize 提供 I2_S → IQ1_BN/IQ2_BN 的转换通道。七、完整落地步骤与验证综合以上分析在 ik_llama.cpp 中运行 BitNet b1.58 2B 的推荐流程如下更新代码确保使用包含 PR 366bitnet-b1.58架构名的版本即当前仓库源码可直接识别该架构准备模型获取微软官方bitnet-b1.58-2B-4TGGUF其中权重为I2_S类型转换量化关键步骤二选一# 标准转换通用推荐 ./bin/llama-quantize --allow-requantize $microsoft_model $converted_model iq2_bn # 仅 CPU 运行追求 prompt processing 性能 ./bin/llama-quantize --allow-requantize $microsoft_model $converted_model iq2_bn_r4 # 追求最小体积1.625 bits/weight ./bin/llama-quantize --allow-requantize $microsoft_model $converted_model iq1_bn验证转换结果转换成功后加载日志中应不再出现unknown type i2_s张量类型应显示为iq1_bn/iq2_bn/iq2_bn_r4架构显示为bitnet-b1.58运行推理./bin/llama-cli -m $converted_model -p hi what are you八、注意事项与已知限制不要直接跑原始 I2_S 模型微软原始 GGUF 中的I2_S在 ik_llama.cpp 中主要用于「读取和转换」直接用于推理可能因缺少对应计算内核而崩溃如vec_dot为 null 断言。务必先转换为IQ2_BN系列必须加--allow-requantize从已量化的I2_S再量化必须显式允许 requantize否则转换会被拒绝iq2_bn_r4的适用前提r4 行交错变体主要面向 CPU 优化若涉及 GPU 卸载建议优先使用标准iq2_bn体积与性能的权衡iq1_bn1.625 bit体积最小但 prompt processing 性能下降是否换来更好的生成速度取决于具体 CPU 平台架构名敏感性bitnet-b1.58、bitnet-25、bitnet三者是独立的架构条目加载模型时general.architecture必须精确匹配其一否则报unknown model architecture。九、小结BitNet b1.58 2B 在 ik_llama.cpp 中的接入过程是一个典型的「模型更新 → 架构名兼容 → 量化格式适配」三重问题。架构层面由 PR 366 补齐bitnet-b1.58名称映射与bitnet-25共用build_bitnet_158计算图解决性能层面则由llama-quantize的I2_S → IQ2_BN / IQ2_BN_R4 / IQ1_BN转换通道解决。整个链路在 src/llama-arch.cpp、src/llama-build-context.cpp、src/llama-quantize.cpp 与 ggml/src/iqk/iqk_quantize.cpp 中均有清晰的源码佐证。对希望以约 2 bit 甚至 1.625 bit 的超低精度在 CPU 上运行 BitNet 类模型的开发者而言本文给出的转换命令与选型建议可以直接复用。【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考