[实测] RTX 3080 (魔改20G) 跑通 Ternary Bonsai 2 27B + rk4v4,256K 上下文,1000+ prefill 65t/s decode
-
在 RTX 3080 20GB 上,用
iamwavecut/ninfer-all
(masterd1a0e07)原生构建跑通了 Ternary Bonsai 2 27B,使用rk4v44-bit KV 量化,
完整 262,144 token 上下文,无需任何代码移植。零编译改动、零源码补丁,
CMAKE_CUDA_ARCHITECTURES=86就是上游默认值。
背景
WaveCut/Ternary-Bonsai-2-27B-NInfer-v3的模型卡列出了 RTX 3090 / 4090 / 5090 的数据,
但 RTX 3080 在docs/gpus.md里是未测试(
)状态,而且卡片写的是 12/10GB SKU。另一个已知限制:在非
ninfer-all的 NInfer 分支上,rk8v4在 sm_86 上被硬编码拒绝,
rk4v4甚至不存在。所以很多人(包括我)一开始以为 3080 需要自己 porting。实测结论:不需要。
ninfer-all上游已经把 4-bit KV 全部实现好,并且
"accepted on every build target"。
环境
项目 值 GPU NVIDIA GeForce RTX 3080 20480 MiB(20GB SKU,GA102) Compute Capability 8.6 驱动 610.57.04(CUDA 13.3 toolkit) OS Omarchy(Arch 衍生)+ 内核 6.x 桌面 Hyprland(同时运行,见下文显存部分) 引擎 ninfer-serve 0.12.0-rtx3090+d1a0e07构建目标 CMAKE_CUDA_ARCHITECTURES=86(上游默认)验证是真·原生 sm_86
cuobjdump --list-elf显示二进制里每个 cubin 都是 sm_86 SASS,不是 PTX JIT:ELF file 1: device_calibration.sm_86.cubin ELF file 2: ninfer-serve.2.sm_86.cubin ELF file 7: device_tier.sm_86.cubin ELF file 8: hyper_connection.sm_86.cubin编译 flag:
--generate-code=arch=compute_86,code=[compute_86,sm_86]
转换
从 PrismML 官方的
Ternary-Bonsai-2-27B-PQ2_0.gguf(6.71 GB,GGUF type 142 /PQ2_0)
转换成 NInfer v3 artifact:python3 -m tools.convert \ --model /path/to/Qwen3.8-27B-config \ --recipe bonsai2_27b_ternary \ --source ternary=Ternary-Bonsai-2-27B-PQ2_0.gguf \ --components text \ --name bonsai2-27b \ --device cpu \ --out bonsai2-27b.ninfer结果:778 objects,771 个张量,70.4 秒,7.20 GB。
注:
--model需要 Qwen3.8-27B 的config.json+ tokenizer 资源(不需要权重,
recipe 只读model.config,所有张量都从 GGUF 来)。
启动
ninfer-serve bonsai2-27b.ninfer \ --model-id bonsai2-27b \ --host 127.0.0.1 --port 1234 \ --max-context 262144 \ --kv-capacity auto \ --kv-headroom-mib 2048 \ --kv-dtype rk4v4 \ --gdn-state-fp16 \ --no-thinking关键点是
--kv-capacity auto+--kv-headroom-mib 2048:引擎先加载权重、实测剩余显存,
再选最大合法 KV 容量,并强制预留 2 GiB。这是桌面和 CUDA 抢显存问题的正解(见下)。
实测性能
合成基准(单请求)
项目 数值 Prefill @20K 1998 t/s Decode @20K 63.0 t/s Decode 短上下文 70.5 t/s 真实负载(28 次请求,约 12 分钟连续使用)
项目 数值 Prefill(平均) 1571 t/s Decode(平均) 64.1 t/s 累计 prefill 70,174 tokens 累计 decode 10,497 tokens 失败请求 0 拒绝请求 0 引擎恢复事件 0 Prefill 从 1998 降到 1571 是正常的:真实负载里混入了更长、更碎的前缀,
且 95% 的输入被前缀缓存吃掉(见下),剩余重算部分占比小、统计噪声大。
前缀缓存命中率 95.1%这是个人助理场景最有价值的数据:
前缀缓存命中: 1,353,465 tokens ← 直接复用,不重算 实际重算: 70,174 tokens ───────────────────────────────── 总输入: 1,423,639 tokens 节省: 95.1%超过 95% 的输入 token 直接从 context cache 恢复,不经过 prefill。
/slots也能看到多级 checkpoint 在复用:{"frontier": 15977, "session_digest": "0b6afd8c..."} {"frontier": 18602, "session_digest": "0fda02d0..."} {"frontier": 18962, "session_digest": "706f16d4..."}
显存:rk4v4 是决定性的
这是 3080 20GB 能开 256K 的核心原因。
KV 理论占用(16 层全注意力 / 共 64 层)
该模型是 混合架构(
full_attention_interval = 4),64 层里只有 16 层有 KV cache:KV 格式 256K 占用 F16 16.0 GiB Q8 8.0 GiB rk4v4 4.36 GiB 实测整机占用
nvidia-smi: 13165 MiB used / 20480 MiB total (剩 6865 MiB)分解(
--max-context 262144 --kv-capacity auto):项目 占用 模型权重 6.70 GiB rk4v4 KV(动态分配) — 运行时 / workspace / CUDA Graph — 合计 12.86 GiB 剩余 6.70 GiB 同时跑桌面 + 256K 上下文,还剩 6.7 GiB 空闲,桌面完全安全。
和 llama.cpp (Prism fork) 的对比
顺手对比了 PrismML 官方 fork(
PrismML-Eng/llama.cpp,分支prism),
它原生支持同一份 GGUF(type 142):指标 llama.cpp (prism) + Q8 KV ninfer-all + rk4v4 上下文 64,000 262,144(4×) KV @256K 8.0 GiB 4.36 GiB(-45%) Prefill @20K ~1,050 t/s 1,998 t/s(1.9×) Decode @20K ~45 t/s 63 t/s(1.4×) Decode 短 65.5 t/s 70.5 t/s llama.cpp 那条路也完全可用,而且胜在零转换(直接读 GGUF)。
但长上下文场景下 ninfer-all 优势明显。
一些说明 / 未做的事
- RTX 3080 未在上游 profile 列表,所以首次启动可能触发设备校准(20 秒 ~ 3.5 分钟),
结果会缓存。我这次没遇到明显延迟,可能命中了同 SM 数的 profile。 - 没有用投机解码。模型卡上 3090 的 201 t/s 是 DFlash2 (5 drafts) 的成绩,
需要额外的 MTP / DFlash2 组件文件,我没有下载。纯 decode 是 ~64-71 t/s。 - Vision 未启用(
--components text),Bonsai 的视觉塔是独立组件。 - 这是纯文本个人助理用途的配置。
结论
RTX 3080 (sm_86) 上跑 Ternary Bonsai 2 27B 是一件"开箱即用"的事:
ninfer-all的默认构建目标就是 86 —— 不需要 portingrk4v4等 9 种 KV 格式上游全部实现,sm_86 不再被拒- 混合注意力架构(只有 16/64 层占 KV)+ rk4v4,让 20GB 卡能开 256K 上下文
--kv-headroom-mib让桌面和模型和平共处- 实测 prefill ~1571-1998 t/s、decode ~64-71 t/s、前缀缓存命中 95%+、零失败
感谢 upstream 的工作 —— 尤其是把 4-bit KV 从"sm_86 拒绝"变成"全平台可用"这件事。
参考
- 模型:https://huggingface.co/WaveCut/Ternary-Bonsai-2-27B-NInfer-v3
- 引擎:https://github.com/iamwavecut/ninfer-all (master
d1a0e07) - PrismML llama.cpp fork:https://github.com/PrismML-Eng/llama.cpp (分支
prism) - 上游构建文档:
docs/build-linux.md、docs/cli.md#context-and-memory
- RTX 3080 未在上游 profile 列表,所以首次启动可能触发设备校准(20 秒 ~ 3.5 分钟),
-
补充一段真实 agent 负载下的实测,供参考。
场景:本地个人 agent(Hermes)连续 8 轮工具调用,每轮约 20 个 tools,上下文从 20K 累积到 34K。
结果:
Decode 稳定在 70–72 t/s,上下文从 20K 涨到 34K 几乎不衰减 —— rk4v4 的 KV 压缩有效抑制了注意力随长度的成本增长。
前缀缓存命中率随会话爬升:88.5% → 91.1% → 93.1% → 94.9%。
TTFT 从首轮的 9.8s 降到稳态 1.1–1.5s,正是缓存命中带来的直接收益。
Prefill 稳定 1.7–2.25k t/s,排队延迟仅 10–26 ms,主机 CPU 占用 5–8%。两处配置修正:
--structured-output 是 agent 前端的刚需 —— tool calling 依赖结构化输出,缺了会直接 HTTP 400。原用 --kv-headroom-mib 2048 时出现警告:CUDA graphs used 34.7 MiB but the KV sizing allowed 12.0 MiB。调到 3072 后警告消失,且 KV 容量完整保住 262,144,剩余显存反而略增(7.00 → 7.12 GiB)。
-
我在3080M上测试结果也是:Ternary-Bonsai-2-27B是可以被NInfer直接使用的。
-
Ninfer跑bonsai 2算是浪费了,20g 可跑27b:
; gsq-rco-iq3s 27B IQ3_S 13.99G 有 有 gsq-rco-iq3s-v3
; swift15-iq3xxs 27B IQ3_XXS 10.33G 有 有 swift15-gsq-rco-ez
; swift15-iq3s 27B IQ3_S 11.91G 有 有 swift15-gsq-rco-ez
; coder390-q2 27B Q2 12.36G 有 无 qwen38-coder390-v3
; coder390-q3 27B Q3 16.11G 有 无 qwen38-coder390-v3
; swift15-v3 27B 高通量 16.96G 有 有 swift15-v3此外,还有kvmem,也能跑ninfer模型有提速
-
Ninfer跑bonsai 2算是浪费了,20g 可跑27b:
; gsq-rco-iq3s 27B IQ3_S 13.99G 有 有 gsq-rco-iq3s-v3
; swift15-iq3xxs 27B IQ3_XXS 10.33G 有 有 swift15-gsq-rco-ez
; swift15-iq3s 27B IQ3_S 11.91G 有 有 swift15-gsq-rco-ez
; coder390-q2 27B Q2 12.36G 有 无 qwen38-coder390-v3
; coder390-q3 27B Q3 16.11G 有 无 qwen38-coder390-v3
; swift15-v3 27B 高通量 16.96G 有 有 swift15-v3此外,还有kvmem,也能跑ninfer模型有提速
@zrlhk 有道理