从 TensorSharp 视角解读 Ternary Bonsai 2 27B:当 1.72 比特的权重遇上 Hadamard 变换
本文基于 PrismML 发布资料、CloudNavi 部署指南(2026-09-19)与 TensorSharp 官方模型文档(
docs/models/bonsai2.md,集成验证日期 2026-09-22)整理,聚焦 TensorSharp 作为推理引擎是怎么"接住"这个模型的,不谈 Ollama / llama.cpp 路线。
1. 引言:一个"普通运行时跑不了"的模型
2026 年 9 月 17 日,PrismML(出自 Caltech 的研究团队,获 Khosla Ventures、Cerberus、Google 支持)发布了 Ternary Bonsai 2 27B:一个把 27.36B 参数压进 5.9GB 文件的三元量化多模态模型,在 20 项基准上保留了基座模型 98.2% 的分数。
数字很诱人,但它有一个苛刻的前提:原版 llama.cpp 与现行 Ollama 都无法运行它。权重不在普通的数值基底上,运行时必须执行 activation 侧的 Walsh–Hadamard 变换,而这个变换至今没有合并进上游 llama.cpp。
这就给推理引擎出了一道工程题:不魔改底层库、不重新量化,怎么把一个"带旋转基底"的低比特模型跑对、跑得可验证?TensorSharp 的集成方案是一个值得拆开看的样本,本文就沿着它展开。
2. 模型速览:压缩了什么,保留了什么
2.1 基本规格
| 项目 | 内容 |
|---|---|
| 参数量 | 273.6 亿(语言 243.5 亿 · 视觉塔 4.7 亿 · 嵌入与 LM head 25.4 亿) |
| 架构 | 混合注意力(线性约 75% · 全注意力约 25%),SwiGLU、RoPE、RMSNorm |
| 权重格式 | 三元 g128 + FP16 分组缩放,分块 Hadamard 旋转 |
| 有效位宽 | 真三元 1.72 bit/权重;发布的 PTQ1_0 为 1.76 bit |
| 最大上下文 | 262,144 token |
| 输入 / 输出 | 文本 + 图像输入 / 文本输出 |
| 许可 | Apache 2.0 |
模型本质上是 PrismML 对 Qwen 系列稠密基座的三元量化版:权重只用 −1、0、+1 三个值存放,配合 FP16 分组缩放,FP16 下 53.8GB 的权重被压到约九分之一。
2.2 基准保留率(官方公布值)
20 项基准在思考模式下平均 83.9 分,相对基座 27B 的 85.4 分保留 98.2%。更值得看的是分项:
| 能力 | Bonsai 2 27B | 基座 27B | 保留率 |
|---|---|---|---|
| 知识与推理 | 83.95 | 86.66 | 96.9% |
| 数学 | 96.57 | 97.06 | 99.5% |
| 编码 | 81.58 | 82.17 | 99.3% |
| 代理与工具调用 | 77.57 | 79.74 | 97.3% |
| 指令遵循 | 82.66 | 81.25 | 102.0% |
| 视觉 | 78.59 | 81.64 | 96.3% |
| 综合 | 83.9 | 85.4 | 98.2% |
数学与编码几乎无损,指令遵循甚至反超基座;知识与推理、视觉各下降约 3%。误差会在长链路代理任务里累积,这个区间需要留意。
2.3 官方发布的三种文件
| 格式 | 体积 | 特点 |
|---|---|---|
| GGUF PTQ1_0 | 5.93GB | 体积最小,每权重 1.76 比特 |
| GGUF PQ2_0 | 7.25GB | 解包更轻,提示词处理更快(demo 默认) |
| MLX 2bit | 8.49GB | 面向 Apple Silicon,含全精度视觉塔,可用于原版 MLX |
3. 核心难点:权重不只是三元数
这是理解整个集成工作的关键,TensorSharp 文档开篇就说得很直白:
Merely interpreting its weights as ordinary ternary numbers produces the wrong network: projection inputs and embedding outputs must also receive the declared transforms.
(仅仅把权重当作普通三元数去解释,得到的是一个错误的网络:投影的输入和嵌入的输出必须施加声明的变换。)
换句话说,单做"把权重换成 −1/0/+1"这一步并不够:权重被存放在一个旋转基底上,运行时必须配合执行逆变换,网络才是原网络。具体来说:
- 嵌入查表后,要经过逆变换;
- 每个低比特投影在矩阵乘之前,要对输入激活做变换;
- 输出 head 之前还要再做一次正变换。
如果运行时"看起来能加载、能出 token",却跳过了这些变换,它输出的其实是一个从未训练过的网络的结果。这正是 CloudNavi 文章警告的陷阱:旧格式文件在某些原版构建上会静默加载并输出乱码;低比特格式没有被原生支持时,有的运行时会静默按高精度反量化运行,输出对了,但速度与内存优势全部消失。
4. TensorSharp 的接入方案:转码而非魔改
4.1 设计哲学:不 patch ggml
TensorSharp 对这两种自定义格式的处理方式很克制:
- GGUF 读取器把 PQ2_0 识别为张量类型 142、PTQ1_0 识别为 143;
- TensorSharp 自有的 native 代码把它们的块打包无损展开为上游 GGML 的 Q2_0 块;
- 保留权重表示值,不做再量化;
- 从不改写原始 GGUF 文件,也不给 ggml 打补丁去引入发行方私有的张量类型。
代价是内存占用不再等于文件体积:无损展开会增大量化负载,PQ2_0 约多 6%,PTQ1_0 约多 29%。这是用内存换兼容性的明确取舍。
4.2 变换契约:prism.hadamard.*
模型文件里带有一组 prism.hadamard.* 元数据,声明了:变换版本、归一化的 Sylvester-Walsh-Hadamard 变换、输入轴、块大小(本组模型为 1,024 元素/块)、显式 ±1 符号表,以及哪些权重名要做正变换或逆变换。
数学上,对一个投影输入 x,每个块计算:
H(D·x) / sqrt(block_size)
其中 D 是存储的 ±1 符号对角矩阵,H 是未归一化 Hadamard 矩阵。嵌入行则用逆序:
D·(H·x) / sqrt(block_size)
此外,分组 GDN 元数据还会把 SSM 输出输入按发行方的 head 顺序重排后再变换;融合的 QKV 和 gate/up 权重保留其原投影各自的变换。
TensorSharp 在加载权重之前校验完整的契约,遇到未知的变换布局直接拒绝:宁可跑不起来,也不静默跑错。
4.3 代码入口
整个集成散布在五个文件里,职责划分清晰:
| 文件 | 职责 |
|---|---|
BonsaiHadamardMetadata.cs |
校验元数据,实现托管侧的逆嵌入变换 |
ModelBase.Bonsai.cs |
模型加载期的转码与变换注册 |
QuantizedWeight.Bonsai.cs |
权重缓存键的变换注册,释放时注销 |
bonsai_quant.cpp |
精确的块解码/转码,不修改上游 GGML |
ggml_ops_bonsai.cpp |
把符号变换接入 TensorSharp 的 native 计算图路径 |
4.4 网络执行流程
token ID -> 低比特嵌入行 -> 逆符号 Hadamard 变换
-> 64 个混合 Qwen 3.5 层:
RMSNorm -> attention 或 GatedDeltaNet -> 残差
RMSNorm -> 稠密门控 FFN -> 残差
(声明的低比特投影会旋转其输入激活)
-> RMSNorm -> 符号 Hadamard 变换 -> 低比特输出 head -> logits
底层架构上,两个 GGUF 文件声明 general.architecture=qwen35:64 层、hidden width 5,120、FFN width 17,408、词表 248,320、262,144 token 上下文。其中 48 层是递归的 GatedDeltaNet,16 层是全注意力;全注意力用 24 个 query 头 + 4 个 KV 头(宽度 256),GatedDeltaNet 用 16 个 key 组 + 48 个 value 头(宽度 128)。TensorSharp 复用了现成的 Qwen 3.5 实现(整模型 prefill/decode、逐序列的 KV 与递归状态、continuous batching),PRISM 变换被插入到这些既有路径里,直接继承其融合与状态管理。
5. 怎么跑:命令与限制
5.1 首版集成的硬性限制
初始集成只接受单设备 GGML backend。纯托管 CPU、直连 CUDA、MLX、张量并行配置都会被直接拒绝,而不是静默省略旋转变换。宁可拒绝加载,也不给出错误结果,这是整条集成线一致的原则。
5.2 运行示例
显式设置上下文上限,而不是按宣传的 262k 全量分配:
# CLI 推理
MAX_CONTEXT=4096 KV_CACHE_DTYPE=f16 \
dotnet run --project TensorSharp.Cli -c Release -- \
--model /path/to/Ternary-Bonsai-2-27B-PQ2_0.gguf \
--backend ggml_metal --input prompt.txt --max-tokens 128 \
--temperature 0
# 带 OpenAI 兼容 API 的服务端,挂载视觉投影器
MAX_CONTEXT=4096 KV_CACHE_DTYPE=f16 \
dotnet run --project TensorSharp.Server.Host -c Release -- \
--model /path/to/Ternary-Bonsai-2-27B-PTQ1_0.gguf \
--mmproj /path/to/Ternary-Bonsai-2-27B-mmproj-Q8_0.gguf \
--backend ggml_metal --host 127.0.0.1 --port 5000
配套的投影器文件有两个:mmproj-BF16(全精度)和 mmproj-Q8_0(更省内存),对比图像质量或内存占用时用 --mmproj 显式指定。
6. 可复现验证:数字摆到桌面上
TensorSharp 的验证流程覆盖:精确 raw-token 参照、单路/并行流式请求、算术、结构化 JSON、工具调用、两个投影器、解析器测试。基线是 PrismML 官方的 llama.cpp 分支(bdc23b56 提交)。文档特别强调:一个连 PQ2_0/PTQ1_0 都加载不了的上游 llama.cpp 构建,不构成有效的性能对比对象。
6.1 正确性(2026-09-22,Metal)
在未改动的上游 ggml 179b60f2 上:
- 两种格式在 Metal 上逐 token 精确复现发行方基线的 4 条贪心提示(各 32 token);
- 4 路并发序列的输出与串行完全一致,31 步融合 decode、零回退步;
- 每种格式通过 21 项 HTTP 单路/并发对比,以及算术、JSON、工具调用、图像颜色检查(PQ2 + Q8_0 投影器、PTQ1 + BF16 投影器各测一组)。
注意这些是功能性冒烟测试,不是全面的质量评估;262k 上下文、CUDA、Vulkan、iOS、张量并行均未验证。
6.2 性能(Apple M5 Pro,48GB 统一内存)
| 格式 | 指标 (tokens/s) | TensorSharp | 发行方 llama.cpp |
|---|---|---|---|
| PQ2_0 | Prefill 512 | 364.05 | 384.44 |
| PQ2_0 | Decode 64 | 25.50 | 26.96 |
| PQ2_0 | HTTP 并发 4 | 28.40 | 32.57 |
| PTQ1_0 | Prefill 512 | 364.49 | 357.67 |
| PTQ1_0 | Decode 64 | 25.53 | 26.31 |
| PTQ1_0 | HTTP 并发 4 | 28.17 | 16.15 |
模型级速率为三次预热运行(零上下文深度)的均值;HTTP 速率为三次运行的均值(每请求 64 生成 token)。两侧引擎均用 F16 KV 和 512 token 物理 prefill 批。
文档对结果的定性很直白:性能目标尚未达成。模型级 decode 比基线慢 5.4%(PQ2)和 3.0%(PTQ1),PQ2 并发 4 的 HTTP 吞吐低 12.8%。旋转变换本身有开销,转码后的权重也比发行方自定义格式更占内存。PTQ1_0 的 prefill 和高并发 HTTP 反而更快,但样本量太小,文档明确声明"小幅差异不构成普遍性能优势的证据"。vLLM/SGLang 的吞吐未测量(其实现参考了融合投影、分块递归 prefill 等模式,但不构成对等基线)。
7. 对照:为什么 Ollama / 原版 llama.cpp 走不通
三条路线放进一张表对照:
| 维度 | PrismML llama.cpp 分支 | 原版 llama.cpp / Ollama | TensorSharp |
|---|---|---|---|
| PQ2_0 / PTQ1_0 加载 | 原生支持 | 拒绝加载(旧 Q2_0 会静默乱码) | 识别为类型 142/143,无损转码 |
| Walsh–Hadamard 变换 | 已实现(未合并上游) | 缺失 | 通过 ggml_ops_bonsai.cpp 接入计算图 |
| ggml 是否被修改 | 是(发行方分支) | — | 否(转码到上游格式) |
| 元数据契约校验 | 内建 | — | 加载前全量校验,未知布局拒绝 |
| 部署方式 | setup.sh 预编译二进制 |
一键(但跑不了) | dotnet run,.NET 生态 |
CloudNavi 的建议是走 PrismML 官方 demo 仓库(PrismML-Eng/Bonsai-demo,setup.sh 获取二进制),这确实是普通用户最省事的路径。而 TensorSharp 的价值在另一面:给 .NET 生态一个可审计、可嵌入的参考实现。它用托管代码加独立 native 层完成接入,不 fork 上游库,全部变换契约显式校验,验证数据和限制如实公开。
8. 内存账本:跑起来要多少资源
总内存 = 权重 + KV 缓存 +(用图像输入时的)视觉塔。27B 的 KV 缓存约 64 KiB/token,随上下文线性增长:
| 用途 | 所需内存 | 合适的硬件 |
|---|---|---|
| 短上下文(约 8K) | 约 8.4GB | 16GB 统一内存 Mac,或 12GB 显存显卡 |
| 实用线(32K) | 约 9.9GB | 16GB 统一内存或 12GB 显存以上 |
| 长上下文(64K)+ 图像 | 约 11.9GB | 24GB 统一内存,或 16GB 显存 |
| 最大上下文(262K) | 约 23.9GB(4bit KV 约 12.5GB) | 32GB 以上内存 + 4bit KV 缓存 |
| 纯 CPU | 建议 32GB | 无独显的迷你主机,速度会下降 |
两个紧凑配置开关(PrismML 侧):BONSAI_KV4=1 把 KV 缓存量化为 4bit(约缩至三分之一),BONSAI_MMPROJ_CPU=1 把视觉投影器移到系统内存(释放约 0.9GiB 显存)。
对 TensorSharp 用户还要叠加 4.1 节的转码开销:加载后的权重内存会比文件体积大 6%(PQ2_0)到 29%(PTQ1_0),规划内存时不能只看磁盘占用。
速度参考(官方公布):RTX 5090(CUDA)最高 143 token/s;M5 Max(MLX)46.8 token/s。
9. 现状与局限:文档没有回避的事
TensorSharp 文档在结尾把局限一条条列了出来:
- 性能目标未达成:decode 慢 3–5.4%,PQ2 高并发吞吐低 12.8%;
- 仅验证 Metal 单设备路径:CUDA、Vulkan、iOS、张量并行均未验证;
- CPU 路径只做了最小检查(PQ2,两条提示各 8 token);
- 262k 上下文未验证;
- native CPU 测试套件中有一个继承自上游 HEAD 的 DeepSeek41 容差失败,未被计入通过项;
- 所有保留率与速度均为 PrismML 公布值,独立复现需要时间。
10. 结语
Ternary Bonsai 2 27B 代表了低比特推理的一个真实拐点:压缩本身已经足够好(98.2% 保留率、1.72 有效位宽),瓶颈转移到了运行时基础设施:变换契约、格式转码、kernel 融合、验证方法学。
TensorSharp 的集成里有三个决策尤其值得参考:
- 转码而非 patch:把私有格式无损展开到上游格式,底层库零改动,兼容性风险被隔离在自己这一层;
- 校验而非假设:
prism.hadamard.*契约加载前全量验证,不满足条件(多设备、无变换能力的 backend)直接拒绝。拒绝加载永远好过静默跑错; - 公开而非粉饰:性能差距、未验证路径、失败用例全部写进文档,对比基线严格限定为"能加载同款文件的引擎"。
对想在 .NET 技术栈里跑端侧大模型、或想搞清楚"带旋转基底的三元量化到底怎么在引擎层落地"的开发者来说,docs/models/bonsai2.md 及其引用的五个实现文件,是目前公开资料里最完整的一条路径。
参考
- PrismML:Ternary Bonsai 2 27B 发布资料(2026-09-17)
- CloudNavi:《【2026】Ternary Bonsai 2 27B 本地部署:内存需求、量化与推荐硬件》(2026-09-19)
- TensorSharp:
https://github.com/zhongkaifu/TensorSharp/docs/models/bonsai2.md(zhongkaifu/TensorSharp,集成验证 2026-09-22)BonsaiHadamardMetadata.cs/ModelBase.Bonsai.cs/QuantizedWeight.Bonsai.cs/bonsai_quant.cpp/ggml_ops_bonsai.cpp
- PrismML-Eng/llama.cpp 分支(
prism-b10658及更新;验证基线bdc23b56)
注:文中基准分数、保留率与速度均为 PrismML 公布值;TensorSharp 性能数据来自其 2026-09-22 在 Apple M5 Pro(48GB)上的测量,样本量有限,不构成普遍性结论。
欢迎大家扫描下面二维码成为我的客户,扶你上云


浙公网安备 33010602011771号