首页 / 文章 / 在配备 RTX 3090 的设备上,通过 llama.cpp 张量卸载技术运行 Qwen3.8-Flash-Next。

在配备 RTX 3090 的设备上,通过 llama.cpp 张量卸载技术运行 Qwen3.8-Flash-Next。

为何88GB、1800亿参数的稀疏模型能够运行在消费级GPU上,以及llama.cpp中的-ot、-ncmoe和mmap等参数是如何将其分配到VRAM、RAM和NVMe中的。

2691 词

Qwen3.8-Flash-Next是一个参数量约为1800亿的开放模型,其量化后的文件总大小达88GB,但有人称能在配备24GB显存的单块RTX 3090上运行它。从理论上看,这相差了一个数量级。它能运行下来得益于该模型的架构设计,而非巧妙的量化技术或异常强大的GPU:模型的大部分内容根本无需存储在显卡上。本文将解释实现这一点的四项设计考量,同时介绍适用于三块GPU组成的系统及单块GPU机器的完整llama.cpp配置,包括各重要参数的功能以及可预期的实际处理速度。

为何值得在本地运行Flash-Next

阿里巴巴在8月发布了Flash-Next。截至本文撰写时,其测试结果显示它优于Qwen3.8-27B、DeepSeek V4 Flash(0731),在多个代理模型基准测试中也优于Opus 4.6,而且每个标记仅需要激活60亿个参数。基准测试的排名变化很快,因此在将这些对比视为定论之前,请先查看最新的评估结果。更为关键的是该模型的架构设计,因为正是这种架构决定了哪些硬件能够支持它。

四种将计算任务从GPU转移出去的架构设计

Flash-Next融合了四种理念,每一种都将部分高成本的计算任务从昂贵的硬件转移到便宜的硬件上,或者完全消除这些计算任务。

超稀疏专家混合模型

该模型共有48层,每层包含512个专家子网络。任何一个标记仅会经过其中的11个:其中10个由负责检查标记并挑选最合适专家的路由器选定,另外还有1个共享专家,所有标记无需经过路由即可使用它。换句话说,大约只有2%的专家会为某个特定标记处理任务。

一个便于理解的类比是:一家医院有512名待命的专家,以及一名始终在场的普通医生。每位患者会根据其症状获得10次咨询服务,其余501名专家则不会参与其中。对于本地推理而言,关键在于“待命”仅意味着“可访问”——专家无需实际运行在GPU上就能提供服务。

之所以需要共享专家,是因为纯路由式设计往往会导致丢失每个标记都需要的通用知识。将这些知识放入始终在线的通用专家中,就能让各路由专家更专注地发展自身专长。目前大多数MoE设计都会包含这样的通用专家,其参数也计入60亿个活跃参数的总数之中。

Gated DeltaNet与Qwen稀疏注意力机制

标准Transformer会为每个已处理的标记保存键/值对信息。这种KV缓存会随着上下文长度呈线性增长,在上下文非常长时就会变得极为庞大。Flash-Next在很大程度上避免了这一问题:每四层中有三层使用Gated DeltaNet,该机制可将历史信息压缩为固定大小的小状态;每组中剩下的那一层则使用Qwen稀疏注意力机制,无论上下文包含32K个标记还是100万个标记,它都只从固定的512个块、2,048个标记的容量中读取信息。

实际效果极为显著:在178K上下文长度下,以下配置中的KV缓存仅占用约6GB空间,而类似规模的密集模型则需要大约十倍的存储量。这正是24GB显存能够支持长时间对话的原因。

带门控的多通道残差流

传统Transformer模型将所有信息从第一层到最后一层都通过同一条残差流传递,而在深度网络中,早期提取的特征往往会在传输过程中逐渐衰减。Flash-Next将这条路径扩展为四条并行通道,通过学习到的门控机制控制信息进入和离开各通道的流量。在训练过程中,其中一条通道逐渐演变为能够将早期信息深入网络深处的长距离传递通道。这只是一个小型的架构改动,却能在不带来显著成本增加的情况下提升模型性能。

n-gram嵌入表

第四个组件是一个包含510亿个参数的表格,其参数量超过了该模型其他所有组件的总和,而且完全不进行矩阵乘法运算。它属于查找结构,这也是单块游戏级GPU仍能发挥作用的根本原因。

n-gram表格:无需GPU即可实现的知识存储

在普通的语言模型中,每个词元都会被映射为一个ID,模型会通过嵌入表来查找该ID——每个词元对应一行。仅包含一个词元的行几乎无法提供任何上下文信息。以“陀思妥耶夫斯基写了《兄弟》”这样的短语为例,“the”的嵌入信息根本无法说明与卡拉马佐夫兄弟相关的内容;模型不得不依靠成本高昂的层结构来推断后续内容,而且每当出现这种模式时都需重复这一过程。

Flash-Next 添加了第二张表格,其行以短短语而非单个标记作为键。从概念上讲,这些条目如下图所示:左侧为哈希后的短语,右侧为其学习到的向量所编码的提示信息。

Drawer "born on october"     → hint: 1985, Honolulu, singer
Drawer "dostoevsky brothers" → hint: Karamazov, novel, 1880
Drawer "def main("           → hint: python entry point

在读取过程中,模型会对最近的几个标记进行哈希处理,获取对应的行,从而几乎免费地得到预先计算好的提示信息。这些行并非人工编写而成。在训练过程中,每当某个短语后出现特定的后续内容时,其对应的行就会朝那个方向稍作调整,因此经过数万亿个标记的训练后,每行都能大致反映通常会出现的内容。该表格包含约2000万个二元组及三元组条目,其输出会在第2层早期被注入一次。实际上,这相当于对常见表达方式的记忆,而大量真实文本都属于常见表达方式。

模型中这两种知识类型的差异正是实现硬件分离的基础。下文的对比总结了这一点。

|                  | Neural network          | N-gram table            |
|------------------|-------------------------|-------------------------|
| Work per token   | Matrix math (expensive) | Drawer lookup (no math) |
| Needs the GPU?   | Yes, every millisecond  | No — CPU can fetch it   |
| Lives in         | VRAM                    | RAM. Even SSD.          |

关键在于,需要获取的行仅取决于输入文本,而与网络内部的任何隐藏状态无关。一旦提示被分词,CPU就能准确知道需要哪些行,因此可以在GPU仍在处理早期层时提前预取这些数据。

这使得模型能够根据不同存储层级各自的优势进行合理分配:

  • VRAM(速度快,成本高):用于实际计算每个分词对应的约60亿个参数。
  • 系统RAM(速度中等,成本低):存储闲置的专家权重以及29GB的n-gram表。
  • NVMe存储(速度慢,成本最低):用于存储超出当前内存容量的数据,在需要时再加载进来。

GPU不再作为存储整个模型的地方,而是成为执行实际计算的地方。

日常使用的三GPU配置

设想这样一台服务器:配备三块RTX 3090显卡(总显存72GB)、48GB的DDR4系统内存,以及一个用于存储模型权重的PCIe Gen3 NVMe硬盘。这台机器并非工作站级别,而是许多开发者用旧款游戏显卡自行组装的。

此处使用的模型文件来自unsloth在Hugging Face上发布的该模型的UD-IQ4_XS版本,大小约为88GB,分为三个部分:大约59GB为模型主干权重,另外29GB为n-gram表。目前对这种架构的支持还比较新,因此在尝试使用前请获取最新的llama.cpp源代码并重新编译。

下面的命令会在机器的三个GPU上启动llama-server。大多数参数都是常规的(主机地址、端口、采样参数、批量大小、上下文长度),因此请注意稍后会介绍的卸载参数、分割参数以及加载模式。

CUDA_VISIBLE_DEVICES=0,2,3 CUDA_SCALE_LAUNCH_QUEUES=4x llama-server \
  -m /mnt/data_2t/ai_models_all/llm_hf_models/unsloth/Qwen3.8-Flash-Next-GGUF/Qwen3.8-Flash-Next-UD-IQ4_XS-00001-of-00003.gguf \
  --alias Qwen3.8-Flash-Next \
  --jinja \
  --metrics \
  --host 0.0.0.0 \
  -ngl 99 \
  --batch-size 4096 \
  --ubatch-size 512 \
  --flash-attn on \
  --temp 1.0 --top-p 0.95 --top-k 20 --min-p 0.0 --repeat-penalty 1.0 \
  --split-mode layer \
  --tensor-split 0.9,0.95,1.0 \
  --fit off \
  --main-gpu 0 \
  --ctx-size 178000 \
  --parallel 1 \
  --image-min-tokens 1024 \
  --reasoning-format none \
  --timeout 1200 \
  --ctx-checkpoints 8 \
  --port 8082 \
  --load-mode mmap \
  --cache-type-k q8_0 --cache-type-v q8_0 \
  -ot '^per_layer_token_embd\.weight$=CPU' \
  --reasoning-effort low \
  -t 14

将n-gram表固定到系统RAM中

-ot '^per_layer_token_embd\.weight$=CPU' 这一参数指示 llama.cpp:凡是名称符合该正则表达式的张量都应存储在 CPU 内存中而非 VRAM 中。n-gram 表是存储在张量名称 per_layer_token_embd.weight 下的,因此这一行配置就能让全部 29GB 的数据都不进入 GPU。当某个标记需要对应的行数据时,CPU 会先将其取出并传递给后续处理,这正是上文所述的预取机制。符号 ^ 和 $ 非常重要:它们能确保匹配仅针对该张量,避免误动其他权重。

利用 mmap 让操作系统管理内存驻留位置

--load-mode mmap 会先将模型文件映射为内存地址,而非提前将其读入RAM。操作系统会将频繁访问的页面保留在可用的页面缓存中,而将很少被访问的页面存储在SSD上。拥有48GB RAM和29GB的模型表时,这种做法是合理的——内核会决定哪些内容应保留在内存中。在内存充足的机器上,比如128GB的机器,改为none更为合适,因为这样只需读取整个文件一次,之后就不会出现页面错误。

在多张显卡间分配层

--split-mode layer 结合 --tensor-split 0.9,0.95,1.0 将 59GB 的模型主干结构分割成连续的层组,每张 GPU 对应一组,各组的大小略有差异,这样作为 --main-gpu 的第一张显卡仍有余力处理其他任务。-ngl 99 会将全部 48 层分配到 GPU 上,每张显卡大约承担 20GB 的负载。通过 --cache-type-k 和 --cache-type-v 将 KV 缓存量化为 q8_0 格式,它与权重数据存储在一起,约 6GB 的空间可容纳 178K 个标记。

三张显卡上的实测吞吐量

在该配置下,具体数值如下所示。

Decode:  30-50 tokens/second
Prefill: 400-700 tokens/second
Context: 178,000 tokens

这一速度甚至超过了中塔机箱中使用的普通消费级显卡在同类前沿模型上的读取速度。

单 GPU 配置及其局限性

只要满足一个条件:系统内存至少为64GB,一台3090显卡就足够了。n-gram表以及卸载后的专家模型需要存储空间,而系统内存通常是升级本地AI设备时成本最低的选择。

该命令使用的仍是相同的GGUF文件,主要区别在于新增了-ncmoe参数、仅显示一个GPU、使用--load-mode none而非mmap,以及CPU线程数量更少。

CUDA_VISIBLE_DEVICES=0 llama-server \
  -m /mnt/data_2t_3/ai_models_all/unsloth/Qwen3.8-Flash-Next-GGUF/Qwen3.8-Flash-Next-UD-IQ4_XS-00001-of-00003.gguf \
  --alias Qwen3.8-Flash-Next \
  --jinja \
  --metrics \
  --host 0.0.0.0 \
  -ngl 99 \
  -ncmoe 38 \
  --batch-size 4096 \
  --ubatch-size 1024 \
  --flash-attn on \
  --temp 1.0 --top-p 0.95 --top-k 20 --min-p 0.0 --repeat-penalty 1.0 \
  --ctx-size 178000 \
  --parallel 1 \
  --image-min-tokens 1024 \
  --reasoning-format none \
  --timeout 1200 \
  --ctx-checkpoints 8 \
  --port 8083 \
  --load-mode none \
  -ot '^per_layer_token_embd\.weight$=CPU' \
  --reasoning-effort low \
  -t 8

-ncmoe 38的作用

-ncmoe 38会将前38层的专家模型权重存储在CPU内存中,而最后10层的专家模型则保存在VRAM中。这样系统内存中大约会占用43GB的专家模型权重。由于存在-ngl 99参数,每层的注意力机制及共享组件仍会在GPU上运行。

由于数据的稀疏性,大量数据存储在RAM中仍然是可行的。每个标记会激活每层512个专家网络中的10个,因此总共只需处理约1.3GB的专家权重数据。存储在RAM中的专家网络会在其所在的CPU上计算,无需复制到GPU;而存储在VRAM中的专家网络则直接在显卡上运行。CPU的速度远慢于3090,因此确实存在性能损失,但这种损失与每个标记所涉及的约2%的权重相关,而非与存储的所有数据量相关。

由于此处RAM的容量较大,--load-mode none选项会在启动时完整读取文件,而非依赖页面错误机制,这也是为何最低需要64GB内存的原因之一。

针对其他显卡的调整

同样的命令也适用于RTX 4090或5090;只需根据可用VRAM容量调整-ncmoe参数即可。下面列出了推荐的初始设置值。

| GPU        | VRAM | Suggested -ncmoe | Experts in RAM |
|------------|------|------------------|----------------|
| RTX 3090   | 24GB | 38               | ~43GB          |
| RTX 4090   | 24GB | 38               | ~43GB          |
| RTX 5090   | 32GB | 28-30            | ~32GB          |

每次降低 -ncmoe 的值,都会将一层的数据量(约1.1GB)重新放回GPU中。模型加载完成后,查看 nvidia-smi 的显示,尽量保持约500MB的VRAM空闲空间;如果GPU内存被完全占满,当处理规模增大时就会出现内存不足的错误。

设定合理的预期

在单张3090显卡上,解码速度为每秒15到20个token。这个速度虽然可以勉强使用,但表现一般:快到足以让用户同步阅读,又慢到使得长文本的生成过程显得十分迟缓,因为部分计算实际上是在系统RAM中的CPU上完成的。作为概念验证,或者为了充分利用已有的硬件,仅靠一张游戏显卡就能以可阅读的速度运行180B级别的模型,已经相当了不起。

对于需要全天候用于编码和日常工作的助手而言,三到四块3090显卡才能让使用体验变得流畅。每秒18到40个token的处理速度差距,正是演示版本与日常工具之间的区别。如果你打算尝试更小的本地Qwen模型来实现智能编码,使用Qwen3.8-27B构建本地游戏的指南展示了更为轻量级的配置方案。

多token预测:值得关注的下一项加速技术

Flash-Next配备了经过训练的多令牌预测(MTP)模块,这是一个小型附加组件,能够同时提出多个后续令牌,以便主模型可以并行验证它们。这是一种基于推测的解码方式,其草稿生成组件是为该模型端到端专门训练的。据vLLM上的报告,在实际提示语处理中,该技术可实现约2.5倍的解码速度提升。

在撰写本文时,llama.cpp本身已支持Flash-Next架构,但其MTP草案路径尚未涵盖该模型。虽然其姊妹模型已得到支持,因此改动应该不会太大,但在认定该功能可用之前,请先查看当前版本的llama.cpp发布说明。一旦该功能正式加入,相同硬件上三块GPU配置的每秒30到50个令牌的处理速度,仅通过软件更新就有可能提升至60到100左右。在能够实际测量之前,这只是一个估算值。

关键要点

  • Flash-Next之所以能适配消费级硬件,得益于精巧的设计而非单纯的力量堆叠:超稀疏的MoE结构、固定大小的注意力状态以及仅用于查询的n-gram表,都减少了需要存储在VRAM中的数据量。
  • 任何访问模式仅取决于输入文本的元素,比如n-gram表,都可以存储在系统RAM中并由CPU预取;使用带有精确正则表达式的-ot选项即可将其放置于此。
  • -ncmoe是单GPU配置的主要参数:逐步降低该值,直到VRAM几乎满载但仍保留少量安全余量。
  • 当RAM资源紧张且希望由操作系统管理内存驻留时,选择mmap;当RAM充足且希望加载后延迟具有可预测性时,选择none。
  • 对于这类模型而言,系统RAM与GPU同样重要;单张GPU的实用最低配置为64GB。
  • 使用一张3090显卡时,处理速度约为每秒15到20个标记;使用三张则可达每秒30到50个标记,而llama.cpp中的MTP支持很可能是下一个提升性能的途径。