☰
RTX 4080 SUPER 原生 Windows 跑 27B:NInfer 80 SM 移植实录,Bonsai 实测 176.6 tok/s
2026/10/8 10:18:14 网站建设 项目流程

一句话概括:上游 NInfer 把目标 SM 数硬编码成 128(只认 RTX 4090),我把它提成一个 CMake 选项,让我这张 80 SM 的 4080 SUPER 成为官方支持的第二档,并跑完了 Bonsai 2 27B 与 Qwen3.8-27B 的完整实测。


一、TL;DR

项目结果
目标卡RTX 4080 SUPER(sm_89 / Ada / 80 SM)
核心改动NINFER_TARGET_SM_COUNT一个 CMake 选项
运行环境原生 Windows 11,无 WSL、无 Docker
Ternary Bonsai 2 27Bdecode 会话均值176.6 tok/s、prefill 2,495 tok/s、MTP 接受率 58.9%
Qwen3.8-27B(int8 产物)decode 会话均值96.3 tok/s、prefill 2,577 tok/s、MTP 接受率 59.3%
显存27B 模型 + 262K 上下文塞进单卡,KV 池占用 20.2%
交付形态一个 zip,解压双击.bat就能起服务
许可证Apache-2.0

需要先说明:下面所有"本机"数据都是我这张 4080 SUPER 实测的;引用的 4090 数据是上游作者 JGamboa 的,我会逐处标注来源。这个区分很重要,因为两种数据的条件不同。


二、背景:为什么不继续用 llama.cpp

本地跑大模型,主流路线是 llama.cpp + GGUF,或者 Ollama / LM Studio 这类封装。它们的优势是通用:支持几百种模型架构,一套计算图适配所有情况。

NInfer 走的是完全相反的取舍:从零手写的 C++20 / CUDA 引擎,只服务一个模型架构家族(Qwen3.5/3.6/3.8,48 层 Gated DeltaNet 线性注意力 + 16 层全注意力)。

没有运行时计算图,每一层根据权重格式直接调手写的 kernel,每个 kernel 都有独立的 FP32/FP64 oracle 测试兜底。专用换来的就是性能。

对我这种只跑一两个 27B 模型的场景,这个取舍是划算的。

血统链

NInfer 不是凭空出现的,它是一串 fork 接力:

Neroued/ninfer 引擎本体,为 RTX 5090(sm_120a)从零开发 ↓ Don-Chad/ninfer-3090 sm_86 兼容层、ReplaySSM 集成 ↓ sergiuszm / UDP / shantanu 4090 各支:Ada 注意力 prefill 调优、 E8 格 2/4-bit KV、/metrics、/slots、timings ↓ JGamboa/ninfer-4090-windows 原生 Windows 构建、Ternary Bonsai 全链路、 n-gram 投机、并发泳道 ↓ zjwan461/ninfer-sm89-windows ← 我这个 fork:SM 数变成构建选项

搞清楚这条链就知道我的定位:改动非常聚焦,就一个构建选项。

这条链上每个仓库的完整链接见文末「资源」一节。


三、问题定位:硬编码的 128 个 SM

我手里是 RTX 4080 SUPER,和 4090 同为 Ada 架构、同样叫sm_89,但 SM 数量不一样:

RTX 4090RTX 4080 SUPER
SM 数12880
架构sm_89(Ada)sm_89(Ada)
CUDA 源码同一份同一份

问题出在引擎内部:attention 的 wave 几何是编译期常量kTargetSmCount = 128,kernel 启动几何直接依赖这个数。

80 SM 的卡跑硬编码 128 的代码,会得到 1.6 个 wave —— 最后一个尾波填不满,occupancy 白白浪费。不会崩,但速度不对。

好消息是:架构相同,二进制能直接跑。所以这不是指令集不兼容,纯粹是调度几何没为这张卡标定。


四、解决方案:把目标 SM 数变成构建选项

改动就一条:把硬编码的 128 提成 CMake 选项NINFER_TARGET_SM_COUNT。

rem 一次 configure 选定目标卡 cmake -S . -B build -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_CUDA_ARCHITECTURES=89 ^ -DNINFER_TARGET_SM_COUNT=80 rem 4090 用 128 cmake --build build -j

产物:

build\apps\ninfer.exe rem CLI build\apps\ninfer-serve.exe rem HTTP 服务

80 SM 不是随便改个数字

这是我认为这个 fork 唯一值得讲的技术点。把 128 改成 80 之后,有两处编译期断言必须过:

  • SM 数必须是偶数
  • SM 数必须≥ 66

80 刚好合法。同时 wave 几何要重新标定(SmallTWaveSplits 40 / 80),256K 上下文能力不缩水。

如果当初是把断言删掉或者放宽,那就是"能编译"而不是"正确"了。保留断言、只参数化输入,是这个改动能站得住的原因。


五、编译与部署(可复现)

工具链

我的环境:

组件版本
系统Windows 11 x64
编译器Visual Studio 2022(MSVC)
CUDA13.1
构建CMake 3.28 + Ninja
依赖vcpkg(curl / ffmpeg / pkgconf)
驱动595+

上游 4090 那批数据是在驱动 595.97 / CUDA 13.4 上测的,和我的环境不完全一致,这一点后面讲倍率时会提到。

不想自己编译的话,直接下 Releases 的 zip:ninfer-sm89-windows-x64-0.6.1.zip,约 1.6 GB ——CUDA 运行时已经静态内嵌进 exe,除驱动和 VC++ 运行库之外什么都不用装。

下载模型

hf download jgamboa/Qwen3.8-27B-NInfer-4090 qwen3_8_27b_a8.ninfer --local-dir E:\models

或者下 Bonsai 那个 6.4 GiB 的文件。

务必按 model card 校验 checksum。权重不对不会报错,但结果会静默变差 —— 这是这种注册制模型格式的坑。

启动(4080 SUPER 保守档)

ninfer-serve.exe E:\models\qwen3_8_27b_a8.ninfer ^ --host 127.0.0.1 --port 8080 ^ --model-id qwen3.8-27b ^ --max-context 131072 ^ --kv-dtype rk4v4-e8 ^ --max-concurrency 3 ^ --prefill-chunk 1024 ^ --spec mtp --draft-tokens 3 --ngram chain ^ --kv-capacity auto

几个参数值得单独讲:

  • --prefill-chunk 1024:4090 档是 1408。80 SM 的 wave 更容易填满,所以调小 —— 这是真正按卡标定的参数,不是照抄。
  • --kv-dtype rk4v4-e8:keys 用 E8 格的 4-bit 编码、values 4-bit。这是能同时装下 131K 上下文和三条并发泳道的关键。
  • --kv-capacity auto:跟随实测空闲显存。
  • 内存计划在listen之前就校验:配不下的组合直接启动失败,而不是跑到一半 OOM。这个设计对本地部署特别重要,因为你没法弹性扩容。

第一条请求

$body= @{model="qwen3.8-27b";max_tokens=512 messages=@(@{role="user";content="用三句话解释 CUDA Graph"})}|ConvertTo-Json-Depth 5Invoke-RestMethod-Uri http://127.0.0.1:8080/v1/chat/completions-Method Post `-ContentType"application/json"-Body$body|Select-Expand choices

服务同时长成三种客户端期待的样子:OpenAI Chat Completions、OpenAI Responses、Anthropic Messages。Open WebUI、LiteLLM、Claude Code 走代理,改个 base URL 就能接。

浏览器打开127.0.0.1:8080/monitor有全套监控:decode / prefill 速度、MTP 草稿接受率、前缀缓存命中率、KV 占用。


六、实测(一):Ternary Bonsai 2 27B

这是 NInfer 自带监控页的原始画面,条件:262,144上下文、3 条并发、MTP 2 drafts、8 条请求。

指标数值
Decode 会话均值176.6 tok/s
Decode 窗口读数191.7 tok/s
单请求区间125.6 – 259.7 tok/s
Prefill 会话均值2,495 tok/s
MTP 接受率58.9%(2,947 草稿)
Prompt 缓存命中85.8%(168,268 / 196,157)
首 token0.38 – 5.91 s
Prompt 规模17,884 – 25,278 token
KV 池占用159,232 / 786,432(20.2%)

Bonsai 是 Prism ML 的三值权重模型,权重只有 -1 / 0 / +1 三个值,整个 27B 压到6.4 GiB。

顺带一个观察:这里的 KV 池容量 786,432 = 262,144 × 3,正好是「上下文长度 × 并发泳道数」。Qwen 那边 393,216 = 131,072 × 3,同一套规则。所以--max-context和--max-concurrency是相乘关系,调参时两个要一起看。


七、实测(二):Qwen3.8-27B(int8 产物)

条件:131,072上下文、3 条并发、MTP 3 drafts、11 条请求。

指标数值
Decode 会话均值96.3 tok/s
Decode 窗口读数106.9 tok/s
单请求区间75.2 – 130.6 tok/s
Prefill 会话均值2,577 tok/s
MTP 接受率59.3%(2,739 草稿)
Prompt 缓存命中59.4%(123,049 / 207,161)
首 token0.34 – 4.07 s
Prompt 规模11,042 – 32,818 token
KV 池占用191,744 / 393,216(48.8%)

关于 int8 产物

Qwen3.8-27B 有两个产物,权重逐字节相同,int8 版只是让 prefill GEMM 的激活也量化成 int8:

官方产物(BF16 prefill)int8 版(推荐)
产物大小19.0 GiB19.0 GiB
Prefill pp20482,762 tok/s5,790 tok/s
Decode120 tok/s120 tok/s

上表是上游 4090 的数据(来源:JGamboa/ninfer-4090-windows),不是我的 4080S。

两边都 int8 就能进 tensor core,prefill 直接快 1.7–1.9 倍,decode 和 perplexity 都在噪声范围内。这个文件从官方产物几分钟就能转出来。


八、llama.cpp 对照与倍率的边界(重点章节)

这部分我要写得比结论更谨慎,因为它是整篇文章最容易误导人的地方。

同机同权重的对照数据

llama.cppNInfer
Bonsai 2 27Bdecode 会话均值65.14 tok/s176.6 tok/s
Bonsai 投机解码未开(草稿 0)MTP 2 · 接受 58.9%
Bonsai max seq522262,144
Qwen3.8-27Bdecode 会话均值57.59 tok/s(Q4_K_M)96.3 tok/s(int8 产物)
Qwen 投机接受率45.3%(2.36 tok/verif)59.3%
Qwen max seq262131,072


按会话均值算,倍率是Bonsai 2.71×、Qwen3.8-27B 1.67×。

但这两个倍率都不是 kernel 对比

我必须把边界说清楚,否则上面那两个数字就是耍流氓:

  1. Bonsai 那组,llama.cpp 根本没开投机。监控页上spec draft tokens = 0,而 NInfer 开了 MTP 2、接受率 58.9%。倍率里含一整套投机解码的贡献。
  2. Qwen 那组,两边都开了投机,但接受率差了 14 个百分点(59.3% vs 45.3%)。这一截不是 kernel 的功劳,反而主要来自工作负载 —— 长上下文里的复述、总结、改文件类任务,草稿更容易被接受。
  3. 上下文规模完全不同。我的 NInfer 会话跑的是 1.1 万–3.3 万 token 的长 prompt,llama.cpp 那两轮 max seq 只有 522 和 262。长上下文 decode 本来就更慢,所以这一点对 NInfer 是不利条件,方向上会压低倍率。
  4. 权重格式不同。llama.cpp 侧是 Q4_K_M GGUF,NInfer 侧是自家 int8 产物,只能算同档量级。

所以正确的读法是:

2.71× / 1.67× 是"整机整体对比"——同一张卡、同一个模型权重、两套引擎各自的最佳实践配置下的实际体感差距。它不是纯 kernel 性能比。

要拿到干净的倍率,得把 llama.cpp 侧也用同样的长上下文、同样打开投机重测一轮,并且把接受率差异单独拆出来。这件事我还没做,所以文章里不把它当结论。

那为什么还要放这组数据?

因为它回答了一个更实际的问题:在你手上这张卡、你要跑的这个模型上,换成 NInfer 到底能快多少。这是端到端的、可直接感知的差距 —— 只要你清楚它包含了哪些东西。


九、NInfer 为什么快:核心机制

1. 手写 kernel,没有通用计算图

每层按权重格式直接选手写 kernel。这个取舍是全部性能的来源,也是全部局限性的来源。

2. 三元权重(Bonsai)

三值码按 base-3 五权重/字节打包(t5_g128_fp16),加上每 128 权重一个 FP16 scale,平均1.75 bit / 权重。

  • decode 是 memory-bound:激活量化到 int8,走dp4a指令
  • prefill 是 compute-bound:走 int8 tensor core(m16n8k32)
  • Prism 原版的 Hadamard 旋转被融合进激活量化,不单独跑 kernel

3. Groupwise 量化(Qwen3.8)

Q4/Q5 码 + 每 64 权重一个 FP16 scale,共享内存里反量化喂 BF16 GEMM。int8 产物则直接让码喂 int8 tensor core。

4. 投机解码:MTP + n-gram chain

关键性质:MTP 的每个草稿 token 都由模型本体验证,所以输出分布和不开投机完全一致。投机只改变速度,不改变质量 —— 这是它敢当默认配置的原因。

n-gram chain 在此之上再叠一层:维护 16 MiB 的 n-gram 草稿池(8-token 键),把上下文里出现过的文本续进草稿。

什么时候收益最大?输出大量复述输入的时候 —— 改文件、生成 JSON、写 tool call,一轮能接受 10+ 个 token。这也解释了为什么上表里长上下文会话的接受率能到 59%。

5. 长上下文三件套

  • 分页 KV:int8 或 E8 格 4-bit / 2-bit 编码
  • warp 特化 prompt attention:producer warps 打分 / worker warps 累加
  • 每轮 decode 整层重放为一个 CUDA Graph
  • 被拒 token 的线性注意力状态靠ReplaySSM回滚

6. 服务化与可观测性

/monitor图形界面、/metrics(llama.cpp 兼容的 Prometheus 指标)、/slots+ save/restore/erase(6.9K token 会话约 0.1s 恢复,重启不丢上下文)、前缀复用 +--auto-long-anchors。


十、踩坑清单

最大的坑:显卡同时接显示器,吃掉 15–18% 解码速度

这是我自己踩了很久的坑。

现象:同一个模型、同一批 prompt,测出来的解码速度比别人低一截。

原因:不是 CUDA、不是量化 ——Windows 桌面合成器每帧都在抢 GPU。桌面一动(动画、视频、拖窗口),CUDA 就得让路。

数字(来源:上游 4090 实测,但机制是 Windows 的,与显卡型号无关):

显示配置每轮 MTP decode 损失
直驱 4K @ 120Hz-18%
直驱 4K @ 60Hz-15%
显示器接核显 / 静态 dummy plug 4K600%

对策:显示器插主板核显或第二块卡;退一步用 60Hz,并在生成时保持桌面静止。静态 dummy plug 4K60 实测零影响,无头跑完全没问题。

推论:跨 run 比较 tok/s,必须固定显示配置,否则数据不可比。这也是为什么所有对比数据都强调「同 session、同显示配置」。

长上下文 decode 会变慢

Bonsai 一轮 MTP 在 128K 深度是 18.5–20.8 ms,短上下文 12.8 ms —— 全部增量都在 attention。

零售 4080 SUPER 大多是 16GB

我这张是 32GB 版,所以--max-context 131072和--max-concurrency 3能这么配。如果你的是零售 16GB 版,这两个参数都要相应下调,别照抄。


十一、限制与适用边界

只讲优点不诚实,所以把限制也列全:

架构性限制

  • 单卡 · 单进程 · 单模型:无多卡、无权重卸载、无请求抢占与优先级
  • prefill 串行执行 ——一条长 prompt 会推迟其他泳道的首 token

硬件性限制

  • NVFP4 / W4A4 用不了:那是 Blackwell tensor core 的特性,sm_89 上没有这些指令。Ada 只能走 groupwise int8/int4 路线。这也是上游 5090 版和这个版本不能简单合并的原因。
  • DFlash2 不支持 Bonsai 三元输出头(Bonsai 用 MTP)
  • Linux 构建与 Dockerfile 继承自上游,本分支未复验

我的实测缺口(如实列出)

  • 编辑类负载的峰值还没测(4090 上是 532 tok/s)
  • llama.cpp 侧同条件的重测还没做—— 也就是第八节讲的倍率边界

十二、结论

  1. 同架构不等于同二进制。4080 SUPER 和 4090 同为 sm_89,指令集完全兼容,但 wave 几何是按 SM 数标定的。把目标 SM 数做成构建选项,80 SM 就成了官方支持的第二档 —— 一个选项,两条编译期断言,一份源码出两个二进制。

  2. 原生 Windows 跑本地大模型,现在完全可行。MSVC 直接编译、CUDA 运行时静态内嵌、.bat启动器,交付形态是"解压即用"。门槛从"会配 Linux"降到"会双击",不需要 WSL2、不需要 Docker、不需要 GPU 直通。

  3. 专用引擎在单卡上确实有代差优势,但要诚实说明它的构成。我这张卡上 Bonsai 176.6 tok/s、Qwen3.8-27B 96.3 tok/s,都远高于同机 llama.cpp —— 而这个差距里既有 kernel 和 KV 路径的功劳,也有投机配置和工作负载的贡献。把两者混在一起报"快 2.71 倍",是不诚实的。

  4. fork 要说得清、验得出。改动只有一个 CMake 选项,但配上完整的构建手册、retarget 验证计划、编译期断言和实测数据,别人能复现、能验证。这比改个 README 署名的 fork 有意义。


资源

本项目

仓库(Apache-2.0):https://github.com/zjwan461/ninfer-sm89-windows

A C++20/CUDA inference engine specialized for one NVIDIAsm_89card — RTX 4090 (128 SMs) or RTX 4080 SUPER (80 SMs), selected at build time withNINFER_TARGET_SM_COUNT

仓库内相关文档:

文档内容
ninfer-windows-build-manual.md中文构建手册,从零装 vcpkg 到打包两个变体
ninfer-4080s-80sm-retarget-plan.md80 SM 重定向设计与验证计划
WINDOWS_PORT.mdWindows 移植全记录 + 实测
docs/llamacpp-comparison.md与 llama.cpp 的完整对比(方法学写得很细)

上游仓库(血统链,按时间顺序)

仓库链接贡献
Neroued/ninferhttps://github.com/Neroued/ninfer引擎本体,为 RTX 5090(sm_120a)从零开发
Don-Chad/ninfer-3090https://github.com/Don-Chad/ninfer-3090sm_86 兼容层、ReplaySSM、MTP3、C1–C8 批处理
sergiuszm/ninfer-4090https://github.com/sergiuszm/ninfer-4090Ada 注意力 prefill 重调、E8 格 4-bit KV、llama.cpp 兼容的/metrics+/slots
UDPSendToFailed/ninfer-4090https://github.com/UDPSendToFailed/ninfer-4090RTX 4090 上的 Qwen3.8-27B 移植
JGamboa/ninfer-4090-windowshttps://github.com/JGamboa/ninfer-4090-windows原生 Windows 构建、Ternary Bonsai 全链路、n-gram 投机、并发泳道

血统链里还有 shantanu 的 4090 分支(贡献 llama.cpp 风格的 timings),我没找到稳定的仓库地址,故未列入。

模型

模型Hugging Face
Ternary Bonsai 2 27B(6.4 GiB)https://huggingface.co/jgamboa/Ternary-Bonsai-2-27B-NInfer-4090
Qwen3.8-27B · int8 产物(19.0 GiB)https://huggingface.co/jgamboa/Qwen3.8-27B-NInfer-4090
Qwen3.8-27B · 上游原版https://huggingface.co/neroued/Qwen3.8-27B-NInfer

数据说明

为避免混淆,本文所有速度数据的来源如下:

数据来源条件
Bonsai 176.6 / Qwen3.8-27B 96.3 tok/s 等本机 RTX 4080 SUPERWindows 11 / CUDA 13.1 / VS 2022
llama.cpp 65.14 / 57.59 tok/s本机 RTX 4080 SUPER同上,llametrics 监控页
218 / 532 / 6,027 / 1.7–1.9× 等上游RTX 4090Windows 11 / 驱动 595.97 / CUDA 13.4
显示税 -18% / -15%上游RTX 40904K 桌面,比例为机制性数据

跨来源的数字不能直接比较—— 显卡、驱动、CUDA 版本、投机配置和上下文长度都不同。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询