您可以将Qwen3.8-Flash-Next模型的大部分KV缓存卸载到RAM中,而不会明显影响解码速度。 在使用8bit量化的Qwen3.8-Flash-Next模型时,KV缓存大小约为每token 12.5MB。通过将大部分KV缓存从显存移至RAM,并只在显存中保留少量热数据,可以显著扩大显存能够支持的上下文长度。这种混合存储方式仅会增加约1.2ms的延迟,对实际推理速度影响微乎其微,为处理超长上下文提供了一种高效且低成本的解决方案。

Reddit r/LocalLLaMA 新闻

摘要

演示了将Qwen3.8-Flash-Next模型的KV缓存卸载至系统内存的技术,通过利用该模型高效架构,可在最大程度减少解码速度下降的情况下支持长上下文推理。

我确信任何基于 qwen4exp 的模型都能实现,这也是通义千问下一代本地模型的基础架构。你甚至可以使用勉强塞满显存的量化版本,无需对 KV 缓存进行量化,就能运行模型的最大上下文长度——因为大部分 KV 缓存可以存储在系统内存中。实际上我已经在 vLLM 上实现了这个方案,现在用 3 张 3090 显卡就能获得 100 万上下文窗口。短上下文时速度约 80 token/秒,当 QSA 达到 2048 token 预算后降至约 60 token/秒,此后随着总上下文增长解码速度保持稳定。吞吐量也很出色,并发 4 个请求时能达到约 150 token/秒。在 248k 上下文下预填充速度可达 3,701 token/秒。(补丁和模型已上传到我的 Hugging Face 页面,有兴趣可查看) 解码速度本质是带宽问题。每个解码步骤生成一个 token,而生成这个 token 需要 GPU 读取该步骤所需的所有权重和注意力状态。在单流情况下,显卡大部分时间都在等待内存而非计算,因此每步读取的数据量决定了 token 生成速率。这也是为什么常规模型会将 KV 缓存保留在显存中的原因。 以 Qwen3.8-27B 为例——它基于 Qwen3-Next 架构,与 Qwen3.8-Flash-Next(`qwen4_exp`)共享大部分特性。它仍然每隔几层包含一个完整注意力层,而完整注意力层每个解码步骤都需要读取整个 KV 缓存。随着上下文增长,这个读取量会增加,导致解码速度随对话长度增加而下降。更严重的是,这个数据量会超过任何主机接口(如 PCIe)的传输能力,因此缓存必须与计算单元物理相邻。该模型的数值完美展现了问题的严重性: 单个 QSA 层包含 2 个键/值头(256维),K 和 V 各 2 字节,即每 token 需要 2,048 字节。在 262,144 token 上下文下,单层每步就需要 512 MiB,全部 12 层则需要 6 GiB。PCIe 4.0 x16 插槽带宽约 32 GiB/s,这意味着主机缓存方案下速度仅能达到约 5 token/秒。 有趣的是,Qwen3.8-Flash-Next 通过两种方式规避了这个问题: 1. 48 层中仅有 12 层具有 KV 缓存,其余 36 层是门控 Delta 网络层——这种线性注意力的循环状态具有固定大小,不会随上下文增长。 2. 这 12 层也不需要关注全部上下文。QSA 通过一个轻量级索引器对池化压缩键进行检索(`indexer_head_dim=128` 除以 `indexer_compress_ratio=4` 得到池化宽度),每个索引器最多选择 `indexer_budget=2048` 个位置。层仅读取索引器选中位置的主 KV 行数据。 因此解码步骤的读取字节数由 `indexer_budget` 决定,而与上下文长度无关: ``` 2048(选中位置)× 2(KV 头)× 256(维度)× 2(K 和 V)× 2(字节)= 每层 4 MiB × 12 层 = 每 token 48 MiB ``` 举例来说,80 token/秒 的速度对应约 3.9 GB/s 的链路带宽,这仅占 PCIe 4.0 x16 插槽带宽的很小比例,且大部分与计算过程重叠。实际上只需将模型本身和少量数据保留在 GPU 上:每个 token 每层需要 2 字节槽位加上池化索引键(`1 × (128/4) × 2 B = 64 B`),总计每 token 每层 66 字节,相比完整 KV 行的 2,048 字节大幅缩减。
查看原文

相似文章

也许将KV缓存卸载到RAM并不差

Reddit r/LocalLLaMA

一位用户分享了在llama.cpp中将KV缓存卸载到RAM的经验,在释放显存以便运行更大模型和上下文窗口的同时,实现了相近的速度,表明这种权衡通常是值得的。