24GB 显卡的极限压榨:用 SGLang 部署激进量化的 born2bewild-Qwen3.8-27B

24GB 显卡的极限压榨:用 SGLang 部署激进量化的 born2bewild-Qwen3.8-27B

当一张 RTX 3090 要塞下 27B 模型、128K 上下文,还要保留 100% 的推理能力,量化到了头发丝是什么体验?这篇文章记录了一次把“省显存”做到极致的部署实战——连语言模型的“门面”(embedding)和“出口”(lm_head)都不放过。而为了让这套激进量化在 SGLang 上真正跑起来,我不得不给推理框架打了三个补丁,其中两个已经以 PR 形式提交给了上游。

一、为什么这是一个值得较真的问题

先看一个尴尬的算术题:一张 RTX 3090 有 24GB 显存。一个 Qwen3.8-27B 的原始 BF16 权重要占 54GB——连两张卡都塞不下。想本地跑,量化是唯一的路。
但量化本身也有个隐形的算术题:权重省下来的每 1GB,都可以变成几十万 token 的 KV 缓存,也就是更长的上下文。在长上下文能力几乎成为大模型标配的今天,显存就是上下文,上下文就是模型的天花板。
常规的 W4A16 量化(权重 4bit、激活 16bit)能把手感不错的 27B 模型压到 19GB 左右,剩 5GB 给 KV 缓存和运行开销,大概能跑到 8 万 token 的上下文。这已经不错了,但还不够。于是有人开始动心思:那些“看起来”不该量化的地方,是不是也能省?

二、先认识两个主角

SGLang:专为大模型推理速度而生的框架

SGLang 是斯坦福 NLP 团队(后来独立为 SGLang 项目)开发的高性能推理框架,核心卖点是三个词:Radix Attention(前缀复用)、Cuda Graph(图捕获)、连续 batching。它和 vLLM 是当前开源社区本地部署大模型的两大主力框架,但 SGLang 在前缀缓存和 MoE 混合专家模型的调度上做得更激进。
对 24GB 单卡玩家来说,SGLang 还有一个关键价值:它把显存预算拆解得极其透明。权重、KV 池、Mamba 缓存、运行余量各占多少,启动日志里写得明明白白,你可以像查水电表一样逐项优化。也正是这份透明,让我能把这张 3090 的每 MB 显存都算到明处。

Qwen3.8-27B:当前 27B 级的最强选择

Qwen3.8-27B 是 Qwen 家族里“能效比”极高的一款:27B 的体量、接近满血 32B 的推理能力,却因为 MoE 稀疏结构在单卡上跑得动。我在上一轮模型横向评测里对比过同期竞品(Muse-Glimmer-30B、Nemotron-3.5-Lightning),结论是 Qwen3.8-27B 在 27B 这个级别没有能撼动它的对手——MLM U-Pro 85.63 分,比 Nemotron 的 81.94 高一截,而模型还更小。
所以问题就聚焦成一个:怎么把 Qwen3.8-27B 压进 24GB,并且把上下文顶到最大。

三、激进量化:连“门面”和“出口”都不放过

传统 W4A16 量化有一个心照不宣的默契:transformer 主干可以压到 4bit,但 embedding 层和 lm_head 层保持 BF16。理由是这两层太敏感——embedding 是模型的“门面”,负责把 token 变成向量,所有语义都从这里出发;lm_head 是“出口”,负责从向量变成概率,最后的输出质量一半由它决定。量化它们被认为会伤精度。
但“省显存”的诱惑太大了。embedding 层和 lm_head 加起来能占到总权重的 5%~10%,在这张卡上就是整整 3~4GB。省下来,等于把上下文从 10 万 token 顶到 12 万以上。
于是有了 born2bewild/Qwen3.8-27B-W4A16-AutoRound-fast 这个模型——技术原创来自 syvai 团队(github.com/syv-ai/qwen38-27b-rtx3090),born2bewild 是把它整合成单仓发布的打包者。它的量化方案是:主干:W4A16 AutoRound 量化(业界公认最无损的量化算法之一);lm_head:INT4,group128,GPTQ 校准;embedding:INT8;MTP(多 token 预测)头:INT4;delta / GDN 线性注意力层:保留 BF16。
整包只有 15.81GB。相比 RedHatAI 官方量化版(~19GB),净省 3.6GB——而官方给出的精度数据是:perplexity 只增加 0.6%,GSM8K 数学成绩不变。
这是什么概念?相当于把模型的“装修”全拆了重做,但房子的承重墙一根没动。

四、部署实战:碰壁才是常态

模型下载下来,迫不及待地启动 SGLang,然后……迎面撞上一堵墙。
SGLang 不认识被量化的 embedding 层。
启动能过,KV 池也能建起来,但一推理,输出全是乱码。原因是:SGLang 的 compressed-tensors 量化支持覆盖了 transformer 里的 Linear 层,但 embedding 和 lm_head 这两个“非标准”层,压根不在它的量化处理名单里。模型配置里写着“embedding 是 INT8、lm_head 是 INT4”,框架却把权重按 BF16 去读,读到一堆“压缩过的比特流”,自然输出垃圾。
这是典型的“模型能力跑在了框架能力前面”的错位。模型的量化方案是合法的、无损的,问题是推理框架没跟上。

五、三个补丁:给框架补上缺失的齿轮

解决思路很清晰:让 SGLang 认识这两种新量化类型。为此我打了三个补丁(完整实现已以 PR 形式提交给 SGLang 官方,见文末链接):
补丁一:让 lm_head 支持 INT4 量化。 在量化方法分发函数里补上 lm_head 的分支,让它走 Marlin 内核的 W4A16 反量化路径。其实 SGLang 的 LogitsProcessor 早已预留了“lm_head 应用量化方法”的开关,只是创建层的代码忘了把它和量化配置接上——把断掉的那根线接上即可。
补丁二:让 embedding 支持 INT8 量化(全新机制)。 这一层更有意思。embedding 的特殊性在于:它不是矩阵乘,而是按行取数(gather)。量化权重不能像 Linear 那样做批量矩阵反量化,必须“取到哪行就反量化哪行”。我参考了 vLLM 官方合并过的 N VFP4 embedding 量化先例,实现了 dequant-on-gather 机制——权重保持压缩存储(显存一点不浪费),forward 时只反量化被 gather 到的那几行。中间踩了一个经典的坑:INT8 的位模式是无符号存储的,反量化时必须“减偏移量”而不是“强转符号类型”——两种写法结果完全不同,差一个符号位就是-56 和 72 的区别。我专门下载了 Qwen 官方的原始 embedding 权重做黄金对照,验证反量化误差 MSE=0.000000、相关系数 1.000
补丁三:修复 SGLang 自身的一个 bug。 排查中发现,Qwen3.5 系列模型在构建时,embedding 层创建时漏传了量化配置(lm_head 一直传了,embedding 漏了)——所以即使有补丁一、二,embedding 也永远不会被量化。一行 quant_config=quant_config 补上,整条链路才真正闭合。
这里有一个重要的技术判断:这三个补丁中,补丁三是框架的原生 bug,补丁一、二是能力扩展。 能力扩展的代码我是严格对齐 vLLM 官方合并的 kernel 语义写的,并用独立 oracle 验证了 INT8/INT4 两种 group128 布局的反量化逐字节一致(max_diff=0)。
我写了两段足够说明问题的测试代码(一个 INT8、一个 INT4 的反量化独立对照),连同三个补丁一起,以 PR 的形式提交给了 SGLang 官方仓库。如果你也打算部署这个模型,直接去 GitHub 上查:

PR #36137:feat(quant): support compressed-tensors quantized lm_head and embed_tokens
打开后 Files changed 页签就能看到全部改动,总共 236 行。在官方合并之前,你也可以按同样思路本地打补丁。

六、测试数据:省下的显存都变成了上下文

补丁打完,重启容器。这是最让人兴奋的部分——数字全部兑现了:
上下文:从 10 万冲到 12.8 万。 KV 缓存池:165,318 tokens(对比 RedHatAI 量化版的 104,845);context-length 直接设到 131072(128K);显存分布:权重 15.36GB + KV 缓存 + Mamba 缓存 + 运行余量,24GB 卡上井井有条。
速度:没有为省显存付出代价。 中等长度输出实测 47.3 t/s,和之前 RedHatAI 量化版(~46 t/s)完全持平;也就是说,3.6GB 的显存是“白捡的”,速度一分没少。
质量:任务级无可见伤害。 我拿这个模型和 RedHatAI 量化版(lm_head 保持 BF16)做了同题对比:代码生成(快速排序):两个版本输出质量一致;数学推理(组合数计算):一致;中文写作:一致。
结论很明确:lm_head 的 INT4 量化在真实任务上没有任何可感知的退化。官方给的 0.6% perplexity 增加,实际落在任务表现上基本无感。这也验证了 syvai 团队那个反直觉的设计判断:embedding 和 lm_head 虽然是“门面”,但对 4bit+8bit 这一档位的量化,它们远比人们想象的皮实。
最终生产配置:GPU0 上跑 born2bewild(128K 上下文),GPU1 上保留 RedHatAI(作为对照与冗余),两张 3090 各司其职。

七、点评与推荐结论

这套方案值不值得抄? 分场景看:
强烈推荐给这些人: 24GB 单卡用户,且上下文需求 >10 万 token——这是目前唯一能把 27B 模型顶到 128K 且质量无损的路径;长文档、长代码仓库、agent 多轮工具调用场景——上下文是硬约束,多 2 万 token 就是质的区别;愿意花半天打补丁、跟上游的人——回报率极高。
不建议的场景: 对 embedding 量化有洁癖、追求“官方原教旨”的——RedHatAI 官方版同样优秀,只是上下文少 2 万;纯聊天场景、上下文需求不高——省下的显存对你没有价值,不必折腾。
技术点评,说几句掏心窝的话:
一、AutoRound + 激进量化是本年度 24GB 单卡的最大红利。它把“能不能跑”和“能跑多大”这两个问题同时解决了
二、lm_head/embedding 量化是大趋势。vLLM 官方已经合并了 NVFP4 embedding 量化先例,说明主流框架都在往这个方向走,SGLang 这次只是慢了一步
三、“框架跑在模型前面”会越来越常见。社区量化速度远快于框架适配速度,遇到这类问题,敢于给上游提 PR 是性价比最高的解决方式
最后补一句负责任的话:我的 PR 还在 open 状态,等待官方评审。如果你在生产环境用它,务必先本地验证(好在补丁改动小、可读性高)。一旦官方合并,这套方案就能“开箱即用”——那一天,也是 24GB 玩家用上 128K 上下文 27B 模型的“标准配置日”。

八、方法论沉淀

这次部署从头到尾是一次“显存预算链”的完整实践:先算清每一 MB 的去向,再找最大的可压缩项,然后动手压缩,最后用数据验证没付出代价。这个方法论比任何单次调优都值钱:
先预算,后动手:权重、KV、缓存、余量逐项列出,找到瓶颈再优化;量化到头发丝,但承重墙不动:主干无损、门面激进、敏感层保护;框架跟不上,就给框架打补丁:与其绕路,不如把能力补回框架本身;所有优化必须用数据兑现:省了显存,还要证明速度没掉、质量没伤。
这大概是本地大模型部署最迷人的地方:每压榨出 1GB 显存,都是在给模型买回几千字的上下文。 而当你把这件事做到极致时,那张 3090 上跑着的,已经不只是个模型,而是一整套“显存经济学”。


本文所有测试数据均来自双 RTX 3090(24GB)实机部署实测。PR 链接:github.com/sgl-project/sglang/pull/36137。模型:huggingface.co/born2bewild/Qwen3.8-27B-W4A16-AutoRound-fast。


皖ICP备2025105865号-2|皖公网安备34010402704739号