Bonsai 2 27B 实测:8G显卡真跑起来了,附厂商没有的速度数据
这几天这个模型到处都是:27B 的模型压到 5.9 GB,厂商说保留了 98.2% 的能力,RTX 5090 上跑到 143 tok/s。两天下载量 40 万。
我一开始是被一个词搞住的。有人说它是"三进制",有人说是"三值量化",我看了半天没搞清这俩是不是一回事。后来查明白了:正确的说法是"三值",网上写"三进制"的,是 ternary 一词多义串台了,数学里的 ternary 指三进制记数法(苏联 Setun 那种),LLM 里的 ternary 指权重只能取三个值。两边都用到 -1、0、+1 这三个符号,所以混了。
然后我注意到一个更实际的问题:厂商那张速度表里,一张 8GB 显卡都没有。
5090、RTX 6000 Ada、4090、L40S、H100、A100、L4、M5 Max、M5 Pro,都是 24GB 起步的卡和苹果新芯片。而本地玩家手里占大头的,恰恰是 3070、3060 这批 8G、12G 的老卡。
所以我把 5.9 GB 的那个版本下下来,塞进了我的 RTX 3070 8GB。
一、Bonsai 2 27B 到底做了什么事
简单说,就三步:
拿阿里的 Qwen3.8-27B(27.36B 参数,原本 FP16 要占 54 GB 左右)当底子,架构一行没改。
把每个权重从浮点数改成三个值之一:-1、0、+1。再给每 128 个权重配一个 FP16 的缩放系数,把数值大小找回来。
打包成 GGUF,落盘 5.95 GB。
那个"1.72 bit"是这么来的,这笔账大部分稿子没算给你看:
三个状态的信息量 log2(3) = 1.585 bit+ 每128个权重分摊1个 FP16缩放系数 16÷128 = 0.125 bit= 1.710 bit+ 不到 0.1% 的张量必须留高精度(循环状态、归一化层)= 1.72 bit(实测均值)
出两个打包文件,装的是同一份权重,只是打包方式不同:
文件 | 位宽 | 大小 | 说明 |
|---|---|---|---|
PTQ1_0 | 1.75 bit/权重 | 5.95 GB | trits 紧密打包,省地方 |
PQ2_0 | 2.13 bit/权重 | 7.21 GB | 每个权重占 2-bit 槽,解包省事,多数新卡上更快 |
8GB 卡其实没得选。只有 5.95 GB 那个塞得进去。
顺带说清一件事:它跟微软的 BitNet 不是一条路。BitNet 是从头训练时就按三值约束去训,代价高;Bonsai 2 是拿已经训好的Qwen3.8-27B 做事后三值化,本质是后处理。有稿子写它"从头训练",那个说法不对。
许可 Apache 2.0,能商用。
二、我的 RTX 3070 8G,把它跑起来了
先说结论:跑起来了,而且不用把层卸载到内存,64 层全在显卡上。
机器配置:RTX 3070 8GB / R9-7900 / 64GB DDR5 5200。
启动命令(这行可以直接抄):
llama-server.exe -m ”D:\AI_Models\Ternary-Bonsai-2-27B-PTQ1_0.gguf” ` -ngl 99 -fa on -c 16384 --parallel 1 ` --cache-type-k q8_0 --cache-type-v q8_0 --host 0.0.0.0 --port 8080几个参数的白话版:
-ngl 99:所有层都丢给显卡算,别让 CPU 掺和-c 16384:上下文给 16K--parallel 1:8G 卡的保命参数。默认开 4 个槽,会多占好几个 G,直接爆--cache-type-k/v q8_0:上下文缓存用 8 位存,省显存-fa on:闪存注意力,省显存
⚠️ 一个前提:必须换 llama.cpp。厂商原版跑不了这个文件,得用 PrismML 自己的分支(我这个版本是 build 10709)。原因后面那期细说,这里先记一句:用原版跑,7.21 GB 那个文件会被拒绝加载,5.95 GB 那个会静默加载然后吐乱码。后者更坑,因为它不报错。
显存实测占用:约 6 GB。8G 卡还剩两个 G。
三、38 tok/s,放在厂商那张表里是什么位置
这是这次重点想补的数据。
稳态生成速度:38 tok/s。具体几次跑下来是 38.14 到 38.56,长任务随着上下文变长会掉到 34~36。
把它放进厂商那条刻度尺里(都用 PTQ1_0 打包、都是生成速度):
显卡 | 生成速度 | 来源 |
|---|---|---|
RTX 5090 | 120.5 tok/s | 厂商 |
RTX 4090 | 91.1 tok/s | 厂商 |
H100 SXM | 86.9 tok/s | 厂商 |
A100 SXM | 54.7 tok/s | 厂商 |
我的 RTX 3070 8G | 38.x tok/s | 本次实测 |
L4(72W 亮机卡) | 32.1 tok/s | 厂商 |
RTX 3060 12G | 约 30 tok/s | 第三方实测 |
看出来什么:
大约是 4090 的 42%
比同为 8~12G 档的 RTX 3060 12G 快约 27%
位置卡在 A100(54.7)和 L4(32.1)之间
⚠️ 关于口径:厂商宣传里常见的"5090 上 143 tok/s"和上表的 120.5 tok/s是两套测法,不是数据打架。上表统一用 llama-bench 口径(128 token 生成、深度 0、batch 1、PTQ1_0 打包),我这边也是同一套口径,所以能直接比。跨口径比速度是很容易翻车的地方,这也是我把厂商表里那列数字重列一遍的原因。
还有一个数,但我得把它说准:读 prompt 的速度波动很大,从 29 到 264 tok/s 都有。
原因出在这儿:读得快不快,读得快不快,跟这次有多少内容能命中上一轮的缓存复用直接相关。我这几次里,长 prompt(132~371 token)能跑到176~264 tok/s;短 prompt(16~53 token)算出来只有 29~78 tok/s,真因是固定开销被摊到几个 token 上,把平均值拉下来了。
所以结论只有一句:让它读长文档是不痛苦的,痛苦的是等它一个字一个字往外吐。
顺带辟一个直觉:三值模型不吃"模型越小越快"那套估算。厂商数据里,5090 上 5.95 GB 的权重按显存带宽本该跑到 300 tok/s,实测只有 120,因为瓶颈是解包三值权重所需的计算指令,不是搬运数据的速度。你要是拿"体积除以带宽"去估它,会高估一倍。
四、为什么 5.9GB 的模型,显存只占 6GB
这条是这篇重点想讲清楚的事,也是它能塞进 8G 卡的真正原因。
5.9 GB 是硬盘上的文件大小,不是它运行时要的显存。正常的模型,权重之外还要给"上下文缓存"留地方,就是模型记住你前面说过什么的那块内存,它会随着你聊得越长而越长。厂商数据:这个模型开满 262K 上下文(f16 缓存)要22.9 GB。
我的 8G 卡开 16K 只用 6 GB,多出来的那一丁点是哪来的?靠的是它的架构:
混合注意力。64 层里大约 75% 是线性注意力层,只有约 25% 是全注意力层。
人话版:大部分层用的是一种"不用记住每一个历史 token"的算法,几乎不吃上下文缓存;真正吃缓存的只有那十几层。所以上下文涨到 16K,缓存也没涨多少。
这就是为什么同样是 27B,别的模型在 8G 卡上连门都进不去,它能进去。
但也要说清楚代价:厂商标的 262K 上下文,在 8G 卡上是纯纸面数字。我这边 16K 是稳的(q8_0 缓存),再往上要换更小的缓存类型,速度也要打折。想跑满 262K,你还是需要一张大卡。
五、它真能干活:写作和数学都过了
跑分是跑分,我用自己会碰到的活试了两项。
写作。我让它以文学系大学生的水平,写一篇 800 字的"异乡人思念陕南秋天"。出来的东西我贴一段:
陕南的秋天不是"落"下来的,是"沉"下来的。汉江上的雾先起来,一层一层,像谁在江面上拉了一张白桌布。然后山里的叶子才慢慢变色,不是北方那种一刀就红到发烈的样子,是绿的、黄的、褐的混在一起,像一桌没吃完的菜。
我奶奶家的院墙在晒柿子。一排一排挂上去,红得像一嘴一嘴的,皮上带着薄薄一层霜。……我那时大概十三四岁,每天放学回来看那墙柿子,哪颗最软就掰哪颗。不急着咬,先拿指甲在皮上刮一下,汁水顺着指缝流出来,甜,酸,有点涩。
就像你站在河边,水在你脚边流过,你认得出那是汉江的水——但够不着。
这个水平我给过。有具体的感官细节,不堆形容词,收得住。当然那句“红的像一嘴一嘴的”实在是没崩住。
数学。一道带矛盾条件的四色花园题(对角守恒 + 相邻差值 ≤7 + 总数 100 + 已知红色 28),它一步步推,答案正确,验证也完整。
这两项加起来能说明一件事:日常会碰到的活,这个 6GB 的 27B 扛得住。
六、一道让它跑了 8 分钟、一个字都没写的题
然后我给了它一道代码题。
题目是这样的:写个 Python 函数,找出列表里出现次数为奇数的元素,要求不能用额外数据结构、时间 O(n)、空间 O(1);然后回答这些要求能不能同时满足,如果不能就证明为什么。
结果:
数字 | |
|---|---|
生成了 | 16210 个 token |
花了 | 469.7 秒(7 分 50 秒) |
结束方式 | 撞到 16K 上限被硬截断 |
正式答案 | 零 |
那个输出文件我看了,59K 字符几乎都是思考过程,思考块结束标记后面是空的。它连一个字的正式答案都没开始写。思考收尾时硬断在半句话上。
有个细节特别有意思:它在思考的前 200 个 token 就把答案想出来了,原话大意是"返回所有"和"返回任意一个"这两句要求互相矛盾,应该指出这一点。然后它没停,自己给自己开了个更难的子问题("如果只要求返回任意一个,O(n) 加 O(1) 到底可不可能"),一路钻到向量空间、位运算、算法验证,直到把自己绕进去、撞在上下文上限上。
这里我要替它说一句公道话:这不代表它 coding 不行。
厂商数据里,它的编码是强项(HumanEval+ 95.12,比满血版的 93.29 还高)。问题出在这道题的性质上,它要的是"证明这个要求本身能不能成立",没有天然的收敛点,得靠模型自己判断"我想够了"。
而它恰恰缺这个判断。所以更准确的分类是:
封闭题(有明确答案的):数学 ✅、写作 ✅
开放/陷阱题(要自己判断何时收手的):❌ 陷进去了
为什么,以及怎么治,我放到下一期,因为解法我找到了,而且是一行参数的事。
七、现在能下的结论
先把这期能定的部分定下来:
8G 卡真能跑,而且不用卸载到内存,全 64 层上显卡,稳态 38 tok/s,显存占约 6 GB。
能塞进去靠的是混合注意力(约 75% 层不吃上下文缓存),不是靠"三值"本身省显存。三值省的是硬盘空间和每个 token 的计算量。
日常活扛得住:我试的写作和数学都过关,写作那篇质量是真的好。
262K 上下文在 8G 卡上是纸面参数,16K 是稳的。
更大的隐藏成本落在工具链上。你得换掉正在用的 llama.cpp。
三值这条路我觉得是真有东西的:它跟常规 2-bit 不一样的地方在于,常规量化是"尺子刻度变粗",还能读数;三值是把尺子换成三个档位的开关。厂商数据里,常规 2-bit 在 AIME26 上从 94.58 塌到 57.50,它在同一题上是 95.83,这就是那条"低比特会选择性崩塌"的路线,它绕过去了。
当然,98.2% 是厂商自己的数,第三方还没复现完,长程任务那部分还另有一笔账。
下期说两件事:那道跑满 8 分钟的题,我用一行参数让它 4 分钟交了卷;以及这个方案本身有哪些还没解决的问题。
本文数据均来自本人机器实测,速度对照中的厂商数字引自 PrismML 模型卡(llama-bench,128 token 生成,深度 0,batch 1),第三方数字引自公开实测。更新相关实测,可以关注同名GZH获取。