在 RTX 3080 20GB 上,用 iamwavecut/ninfer-all
(master d1a0e07)原生构建跑通了 Ternary Bonsai 2 27B,使用 rk4v4 4-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 —— 不需要 porting
rk4v4 等 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 拒绝"变成"全平台可用"这件事。
参考