news 2026/9/18 9:25:02

ik_llama.cpp 运行 BitNet b1.58 2B 模型实战:从 bitnet-b1.58 架构兼容到 I2_S 量化转换

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ik_llama.cpp 运行 BitNet b1.58 2B 模型实战:从 bitnet-b1.58 架构兼容到 I2_S 量化转换

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_BITNETLLM_ARCH_BITNET_25LLM_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-25bitnet-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 模型时,遇到两类典型错误:

  1. 架构无法识别llama-quantizeunknown model architecture: 'bitnet-b1.58',直接导致量化失败;
  2. 张量类型无法处理:模型加载器提示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_bn
main: 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_r4iq1_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_r4iq2_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 = 136LLAMA_FTYPE_MOSTLY_IQ2_BN = 137LLAMA_FTYPE_MOSTLY_IQ2_BN_R4 = 337(见 include/llama.h),对应的底层张量类型为GGML_TYPE_IQ1_BN = 134GGML_TYPE_IQ2_BN = 135GGML_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 个元素为一个 block(QK_IQ1BN = 64),每个 block 用极紧凑的位打包表示{-1, 0, +1}三元权重,反量化时通过乘加移位还原出整数值。IQ2_BN则基于同一套IQ1BNQuantizer实现(quantize_one_row_2bn),在 1.58-bit 的基础上提供约 2 bit 的更高精度表示——这也解释了为什么iq2_bn是官方首推的转换目标:它在模型质量与体积之间取得了更平衡的取舍。

从仓库的模型支持公告看(README.md),bitnet-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 的推荐流程如下:

  1. 更新代码:确保使用包含 PR 366(bitnet-b1.58架构名)的版本,即当前仓库源码可直接识别该架构;
  2. 准备模型:获取微软官方bitnet-b1.58-2B-4TGGUF(其中权重为I2_S类型);
  3. 转换量化(关键步骤,二选一):
# 标准转换,通用推荐 ./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
  1. 验证转换结果:转换成功后,加载日志中应不再出现unknown type i2_s,张量类型应显示为iq1_bn/iq2_bn/iq2_bn_r4,架构显示为bitnet-b1.58
  2. 运行推理
./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_bn(1.625 bit)体积最小,但 prompt processing 性能下降;是否换来更好的生成速度取决于具体 CPU 平台;
  • 架构名敏感性bitnet-b1.58bitnet-25bitnet三者是独立的架构条目,加载模型时general.architecture必须精确匹配其一,否则报unknown model architecture

九、小结

BitNet b1.58 2B 在 ik_llama.cpp 中的接入过程,是一个典型的「模型更新 → 架构名兼容 → 量化格式适配」三重问题。架构层面由 PR 366 补齐bitnet-b1.58名称映射(与bitnet-25共用build_bitnet_158计算图)解决;性能层面则由llama-quantizeI2_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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 9:23:39

SpringBoot健康饮食管理系统:架构设计与爬虫实践

1. 项目概述:健康饮食管理系统的技术实现路径这个基于SpringBoot的健康饮食管理系统,本质上是一个融合了数据采集、业务逻辑处理和可视化展示的复合型应用。作为一名长期从事Web系统开发的工程师,我认为这类系统的核心价值在于打通了从原始数…

作者头像 李华
网站建设 2026/9/18 9:23:31

cmd彩色输出完全指南:从color命令到ANSI转义序列实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 9:23:01

用unity-studio提取崩坏学园2看板资源:从定位到导出全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 9:22:02

Mac上用Ollama跑本地大模型:安装、调优与落地实践

如果你手头正好有一台 Mac,又刷到过 “Ollama 本地大模型” 这个词,那么这篇东西就是给你准备的。标题里的关键词很直白:Mac、Ollama、本地大模型、落地优化。我用一台 M 系列芯片的 MacBook 从零开始实操,把安装、下载慢、模型管…

作者头像 李华
网站建设 2026/9/18 9:21:49

PyWxDump 实操指南:完整导出微信聊天记录

PyWxDump 实操指南:完整导出微信聊天记录 【免费下载链接】PyWxDump 删库 项目地址: https://gitcode.com/GitHub_Trending/py/PyWxDump 换电脑后翻不到旧微信记录?PyWxDump 是一个本地运行的 Python 工具,直接读取微信 PC 版加密数据…

作者头像 李华
网站建设 2026/9/18 9:21:31

Agent-Reach:大模型API统一调度CLI工具

1. 项目概述:Agent-Reach 是什么,它解决的不是“能不能用”,而是“怎么稳、怎么快、怎么可维护”Agent-Reach 这个名字乍看像某个开源模型或框架,但结合 CLI、API、Python、GitHub 这几个高频关键词,以及热词中反复出现…

作者头像 李华