FreeToken 支持模型完全指南:模型家族、图片输入与 MoE 专家调度策略
FreeToken 是一个面向个人硬件(消费级 GPU、主机内存与 PCIe 互连)的边缘原生 MoE(Mixture-of-Experts)推理引擎,其核心目标是把数据中心级别的模型服务搬到桌面上。本文以官方文档 docs/models.md 为骨架,完整梳理 FreeToken 当前支持的全部模型家族与已验证的 HF 检查点、各家族图片输入(视觉编码器)的接入方式与 token 预算语义,以及决定 MoE 专家驻留与调度方式的五种策略(fused/offload/cpu/hybrid/auto)。读完本文,你将能依据自己的显存、内存与 PCIe 带宽,为任意受支持检查点选择正确的启动参数,并理解 FTW 快速加载格式、图片输入与 MoE offload 背后源码级的实现原理。
支持的模型与 HF 检查点
FreeToken 直接加载 Hugging Face 的 safetensors 检查点(ft serve --model <path-or-hf-id>),无需预先转换。下表列出的是**已知良好(known-good)**的检查点——预编译内核针对它们做过调优;同一架构的其它检查点通常也可以工作,但不在官方验证范围内。
| 模型 | HF 检查点 |
|---|---|
| DeepSeek-V4 | deepseek-ai/DeepSeek-V4-Flash-0731 |
| GLM-5.3-Flash | RedHatAI/GLM-5.3-Flash-NVFP4 |
| GLM-5.2 | nvidia/GLM-5.2-NVFP4 |
| GLM-4.7 | nvidia/GLM-4.7-NVFP4 |
| Qwen3.8-Flash-Next | Qwen/Qwen3.8-Flash-Next-FP8、RadixArk/Qwen3.8-Flash-Next-NVFP4、nvidia/Qwen3.8-Flash-Next-NVFP4 |
| Qwen3.6 / Qwen3.5 MoE | Qwen/Qwen3.6-35B-A3B(及-FP8)、nvidia/Qwen3.6-35B-A3B-NVFP4、Qwen/Qwen3.5-35B-A3B(及-FP8) |
| Qwen3.8 / Qwen3.6 dense | Qwen/Qwen3.8-27B(及-FP8)、RadixArk/Qwen3.8-27B-NVFP4、Qwen/Qwen3.6-27B(及-FP8)、nvidia/Qwen3.6-27B-NVFP4 |
| Qwen3-MoE | Qwen/Qwen3-30B-A3B |
| Qwen3-VL | Qwen/Qwen3-VL-8B-Instruct、Qwen/Qwen3-VL-30B-A3B-Instruct |
| gpt-oss | openai/gpt-oss-120b、openai/gpt-oss-20b |
| Gemma-4 | google/gemma-4-26B-A4B-it、nvidia/Gemma-4-26B-A4B-NVFP4、google/gemma-4-12B-it、nvidia/Gemma-4-31B-IT-NVFP4等 |
| MiniMax-M2.5 | nvidia/MiniMax-M2.5-NVFP4 |
| MiniMax-M3 | nvidia/MiniMax-M3-NVFP4 |
| Muse-Glimmer | meta-models/Muse-Glimmer-30B、RedHatAI/Muse-Glimmer-30B-NVFP4 |
从仓库源码看,每个家族都在模型注册表 python/freetoken/models/register.py 中登记为一张ModelSpec:DeepseekV4ForCausalLM对应 deepseek_v4,GlmMoeDsaForCausalLM对应 GLM-5.2(glm_moe_dsa),Glm5NextForConditionalGeneration对应 GLM-5.3-Flash(glm5_next),Qwen4ExpForConditionalGeneration对应 Qwen3.8-Flash-Next(qwen4_exp),dense 与 MoE 的 Qwen3.5/3.6/3.8 统一落在 qwen3_5_moe 包内,Qwen3-VL 在 qwen3_vl,Gemma-4 的gemma4/gemma4_unified两个变体都在 gemma4,gpt-oss 在 gpt_oss。注册表通过architectures字段自动识别检查点,因此ft serve只需要--model一个必填参数。
不同量化的落地方式
上表中同一模型往往有 FP8、NVFP4、BF16 等多个 HF 发布,FreeToken 按量化配置(quantization_config)自动选择内核路径:例如 NVFP4 专家可由--quant-backend moe.nvfp4=指定marlin/b12x/triton之一(--nvfp4-backend是已废弃的旧拼写,等价于--quant-backend moe.nvfp4=<...>,详见 docs/cli.md)。量化方案的解析逻辑集中在 layers/quantization,ModelSpec中的packed_modules_mapping(如把qkv_proj拆回 HF 的q_proj/k_proj/v_proj叶子)保证量化配置查表时能找到与 HF 检查点一致的名字。
图片输入(Image input)
以下家族默认接受图片输入;传--text-model-only可跳过视觉编码器只做纯文本服务。相关 flags 的完整说明见 CLI 参考,每个家族用自己的单位解释这些 flag(token 预算的换算方式不同,见下表)。
| 家族 | 图片 token 计算 | --image-min-tokens/--image-max-tokens语义 | --mm-processor-kwargs示例 |
|---|---|---|---|
| Qwen3.6(两种变体、表内全部权重格式)、Qwen3.8-Flash-Next、Qwen3-VL | 缩放后图片每 32x32 像素 1 个 token,动态分辨率 | 以像素面积形式传给size.shortest_edge/longest_edge;检查点默认 64 到 16384 token | {"size": {"longest_edge": 1048576}} |
Gemma-4 26B-A4B、31B(gemma4:ViT tower,--mm-encoder-weights host下流式加载) | 从 70 / 140 / 280 / 560 / 1120 软 token 预算中取一档,每张图在宽高比允许范围内缩放到对应预算 | 最大值会选取落在区间内的最大档位,低于 70 启动时直接拒绝;最小值无效 | {"max_soft_tokens": 1120} |
Gemma-4 12B(gemma4_unified:线性 patch embedder,两种驻留方式下都常驻) | 同上预算,每个软 token 对应一个 48x48 超级 patch | 与 tower 版本一致 | 同上 |
GLM-5.3-Flash(glm5_next:ViT tower,--mm-encoder-weights host下流式加载) | 缩放后图片每 28x28 像素 1 个 token,动态分辨率,画布零填充到 28 的倍数 | 直接透传为处理器的min_image_tokens/max_image_tokens;检查点默认 16 到 8000 token | {"max_image_tokens": 2048} |
Muse-Glimmer-30B(windowed ViT tower,--mm-encoder-weights host下流式加载) | 缩放后图片每 28x28 像素 1 个 token,宽高比控制在 token 上限内;检查点默认 4096 token | 最大值即上限(max_image_tokens);最小值无效 | {"max_image_tokens": 1024} |
MiniMax-M3(minimax_m3:CLIP 风格 ViT tower,--mm-encoder-weights host下流式加载) | 缩放后图片每 28x28 像素 1 个 token,动态分辨率 | 以像素面积形式传给size.shortest_edge/longest_edge;检查点默认 4 到 576 token | {"size": {"longest_edge": 1048576}} |
视觉编码器在源码中的登记与接入
- 编码器塔以
EncoderSpec登记在ModelSpec.encoders上(kind 为"vision"/"audio",即--mm-disable可关闭的种类),并在register.py中挂接对应的多模态处理器:Qwen 系共用QwenVLMMProcessor(mm/processors/qwen_vl.py),Gemma-4 用Gemma4MMProcessor/Gemma4UnifiedMMProcessor(mm/processors/gemma4.py),GLM-5.3-Flash 用Glm5NextMMProcessor(mm/processors/glm5_next.py),MiniMax-M3 与 Muse-Glimmer 各有独立处理器。这些处理器把上表的 token 预算语义翻译成各家的图像缩放与 patch 划分逻辑。 --mm-encoder-weights host(默认)表示编码器塔的块权重从 pinned host bank 每次两块地流式送入 GPU(计算与拷贝重叠),GPU 只保留两块而非整座塔;gpu则让权重常驻显存。没有块堆栈的编码器无论哪种方式都常驻。GET /v1/stats会以model.input_modalities(["text"]或["text", "image"])上报服务器实际接受的输入模态,客户端无需解析检查点配置即可决定是否开放附件入口(docs/cli.md)。
MoE 策略(专家驻留与调度)
MoE 模型的专家权重很大,不可能全部常驻消费级显存。FreeToken 通过ft serve --moe-strategy {auto,fused,offload,cpu,hybrid}控制专家"住哪里、miss 时怎么办"(--moe-backend是已废弃的旧拼写;在 engine/config.py 的EngineConfig.__post_init__中会把它折叠进moe_strategy):
- fused— 所有专家常驻 GPU(需要足够的显存);永远不会被自动选中。
- offload— 专家存放在主机 RAM(pinned host banks),GPU 上维护一个专家槽位的 LRU 缓存;缓存 miss 时通过 PCIe 流式取回。
- cpu— miss 的专家不取回 GPU,而是直接在 CPU 上用主机内存计算。
- hybrid— 每个 step 一部分 miss 走 PCIe 取回,其余在 CPU 计算,两者重叠执行。需要在每台机器上跑一次
ft bench bw校准拆分比例。 - auto— dense 模型恒定为
fused;MoE 模型解析为offload,当存在ft bench bw的缓存 profile 且推荐 hybrid 时升级为hybrid。
策略集合在 python/freetoken/moe/init.py 中定义为MOE_STRATEGIES = ("fused", "offload", "cpu", "hybrid"),offload/cpu/hybrid同属 offload 家族(OFFLOAD_MOE_STRATEGIES)。
源码视角:offload 家族如何工作
- 专家 bank 与 LRU 槽位缓存:offload_cache.py 中的
OffloadMoeCache以cache_policy="lru"在 GPU 上维护专家槽位,并记录每个 (layer, expert) 的最近活跃 step(expert_recency)供 hybrid 的逐层抓取上限挑选最活跃的 miss 先取。缓存大小由--moe-cache-size(槽位数)/--moe-cache-rate(专家总数占比)/--moe-cache-auto(按空闲显存自动推导)三者互斥指定;offload 家族默认开启 auto,由 engine/cache_budget.py 的resolve_moe_cache_auto统一求解专家槽位与 KV page 的显存划分。 - 最小缓存约束:engine.py 中的
_require_offload_cache_size强制缓存至少每层每专家一个槽位,太小会直接报错——这是避免 offload 空转的关键保护。 - CPU 层拆分:
--moe-cpu-layers与--moe-strategy offload组合时,可以把指定 MoE 层的 decode 放到 CPU 执行(_resolve_cpu_layers);--moe-strategy cpu则所有层都在 CPU。该参数仅接受 CPU 执行器能服务的专家格式(bf16、nvfp4、mxfp4),fp8 专家无法使用(docs/cli.md)。 - hybrid 的自动决策:
auto升级到 hybrid 依赖 moe/bench_profile.py 的load_backend_recommendation,它读取ft bench bw写入的 profile(按 GPU UUID 存放于~/.cache/freetoken/benchbw/<gpu-uuid>.json,按专家格式 + GPU 键控,硬件不匹配时直接忽略)。只有当 CPU 带宽超过 PCIe 带宽达到--threshold(默认 2.0)倍才推荐 hybrid;统一内存设备(GB10/DGX Spark、Jetson)没有 host/device 边界,会直接跳过该升级逻辑并默认fused,因为此时 offload 家族只会引入无意义的搬运。
用 ft bench bw 校准本机
ft bench bw用真实的 cpu/offload MoE 内核测量主机内存与 PCIe 的带宽,并把 profile 交给--moe-strategy auto与--moe-hybrid-max-fetch -1读取:
ft bench bw # 每块 GPU 跑一次即可 ft bench bw --dtype nvfp4,bf16 # 只测你实际服务的格式 ft bench bw --gpu 1 # 指定 GPU(UUID 或 nvidia-smi 索引,同 ft serve)注意事项(Notes)
- FTW 转换是可选的:ft checkpoint 把 HF 检查点预先转换为 FreeToken 的 FTW 快速加载格式,
ft serve --model会自动探测 FTW 目录(也接受原始 HF 目录或 HF repo id)。 - 旧版 FTW 兼容性:量化重构之前构建的 FTW 可能加载失败;受影响检查点与修复工具见 FTW 修复指南。修复脚本 scripts/ftw_hotfix.py 按字节范围只下载缺失的张量,从不下载整个检查点,且能在中断后安全续跑(每步原子替换 index)。
- 图片能力缺失的 FTW:在某个家族支持图片输入之前转换的 FTW 不含视觉编码器,
ft serve会拒绝加载它,除非以--text-model-only(或--mm-disable vision)启动;解决办法是用ft checkpoint重新转换,或通过 scripts/ftw_hotfix.py 就地补齐编码器。加载侧对"缺视觉编码器"的判定在 models/weight.py 的ftw_lacks_vision中实现。 - DeepSeek-V4 的目录结构要求:检查点必须保留
inference/config.json子目录——权威的模型参数从那里读取(对应 register.py 中DeepseekV4ForCausalLM的特殊checkpoint_roots映射)。 - Qwen3.8-Flash-Next 的 PLE 表:该模型把 47.7 GiB 的 PLE n-gram 表钉在主机 RAM(
ple_backend="pinned",见 engine/config.py),启动时需要预留足够的主机内存。
快速上手示例
# 用 Qwen3.6-35B-A3B(MoE,自动选择 offload/hybrid)启动服务 ft serve --model Qwen/Qwen3.6-35B-A3B # 在无显存压力的机器上让专家全部常驻 GPU ft serve --model Qwen/Qwen3.6-35B-A3B --moe-strategy fused # 先用 benchbw 校准本机,再让 auto 决定是否升级 hybrid ft bench bw --dtype nvfp4,bf16 ft serve --model nvidia/Qwen3.6-35B-A3B-NVFP4 # 多模态模型只做文本服务,省下视觉编码器的显存给 KV/专家池 ft serve --model Qwen/Qwen3-VL-8B-Instruct --text-model-only # 限制单张图片的 token 预算并调整 GLM-5.3-Flash 的视觉处理器 ft serve --model RedHatAI/GLM-5.3-Flash-NVFP4 --image-max-tokens 2048至此,你可以依据模型家族(dense 还是 MoE、是否多模态)、可用显存与主机内存、以及ft bench bw校准出的 CPU/PCIe 带宽比,为受支持检查点组合出正确的启动参数;遇到旧 FTW 加载失败时,也知道该用ft checkpoint重转还是用scripts/ftw_hotfix.py就地修复。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考