Ktransformers 文档

基本信息

转载自:Ktransformers
防止丢失、学习记录备忘。
中译为本站翻译,内容同步于 2026-11-10,对应官方文档最新版(v0.7.x)。

简介

KTransformers

一个能上手玩前沿 LLM 推理与微调优化的灵活框架

🎯 概览 | 🚀 推理 | 🎓 微调 | 🔥 引用 | 🚀 路线图(2026Q2)

🎯 概览

KTransformers 是个研究性质的项目,靠 CPU 和 GPU 一起干活,把大模型的推理和微调都做得更快、更省资源。现在它把 kt-kernel 代码树里的两样东西单独拿出来给用户用:推理(Inference) 和 微调(SFT)。

🔥 更新记录

  • 2026 年 10 月 15 日:DeepSeek-V4-Flash LoRA 微调支持原生 MXFP4 路由专家。快速开始。
  • 2026 年 10 月 8 日:发布 KTransformers-FineTune (KT-FT) 作者预印本,提出面向 MoE 微调的布局感知、调度优化的 CPU-GPU 协同计算方案。论文与引用 · PDF。
  • 2026 年 9 月 13 日:Kimi K2.5 / K2.6 LoRA 微调支持原生 RAWINT4 路由专家。
  • 2026 年 8 月 26 日:原生支持 GLM-5.3-flash,把 100 万 token 上下文与多模态输入带到消费级 GPU。(教程)
  • 2026 年 8 月 25 日:新增一份易用的 KTransformers × LlamaFactory MoE 微调 Cookbook,覆盖硬件检查、安装、BF16/FP8/INT8 配方、LoRA 与全量微调、资源规划以及故障排查。
  • 2026 年 8 月 17 日:LoRA 微调现已支持兼容的 AVX512 x86 CPU(包括 AMD 服务器),无需 AMX。(v0.7.0 发布说明)
  • 2026 年 8 月 16 日:在单张昇腾 NPU 上通过 CPU 专家卸载运行 DeepSeek-V4-Flash。(教程)
  • 2026 年 8 月 5 日:引入原生 block-FP8 LoRA 微调(PR #2141)
  • 2026 年 7 月 23 日:新增 MoE 模型的端到端 BF16 全参数微调,支持完整 checkpoint 保存。(PR #2094)
  • 2026 年 6 月 21 日:MiniMax-M3 Day0 支持!(教程)
  • 2026 年 6 月 17 日:GLM-5.2 Day0 支持!(教程)
  • 2026 年 5 月 6 日:KTransformers 亮相 GOSIM Paris 2026 的”Agentic AI on Edge”分论坛,将分享 KT 在消费级硬件上的推理性能。
  • 2026 年 5 月 2 日:DeepSeek-V4-Flash 支持!(教程)
  • 2026 年 4 月 30 日:KTransformers v0.6.1 更新 kt-kernel 推理与 SFT 文档,拆分为 推理 与 SFT 快速开始 两个入口。
  • 2026 年 3 月 26 日:KT-Kernel 推理支持仅 AVX2 的 CPU 后端。(教程)
  • 2026 年 2 月 13 日:MiniMax-M2.5 Day0 支持!(教程)
  • 2026 年 2 月 12 日:GLM-5 Day0 支持!(教程)
  • 2026 年 1 月 27 日:Kimi-K2.5 Day0 支持!(教程)(SFT 教程)
  • 2026 年 1 月 22 日:支持 CPU-GPU 专家调度、原生 BF16 与 FP8 per-channel 精度 以及 AutoDL 训推一体化
  • 2025 年 12 月 24 日:支持原生 MiniMax-M2.1 推理。(教程)
  • 2025 年 12 月 22 日:支持使用 LLaMA-Factory 进行 RL-DPO 微调。(教程)
  • 2025 年 12 月 5 日:支持原生 Kimi-K2-Thinking 推理(教程)
  • 2025 年 11 月 6 日:支持 Kimi-K2-Thinking 推理(教程)与微调(教程)
  • 2025 年 11 月 4 日:KTransformers 微调 × LLaMA-Factory 集成。(教程)
  • 2025 年 10 月 27 日:支持昇腾 NPU。(教程)
  • 2025 年 10 月 10 日:集成进 SGLang。(路线图,博客)
  • 2025 年 9 月 11 日:支持 Qwen3-Next。(教程)
  • 2025 年 9 月 5 日:支持 Kimi-K2-0905。(教程)
  • 2025 年 7 月 26 日:支持 SmallThinker 与 GLM4-MoE。(教程)
  • 2025 年 7 月 11 日:支持 Kimi-K2。(教程)
  • 2025 年 6 月 30 日:支持三层(GPU-CPU-磁盘)prefix cache 复用。
  • 2025 年 5 月 14 日:支持 Intel Arc GPU(教程)。
  • 2025 年 4 月 29 日:支持 AMX-Int8、AMX-BF16 与 Qwen3MoE(教程)
  • 2025 年 4 月 9 日:实验性支持 LLaMA 4 模型(教程)。
  • 2025 年 4 月 2 日:支持多并发。(教程)。
  • 2025 年 3 月 15 日:支持 AMD GPU 上的 ROCm(教程)。
  • 2025 年 3 月 5 日:支持 unsloth 1.58/2.51 bits 权重以及 IQ1_S/FP8 混合权重。在 24GB 显存下支持 DeepSeek-V3 与 R1 的 139K 长上下文。
  • 2025 年 2 月 25 日:为 DeepSeek-V3 与 R1 支持 FP8 GPU kernel;更长上下文。
  • 2025 年 2 月 15 日:更长上下文(24GB 显存下从 4K 提升到 8K)与略快的速度(+15%,最高 16 tokens/s),更新文档与在线书。
  • 2025 年 2 月 10 日:支持在单卡(24GB 显存)/多卡加 382G DRAM 上运行 Deepseek-R1 与 V3,最高 3~28 倍加速。详细的演示与复现教程见此处。
  • 2024 年 8 月 28 日:将 DeepseekV2 所需显存从 21G 降至 11G。
  • 2024 年 8 月 15 日:更新注入与多 GPU 的详细教程。
  • 2024 年 8 月 14 日:支持 llamfile 作为 linear 后端。
  • 2024 年 8 月 12 日:支持多 GPU;支持新模型 mixtral 8*7B 和 8*22B;支持 GPU 上的 q2k、q3k、q5k 反量化。
  • 2024 年 8 月 9 日:支持 Windows 原生环境。

📦 能力概览

🚀 推理 - 高性能 kt-kernel 服务

这是一组针对 CPU 优化的 kernel 运算,专门服务于 CPU/GPU 混合的 LLM 推理。

image

核心特性:

  • AMX/AVX 加速:针对 INT4/INT8 量化推理的 Intel AMX 与 AVX512/AVX2 优化 kernel
  • MoE 优化:结合 NUMA 感知内存管理的高效混合专家推理
  • 量化支持:CPU 侧 INT4/INT8 量化权重,GPU 侧支持 GPTQ
  • 易于集成:为 SGLang 等框架提供简洁的 Python API

快速开始:

1
2
cd kt-kernel
pip install .

适用场景:

  • 大 MoE 模型的 CPU-GPU 混合推理
  • 与 SGLang 集成用于生产环境服务
  • 异构专家放置(热专家放 GPU,冷专家放 CPU)

性能示例:

模型 硬件配置 总吞吐 输出吞吐
DeepSeek-R1-0528 (FP8) 8×L20 GPU + Xeon Gold 6454S 227.85 tokens/s 87.58 tokens/s(8 路并发)

👉 完整文档 →


🎓 微调 - 使用 LlamaFactory 做微调

论文: KTransformers-FineTune (KT-FT) · PDF。

KTransformers 和 LlamaFactory 已经打通,可以用来微调超大规模 MoE 模型。新写的 Cookbook 是一条照着做就行的路径:从检查硬件、装环境,到 BF16/FP8/INT8 各种配法,再到 LoRA 与全量训练、资源规划、出问题怎么排查,全都覆盖。

Kimi K2.5 / K2.6 LoRA 微调支持原生 RAWINT4 路由专家。参见 PyPI 安装、训练、断点续训与 SGLang 服务指南(中文)。端到端验证使用 Kimi K2.5,K2.6 沿用相同的模型架构路径。

LlamaFactory 与 KTransformers 的 MoE 微调架构

核心特性:

  • 多后端支持:INT8/INT4 量化的 CPU/GPU 混合微调
  • 超大规模 MoE 支持:在有限显存下微调 DeepSeek-V3/R1 等模型
  • 快于 ZeRO-Offload:在基准测试的 MoE SFT 负载中训练提速 6-12 倍
  • 更低的 CPU 内存:在基准配置下约为此前 KT SFT 路径的一半 CPU 内存
  • LlamaFactory 集成:与该流行微调框架无缝集成
模型 显存 训练速度 硬件
DeepSeek-V3 约 80GB 总计 3.7 it/s 4x RTX 4090
DeepSeek-R1 约 80GB 总计 3.7 it/s 4x RTX 4090
Qwen3-30B-A3B 约 24GB 总计 8+ it/s 1x RTX 4090

快速开始:

1
2
3
4
5
6
7
8
cd /path/to/LLaMA-Factory
python -m pip install -e .
python -m pip install "ktransformers[sft]==0.7.0"
python -m pip install "sglang-kt==0.7.0"
CUDA_VISIBLE_DEVICES=0,1,2,3 accelerate launch \
--config_file examples/ktransformers/accelerate/fsdp2_kt_int8.yaml \
src/train.py \
examples/ktransformers/train_lora/qwen3_5moe_lora_sft_kt.yaml

👉 易用的微调 Cookbook → 👉 快速开始 → 👉 完整文档 →


🔥 引用

如果你的研究用到了 KTransformers,麻烦顺手引一下对应的论文。

推理论文

1
2
3
4
5
6
@inproceedings{10.1145/3731569.3764843,
title = {KTransformers: Unleashing the Full Potential of CPU/GPU Hybrid Inference for MoE Models},
author = {Chen, Hongtao and Xie, Weiyu and Zhang, Boxin and Tang, Jingqi and Wang, Jiahao and Dong, Jianwei and Chen, Shaoyuan and Yuan, Ziwei and Lin, Chen and Qiu, Chengyu and Zhu, Yuening and Ou, Qingliang and Liao, Jiaqi and Chen, Xianglin and Ai, Zhiyuan and Wu, Yongwei and Zhang, Mingxing},
booktitle = {Proceedings of the ACM SIGOPS 31st Symposium on Operating Systems Principles},
year = {2025}
}

微调论文

KTransformers-FineTune (KT-FT) · 完整 BibTeX

1
2
3
4
5
6
7
8
@misc{li2026ktft,
title = {{KTransformers-FineTune: Beyond Offload with Layout-Aware and Schedule-Optimized Heterogeneous MoE Fine-Tuning}},
author = {Li, Peilin and Hao, Xingxing and Chen, Hongtao and Xie, Weiyu and Zheng, Yaowei and Wu, Bowen and Yang, Yujie and Shen, Huanming and Ou, Qingliang and Zhang, Boxin and Tang, Jingqi and Yuan, Ziwei and Dong, Jianwei and Kuang, Dongdong and Feng, Zhangchi and Dai, Jiaheng and Yang, Qianrui and Chen, Shaoyuan and Wang, Jiahao and Han, Yaochen and Zhu, Yuening and Liao, Jiaqi and Chen, Xianglin and Ai, Zhiyuan and Wu, Yongwei and Zhang, Mingxing},
year = {2026},
note = {Author preprint, version paper-ktft-v1.1},
howpublished = {Author preprint, GitHub},
url = {https://github.com/kvcache-ai/ktransformers/tree/paper-ktft-v1.1/papers/kt-ft}
}

👥 贡献者与团队

由以下团队开发与维护:

  • MADSys Lab @ 清华大学
  • Approaching.AI
  • 9#AISoft
  • 社区贡献者

欢迎一起贡献:发现问题可以提 issue,有改动可以直接提 pull request。

💬 社区与支持

  • GitHub Issues:反馈 bug 或提出需求
  • 微信群:见 archive/WeChatGroup.png

📦 KT 原始代码

原来那套一体化的 KTransformers 框架已经挪到 archive/ 目录存档备查。现在项目以 kt-kernel 源码树为基准,把上面这两项能力分开组织,文档看得更清楚,维护也省事一些。

想看带完整快速开始和示例的原始文档,可以看这几份:

  • archive/README.md(英文)
  • archive/README_ZH.md(中文)

KT-Kernel

KT-Kernel 是 KTransformers 的高性能 kernel 层,用 AMX、AVX、KML 以及 blis(AMD 的库)在 CPU 上把 MoE 推理跑快。

  • 说明
  • 特性
  • 安装
    • 方式 1:从 PyPI 安装(推荐大多数用户)
    • 方式 2:从源码安装(本地使用或自定义构建)
  • 验证
  • KT CLI 概览
  • 与 SGLang 集成
    • 安装步骤
    • 完整示例:Qwen3-30B-A3B
    • KT-Kernel 参数
  • 直接使用 Python API
    • 高级选项
    • 手动配置(进阶)
  • 构建配置
    • 手动安装(不使用 install.sh)
  • 错误排查
    • 找不到 CUDA
    • 找不到 hwloc
  • 权重量化
  • 提交代码之前!

说明

当前支持状态:

  • ✅ AVX512/AMX 原生精度:在支持 FP8、BF16 与 RAWINT4 格式的 AVX512 CPU 上可用 - 指南
  • ✅ 带 AMX 的 Intel CPU:完整支持(使用转换为 INT4/INT8 格式的权重)
  • ✅ 通用 CPU(llamafile 后端):支持(使用 GGUF 格式权重)
  • ✅ 带 BLIS 的 AMD CPU:支持(用于 int8 预填充与解码)- 指南

KT-CLI

我们还在做一个更省事的用法,细节见 KT-CLI 指南。

特性

  • CPU 优化 MoE Kernel:针对指令集优化的高吞吐 MoE 专家 kernel。
  • AVX512 原生精度后端:面向支持 AVX512 的服务器,提供 FP8 / BF16 / INT4 原生 MoE 后端。
  • AMX INT4/INT8 后端:面向支持 AMX 的服务器,提供 INT4 / INT8 量化专家推理后端。
  • Llamafile CPU 后端:基于 Llamafile 的 AVX2/AVX512 MoE 后端,用于通用 CPU 部署。
  • NUMA 感知执行:为多路 / 多 NUMA 机器设计的线程池与内存布局。

安装

方式 1:从 PyPI 安装(推荐大多数用户)

一条命令就能装上最新版:

1
pip install kt-kernel

注意:查看 PyPI 上的最新版本

特性:

  • ✅ 自动 CPU 检测:识别你的 CPU 并加载最优 kernel 变体
  • ✅ CPU 多变体支持:内置 AMX、AVX512(Base/VNNI/VBMI/BF16)与 AVX2 变体
  • ✅ 包含 CUDA 支持:为 NVIDIA GPU(SM 80、86、89、90)提供 GPU 加速
  • ✅ 无需编译:为 Python 3.10、3.11、3.12 提供预编译 wheel
  • ✅ 静态 CUDA 运行时:无需安装 CUDA toolkit
  • ✅ 纯 CPU 系统可用:无 GPU 时自动禁用 CUDA 功能

环境要求:

  • Python 3.10、3.11 或 3.12
  • Linux x86-64(兼容 manylinux_2_17)
  • 支持 AVX2 的 CPU(Intel Haswell 2013+、AMD Zen+)
  • 可选:计算能力 8.0+ 的 NVIDIA GPU 以启用 CUDA 功能
CUDA 安装(GPU 加速)

想让 NVIDIA GPU 参与加速的话:

1
pip install kt-kernel

特性:

  • ✅ 多架构支持:单个 wheel 支持 SM 80/86/89/90(Ampere、Ada、Hopper)
  • ✅ 静态 CUDA 运行时:无需安装 CUDA toolkit
  • ✅ 广泛兼容:兼容 CUDA 11.8+ 与 12.x 驱动
  • ✅ PyTorch 兼容:可搭配任意 PyTorch CUDA 变体(cu118、cu121、cu124)

环境要求:

  • Python 3.10、3.11 或 3.12
  • Linux x86-64(兼容 manylinux_2_17)
  • 计算能力 8.0+ 的 NVIDIA GPU(Ampere 或更新)
    • ✅ 支持:A100、RTX 3000/4000 系列、H100
    • ❌ 不支持:V100、P100、GTX 1000/2000 系列(过旧)
  • 支持 CUDA 11.8+ 或 12.x 的 NVIDIA 驱动(无需 CUDA toolkit)

GPU 兼容性矩阵:

GPU 架构 计算能力 是否支持 示例 GPU
Hopper 9.0 ✅ H100, H200
Ada Lovelace 8.9 ✅ RTX 4090, 4080, 4070
Ampere 8.6 ✅ RTX 3090, 3080, 3070, 3060
Ampere 8.0 ✅ A100, A30
Turing 7.5 ❌ RTX 2080, T4
Volta 7.0 ❌ V100

CUDA 驱动兼容性(针对 GPU 功能):

  • CUDA 11.8、11.9、12.0-12.6+:完整支持
  • CUDA 11.0-11.7:不支持(请升级驱动或仅使用 CPU)

内置的 CPU 变体:

wheel 里打包了 6 个优化变体,运行时按你的 CPU 自动挑一个:

变体 CPU 支持 性能 自动选择条件
AMX Intel Sapphire Rapids+(2023+) ⚡⚡⚡ 最佳 检测到 AMX 指令
AVX512+BF16 Ice Lake 服务器、Zen 4+(2021+) ⚡⚡⚡ 优秀 检测到 AVX512 + BF16
AVX512+VBMI Ice Lake 客户端(2019+) ⚡⚡ 很好 检测到 AVX512 + VBMI
AVX512+VNNI Cascade Lake+(2019+) ⚡⚡ 很好 检测到 AVX512 + VNNI
AVX512 Base Skylake-X+(2017+) ⚡⚡ 良好 检测到 AVX512 base
AVX2 Haswell+(2013+)、AMD Zen+ ⚡ 可用 兜底以保证最大兼容性

验证安装:

1
2
3
4
5
6
7
8
9
10
11
12
13
import kt_kernel

# 查看加载了哪个 CPU 变体
print(f"CPU variant: {kt_kernel.__cpu_variant__}")
print(f"Version: {kt_kernel.__version__}")

# 检查 CUDA 支持
from kt_kernel import kt_kernel_ext
cpu_infer = kt_kernel_ext.CPUInfer(4)
has_cuda = hasattr(cpu_infer, 'submit_with_cuda_stream')
print(f"CUDA support: {has_cuda}")

print("✓ kt-kernel installed successfully!")

环境变量:

1
2
3
4
5
6
# 覆盖自动 CPU 检测(用于测试或调试)
export KT_KERNEL_CPU_VARIANT=avx2 # 强制指定变体

# 打开调试输出以查看检测过程
export KT_KERNEL_DEBUG=1
python -c "import kt_kernel"

方式 2:从源码安装(本地使用或自定义构建)

需要本地安装,或者要用 AMD(BLIS)、ARM(KML)、自定义 CUDA 版本时,就走源码构建这条路。

前置条件

先把 git 子模块拉下来,再建一个 conda 环境:

1
2
3
git submodule update --init --recursive
conda create -n kt-kernel python=3.11 -y
conda activate kt-kernel
快速安装(推荐)

直接跑安装脚本就行——它会自己认出你的 CPU,按最佳性能来编译:

1
./install.sh

脚本会自动完成:

  • 自动检测 CPU 能力(AMX、AVX512_VNNI、AVX512_BF16)
  • 安装系统依赖(cmake、libhwloc-dev、pkg-config)
  • 为你的 CPU 专门构建优化二进制(使用 -march=native)
  • 对不支持 VNNI/BF16 的 CPU 自动启用软件兜底

可选:分两步安装

1
2
./install.sh deps   # 仅安装依赖
./install.sh build # 构建并安装 kt-kernel

各后端的 CPU 要求:

后端 最低 CPU 要求 示例 CPU 说明
LLAMAFILE AVX2 Intel Haswell(2013+)、AMD Zen+ 通用兼容性
RAWINT4 AVX512F + AVX512BW Intel Skylake-X(2017+)、Ice Lake、Cascade Lake 为 VNNI/BF16 提供软件兜底
AMXINT4/INT8 AMX Intel Sapphire Rapids(2023+) 最佳性能,需 AMX 硬件
FP8 AVX512F + AVX512BW + AVX512_BF16 + AVX512_VBMI Intel Cooper Lake(2020+)、Sapphire Rapids(2023+);AMD Zen 4+(如 EPYC 9355) 原生精度(如 DeepSeek V3.2、MiniMax M2.1)
BF16 AVX512F + AVX512BW + AVX512_BF16 Intel Cooper Lake(2020+)、Sapphire Rapids(2023+);AMD Zen 4+(如 EPYC 9355) 原生精度(如 Qwen3-235B-A22B、GLM-4.7)

软件兜底支持(AVX512 后端):

  • ✅ VNNI 兜底:使用 AVX512BW 指令
  • ✅ BF16 兜底:使用 AVX512F 指令
  • ✅ 较老的 AVX512 CPU(Skylake-X、Cascade Lake)可通过兜底运行 RAWINT4

⚠️ 可移植性提醒: 默认构建只针对你这颗 CPU 优化,换台机器或换到更老的 CPU 上可能就跑不起来。要做可移植构建或二进制分发,看下文手动配置。

⚠️ 用 AMD BLIS 后端的话: AMD 平台的装法见这份指南。

验证

装完先确认 CLI 能用:

1
kt version

预期输出:

1
2
3
4
5
6
7
KTransformers CLI v0.x.x

Python: 3.11.x
Platform: Linux 5.15.0-xxx-generic
CUDA: 12.x
kt-kernel: 0.x.x (amx)
sglang: 0.x.x

也可以直接验证 Python 模块:

1
python -c "from kt_kernel import KTMoEWrapper; print('✓ kt-kernel installed successfully')"

KT CLI 概览

kt 命令行工具把「跑模型」和「管模型」的事都收到一个入口下:

命令 说明
kt run 以自动优化参数启动模型推理服务
kt chat 跟正在跑的模型服务聊天
kt model 管理模型与存储路径
kt doctor 诊断环境问题并检查系统兼容性
kt config 管理 CLI 配置
kt version 显示版本信息

快速开始示例:

1
2
3
4
5
6
7
8
# 启动模型服务(自动检测硬件并应用最优设置)
kt run m2

# 在另一个终端中与模型对话
kt chat

# 检查系统兼容性
kt doctor

想看更多选项就跑 kt --help,想看某个命令的细节就跑 kt <command> --help。

与 SGLang 集成

KT-Kernel 可以单独用(直接调 Python API),也可以接进 SGLang 做生产部署。这一节讲怎么接 SGLang,从而开启 CPU-GPU 异构推理:「热」专家放在 GPU 上,「冷」专家放在 CPU 上,资源才用得最划算。

安装步骤

1. 安装 SGLang

装 kvcache-ai 维护的 SGLang 分支(kt-kernel 要靠它):

1
2
3
4
5
6
7
8
9
10
# 方式 A:一键安装(在 ktransformers 根目录执行,安装 sglang + kt-kernel)
./install.sh

# 方式 B:pip 安装
pip install kt-kernel sglang-kt

# 方式 C:从源码安装(可编辑模式)
git clone --recursive https://github.com/kvcache-ai/ktransformers.git
cd ktransformers
pip install -e "third_party/sglang/python[all]"

重要:请使用 sglang-kt(kvcache-ai 分支),不要使用官方 sglang 包。如果已安装官方版本,请先卸载:pip uninstall sglang -y

2. 准备权重

异构推理得准备两份权重:GPU 权重和 CPU 侧的专家权重。用什么格式取决于后端:

GPU 权重(所有后端通用):
就是 SGLang 做 GPU 推理要用的那份模型权重(比如 Hugging Face 上的原始模型目录,或者已经量化好的目录)。

CPU 权重(AMX 后端:AMXINT4 / AMXINT8): 使用提供的脚本将权重转换为 AMX 优化的 INT4/INT8 格式:

1
2
3
4
5
python scripts/convert_cpu_weights.py \
--input-path /path/to/model \
--input-type bf16 \
--output /path/to/cpu-weights \
--quant-method int8 # 或 int4 或 moe_int8(目前用于 amd)
  • --input-path:GPU 侧原始权重路径
  • --input-type:取决于你的 GPU 权重类型(fp8、fp16 或 bf16)

接进 SGLang 时,--kt-weight-path 指向转换好的 CPU 权重目录。

支持的输入格式: FP8、FP16、BF16 → INT4/INT8。

CPU 权重(LLAMAFILE 后端:LLAMAFILE): LLAMAFILE 直接在 CPU 侧使用预量化的 GGUF 权重,无需运行 convert_cpu_weights.py。你需要:

  • 直接从网上下载 GGUF 模型(例如 Hugging Face / Modelscope 上的 GGUF 仓库);
  • 在 SGLang 集成中,将该 GGUF 目录作为 --kt-weight-path。KT-Kernel 支持 Q4_KM、Q4_K、Q5_K 等多种 GGUF 量化格式,可按延迟与精度需求选择。
3. 启动 SGLang 服务

用你平时的 SGLang 参数启动服务,再补上下面这几个 KT-Kernel 专用参数,就能走 CPU-GPU 异构推理:

需要追加的 KT-Kernel 参数:

  • --kt-method:后端方法(AMXINT4、AMXINT8 或 LLAMAFILE)
  • --kt-weight-path:转换后的 CPU 权重路径
  • --kt-cpuinfer:CPU 推理线程数(设为物理核心数)
  • --kt-threadpool-count:线程池数量(设为 NUMA 节点数)
  • --kt-num-gpu-experts:保留在 GPU 上的专家数量
  • --kt-max-deferred-experts-per-token:用于流水线执行的延迟专家数

示例:

1
2
3
4
5
6
7
8
python -m sglang.launch_server \
[your normal SGLang parameters...] \
--kt-method AMXINT8 \
--kt-weight-path /path/to/cpu-weights \
--kt-cpuinfer 64 \
--kt-threadpool-count 2 \
--kt-num-gpu-experts 32 \
--kt-max-deferred-experts-per-token 2

参数该怎么调,下面 KT-Kernel 参数 一节有详细说明。

完整示例:Qwen3-30B-A3B

这个例子把「下权重 → 起服务」的全流程走一遍,同时给出 Native 后端、AMX 后端 和 LLAMAFILE 后端 三种选择。

硬件配置:

  • GPU:NVIDIA RTX 4090 24GB
  • CPU:2x Intel Xeon Gold 6454S(共 64 个物理核心、128 线程、2 个 NUMA 节点)
  • 模型:Qwen3-30B-A3B

如何确认系统配置:

1
2
3
4
5
6
7
8
# 检查 CPU 配置
lscpu | grep -E "^CPU(s)|Thread(s) per core|Socket(s)|NUMA node(s)"
# 预期输出示例:
CPU(s): 128
Thread(s) per core: 2
Socket(s): 2
NUMA node(s): 2
# → 物理核心数 = CPU(s) / Thread(s) per core = 128 / 2 = 64

参数取值理由:

  • --kt-cpuinfer 64:设为物理核心数(64),而非超线程数(128)
  • --kt-threadpool-count 2:检测到 2 个 NUMA 节点(双路系统)
  • --kt-num-gpu-experts 32:24GB 显存下,这个模型大概能把 32 个专家放在 GPU 上(具体看模型架构和实际占用)
  • --kt-max-deferred-experts-per-token 2:启用流水线执行;让 CPU 在 GPU 完成当前批次时就开始处理下一批次
  • --kt-gpu-prefill-token-threshold 2048:token 数超过 2048 时使用逐层预填充策略(仅原生后端)

方式 A:原生后端(BF16)

适合支持 BF16 的 AVX512 CPU。

第 1 步:下载模型权重

1
2
3
4
# 如未安装 huggingface-cli 请先安装
pip install huggingface-hub
# 从 Hugging Face 下载模型
huggingface-cli download Qwen/Qwen3-30B-A3B --local-dir /mnt/data/models/Qwen3-30B-A3B

第 2 步:启动 SGLang 服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
python -m sglang.launch_server \
--host 0.0.0.0 \
--port 30000 \
--model /mnt/data/models/Qwen3-30B-A3B \
--kt-weight-path /mnt/data/models/Qwen3-30B-A3B \
--kt-cpuinfer 64 \
--kt-threadpool-count 2 \
--kt-num-gpu-experts 32 \
--kt-method BF16 \
--attention-backend flashinfer \
--trust-remote-code \
--mem-fraction-static 0.80 \
--chunked-prefill-size 16384 \
--max-running-requests 4 \
--served-model-name Qwen3 \
--enable-mixed-chunk \
--tensor-parallel-size 1 \
--enable-p2p-check \
--disable-shared-experts-fusion \
--kt-gpu-prefill-token-threshold 4096 \
--kt-enable-dynamic-expert-update

方式 B:AMX 后端(AMXINT8)

适合支持 AMX 指令集的 Intel CPU。

第 1 步:下载模型权重

1
2
3
4
5
# 如未安装 huggingface-cli 请先安装
pip install huggingface-hub

# 从 Hugging Face 下载模型
huggingface-cli download Qwen/Qwen3-30B-A3B --local-dir /mnt/data/models/Qwen3-30B-A3B

第 2 步:转换为 CPU 权重(AMXINT8)

1
2
3
4
5
python scripts/convert_cpu_weights.py \
--input-path /mnt/data/models/Qwen3-30B-A3B \
--input-type bf16 \
--output /mnt/data/models/Qwen3-30B-A3B-INT8 \
--quant-method int8

第 3 步:启动 SGLang 服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
python -m sglang.launch_server \
--host 0.0.0.0 \
--port 8000 \
--model /mnt/data/models/Qwen3-30B-A3B \
--trust-remote-code \
--mem-fraction-static 0.92 \
--chunked-prefill-size 4096 \
--served-model-name Qwen3-30B-A3B \
--enable-mixed-chunk \
--kt-method AMXINT8 \
--kt-weight-path /mnt/data/models/Qwen3-30B-A3B-INT8 \
--kt-cpuinfer 64 \
--kt-threadpool-count 2 \
--kt-num-gpu-experts 32 \
--kt-max-deferred-experts-per-token 2

方式 C:LLAMAFILE 后端(GGUF)

适合普通 CPU(不需要 AMX),直接用预量化的 GGUF 权重。

第 1 步:下载 GPU 权重(原始模型)

1
2
3
pip install huggingface-hub

huggingface-cli download Qwen/Qwen3-30B-A3B --local-dir /mnt/data/models/Qwen3-30B-A3B

第 2 步:下载 CPU 权重(GGUF 格式)

1
2
huggingface-cli download Qwen/Qwen3-30B-A3B-GGUF Qwen3-30B-A3B-Q4_K_M.gguf \
--local-dir /mnt/data/models/Qwen3-30B-A3B-Q4_K_M

第 3 步:启动 SGLang 服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
python -m sglang.launch_server \
--host 0.0.0.0 \
--port 8000 \
--model /mnt/data/models/Qwen3-30B-A3B \
--trust-remote-code \
--mem-fraction-static 0.92 \
--chunked-prefill-size 4096 \
--served-model-name Qwen3-30B-A3B \
--enable-mixed-chunk \
--kt-method LLAMAFILE \
--kt-weight-path /mnt/data/models/Qwen3-30B-A3B-Q4_K_M \
--kt-cpuinfer 64 \
--kt-threadpool-count 2 \
--kt-num-gpu-experts 32 \
--kt-max-deferred-experts-per-token 2

KT-Kernel 参数

参数 说明 示例值
--kt-method CPU 推理后端方法 AMXINT4、AMXINT8、RAWINT4、FP8、FP8_PERCHANNEL、BF16 或 LLAMAFILE
--kt-weight-path 量化 CPU 权重路径 /path/to/cpu-weights
--kt-cpuinfer CPU 推理线程数 64(按 CPU 核心数调整)
--kt-threadpool-count 并行执行的线程池数量 2(通常 1-4)
--kt-num-gpu-experts 保留在 GPU 上的专家数量 32(其余专家放到 CPU)
--kt-max-deferred-experts-per-token 每个 token 中延迟执行以形成流水线的专家数 2(0 表示关闭,建议 1-4)
--kt-gpu-prefill-token-threshold 预填充策略的 token 数阈值(仅原生后端) 约 1024-4096
--kt-enable-dynamic-expert-update 依据实际路由统计在预填充期间动态更新专家放置 (标志位,无需取值)
--kt-expert-placement-strategy 初始 GPU 专家放置策略 uniform、frequency、front-loading 或 random

参数取值指南:

  • kt-method:按 CPU 与权重格式选择:

    • AMXINT4:在支持 AMX 的 CPU 上配合 INT4 量化权重性能最佳(部分模型可能出现较大精度下降,例如 Qwen3-30B-A3B)
    • AMXINT8:在 AMX CPU 上使用 INT8 量化权重,精度更高
    • RAWINT4:CPU 与 GPU 共享原生 INT4 权重(目前支持 Kimi-K2-Thinking 模型)。详见 Kimi-K2-Thinking 原生教程。
    • FP8、FP8_PERCHANNEL:CPU 与 GPU 共享 FP8 权重
    • BF16:CPU 与 GPU 共享 BF16 权重
    • LLAMAFILE:基于 GGUF 的后端
  • kt-cpuinfer:设为物理 CPU 核心数(不是超线程数)。

    • 查看物理核心数:lscpu | grep -E "^CPU(s)|Thread(s) per core"
    • 物理核心数 = CPU(s) / Thread(s) per core
    • 示例:若 CPU(s)=128、Thread(s) per core=2,则物理核心数为 64
    • 重要:不要设为超线程数——那会导致性能下降
  • kt-threadpool-count:设为 NUMA 节点数。

    • 查看 NUMA 数量:lscpu | grep "NUMA node(s)"
    • 或使用:numactl --hardware | grep "available"
    • 注意:NUMA 节点数不必然等于物理 CPU 数
      • 它表示内存域,可能在单个 CPU 内划分,也可能跨多个 CPU
      • 以 lscpu 显示的 NUMA 节点数为准,与物理 CPU 数量无关
    • 典型取值:单路 1-2,双路 2-4
    • 这样可以在各 NUMA 域之间更好地利用内存带宽
  • kt-num-gpu-experts:根据显存与 profiling 结果确定:

    • GPU 专家越多 = 延迟越低但显存占用越高(可能导致 OOM)
  • kt-max-deferred-experts-per-token:启用流水线执行:

    • 0:同步执行(更简单,延迟更高)
    • 1-4:延迟执行(推荐区间;延迟与质量平衡较好,需要调优)
    • 5-7:延迟降低最多,但可能带来明显精度损失,谨慎使用
  • kt-gpu-prefill-token-threshold(仅 FP8 与 RAWINT4):控制原生 FP8 与 INT4 推理的预填充策略:

    • ≤ 阈值:使用 CPU+GPU 混合预填充。不需要额外显存,但随 token 数增加性能会逐渐下降。
    • > 阈值:使用逐层 GPU 预填充。长序列下性能扩展更好,但需要多一层 MoE 的显存(例如 Kimi-K2-Thinking 约 9GB+,MiniMax-M2.1 约 3.6GB)。
    • 仅在 --kt-method RAWINT4 或 --kt-method FP8 时生效。
  • kt-enable-dynamic-expert-update:在推理期间启用动态专家放置更新。

    • 在逐层预填充过程中,系统收集真实路由统计并据此重新分配 GPU 专家。
    • 需要设置 --kt-gpu-prefill-token-threshold,且预填充长度必须 ≥ 该阈值。
    • 在较低的 GPU 专家比例(10%-70%)下尤其有效,可显著优于静态策略。
    • 基准数据与细节见专家调度教程。
  • kt-expert-placement-strategy:决定服务启动时哪些专家放到 GPU。

    • uniform:把所有 MoE 层均分。默认选项,无需先验统计。
    • frequency:把激活最频繁的专家放到 GPU。有激活统计时性能最佳;需要 --init-expert-location 指向 .pt 统计文件。
    • front-loading:从第一个 MoE 层开始依次填满 GPU 专家。
    • random:以固定随机种子(42)随机选择专家。
    • 策略对比见专家调度教程。

直接使用 Python API

不想用 SGLang 的话,也可以直接调 Python API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from kt_kernel import KTMoEWrapper

# 初始化 MoE 封装
wrapper = KTMoEWrapper(
layer_idx=0,
num_experts=8,
num_experts_per_tok=2,
hidden_size=4096,
moe_intermediate_size=14336,
num_gpu_experts=2,
cpuinfer_threads=32,
threadpool_count=2,
weight_path="/path/to/weights",
chunked_prefill_size=512,
method="AMXINT4" # Options: "AMXINT4", "AMXINT8", "LLAMAFILE"
)

# 加载权重(从磁盘——已量化)
wrapper.load_weights(physical_to_logical_map)

# 或从张量加载权重(在线量化)
wrapper.load_weights_from_tensors(gate_proj, up_proj, down_proj, physical_to_logical_map)

# 执行推理
output = wrapper.forward(hidden_states, topk_ids, topk_weights, cuda_stream)

# 或使用异步 API 获得更好性能
wrapper.submit_forward(hidden_states, topk_ids, topk_weights, cuda_stream)
# ... 做其他事情 ...
output = wrapper.sync_forward(hidden_states, cuda_stream)

高级选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 使用额外选项初始化
wrapper = KTMoEWrapper(
layer_idx=0,
num_experts=8,
num_experts_per_tok=2,
hidden_size=4096,
moe_intermediate_size=14336,
num_gpu_experts=2,
cpuinfer_threads=32,
threadpool_count=2,
weight_path="/path/to/weights",
chunked_prefill_size=512,
method="AMXINT4",
cpu_save=False, # 加载后把权重保留在 CPU 内存中
max_deferred_experts_per_token=0 # 延迟执行的专家数(用于流水线执行)
)

# 为特定批大小预分配缓冲区(提升性能)
KTMoEWrapper.set_capture_batch_sizes([1, 2, 4, 8, 16])

# 查询已捕获的批大小
batch_sizes = KTMoEWrapper.get_capture_batch_sizes()

# 清理缓冲区缓存以释放内存
KTMoEWrapper.clear_buffer_cache()

手动配置(进阶)

要做可移植构建、二进制分发,或者跨机器部署,就得手动指定目标指令集:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 通用分发(可运行在 2017 年以来的任意 AVX512 CPU 上)
export CPUINFER_CPU_INSTRUCT=AVX512
export CPUINFER_ENABLE_AMX=OFF
./install.sh build --manual

# 最大兼容性(可运行在 2013 年以来的任意 CPU 上)
export CPUINFER_CPU_INSTRUCT=AVX2
export CPUINFER_ENABLE_AMX=OFF
./install.sh build --manual

# 仅限现代 CPU(Ice Lake+、Zen 4+)
export CPUINFER_CPU_INSTRUCT=FANCY
export CPUINFER_ENABLE_AMX=OFF
./install.sh build --manual

可选:覆盖 VNNI/BF16 检测

1
2
3
4
# 强制启用/禁用 VNNI 与 BF16(用于测试兜底路径)
export CPUINFER_ENABLE_AVX512_VNNI=OFF
export CPUINFER_ENABLE_AVX512_BF16=OFF
./install.sh

可选:在非 AMX 的 AVX512 CPU 上使用 oneDNN INT8 BRGEMM

1
2
3
4
5
6
7
8
9
# 需要已安装 oneDNN >= 3.9:
export CPUINFER_ENABLE_ONEDNN_VNNI=ON

# 或基于 oneDNN 源码树构建:
export CPUINFER_ONEDNN_SOURCE_DIR=/path/to/oneDNN
./install.sh

# 编译后的 wheel 默认使用 oneDNN;native 仍可用于 A/B 测试。
export KT_INT8_VNNI_BACKEND=auto # auto | onednn | native

全部可选参数见 ./install.sh --help。


构建配置

手动安装(不使用 install.sh)

如果你想抛开 install.sh 自己手动装:

1. 安装系统依赖

前置条件:

  • cmake(推荐:conda install -y cmake)
  • libhwloc-dev 与 pkg-config
2. 设置构建配置

核心选项:

变量 可选值 说明
CPUINFER_CPU_INSTRUCT NATIVE、AVX512、AVX2、FANCY 使用的 CPU 指令集
CPUINFER_ENABLE_AMX ON、OFF 启用 Intel AMX 支持
CPUINFER_ENABLE_ONEDNN_VNNI ON、OFF 在非 AMX 的 AVX512 CPU 上启用 oneDNN INT8 BRGEMM
CPUINFER_ONEDNN_SOURCE_DIR 路径 可选的 oneDNN >= 3.9 源码树
CPUINFER_BUILD_TYPE Release、Debug、RelWithDebInfo 构建类型(默认:Release)
CPUINFER_PARALLEL 数字 并行构建任务数(默认自动检测)
CPUINFER_VERBOSE 0、1 详细构建输出(默认:0)

指令集细节:

选项 目标 CPU 使用场景
NATIVE 仅你的特定 CPU 本地构建(性能最佳,默认)
AVX512 Skylake-X、Ice Lake、Cascade Lake、Zen 4+ 通用分发
AVX2 Haswell(2013)及更新 最大兼容性
FANCY Ice Lake+、Zen 4+ 具备完整 AVX512 扩展的现代 CPU

配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 本地使用——性能最佳(默认行为)
export CPUINFER_CPU_INSTRUCT=NATIVE
export CPUINFER_ENABLE_AMX=ON # 或 OFF

# 分发构建——可运行在任意 AVX512 CPU 上
export CPUINFER_CPU_INSTRUCT=AVX512
export CPUINFER_ENABLE_AMX=OFF

# 最大兼容性——可运行在 2013 年以来的 CPU 上
export CPUINFER_CPU_INSTRUCT=AVX2
export CPUINFER_ENABLE_AMX=OFF

# Debug 构建
export CPUINFER_BUILD_TYPE=Debug
export CPUINFER_VERBOSE=1
3. 构建并安装
1
2
3
4
5
# 可编辑安装(用于开发)
pip install -e .

# 标准安装
pip install .

错误排查

找不到 CUDA

1
2
3
-- Looking for a CUDA compiler - NOTFOUND
CMake Error at CMakeLists.txt:389 (message):
KTRANSFORMERS_USE_CUDA=ON but CUDA compiler not found

先确认装好了 CUDA toolkit,而且 nvcc 在系统 PATH 里。

可以试试 export CMAKE_ARGS="-D CMAKE_CUDA_COMPILER=$(which nvcc)" 之后再装一遍。

找不到 hwloc

Debian 系系统直接 sudo apt install libhwloc-dev;其他系统从源码编译:https://www.open-mpi.org/projects/hwloc/。

1
2
3
4
5
6
wget https://download.open-mpi.org/release/hwloc/v2.12/hwloc-2.12.2.tar.gz
tar -xzf hwloc-2.12.2.tar.gz
cd hwloc-2.12.2
./configure
make
sudo make install

权重量化

AMX 后端(AMXINT4 / AMXINT8)得先用脚本把 CPU 侧专家转成 AMX 友好的 INT4/INT8:

1
2
3
4
5
python scripts/convert_cpu_weights.py \
--input-path /path/to/model \
--input-type bf16 \
--output /path/to/output \
--quant-method int4

支持的格式: FP8、FP16、BF16 → INT4/INT8

LLAMAFILE 后端(LLAMAFILE)的 CPU 侧专家直接读 GGUF 权重,不用跑 AMX 转换脚本。从网上下一个 GGUF 模型(比如 Hugging Face 上的 GGUF 仓库),再把 weight_path / SGLang 的 --kt-weight-path(有些场景用 --model)指向那个 GGUF 目录就行。KT-Kernel 支持 Q4_KM、Q4_K、Q5_K 等多种 GGUF 量化类型。


更多细节、进阶选项和低内存模式见 scripts/README.md。

提交代码之前!

提交信息请按 Conventional Commits 规范来写:https://www.conventionalcommits.org/

提交前先把代码格式化:

1
2
3
cmake -B build
cd build
make format

需要比较新的 clang-format(至少 18 版)。conda 环境里这样装:

1
2
conda install -c conda-forge clang-format=18
rm -rf build

另外建议装个 black,用来格式化 Python 代码:

1
conda install black

KTransformers 微调 × LLaMA-Factory 集成 – 用户指南

MadSys Lab、KVCache-AI 团队、Approaching AI、LLaMA-Factory 团队

简介

从 DeepSeek-V3/R1 到 Qwen3-MoE、Kimi-K2,每一波开源大模型都把性能和规模往上推了一大截。可另一面是 GPU 太贵、模型动辄几百亿上千亿参数,资源有限时想微调超大模型几乎无路可走。为了填上这个坑,我们给出一条很实在的路子:把 KTransformers 和 LLaMA-Factory 接起来。2–4 张 RTX 4090 加一台大内存的 CPU 机器,就能微调 DeepSeek-671B 这类超大 MoE 模型。

我们想让资源紧张的研究者也能在本地摸一摸超大模型的微调,顺便给 14B/30B 这类小模型留一条快速定制的路子。方案用风格化对话、西式翻译腔和医疗问答三个代表性任务做了验证,几个小时内就能完成个性化适配。

如下图所示,LLaMA-Factory 管着整个微调流程的编排与配置——数据、训练调度、LoRA 注入、推理接口都归它。KTransformers 则作为一个可插拔的高性能后端,在训练配置不变的前提下接管 Attention/MoE 这些核心算子,让 GPU 和 CPU 一起干活。

image-20251011010558909

在 LLaMA-Factory 里,我们拿 HuggingFace、Unsloth、KTransformers 三种后端的 LoRA 微调做了对比。671B 这种超大 MoE,KTransformers 是目前唯一能在 4090 级硬件上跑通的方案;换成 DeepSeek-14B 这类小一点的 MoE,它吞吐更高、显存也更省。

在 LoRA(BF16)+ NekoQA-10K 风格化对话 下 HuggingFace 后端 Unsloth 后端 KTransformers 后端
[14B-DeepSeekV2-Lite] LoRA 微调吞吐 303.58 token/s 455.37 token/s 530.38 token/s
[14B-DeepSeekV2-Lite] 显存 32.12 GB 9.64 GB 6.08 GB
[671B-DeepSeekV3] LoRA 微调吞吐 规模太大无法运行 不支持 40.35 token/s
[671B-DeepSeekV3] 显存(各 GPU 合计) 理论值 1400 GB † 不支持 70 GB †

† 1400 GB 是按 FP16 全参数常驻算出来的理论值(实际上跑不起来)。70 GB 是用 KT 策略(Attention 留在 GPU + MoE 分层卸载)实测到的峰值。

按照模型划分的对比图_02

微调效果(示例)

风格化对话(猫娘语气)

数据集:NekoQA-10K。目标是让风格更一致、更好辨认。

图里是基座模型和微调后模型的回复对比。微调后的模型能更稳地保持目标语气和称呼(红框处),说明风格迁移微调确实有效。

image-20251016175046882

基准评测

我们使用:

(1) Translational-Style-ChatLLM,要的是那种夸张的西式翻译腔——定制目标很清晰,也很风格化。

(2) AfriMed-QA(ACL 2025),面向非洲医疗场景的数据集,领域特征很强,既有选择题也有简答题——拿来评估垂直领域微调正合适。

下表是 LoRA 微调前后的指标对比,各项都涨了一大截,说明微调确实起了作用:

Translational-Style 数据集 BLEU-1 BLEU-2 BLEU-3 BLEU-4 ROUGE-1 ROUGE-2 ROUGE-L
V2-Lite(无 LoRA) 20.66 8.33 4.54 2.89 22.71 4.52 19.19
KT-LoRA 微调后的 V2-Lite 35.41 22.44 15.42 11.18 42.03 18.38 33.10
V3 基座(无 LoRA) 8.49 3.34 1.62 0.96 15.91 2.55 10.07
KT-LoRA 微调后的 V3 37.02 23.70 16.21 11.49 43.43 18.96 34.54
AfriMed-QA(简答) BLEU-1 BLEU-2 BLEU-3 BLEU-4 ROUGE-1 ROUGE-2 ROUGE-L
V2-Lite(无 LoRA) 13.58 11.12 9.10 7.23 22.48 7.81 11.73
KT-LoRA 微调后的 V2-Lite 35.90 27.63 22.99 19.15 35.25 17.50 28.44
V3 基座(无 LoRA) 12.75 10.27 8.05 5.99 20.33 5.65 10.11
KT-LoRA 微调后的 V3 42.42 34.12 28.95 24.54 41.97 22.37 33.28
AfriMed-QA(选择题) 准确率
V2-Lite(无 LoRA) 0.0645
KT-LoRA 微调后的 V2-Lite 0.4812
V3 基座(无 LoRA) 0.5833
KT-LoRA 微调后的 V3 0.7930

就算是超大 MoE 模型,用 KTransformers 微调也能很快练出很强的任务表现。

快速开始

这一节讲怎么装、怎么用 LLaMA-Factory + KTransformers 做微调和推理:

  • 环境准备
  • 使用 KTransformers 后端微调超大 MoE 模型
  • 加载微调后的模型(基座 + LoRA 适配器)来聊天/推理
  • 批量推理与指标评估

环境准备

照着下面的例子,把 KTransformers 和 LLaMA-Factory 两个环境一起装好。这次为了省掉本地编译的麻烦,KTransformers 直接用 PyPI 上的包。步骤如下:(注意:本地的 Python、Torch、CUDA 版本要和装的包对得上。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 创建 conda 环境
conda create -n Kllama python=3.12 # choose from : [3.11, 3.12, 3.13]
conda install -y -c conda-forge libstdcxx-ng gcc_impl_linux-64
conda install -y -c nvidia/label/cuda-11.8.0 cuda-runtime

# 2. 安装 LLaMA-Factory 环境
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .

# 3. 安装 KTransformers SFT 包
pip install "ktransformers[sft]"

# 4. 安装 flash-attention,按你的 Python 与 Torch 版本从 https://github.com/Dao-AILab/flash-attention/releases 下载对应文件
pip install flash-attn --no-build-isolation
# abi=True/False can find from below
# import torch
# print(torch._C._GLIBCXX_USE_CXX11_ABI)

# 5. (可选)如果你想使用 flash_infer(否则默认使用 triton)
git clone https://github.com/kvcache-ai/custom_flashinfer.git
pip install custom_flashinfer/

使用提示: 在 LLaMA-Factory 的 YAML 中设置 use_kt: true 并选择一个 kt_optimize_rule 文件,即可让 KTransformers 接管核心计算。下面的特性展示了几种典型配置。

核心特性 1:使用 KTransformers 后端微调超大 MoE 模型

运行命令:USE_KT=1 ACCELERATE_USE_KT=true accelerate launch --config_file examples/ktransformers/accelerate/fsdp2_kt_bf16.yaml -m llamafactory.cli train examples/ktransformers/train_lora/deepseek_v3_lora_sft_kt.yaml。

注意:模型必须是 BF16。DeepSeek-V3-671B 官方发布的是 FP8,先用 DeepSeek-V3/inference/fp8_cast_bf16.py 转一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
### model

model_name_or_path: opensourcerelease/DeepSeek-V3-bf16
trust_remote_code: true

### method

stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset

dataset: identity
template: deepseek
cutoff_len: 2048
max_samples: 100000
overwrite_cache: true
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output

output_dir: saves/Kllama_deepseekV3
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: none # choices: [none, wandb, tensorboard, swanlab, mlflow]

### train

per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
resume_from_checkpoint: null

### ktransformers

use_kt: true # use KTransformers as LoRA sft backend
kt_optimize_rule: examples/kt_optimize_rules/DeepSeek-V3-Chat-sft-amx-multi-gpu.yaml
cpu_infer: 32
chunk_size: 8192

kt_optimize_rule 决定放置策略,规则文件都在 ktransformers/optimize_rules。看文件名基本就能猜到用途(* 是通配符):

命名模式 含义
DeepSeek-V2-Lite-Chat-* / DeepSeek-V3-Chat-* 目标模型变体
-sft- 用于微调的策略;其余为推理策略
-amx- CPU 上使用 AMX;否则使用 llamafile
-multi-gpu-X 在 X 张 GPU 上模型并行(省略 X 则默认 2 张)

比如 DeepSeek-V3-Chat-sft-amx-multi-gpu.yaml,意思是 V3-Chat 微调、开 AMX、两张卡做模型并行。

能用 AMX 就尽量用(lscpu | grep amx 看一眼)。AMX 支持 BF16/INT8。示例:

1
2
3
4
5
6
7
8
9
10
11
- match:
name: "^model\.layers\..*\.mlp\.experts$"
replace:
class: ktransformers.operators.experts.KTransformersExperts # custom MoE Kernel with expert parallelism
kwargs:
prefill_device: "cpu"
prefill_op: "KExpertsTorch"
generate_device: "cpu"
generate_op: "KSFTExpertsCPU"
out_device: "cuda"
backend: "AMXInt8" # or "AMXBF16" or "llamafile" (default)

训练结果会写到 output_dir,safetensors 格式,外加适配器元数据,后面加载要用。

image-20251016171537997

核心特性 2:与微调后的模型对话(基座 + LoRA 适配器)

运行命令:llamafactory-cli chat examples/inference/qwen3_lora_sft.yaml。

拿 KT 训出来的 safetensors 适配器直接推理就行。

1
2
3
4
5
6
7
8
9
10
model_name_or_path: opensourcerelease/DeepSeek-V3-bf16
adapter_name_or_path: saves/Kllama_deepseekV3
template: deepseek
infer_backend: ktransformers # choices: [huggingface, vllm, sglang, ktransformers]
trust_remote_code: true

use_kt: true # use KTransformers as LoRA sft backend to inference
kt_optimize_rule: examples/kt_optimize_rules/DeepSeek-V3-Chat-sft-amx-multi-gpu.yaml
cpu_infer: 32
chunk_size: 8192

GGUF 适配器也支持:safetensors 就把 adapter_name_or_path 填成目录,GGUF 就填文件路径。

加载时 LLaMA-Factory 会把层名映射成 KT 的命名,日志里能看到类似 Loaded adapter weight: XXX -> XXX 的行:

image-20251016171526210

核心特性 3:批量推理 + 指标评测(基座 + LoRA 适配器)

运行 API_PORT=8000 llamafactory-cli api examples/inference/qwen3_lora_sft.yaml,用 KT 微调出的适配器对外提供 API;其他 API 的用法和原生 LLaMA-Factory 完全一样。

1
2
3
4
5
6
7
8
9
10
model_name_or_path: opensourcerelease/DeepSeek-V3-bf16
adapter_name_or_path: saves/Kllama_deepseekV3
template: deepseek
infer_backend: ktransformers # choices: [huggingface, vllm, sglang, ktransformers]
trust_remote_code: true

use_kt: true # use KTransformers as LoRA sft backend to inference
kt_optimize_rule: examples/kt_optimize_rules/DeepSeek-V3-Chat-sft-amx-multi-gpu.yaml
cpu_infer: 32
chunk_size: 8192

KT 微调速度(用户视角)

端到端性能

定义

  • step_time:一个完整优化步的墙钟时间(张量搬运 + Attention + MoE + 其他计算)。
  • tokens_per_step = GAS × qlen;token/s = tokens_per_step / step_time。

设置: GAS=16、qlen=512(→ tokens_per_step = 8192);LoRA(r=8, alpha=32, dropout=0.1);启用 AMX;GPU:RTX 4090,CPU:Intel Xeon Platinum 8488C。

实测

  • DeepSeek-V3-671B: step_time = 203 s → token/s ≈ 8192 / 203 ≈ 40.35
  • DeepSeek-V2-Lite-14B: step_time = 36 s → token/s ≈ 8192 / 36 ≈ 227.6

GPU/CPU 内存占用

  • DeepSeek-V3(671B;61 层中 58 层为 MoE):GPU 显存合计约 70 GB(多卡),CPU 内存约 1.2–1.3 TB。
  • DeepSeek-V2-Lite(14B;27 层中 26 层为 MoE):GPU 显存约 5.5 GB,CPU 内存约 30 GB。

结论

把 KTransformers LoRA 微调接进 LLaMA-Factory,等于给 MoE 大模型的训练和部署配了一份实用说明书。KT 负责前沿优化(DeepSeek/Qwen/Kimi 都能跑,还有 AMX 加速 kernel),LoRA 让很低显存下的定制成为可能,LLaMA-Factory 则提供了一套顺手的统一接口。

这么一接(有点像 Unsloth 那种提速思路),几百亿到上千亿参数的模型也能在普通硬件上微调、以低延迟上线。省内存、跑得快、还好用,三样都占。下一个 MoE 项目不妨试试 LLaMA-Factory + KT,照着这份指南走;有问题也欢迎反馈。

KTransformers SFT 文档

  • Kimi K2.5:PyPI 安装、LoRA 训练、断点续训与部署(中文)
  • KTransformers × LlamaFactory MoE 微调 Cookbook
  • KTransformers × LlamaFactory MoE 微调 Cookbook(中文)
  • v0.6.1 快速开始
  • 微调用户指南
  • KT-FT 微调与推理闭环
  • DeepSeek-V4-Flash LoRA 快速开始
  • DeepSeek-V4-Flash MXFP4 LoRA 训练与静态部署
  • 开发者技术说明
  • DPO 教程
  • 注入教程

KTransformers × LlamaFactory MoE 微调 Cookbook

论文: KTransformers-FineTune (KT-FT) · PDF。

从 Qwen3.5 到 DeepSeek-V4、Kimi-K3、GLM-5.2,每一个新的超大规模开源模型,能力和规模都上了一个大台阶。可高端 GPU 的价格摆在那儿,很多人和团队还是没法在有限资源下微调这些模型。KTransformers 和 LlamaFactory 给出一条更现实的路:凑 1–4 张 RTX 4090,再加一台内存够大的 CPU 机器,就能微调 DeepSeek-V3/V4 系列、Kimi-K2.5、GLM-5.2 这些万亿参数级别的 MoE 模型。

KTransformers 接进了 LlamaFactory,同时没打断它原来的训练流程。数据处理、训练编排、LoRA 注入、推理集成,仍然统一由 LlamaFactory 来配置和调度。GPU 上跑 Attention 和 Shared Expert,Routed Experts 交给 KTransformers 放在 CPU 内存里,GPU 和 CPU 配合着跑。

LlamaFactory 与 KTransformers 的 MoE 微调架构

技术概览: KTransformers 把计算密集的 Attention 与共享模块放在 GPU,把体量大但稀疏激活的 Routed Experts 存放在 CPU 内存。这样无需反复通过 PCIe 传输庞大的专家权重,CPU 运行时还能根据权重格式与可用指令集自动选择优化后端。

KTransformers MoE 模型与异构硬件映射

指南速览: 首次运行时,从 原生 BF16 + LoRA 或全量微调 + kt_backend: auto 开始。这条路径无需权重转换,只需两个 YAML 文件即可启动。如果模型提供原生 FP8 checkpoint 且训练方式为 LoRA,KTransformers 可以直接加载原生 FP8 专家权重以降低主机内存占用。仅当主机内存仍是瓶颈、且已准备好相匹配的转换产物时,才使用转换后的 INT8 或 AMXINT4 权重。

目录

  • 检查硬件并安装
  • 选择微调方案
  • 自定义 YAML:进阶设置
  • 性能与资源估算
  • 附录:完整配置与问答

1. 检查硬件并安装

1.1 检查硬件资源

先看 CPU 指令集,确定能用哪个加速后端:

1
lscpu | grep -i -E 'Model name|Socket|NUMA|avx512|amx'

再看显存、主机内存和磁盘空间:

1
2
3
nvidia-smi
free -h
df -h /data

请确认两项要求:

  • 指令集兼容性: 原生 FP8 要的是带 AVX512F、AVX512_BF16、AVX512_VNNI、AVX512_VBMI 的 AMD/x86 CPU。INT8 的话,auto 能选 AMX-INT8 或 AVX512-VNNI 实现。AMXINT4 需要 AMX 硬件加配套的转换权重。有 AMX 时,原生 BF16 跑得最好。
  • 容量充足: 主机内存需容纳专家权重,并为激活、梯度与优化器状态留出空间。磁盘容量也需覆盖 checkpoint 与临时文件。

1.2 安装环境

环境用干净的 Python 3.11。装 LlamaFactory 之前先把 PyTorch 固定到 2.9.1,KT 的依赖放到最后装,免得标准版 transformers 或 accelerate 把 KT 的变体覆盖掉:

1
2
3
4
5
6
7
8
9
10
conda create -n kt-sft python=3.11 -y
conda activate kt-sft

git clone --depth 1 https://github.com/hiyouga/LlamaFactory.git
cd LlamaFactory

python -m pip install torch==2.9.1 torchaudio==2.9.1 torchvision==0.24.1
python -m pip install -e .
python -m pip install "ktransformers[sft]==0.7.0"
python -m pip install "sglang-kt==0.7.0"

装完检查一下依赖是否一致,再看 Python 实际导入的是哪些版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
python -m pip check

python - <<'PY'
from importlib.metadata import version

import accelerate
import ktransformers
import kt_kernel
import torch
import transformers

for name, module in {
"torch": torch,
"transformers": transformers,
"accelerate": accelerate,
"kt_kernel": kt_kernel,
"ktransformers": ktransformers,
}.items():
print(f"{name:14s} {getattr(module, '__version__', 'unknown')}")

print(f"{'sglang-kt':14s} {version('sglang-kt')}")
print(f"{'transformers-kt':14s} {version('transformers-kt')}")
print(f"{'accelerate-kt':14s} {version('accelerate-kt')}")

from accelerate.utils.dataclasses import KTransformersPlugin # noqa: F401
PY

一份能用的环境,版本大概是这样的:

1
2
3
4
5
6
7
8
9
No broken requirements found.
torch 2.9.1
transformers 5.6.0
accelerate 1.14.0
kt_kernel 0.7.0
ktransformers 0.7.0
sglang-kt 0.7.0
transformers-kt 5.6.0.post2
accelerate-kt 1.14.0.post2

2. 选择微调方案

先定专家权重格式,再定 LoRA 还是全量微调。两个都定下来,就用下面对应的训练 YAML 和 Accelerate YAML。

2.1 选择专家权重格式

原生精度/转换精度说的是专家权重格式;AMX(Advanced Matrix Extensions)和 AVX512(Advanced Vector Extensions 512-bit)说的是 CPU 指令集和后端——这两件事不在一个维度上。

权重选项 何时使用 要求与取舍
原生 BF16 checkpoint 主机内存充足,且优先考虑稳定、直接的训练路径 无需权重转换。有 AMX 时,auto 会选择当前最快的 AMXBF16 路径
原生 FP8(8 位浮点) 模型提供原生 FP8 checkpoint,且希望保持原始权重格式 目前用于基座专家冻结的 LoRA。需要完整的 AVX512 FP8 扩展集;AMX 不支持这条原生 FP8 路径
KT 转换的 INT8 原生专家权重放不进主机内存 需要相互匹配的一对 INT8 路由专家权重与 BF16 非专家缓存。auto 可选择 AMX-INT8 或 AVX512-VNNI
KT 转换的 AMXINT4 内存压力更严重,且可接受额外的精度风险 需要 AMX 与相匹配的 AMXINT4 权重。请在代表性评测集上验证质量

主机内存够的话,优先用原生 BF16 或原生 FP8。只有在已经备好配套的转换权重、又确实要压专家内存时,才上 INT8 或 AMXINT4。

2.2 选择 LoRA 或全量微调

专家权重格式和「更新哪些参数」是两件独立的事,但能搭配的组合有明确边界。原生 BF16 既能 LoRA 也能全量微调。原生 FP8、INT8、AMXINT4 这几套配方都是基座专家冻结的 LoRA。全量微调走 BF16。

方式 何时使用 资源与产出
LoRA(Low-Rank Adaptation) 默认推荐,用于快速任务适配、反复实验或资源受限场景 显存、主机内存与磁盘开销更低。产出 LoRA 适配器与 KT 专家 LoRA 产物
全量微调 任务需要更新全部目标参数,且能承担更高的训练与 checkpoint 开销 需要更多显存、主机内存与磁盘容量。产出完整模型 checkpoint

2.3 两个 YAML 文件的职责

训练 YAML、Accelerate YAML 与 KTransformers 执行

每次跑都要两个 YAML。训练 YAML 定义任务,KTransformers 的所有设置也都写在这里。Accelerate YAML 只管分布式执行和 FSDP2。目前 LlamaFactory 不接受在 Accelerate YAML 里写 kt_config。

文件 职责 常见字段
训练 YAML 模型、数据、LoRA 或全量微调、批大小、序列长度、输出目录以及全部 KT 设置 model_name_or_path、dataset、finetuning_type、lora_*、cutoff_len、output_dir、use_kt、kt_cpu_activation、kt_weight_path、kt_non_expert_weight_path、kt_config
Accelerate YAML GPU 进程数、FSDP2(Fully Sharded Data Parallel 2)与全局混合精度 num_processes、mixed_precision、fsdp_config

启动前先核对三件事:

  1. CUDA_VISIBLE_DEVICES 中的 GPU 数量必须等于 num_processes。
  2. 如果在训练 YAML 中手动设置了 kt_config.kt_model_max_length,它必须覆盖 cutoff_len 加上运行时 token 余量。
  3. LoRA rank 只写在训练 YAML 顶层。LlamaFactory 会推导 KTransformers 内部使用的字段。全量微调时请删除仅 LoRA 需要的字段。

2.4 四种常见方案的基础 YAML

从附录 A.1 和 A.2 抄完整配置,再把所选方案对应的字段替换掉。每个代码块都标了是训练 YAML 还是 Accelerate YAML。kt_config 一律写在训练 YAML 里。

2.4.1 原生 BF16 + LoRA
1
2
3
4
5
6
7
8
9
10
11
12
13
# File 1: training YAML
model_name_or_path: /data/models/Your-BF16-Model
finetuning_type: lora
lora_rank: 8
use_kt: true
# Do not set kt_weight_path for native BF16
kt_config:
kt_backend: auto
kt_expert_weight_format: bf16

# File 2: Accelerate YAML
mixed_precision: bf16
num_processes: 2
2.4.2 原生 FP8 + LoRA
1
2
3
4
5
6
7
8
9
10
11
12
13
# File 1: training YAML
model_name_or_path: /data/models/Your-Native-FP8-Model
finetuning_type: lora
lora_rank: 8
use_kt: true
# Do not set kt_weight_path for native FP8
kt_config:
kt_backend: auto
kt_expert_weight_format: fp8

# File 2: Accelerate YAML
mixed_precision: bf16
num_processes: 2
2.4.3 INT8 / AMXINT4 + LoRA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 1: training YAML
finetuning_type: lora
lora_rank: 8
use_kt: true
# INT8 setup
kt_weight_path: /data/models/Your-Routed-Experts-INT8
kt_non_expert_weight_path: /data/models/Your-Non-Expert-Cache-BF16
kt_config:
kt_backend: auto
kt_expert_weight_format: int8
kt_weight_lifecycle: persistent

# For AMXINT4, use matching paths and replace kt_config above with:
# kt_weight_path: /data/models/Your-Model-AMXINT4
# kt_non_expert_weight_path: /data/models/Your-Non-Expert-Cache-BF16
# kt_config:
# kt_backend: AMXINT4

# File 2: Accelerate YAML
mixed_precision: bf16
num_processes: 2
2.4.4 原生 BF16 + 全量微调
1
2
3
4
5
6
7
8
9
10
11
12
# File 1: training YAML
finetuning_type: full
learning_rate: 1.0e-5
use_kt: true
# Remove lora_rank, lora_alpha, lora_dropout, lora_target, and other LoRA fields
kt_config:
kt_backend: auto
kt_expert_weight_format: bf16

# File 2: Accelerate YAML
mixed_precision: bf16
num_processes: 2

2.5 启动

1
CUDA_VISIBLE_DEVICES=0,1 accelerate launch --main_process_port 0 --config_file qwen35_fsdp2_2gpu.yaml src/train.py qwen35_397b_bf16_lora.yaml

3. 自定义 YAML:进阶设置

基础方案能跑起来之后,再按训练目标和资源瓶颈调下面这些参数。没有明确理由就保持推荐值,也别一次动好几组。

(1) LoRA 容量:lora_rank、lora_alpha、lora_target、lora_dropout

这四个字段只在训练 YAML 顶层改。KTransformers 内部用的 rank、alpha、dropout 由 LlamaFactory 自动推导,不用在 kt_config 或 Accelerate YAML 里再写一遍。起步建议 lora_rank: 8、lora_alpha: 16、lora_target: all、lora_dropout: 0.0。

要是任务适配不够,先把 rank 提到 16,再提到 32,alpha 保持在 rank 的两倍左右。小数据集出现过拟合,就把 dropout 提到 0.05。

(2) 序列长度:cutoff_len

按大多数样本的实际 token 长度来设,别为了几条长样本就直接用数据集的最大长度。序列越长,激活和 KT 缓冲区占得越多,主机内存和显存需求一起往上走。

KT 的模型长度容量是从 cutoff_len 推出来的。想手动加大,就在训练 YAML 的 kt_config 里设 kt_model_max_length,它得大于 cutoff_len,还要给运行时的额外 token 留点余量。

(3) 批大小:per_device_train_batch_size、gradient_accumulation_steps

两个都在训练 YAML 里设。超大 MoE 从 per_device_train_batch_size: 1 起步,确认显存和主机内存够用了,再往上加 micro batch。显存不够就把 micro batch 压回 1,靠梯度累积把有效批大小做上去。

1
effective batch size = per_device_train_batch_size × number of GPUs × gradient_accumulation_steps

(4) 激活重算与 CPU 激活复用:disable_gradient_checkpointing、kt_cpu_activation

训练 YAML 里 disable_gradient_checkpointing: false 会打开梯度 checkpointing,用多算一点换取更低的激活内存。设成 true 会保留更多中间结果,可能更快,但也更吃内存。

主机内存够的话,可以在同一个训练 YAML 里加上这个顶层字段:

1
kt_cpu_activation: retain

这个开关会在 checkpoint 重算时保留 CPU 专家激活,用更多主机内存换掉重复的 CPU 计算。开了梯度 checkpointing 又没写这个字段,CPU 和 GPU 的激活都会被重算。kt_cpu_activation 管的是 CPU 专家激活保不保留,disable_gradient_checkpointing 管的是整体的重算策略——别当成一个开关用。

(5) CPU 专家复用与线程:kt_share_backward_bb、kt_num_threads

这两个都在训练 YAML 的 kt_config 里。kt_share_backward_bb: true 保持打开,CPU 专家反向计算要用的缓冲区就能复用。它和 kt_cpu_activation 是两回事;除非当前模型的配置明确要求,别关它。

kt_num_threads 填这个任务能用的物理核心数,不是含 SMT 的逻辑核心总数。如果数据预处理也占同一批 CPU,记得给 DataLoader 和系统进程留几个核。

kt_threadpool_count 由 NUMA 拓扑自动推导。确认过 CPU socket 和 NUMA 布局之后,再手动改它。

(6) 从 checkpoint 续训:resume_from_checkpoint

在训练 YAML 里把它设成目标 checkpoint-* 目录。全新训练就不写这个字段。output_dir 始终指向当前任务的输出目录,别指到基座模型目录去;overwrite_output_dir: false 也保持住,免得把已有结果盖掉。

4. 性能与资源估算

下表基于 2K 上下文(sequence length = 2048)、单卡批大小 1、梯度累积 1,且只包含完成真实 LoRA 训练的、被接受的 KTransformers BF16 运行结果。吞吐包含前向、loss、反向与优化器步骤。

模型与权重 GPU 数 全局批大小 单卡显存最低参考 主机内存最低参考 微调吞吐(tokens/s)
Qwen3-235B-2507 BF16 LoRA 2 2 ≥ 27.14 GiB ≥ 545.36 GiB 147.91
Qwen3.5-397B BF16 LoRA 8 8 ≥ 20.37 GiB ≥ 1075.68 GiB 215.25

显存那列是实测里单卡的最高峰值,主机内存那列是训练进程树的峰值 CPU RSS(统一折成 GiB)。这些是实测配置的最低参考值,不是安全余量。数据加载、缓存、存 checkpoint、系统进程,都得另外留出空间。

不同 GPU 数量的结果没法直接拿来做线性外推。cutoff_len、批大小、KT 缓存深度,任何一个往上加,资源占用都跟着涨。全量微调还得额外准备梯度、master 权重、优化器状态和完整 checkpoint 的空间。

附录

A.1 Qwen3.5-397B BF16 LoRA 训练 YAML

存成 qwen35_397b_bf16_lora.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
### model

model_name_or_path: /data/models/Qwen3.5-397B-A17B
trust_remote_code: true
disable_gradient_checkpointing: false

### method

stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_alpha: 16
lora_dropout: 0.0
lora_target: all

### dataset

dataset: your_dataset
template: qwen3_5
cutoff_len: 2048
packing: false
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output

output_dir: /data/output/qwen35-bf16-lora
logging_steps: 10
save_strategy: steps
save_steps: 500
plot_loss: true
overwrite_output_dir: false
save_only_model: false
report_to: none

### train

per_device_train_batch_size: 1
gradient_accumulation_steps: 1
learning_rate: 1.0e-4
num_train_epochs: 3
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000

### ktransformers

use_kt: true
# kt_cpu_activation: retain # Optional: use more host memory to reduce CPU Expert recomputation
# kt_weight_path: /data/models/Your-Routed-Experts-INT8 # Converted INT8 Routed Experts
# kt_non_expert_weight_path: /data/models/Your-Non-Expert-Cache-BF16 # Must match the path above
kt_config:
kt_expert_weight_format: bf16
kt_backend: auto
kt_num_threads: 64
kt_tp_enabled: true
kt_threadpool_count: 2
kt_max_cache_depth: 2
kt_share_backward_bb: true

A.2 FSDP2 Accelerate YAML

存成 qwen35_fsdp2_2gpu.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
compute_environment: LOCAL_MACHINE
distributed_type: FSDP
fsdp_config:
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
fsdp_cpu_ram_efficient_loading: true
fsdp_offload_params: false
fsdp_reshard_after_forward: true
fsdp_state_dict_type: FULL_STATE_DICT
fsdp_version: 2
mixed_precision: bf16
num_machines: 1
num_processes: 2
rdzv_backend: static
same_network: true
use_cpu: false

A.3 问答

A.3.1 为什么原生 FP8 checkpoint 不能使用转换后的 INT8 配置?

两者的权重格式和加载路径都不一样。原生 FP8 保留 checkpoint 里的 FP8 权重和 scale,走 AVX512 原生精度后端。INT8 配方读的是配套的一对 INT8 路由专家权重加 BF16 非专家缓存,再由 auto 选 AMX-INT8 还是 AVX512-VNNI。原生 FP8 的 checkpoint 别往 kt_weight_path 里塞。

A.3.2 auto 没有选到预期的后端

把 lscpu 输出和启动日志留好,先确认容器或虚拟化没把需要的指令集藏起来。有 AMX 时,原生 BF16 会选 AMXBF16;原生 FP8 应该选 AVX512。CPU 或权重格式不支持的后端,别硬指定。

A.3.3 主机内存不足

先把并发数据加载、序列长度、缓存深度降下来,再确认专家权重没被加载成两份。还是不够,就去准备转换后的 INT8 或 AMXINT4 权重。全量微调的话,梯度、master 权重、优化器状态的内存要单独算。

A.3.4 GPU OOM

OOM 就是显存或主机内存不够。先降 cutoff_len、单卡批大小和激活占用,再把 gradient_accumulation_steps 提上去,保住全局批大小。num_processes、可见 GPU 数量、实际模型放置,三者必须一致。

A.3.5 kt_model_max_length 与 cutoff_len 不匹配

调大 cutoff_len 的时候,kt_model_max_length 也要跟着调大,并给运行时的有效序列长度留出余量。值太小会报缓冲区或形状错误;值大得没必要,又白白吃主机内存。

使用 SGLang-KT 部署 Qwen3.5 MoE 的 KT LoRA

最后更新:2026-06-23

这份文档梳理 Qwen3.5 MoE 现在的 KT-FT 闭环:先用 KT SFT 训练,把输出转换一次,再用 SGLang 通过一条合并后的适配器路径把微调结果跑起来。

1
2
3
4
5
6
KT SFT raw output
-> convert_kt_to_sglang_adapter.py
-> <MERGED_ADAPTER_DIR>
-> sglang --lora-paths <name>=<MERGED_ADAPTER_DIR>
-> server auto-splits expert / non-expert internally
-> request model=<served_model>:<name>

训练侧的 KT SFT 文档另有说明。这一页只讲怎么把训好的 LoRA 产物接到在线推理上。

1. 适用范围

当前支持并验证过的流程:

  • 基座模型:Qwen3.5 MoE,例如 Qwen3.5-35B-A3B
  • KTransformers 版本:v0.6.3 或更新
  • KT 专家权重:AMX/BF16 SFT 兼容的 KT CPU 专家路径
  • 面向用户的部署输入:一个转换后的合并适配器目录
  • 运行时拆分:专家 LoRA 走 KT CPU 专家路径;非专家 LoRA 走 SGLang 的 LoRA 管理器。该拆分在服务启动时自动完成。
  • 该工作流针对 KT MoE 专家 LoRA 产物。标准的稠密模型 PEFT LoRA 适配器通常不需要这个转换器。

2. 各阶段的产物

原始 KT SFT 输出

用 LLaMA-Factory + KT 训完之后,输出目录里有两个 LoRA 产物:

1
2
3
4
<KT_SFT_OUTPUT_DIR>/
adapter_model.safetensors # non-expert LoRA
fused_expert_lora.safetensors # expert LoRA in KT fused format
adapter_config.json

这个原始目录别直接丢给 SGLang 部署。

转换后的合并适配器

跑一次转换器,生成部署用的输入:

1
2
3
<MERGED_ADAPTER_DIR>/
adapter_config.json
adapter_model.safetensors

这个合并目录在一个 PEFT 风格适配器里同时装了专家和非专家 LoRA 张量。传给 --lora-paths 的只该是它。

3. 转换一次

1
2
3
4
5
python kt-kernel/scripts/convert_kt_to_sglang_adapter.py \
<KT_SFT_OUTPUT_DIR> \
<MERGED_ADAPTER_DIR> \
--base-model-name-or-path /path/to/Qwen3.5-35B-A3B \
--overwrite

示例:

1
2
3
4
5
python kt-kernel/scripts/convert_kt_to_sglang_adapter.py \
saves/KT_FT_qwen35B_Moe_custom \
saves/KT_FT_qwen35B_Moe_custom_sglang \
--base-model-name-or-path /mnt/data3/models/Qwen3.5-35B-A3B \
--overwrite

转换器会读 fused_expert_lora.safetensors 和已有的非专家 adapter_model.safetensors,然后写出一个合并适配器目录。

如果原始 KT SFT 输出里没有带 lora_alpha 的 adapter_config.json,就用 --lora-alpha <value> 显式传进去。转换器不会把 LoRA 缩放折进张量,运行时缩放仍然是 lora_alpha / r。

想调试的话,也可以把专家和非专家分开输出:

1
2
3
4
5
6
7
python kt-kernel/scripts/convert_kt_to_sglang_adapter.py \
<KT_SFT_OUTPUT_DIR> \
<MERGED_ADAPTER_DIR> \
--base-model-name-or-path /path/to/Qwen3.5-35B-A3B \
--expert-output-dir <EXPERT_ADAPTER_DIR> \
--nonexpert-output-dir <NONEXPERT_ADAPTER_DIR> \
--overwrite

正常部署只需要 <MERGED_ADAPTER_DIR>。

4. 启动 SGLang

用本仓库里的 KTransformers SGLang 分支,并把 PYTHONPATH 同时指向 kt-kernel/python 和 third_party/sglang/python。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cd /path/to/ktransformers

PYTHONPATH=/path/to/ktransformers/kt-kernel/python:/path/to/ktransformers/third_party/sglang/python:$PYTHONPATH \
python -m sglang.launch_server \
--host 127.0.0.1 \
--port 30006 \
--model-path /path/to/Qwen3.5-35B-A3B \
--tokenizer-path /path/to/Qwen3.5-35B-A3B \
--kt-weight-path /path/to/Qwen3.5-35B-A3B-AMXINT4 \
--kt-method AMXINT4 \
--kt-cpuinfer 60 \
--kt-threadpool-count 2 \
--kt-numa-nodes 0 1 \
--kt-num-gpu-experts 0 \
--attention-backend flashinfer \
--trust-remote-code \
--mem-fraction-static 0.98 \
--chunked-prefill-size 4096 \
--max-running-requests 2 \
--max-total-tokens 32000 \
--served-model-name qwen3.5-kt-ft \
--enable-mixed-chunk \
--tensor-parallel-size 4 \
--enable-p2p-check \
--disable-cuda-graph \
--disable-custom-all-reduce \
--enable-lora \
--lora-backend triton \
--lora-paths qwen35b_lora=/path/to/KT_FT_qwen35B_Moe_custom_sglang \
--log-level info

要点:

  • 只通过 --lora-paths 传入一个合并适配器。
  • 在正常用户工作流中不要同时传 --kt-expert-lora-path。
  • 启动时,服务会识别合并的 KT MoE 适配器,在内部完成拆分,并把运行时缓存目录写到 $TMPDIR/sglang_kt_lora_cache/(若设置了 $SGLANG_KT_LORA_CACHE_DIR 则写到该处)。
  • Qwen3.5 全量 LoRA 生成建议使用 --lora-backend triton。

当前约束:

  • 仅支持单个合并的 KT 复合适配器
  • --kt-num-gpu-experts 0
  • 不要启用 --kt-enable-dynamic-expert-update
  • 不要使用 --kt-gpu-prefill-token-threshold
  • --max-running-requests 必须至少为 2
  • 使用 AMX/BF16 SFT 兼容的 KT 方法,例如 AMXINT4、AMXINT8、AMXBF16 或 BF16

5. 请求语义

OpenAI 兼容请求里的 model 字段填的是名称,不是路径。

1
2
--served-model-name qwen3.5-kt-ft
--lora-paths qwen35b_lora=/path/to/merged_adapter

现在这套单适配器实现下,请求行为是这样的:

1
2
3
4
5
model=qwen3.5-kt-ft
=> base + KT expert LoRA

model=qwen3.5-kt-ft:qwen35b_lora
=> base + KT expert LoRA + SGLang non-expert LoRA

: 后面的后缀必须和 --lora-paths 左边的名字对上。

想做一个只走基座的对照,就另起一个不带 --lora-paths 的服务。

6. 冒烟测试

1
2
3
4
5
6
7
8
9
curl -sS http://127.0.0.1:30006/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "qwen3.5-kt-ft:qwen35b_lora",
"messages": [{"role": "user", "content": "Explain what LoRA is in one sentence."}],
"temperature": 0.7,
"max_tokens": 160,
"chat_template_kwargs": {"enable_thinking": false}
}'

启动日志里应该有类似这几行:

1
2
3
Prepared merged KT LoRA adapter ... for runtime: expert=... nonexpert=...
Loaded KT expert LoRA for layer ...
Using triton as backend of LoRA kernels.

7. 进阶:手动拆分部署

老的分体运行时约定还能用,主要留给调试:

1
2
3
--kt-expert-lora-path <EXPERT_ADAPTER_DIR> \
--enable-lora \
--lora-paths <NONEXPERT_LORA_NAME>=<NONEXPERT_ADAPTER_DIR>

这不是推荐给用户的路子。普通用户只通过 --lora-paths 传一个合并适配器目录就够了。

8. 故障排查

Got LoRA adapter that has never been loaded: lora0

请求里的适配器名必须和 --lora-paths 左边的名字一致。启动时写的是 qwen35b_lora=...,请求就得写 model=qwen3.5-kt-ft:qwen35b_lora,不是 :lora0。

看不到适配器效果

确认你部署的是转换器产出的合并适配器目录,不是原始 KT SFT 输出目录,也不是别的测试适配器。

connection refused

看看服务是不是监听在你 curl 的那个端口上;另外注意上面示例绑的是 127.0.0.1,不是 0.0.0.0。

服务解析到上游 SGLang 而不是本仓库

1
2
3
4
5
python - <<'PY'
import inspect
import sglang.srt.models.qwen3_5 as qwen3_5
print(inspect.getfile(qwen3_5))
PY

这个路径应该来自本仓库的 third_party/sglang。

教程:逐步注入算子

作者:Azure-Tang

TL;DR

本教程带你把自定义算子注入模型,例子用 DeepSeekV2-Chat,一步一步来。涵盖这些内容:

  • TL;DR
  • 如何编写注入规则
  • 理解模型结构
  • 基于矩阵吸收的 MLA 注入
  • 路由专家的注入
  • 线性层注入
  • 带预计算 Buffer 的模块注入
  • 为模块指定运行设备
  • 多 GPU
  • 如何编写新算子并注入模型

如何编写注入规则

Inject 框架的注入规则,基本长这样:

1
2
3
4
5
6
7
8
9
10
- match:
name: "^model\.layers\..*\.*$" # Target module name
class: torch.nn.Linear # Target module
replace:
class: "default"
kwargs:
generate_device: "cuda:0"
# your_op_param_1: 1234
# your_op_param_2: 5678
recursive: True
  • match:该字段标记匹配规则,可以以 name 和 class 两种形式出现。这两种匹配规则可以同时出现,也可以单独出现;只有同时满足两个条件时才会匹配。
  • replace:
    • class:可导入的 Python 类,用于替换目标模块。如果不想替换,可设为 default。
    • kwargs:模块初始化所需的参数列表。
      • generate_device:这个模块挂在哪个设备上,可以填 “cpu”、”cuda”、”cuda:1” 等。
  • recursive:要不要递归注入这个模块的子模块,默认是 True。

关于 recursive:有些模块本身带着一堆子模块,比如自注意力模块里通常有 q/k/v/o 四个线性层。替换了自注意力模块,又不希望内部的线性层被别的规则接管,就把这条规则的 recursive 设成 False。

理解模型结构

拿 deepseek-ai/DeepSeek-V2-Lite-Chat 当例子,可以按上面的规则一步步把自定义模块注进去跑起来。KTransformers 给的灵活度很高,基础算子随你替换、随你实验;代价是,你得清楚自己正在跑的模型是什么结构。

好在弄清楚结构并不难。打开 deepseek-ai/DeepSeek-V2-Lite 主页的文件列表,能看到这几个文件:

Inject-Struction

.saftensors 文件里能看到每一层权重的名字,对应注入规则里的 match.name;modeling_deepseek.py 里能看到各个模块类的具体实现,类名对应 match.class。

从 .saftensors 和 modeling_deepseek.py 看,DeepSeekV2 的结构是这样的:

Inject-Struction

支持的算子与对应的类如下:

match replace backends descriptions
Linear KTransformersLinear KLinearMarlin 以 Marlin 为后端
KLinearTorch 以 pytorch 为后端
KLinearCPUInfer 以 llamafile 为后端
KLinearFP8 Triton fp8_gemm kernel。要求 GPU 具备 fp8 计算能力
experts KTransformersExperts KExpertsTorch 以 pytorch 为后端
KExpertsMarlin 以 Marlin 为后端
KExpertsCPU 以 llamafile 为后端
Attention KDeepseekV2Attention KDeepseekV2Attention MLA 实现
MoE KMistralSparseMoEBlock KQwen2MoeSparseMoeBlock 用于 Qwen2 的 MoE
KDeepseekV2MoE KDeepseekV2MoE 用于 DeepseekV2 的 MoE
Model KQwen2MoeModel KQwen2MoeModel 用于 Qwen2 的 Model
KDeepseekV2Model KDeepseekV2Model 用于 DeepseekV2 的 Model
RoPE RotaryEmbedding RotaryEmbedding RoPE 模块
YarnRotaryEmbedding YarnRotaryEmbedding RoPE 模块

接下来一步步注入自定义模块,目标是:

  • 将 linear 模块替换为自定义的 Marlin linear 模块。
  • 将自注意力模块替换为自定义的基于矩阵吸收的 MLA 模块。
  • 将 experts 模块替换为自定义的 Experts 模块。
  • 将 MoE 模块替换为自定义的 MoE 模块。
  • 将 RoPE 模块替换为自定义的 RoPE 模块。
  • 为每个模块设置运行设备。

注入规则的完整实现见此处。

基于矩阵吸收的 MLA 注入

注入 Attention 模块很简单:用正则匹配 transformers 里的模块名,替换成我们自己的 MLA 实现。YAML 规则如下:

1
2
3
4
- match:
name: "^model\.layers\..*\.self_attn$" # Regular expression
replace:
class: ktransformers.operators.attention.KDeepseekV2Attention # Optimized MLA implementation

可以看到,YAML 里每条规则都分两块:match 和 replace。match 指定要替换哪个模块,replace 指定注入的模块以及它的初始化参数。

路由专家的注入

路由专家(也就是图里的 exps)注入的是 CPUInfer,外面包了一层 KTransformersExperts。这层封装有几种实现,得用参数告诉它用哪种、怎么用。

transformer 源码里 MoE 是用 nn.ModuleList 实现的。我们不希望 KTransformers 把列表里的子模块一个个遍历、逐个注入,所以这条规则里设了 recursive: False,阻止它递归往下走。YAML 规则如下:

1
2
3
4
5
6
7
8
9
- match:
name: "^model\.layers\..*\.mlp\.experts$"
replace:
class: ktransformers.operators.experts.KTransformersExperts # Custom MoE kernel with expert parallelism
kwargs:
generate_device: "cpu"
generate_op: "MLPCPUExperts"
out_device: "cuda"
recursive: False # Don't recursively inject submodules of this module

把路由专家当成自定义模块注入之后,原来 nn.ModuleList 的接口就用不了了,FFN 模块里的 forward 得改。最省事的办法是写个带自定义 forward 的新模块,再把它注进去。

1
2
3
4
- match:
class: ktransformers.models.modeling_deepseek.DeepseekV2MoE
replace:
class: ktransformers.operators.experts.KDeepseekV2MoE # MLP module with custom forward function

线性层注入

剩下的线性层,我们希望换成量化算子,既省存储又更快。但 MLA 和量化放在一起用目前还没有研究,所以不想往 MLA 算子里注入 linear。于是可以改正则,并在规则的 match 部分加类型判断:只有名字和类都对上的模块才会被注入。这里同样要传一些关键字,和注入路由专家时类似。YAML 规则如下:

1
2
3
4
5
6
7
8
- match:
name: "^model\.layers\.(?!.*self_attn).*$" # Regular expression
class: torch.nn.Linear # Only match modules matching name and class simultaneously
replace:
class: ktransformers.operators.linear.KTransformersLinear # Optimized kernel on quantized data types
kwargs:
generate_device: "cuda"
generate_op: "QuantizedLinearMarlin"

带预计算 Buffer 的模块注入

为了初始化被注入的原始模型时不占资源,我们用 torch 的 meta device 来建原始模型。RoPE 模块初始化时会预先算一些 buffer,可 meta device 下什么都不会算。所以加载模型时得把这块补上。做法很简单:往旋转位置编码模块里注入一个自定义模块,让它在加载时做预计算。YAML 规则如下:

1
2
3
4
- match:
class: ktransformers.models.modeling_deepseek.DeepseekV2YarnRotaryEmbedding
replace:
class: ktransformers.operators.RoPE.YarnRotaryEmbedding

为模块指定运行设备

最后,给所有模块兜底设一个基础属性 generate_device:

1
2
3
4
5
6
7
8
9
10
11
12
13
- match:
name: "^model\.layers\..*\.|^lm_head"
replace:
class: "default"
kwargs:
generate_device: "cuda"

- match:
name: "^model.embed_tokens"
replace:
class: "default"
kwargs:
generate_device: "cpu"

这两条规则把之前没匹配上的层(连同子模块)和 lm_head 放到 cuda 上,embedding 放到 cpu 上。注意模块的属性由它匹配到的第一条规则决定:比如你后面又在某个注入模块里写了新的 replace.kwargs.generate_device,先设的那个仍然生效。机器上有多张卡的话,也可以把模型摊到多张卡上。

多 GPU

有多张 GPU 的话,可以把不同模块放到不同卡上。DeepseekV2-Chat 一共 60 层,两张卡就每张分 30 层。完整的多 GPU 规则示例见此处。

Inject-Struction

首先,多 GPU 下必须注入一个新算子 KDeepseekV2Model,并把层划分到不同 GPU。我们这里要在 KDeepseekV2Model 里这样设 transfer_map:

1
2
3
4
5
6
7
- match:
name: "^model$"
replace:
class: "ktransformers.operators.models.KDeepseekV2Model"
kwargs:
transfer_map:
30: "cuda:1"

而且还得给模型里每个模块都指定设备。

比如 routed experts,单卡的 yaml 是这样:

1
2
3
4
5
6
7
8
9
- match:
name: "^model\.layers\..*\.mlp\.experts$"
replace:
class: ktransformers.operators.experts.KTransformersExperts # Custom MoE kernel with expert parallelism
kwargs:
generate_device: "cuda:0"
generate_op: "MLPCUDAExperts"
out_device: "cuda:0"
recursive: False # Don't recursively inject submodules of this module

但换成两张卡,就得逐个模块指定设备。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# allcate 0-29 layers‘s out_device to cuda:0
- match:
name: "^model\.layers\.(0|[1-9]|[12][0-9])\.mlp\.experts$"
replace:
class: ktransformers.operators.experts.KTransformersExperts # custom MoE Kernel with expert paralleism
kwargs:
generate_device: "cpu"
generate_op: "KExpertsCPU"
out_device: "cuda:0"
recursive: False # don't recursively inject submodules of this module

# allocate 30-59 layers‘s out_device to cuda:1
- match:
name: "^model\.layers\.([345][0-9])\.mlp\.experts$"
replace:
class: ktransformers.operators.experts.KTransformersExperts # custom MoE Kernel with expert paralleism
kwargs:
generate_device: "cpu"
generate_op: "KExpertsCPU"
out_device: "cuda:1"
recursive: False # don't recursively inject submodules of this module

其他模块也照这个办法设。

如何编写新算子并注入模型

这一节拿实现一个新的 linear 举例,讲讲怎么写出一个能注入的算子。

首先,所有可注入算子都要继承 BaseInjectedModule,它带着注入框架需要的一些属性。初始化函数要满足这个基本格式:

1
2
3
4
5
6
7
8
9
10
11
class LinearTorchInject(BaseInjectedModule):
def __init__(
self,
key: str,
gguf_loader: GGUFLoader,
config: PretrainedConfig,
orig_module: nn.Module = None,
generate_device: str = "cuda",
**kwargs,
):
super().__init__(key, gguf_loader, config, orig_module, generate_device, **kwargs)

如果你还有其他参数要传进去,也可以加到 init 里,然后在 yaml 的 kwargs 里传。比如想让算子接收一个 my_param,init 可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
class LinearTorchInject(BaseInjectedModule):
def __init__(
self,
key: str,
gguf_loader: GGUFLoader,
config: PretrainedConfig,
orig_module: nn.Module = None,
generate_device: str = "cuda",
my_param: bool = True,
**kwargs,
):
super().__init__(key, gguf_loader, config, orig_module, generate_device, **kwargs)
self.my_param = my_param

那么注入规则就可以写成:

1
2
3
4
5
6
7
8
- match:
name: "^model\.layers\..*$" # Regular expression matches the module name.
class: torch.nn.Linear # Type restrictions can be added.
replace:
class: ktransformers.operators.linear.LinearTorchInject # Inject module path
kwargs: # Extra parameters
generate_device: "cuda"
my_param: True

linear 模块还得从 gguf 文件读权重。我们提供了 KLinearBase 类帮忙读,你只需要继承它并实现 load、unload、forward。一个能完整注入的 linear 类大概长这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class LinearTorchInject(BaseInjectedModule, KLinearBase):
def __init__(
self,
key: str,
gguf_loader: GGUFLoader,
config: PretrainedConfig,
orig_module: nn.Module = None,
generate_device: str = "cuda",
**kwargs,
):
super().__init__(key, gguf_loader, config, orig_module, generate_device, **kwargs)
KLinearBase.__init__(self)
self.has_bias = False
self.dtype = torch.get_default_dtype()
self.w = None
self.has_bias = False

def load(self, w: dict | nn.Parameter | tuple | None = None, device: str|None = None):
if device is None: device = self.device
if w is None: w = self.load_weight(device=device)

if isinstance(w, nn.Parameter):
self.w = w.to(dtype=self.dtype).view(self.out_features, self.in_features).T
self.has_bias = False
elif isinstance(w, tuple):
self.w = w[0].to(dtype=self.dtype).view(self.out_features, self.in_features).T
self.bias = w[1].to(dtype=self.dtype)
self.has_bias = True
else:
raise ValueError("Invalid weight type")
self.w = self.w.to(device)
if self.has_bias:
self.bias = self.bias.to(device)

def unload(self):
if self.w is not None:
self.w = None
if self.has_bias:
self.bias = None

def forward(self, x: torch.Tensor) -> torch.Tensor:
dtype = x.dtype
out_device = x.device
x = x.to(device=self.device, dtype=self.dtype)
x = x @ self.w
if self.has_bias:
x = x + self.bias
x = x.to(dtype=dtype, device=out_device)
return x

注意 self.load_weight 是 KLinearBase 提供的,用来把 gguf 里的权重读进模块。KLinearBase 的实现细节在 GITHUB 上。

KTransformers 微调 × LLaMA-Factory 集成 – 开发者技术说明

MadSys Lab、KVCache-AI 团队、Approaching AI、LLaMA-Factory 团队

简介

最近这一波开源大模型——从 DeepSeek-V3/R1 到 Qwen-MoE、Kimi-K2——性能和规模都往上跳了一大截。但算力和内存卡在那儿,普通研究者很难微调万亿参数级别的模型。所以我们把 KTransformers 和 LLaMA-Factory 接在一起:2–4 张 RTX 4090 加足够大的 CPU 内存,就能微调 DeepSeek-671B 这类超大 MoE 模型。

这套架构把资源上的缺口填上了,超大模型的本地微调成为可能,14B/30B 这个量级的场景定制也能高效完成。我们用风格化对话、西式翻译腔和医疗问答做了验证,几个小时就能适配好。

架构上,LLaMA-Factory 负责数据、配置、训练编排、LoRA 插入和推理;KTransformers 是可插拔的高性能算子后端,在同一份训练代码下接管 Attention 和 MoE,让 GPU 和 CPU 异构协作,既提速又省显存。

image-20251011010558909

相同设置、相同数据下,我们对比了 HuggingFace 默认、Unsloth 和 KTransformers 三种后端的 LoRA 微调。671B 级 MoE,KTransformers 是目前唯一能在 2–4×24GB 4090 上跑通的方案;14B 的 MoE 上,它吞吐更高、显存更省。

在 LoRA(BF16)+ NekoQA-10K 风格化对话 下 HuggingFace 后端 Unsloth 后端 KTransformers 后端
[14B-DeepSeekV2-Lite] LoRA 微调吞吐 303.58 token/s 455.37 token/s 530.38 token/s
[14B-DeepSeekV2-Lite] 显存 32.12 GB 9.64 GB 6.08 GB
[671B-DeepSeekV3] LoRA 微调吞吐 规模太大无法运行 不支持 40.35 token/s
[671B-DeepSeekV3] 显存(各 GPU 合计) 理论值 1400 GB † 不支持 70 GB †

† 1400 GB 是 FP16 全参数常驻的理论值(跑不起来)。70 GB 是用 KT(Attention 放 GPU + MoE 分层卸载)实测的峰值。

从表里能看出来:14B 模型上,KTransformers 后端比默认 HuggingFace 方案吞吐高约 75%,显存只用到约五分之一。671B 模型上,HuggingFace 和 Unsloth 在单张 4090 上都跑不起来,KTransformers 能以 40 tokens/s 做 LoRA 微调,显存压在 70 GB 以内。

按照模型划分的对比图_02

KT 微调框架总览

下面说说 KTransformers 是怎么接管 LLaMA-Factory 微调框架里的核心算子、把 Attention 和 MoE 优化掉的。

DeepSeek-V3/V2 这类 MoE 模型,一半是参数不多的稠密 Attention,一半是参数庞大的稀疏 MoE。以 DeepSeek-V2-Lite-Chat 的第 2 层为例(每层都是 Attention + MoE 的组合):Attention 计算和 KV cache 主要在 GPU 上,重量级的 MoE 部分主要在 CPU 上跑。先说 Attention 的替换与继承,再说 MoE 的封装与后端对接,最后说 多 GPU 放置。

Attention(LoRA + KT 共存)

KTransformers 提供算子注入能力(BaseInjectedModule),PEFT 负责插 LoRA 层。为了微调,我们写了 KTransformersLinearLora,同时继承 KTransformersLinear 和 LoraLayer:

  • 继承: KTransformersLinearLora 保留 KT 的高性能路径(prefill_linear/generate_linear),同时接受 LoRA 参数(lora_A/lora_B)。
  • 替换: 在准备阶段,我们把原有的 KTransformersLinear 层(Q/K/V/O)替换为 KTransformersLinearLora,既保留 KT 优化,又让 LoRA 可训练。

image-20251016182810716

替换完成之后,LoRA 落在 Q/K/V/O 这几处线性变换上(左图),KTransformersLinearLora 里既有 KT 的快速路径,也有 LoRA 矩阵(右图)。

image-20251016182920722

MoE(算子封装 + 反向)

封装

参数大、计算又稀疏,所以专家计算被我们封装成一个可微的黑盒算子——上游看起来是透明的,下游随时能换。

  • 上游(PyTorch 计算图): 我们注册自定义 Autograd Function,使 MoE 层在图中表现为单个节点。在左图(红框)中只能看到 KSFTExpertsCPU;右图则是未封装时展开的路由、分发与 FFN 专家。封装后,MoE 层就像一个带梯度的标准 nn.Module。
  • 下游(后端): 在 Autograd Function 内部,通过 pybind11 调用 C++ 扩展完成前向/反向。存在多个可插拔后端(AMX BF16/INT8;llamafile)。可通过 YAML 切换后端(例如 "backend": "AMXBF16" 与 "llamafile")。

image-20250801174623919

反向(CPU)

MoE 反向经常要用转置后的权重 $W^\top$。为了不在运行时反复转置,我们在加载时就把 $W^\top$ 预先算好并缓存(蓝框)。必要的中间激活也会缓存(比如专家投影,红框),反向时直接复用,少算一遍。llamafile 和 AMX(INT8/BF16) 的反向实现我们都有,还做了 NUMA 感知优化。

image-20251016182942726

多 GPU 加载/训练:用放置策略代替 DataParallel

要在 2–4 张 GPU 上把单卡显存峰值压下来,我们走的是模型并行 + 显式放置,而不是 DataParallel(后者会在每张卡上复制整个模型)。

关键改动:

  1. KTrainer: 接管 .to(device),防止”把整个模型搬到单张 GPU”。借助 KT 的 optimize-rule YAML,每一层声明 device: cuda:0/cuda:1/...,并直接在目标 GPU 上构造(无额外拷贝)。
  2. 禁用自动 DataParallel: 当 USE_KT=1 时,我们禁用 LLaMA-Factory/HF Trainer 的自动 DP 包装,避免复制,并完全掌控分片。
  3. 梯度聚合: 梯度归约到 cuda:0。中间激活留在本地,只传输必要的张量,降低通信与激活开销。

这样,多 GPU 微调下 KT 的放置策略照样生效。用户挑一个带 multi-gpu 的 kt_optimize_rule 就行。DeepSeek-671B 上,DeepSeek-V3-Chat-sft-amx-multi-gpu.yaml 是典型的双卡方案:KV/attention 分在各卡上,MoE 专家分片放在 CPU,两张卡一起分担。

KT-LoRA 微调评测

设置

编排用 LLaMA-Factory,后端是 KTransformers,LoRA 取 rank=8、α=32、dropout=0.1、BF16,GAS=16、qlen=512,KT optimize 规则与训练时一致。评测两件事:(a) 风格化对话迁移;(b) 两个小规模但有代表性的基准:Translational-Style(生成式)和 AfriMed-QA(医疗垂直,SAQ 与 MCQ)。开 AMX;GPU 是 2×48GB RTX 4090,CPU 是 Intel Xeon Platinum 8488C。

结果

风格化对话(猫娘语气)

数据集:NekoQA-10K。跟中性、理性的基座比(蓝框),微调后的模型稳定地带着目标风格(红框)。这说明 KT-LoRA 用很低的 GPU 成本,就把风格特征注进了生成分布。

image-20251016175848143

Translational-Style 基准(生成式)

数据集:Translational-Style-ChatLLM。指标:BLEU-1/2/3/4、ROUGE-1/2/L。

Translational-Style 数据集 BLEU-1 BLEU-2 BLEU-3 BLEU-4 ROUGE-1 ROUGE-2 ROUGE-L
V2-Lite(无 LoRA) 20.66 8.33 4.54 2.89 22.71 4.52 19.19
KT-LoRA 微调后的 V2-Lite 35.41 22.44 15.42 11.18 42.03 18.38 33.10
V3 基座(无 LoRA) 8.49 3.34 1.62 0.96 15.91 2.55 10.07
KT-LoRA 微调后的 V3 37.02 23.70 16.21 11.49 43.43 18.96 34.54

从上面的测试结果看,同一套工作流和放置策略下,两个规模的模型微调后都有稳定提升,说明「KT 后端 + LoRA 微调」这套组合在生成式风格控制上确实能用、也确实有效。这同时说明 KT 的异构放置和算子优化,能稳稳撑住风格领域的小样本适配。

医疗垂直基准(AfriMed-SAQ/MCQ)

数据集用 AfriMed-QA(ACL 2025),面向非洲医疗的领域数据集,场景定制特征明显,分选择题(MCQ)和简答题(SAQ)两种形式,这里拿来评估垂直领域微调。指标上,SAQ 用 BLEU/ROUGE,MCQ 用 Accuracy。

AfriMed-QA(SAQ) BLEU-1 BLEU-2 BLEU-3 BLEU-4 ROUGE-1 ROUGE-2 ROUGE-L
V2-Lite(无 LoRA) 13.58 11.12 9.10 7.23 22.48 7.81 11.73
KT-LoRA 微调后的 V2-Lite 35.90 27.63 22.99 19.15 35.25 17.50 28.44
V3 基座(无 LoRA) 12.75 10.27 8.05 5.99 20.33 5.65 10.11
KT-LoRA 微调后的 V3 42.42 34.12 28.95 24.54 41.97 22.37 33.28
AfriMed-QA(MCQ) 准确率
V2-Lite(无 LoRA) 0.0645
KT-LoRA 微调后的 V2-Lite 0.4812
V3 基座(无 LoRA) 0.5833
KT-LoRA 微调后的 V3 0.7930

从表里看:(1) DeepSeek-V3(671B)经 KT-LoRA 微调后,MCQ 和 SAQ 上都明显好于微调后的 DeepSeek-V2-Lite(14B),也超过了 V3 基座。在我们这个偏小的设置下,这至少初步说明:超大参数模型做 KT-LoRA 微调,在垂直领域是有实际意义的。

(2) SAQ 和 MCQ 两个子任务上,KT-LoRA 都带来一致提升,说明在 KT 的异构放置和后端算子支持下,LoRA 微调能有效把医疗这类垂直领域的关键知识灌进模型。

局限性

目前测试大多只跑了单个数据集,规模也小(≤ 20k 样本)。我们要给的是 KT-LoRA 微调系统有效性的存在性证据,而不是关于算法泛化性或缩放律的普适结论。报告里主要还是代表性数据;想撑起更强的算法论断,得靠更大的样本量、多语言/多领域数据集和多随机种子重复实验——这些不在本文范围内。

我们也热忱欢迎大家一起参与开源 LLaMA-Factory KT 微调项目。如果你有额外的测试结果,特别欢迎记录到下方的共享表格中,并附上对应的 kt_optimize_rule 文件、数据集样例、训练/评测 YAML,以及详细的显存与 CPU 配置,供社区参考与复现~!

速度测试

端到端性能

定义

step_time:一个优化步要多久(张量搬运 + Attention + MoE + 其他)。

tokens_per_step = GAS × qlen,token/s = tokens_per_step / step_time。这里取 GAS=16、qlen=512,所以 tokens_per_step=8192。

实测

模型 step_time (s) tokens/step token/s
DeepSeek-V3-671B 203 8192 40.35
DeepSeek-V2-Lite-14B 36 8192 227.6
MoE 计算(DeepSeek-V3-671B)

理论

  • 每层、每 token 的 MoE FLOPs(前向+反向)约为:$$ \text{FLOPs}_{\text{per-layer, per-token}} \approx c \cdot k \cdot H \cdot I $$

​ 其中 $k = 8$(Top-k),$H = 7168$(hidden size),$I = 2048$(intermediate size),$c\approx16$(约 6 次前向 + 约 10 次反向矩阵乘)。

  • 每个 step 跨所有 MoE 层:$$ \text{FLOPs}{\text{per-step}} \approx c \cdot qlen \cdot k \cdot H \cdot I \cdot L{\text{MoE}} $$

​ 代入 $c=16, qlen=512, k=8, H=7168, I=2048, L_{MoE}=58$,得 $\text{FLOPs}_{\text{per-step}} \approx 55.8\ \text{TFLOPs}$。

实测(CPU 上的 MoE TFLOPS)

若单个 step 中仅 MoE 的耗时为 t_moe(秒),则 $\text{TFLOPS} = \text{FLOPs}_{\text{per-step}} / \text{step_per_second}.$

算 MoE 吞吐要用 MoE 那一段的耗时,不是完整的 step_time。

TFLOPS 前向 反向
平均 17.55 18.41

内存占用

  • DeepSeek-V3(671B;61 层中 58 层为 MoE):GPU 合计约 70 GB,主机内存约 1.2–1.3 TB。
  • DeepSeek-V2-Lite(14B;27 层中 26 层为 MoE):GPU 约 5 GB,主机内存约 30 GB。

结论

把 KTransformers LoRA 接进 LLaMA-Factory,等于给 MoE 大模型的高效训练和部署铺了一条实用路子。KT 贡献放置策略和算子优化(DeepSeek/Qwen/Kimi 都能跑,带 AMX 加速 kernel),LoRA 让很低显存下的定制成为可能,LLaMA-Factory 则给出一套一致的接口。

也就是说,几百亿到上千亿参数的 MoE 模型,也能在普通硬件上微调、以低延迟上线。省内存、速度快、好用,这套方案把三者都兼顾到了,超大模型也就真成了开发者能上手的工具。

使用 LLaMA-Factory 进行 DPO 训练

这篇教程讲怎么用直接偏好优化(DPO)配合 LLaMA-Factory 微调语言模型。DPO 是拿人类偏好来训练模型的法子,训出来的输出更对齐,也更贴近用户想要的样子。

安装

第 1 步:创建 conda 环境并适配 KTransformers

1
2
3
conda create -n Kllama python=3.12 # choose from : [3.11, 3.12, 3.13]
conda install -y -c conda-forge libstdcxx-ng gcc_impl_linux-64
conda install -y -c nvidia/label/cuda-12.8.0 cuda-runtime

第 2 步:安装 LLaMA-Factory 环境

1
2
3
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e ".[torch,metrics]" --no-build-isolation

第 3 步:安装 KTransformers

方式 1:从 https://github.com/kvcache-ai/ktransformers/releases/tag/v0.4.4 安装与你 Torch、Python 版本匹配的 KTransformers wheel

(注意:实际 CUDA 版本和 wheel 文件名里写的不一定一样。)

1
pip install ktransformers-0.4.4+cu128torch28fancy-cp312-cp312-linux_x86_64.whl
方式 2:从源码安装 KTransformers
1
2
3
4
5
6
git clone --depth 1 https://github.com/kvcache-ai/ktransformers.git
cd ktransformers/kt-sft
export TORCH_CUDA_ARCH_LIST="8.0;8.9;9.0" # set according to your GPU

pip install -r "requirements-sft.txt"
KTRANSFORMERS_FORCE_BUILD=TRUE pip install -v . --no-build-isolation

第 4 步:从 https://github.com/Dao-AILab/flash-attention/releases 安装与你 Torch、Python 版本匹配的 flash-attention wheel

1
2
3
4
5
# abi=True/False can find from below
# import torch
# print(torch._C._GLIBCXX_USE_CXX11_ABI)

pip install https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.3/flash_attn-2.8.3+cu12torch2.8cxx11abiTRUE-cp312-cp312-linux_x86_64.whl

第 5 步:(可选)如果你想使用 flash_infer(否则默认使用 triton)

1
2
git clone https://github.com/kvcache-ai/custom_flashinfer.git
pip install custom_flashinfer/

准备模型

这里拿 deepseek-ai/DeepSeek-V2-Lite 举例,换成 Kimi K2 之类的模型也一样。

如何启动

1
2
3
4
5
6
# For LoRA SFT
USE_KT=1 llamafactory-cli train examples/train_lora/deepseek2_lora_dpo_kt.yaml
# For Chat with model after LoRA SFT
llamafactory-cli chat examples/inference/deepseek2_lora_dpo_kt.yaml
# For API with model after LoRA SFT
llamafactory-cli api examples/inference/deepseek2_lora_dpo_kt.yaml

示例的 YAML 文件如下:

(1)examples/train_lora/deepseek2_lora_dpo_kt.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
### model

model_name_or_path: deepseek-ai/DeepSeek-V2-Lite
trust_remote_code: true

### method

stage: dpo
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all
pref_beta: 0.1
pref_loss: sigmoid # choices: [sigmoid (dpo), orpo, simpo]

### dataset

dataset: dpo_en_demo
template: llama3
cutoff_len: 2048
max_samples: 1000
overwrite_cache: true
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output

output_dir: saves/Kllama_deepseekV2_DPO
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: none # choices: [none, wandb, tensorboard, swanlab, mlflow]

### train

per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 5.0e-6
num_train_epochs: 3
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
resume_from_checkpoint: null

### ktransformers

use_kt: true # use KTransformers as LoRA sft backend
kt_optimize_rule: examples/kt_optimize_rules/DeepSeek-V2-Lite-Chat-sft-amx.yaml
cpu_infer: 64
chunk_size: 8192

kt_optimize_rule 的更多细节见 https://github.com/kvcache-ai/ktransformers/blob/main/doc/en/KTransformers-Fine-Tuning_User-Guide.md

之后就能像 SFT 训练那样,用 saves/Kllama_deepseekV2_DPO 里存下来的 LoRA 适配器做推理。比如:

1
2
3
4
5
6
7
8
9
10
model_name_or_path: DeepSeek-V2-Lite-Chat
adapter_name_or_path: saves/Kllama_deepseekV2_DPO
template: deepseek
infer_backend: ktransformers # choices: [huggingface, vllm, sglang, ktransformers]
trust_remote_code: true

use_kt: true # use KTransformers as LoRA sft backend to inference
kt_optimize_rule: examples/kt_optimize_rules/DeepSeek-V2-Lite-Chat-sft-amx.yaml
cpu_infer: 32
chunk_size: 8192

KT-CLI

⚠️ 注意: 该功能目前仍在积极开发中,许多功能尚未完成,正在持续改进,请关注后续更新。

设计理念

KT-CLI 的设计目标很直接:尽量少让人去翻文档。与其让你读一大篇说明,不如让 CLI 主动问你:

  • 交互模式:不带参数运行命令即可获得逐步引导提示

  • 直接模式:直接传入参数,便于自动化与脚本化

    💡 提示: 参数与此前的 SGLang + KTransformers 方式完全兼容,可以无缝迁移。

敲一条命令,CLI 就一步步带着你走完。

用法

想看用法,执行 kt --help:

1
kt [OPTIONS] COMMAND [ARGS]...

KTransformers CLI —— KTransformers 的统一命令行入口。

选项

选项 说明
--help 显示该帮助信息并退出。

命令

命令 说明
version 显示版本信息
chat 与运行中的模型交互式对话
quant 量化模型权重
bench 运行完整基准测试
microbench 运行微基准测试
doctor 诊断环境问题
model 管理模型与存储路径
config 管理配置
sft 使用 LlamaFactory 微调

GLM-5.3-flash:1M 上下文,KTransformers 原生支持

1. 1M 上下文与原生多模态

GLM-5.3-flash 原生支持最长 100 万 token 的上下文。一个请求就能吃下大型代码库、长文档,或者一次跑很久的智能体任务,不用把上下文反复切开。

它还支持图像、视频、推理和工具调用,通过 OpenAI 兼容 API 就能直接被编码智能体调用。GLM-5.3-flash 约有 321B 参数,45 层里有 34 层 Linear Attention、11 层 DSA。

2. 原生精度的 KTransformers 支持

KTransformers(KT)直接读官方的 GLM-5.3-flash FP8 权重,不用转换模型,也不用对专家权重再做一轮量化。

FP8 模型大约占 306 GiB,系统内存至少留出 350 GB。当前实现支持:

  • NVIDIA SM89 与 SM120 GPU(RTX 40 与 50 系列)
  • AVX-512 FP8 CPU 专家 kernel
  • CPU-GPU 异构专家推理与逐层预填充(Layerwise Prefill)
  • 最长 1M token 的上下文窗口
  • 多模态:文本、多张图片、视频
  • 工具调用

3. 安装

准备一个干净的 Python 3.11 环境,执行:

1
pip install "ktransformers[sglang]"

这条命令会把版本互相匹配的 KT Kernel、SGLang-KT 和 Transformers-KT 一起装上。

4. 启动

把 /path/to/GLM-5.3-flash 换成你的模型目录。下面的配置默认打开逐层预填充、多模态输入和解码 CUDA Graph。模型最长支持 1M 上下文,示例用的是验证过的 501025 token 配置。

4.1 四卡启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MODEL_PATH=/path/to/GLM-5.3-flash

CUDA_VISIBLE_DEVICES=0,1,2,3 \
python -m sglang.launch_server \
--model-path "$MODEL_PATH" \
--kt-weight-path "$MODEL_PATH" \
--served-model-name GLM-5.3-flash \
--host 0.0.0.0 \
--tp-size 4 \
--context-length 501025 \
--mem-fraction-static 0.60 \
--chunked-prefill-size 4096 \
--kt-method FP8 \
--kt-cpuinfer 64 \
--kt-threadpool-count 2 \
--kt-num-gpu-experts 40 \
--kt-gpu-prefill-token-threshold 2048 \
--cuda-graph-bs 1 2 4 \
--limit-mm-data-per-request '{"image":8,"video":1}' \
--mm-process-config '{"image":{"max_pixels":1254400}}' \
--tool-call-parser glm47 \
--reasoning-parser glm45

4.2 单卡启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MODEL_PATH=/path/to/GLM-5.3-flash

CUDA_VISIBLE_DEVICES=0 \
python -m sglang.launch_server \
--model-path "$MODEL_PATH" \
--kt-weight-path "$MODEL_PATH" \
--served-model-name GLM-5.3-flash \
--host 0.0.0.0 \
--tp-size 1 \
--context-length 501025 \
--mem-fraction-static 0.65 \
--chunked-prefill-size 2048 \
--kt-method FP8 \
--kt-cpuinfer 64 \
--kt-threadpool-count 2 \
--kt-num-gpu-experts 0 \
--kt-gpu-prefill-token-threshold 2048 \
--cuda-graph-bs 1 2 4 \
--limit-mm-data-per-request '{"image":8,"video":1}' \
--mm-process-config '{"image":{"max_pixels":1254400}}' \
--tool-call-parser glm47 \
--reasoning-parser glm45

对 GLM-5.3-flash 开逐层预填充时,当前实现会把常驻 GPU 专家数归零。所以四卡示例里的 --kt-num-gpu-experts 40,在逐层预填充期间并不会真的保留 40 个常驻专家。

服务默认监听 http://localhost:30000。启动后可以这样确认:

1
curl http://localhost:30000/v1/models

OpenAI 兼容端点为:

1
http://localhost:30000/v1/chat/completions

5. 多模态请求边界

  • 一个请求可以只含文本,或文本加最多八张图片。
  • 一个请求也可以是文本加一个视频。
  • 图片与视频不能出现在同一个请求中。
  • 视频走常规的混合预填充路径,而不是逐层预填充。解码 CUDA Graph 仍受支持。

在 AVX2 CPU 上运行 KTransformers

这篇教程讲怎么在只支持 AVX2(没有 AVX512、也没有 AMX)的机器上跑 KTransformers。

目录

  • 支持的精度格式
  • 硬件要求
  • 安装
  • 验证
  • 启动推理服务
    • 示例:Qwen3-30B-A3B(BF16)
    • 示例:Qwen3.5-35B-A3B-FP8(FP8)
    • 示例:Qwen3-30B-A3B-GPTQ-Int4(GPTQ_INT4)
    • 示例:Kimi-K2.5(RAWINT4)
    • 发送请求
  • 性能调优
  • 常见问题

支持的精度格式

--kt-method 精度 说明
BF16 BF16 原生精度 零精度损失,直接使用 BF16 权重
FP8 FP8 block 量化
GPTQ_INT4 INT4 GPTQ
RAWINT4 带 BF16 scale 的原始 INT4 由 Kimi-K2.5 使用;权重以压缩的 SafeTensor 格式存储

硬件要求

  • CPU:x86-64 + AVX2 + FMA(Intel Haswell 2013+ / AMD Zen+)
  • GPU:NVIDIA 24GB+ 显存(RTX 3090/4090/5090 等)
  • 内存:至少等于模型权重大小(例如 Qwen3-30B-A3B BF16 需要 64GB+)
  • 操作系统:Linux

安装

从源码构建安装(kt-kernel + SGLang 一条命令搞定):

1
2
3
4
5
6
git clone https://github.com/kvcache-ai/ktransformers.git
cd ktransformers
git submodule update --init --recursive

# One-click install
./install.sh

机器本身支持 AVX512 或 AMX 的话,也可以手动强制按 AVX2 编译:

1
2
3
4
export KT_RAWINT4_BACKEND=avx2
export CPUINFER_CPU_INSTRUCT=AVX2
export CPUINFER_ENABLE_AMX=OFF
./install.sh kt-kernel --manual

验证

1
2
3
4
5
6
7
8
9
# 检查 CPU 是否支持 AVX2
lscpu | grep -i avx2

# 检查加载的 kt-kernel 变体
python -c "import kt_kernel; print(kt_kernel.__cpu_variant__)"
# 预期输出:avx2

# 系统诊断
kt doctor

启动推理服务

用 --kt-method BF16、FP8、GPTQ_INT4 或 RAWINT4。AVX512/AMX 不可用时,KT-Kernel 会自己检测并退到 AVX2 后端。

示例:Qwen3-30B-A3B(BF16)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 下载模型
huggingface-cli download Qwen/Qwen3-30B-A3B --local-dir /path/to/Qwen3-30B-A3B

# 查看物理核心数与 NUMA 节点数
lscpu | grep -E "^CPU(s)|Thread(s) per core|NUMA node(s)"

# 启动服务(按你的硬件调整 kt-cpuinfer 与 kt-threadpool-count)
python -m sglang.launch_server \
--host 0.0.0.0 --port 30000 \
--model /path/to/Qwen3-30B-A3B \
--kt-weight-path /path/to/Qwen3-30B-A3B \
--kt-cpuinfer 16 \
--kt-threadpool-count 1 \
--kt-num-gpu-experts 32 \
--kt-method BF16 \
--attention-backend flashinfer \
--trust-remote-code \
--mem-fraction-static 0.80 \
--chunked-prefill-size 8192 \
--max-running-requests 2 \
--served-model-name Qwen3 \
--enable-mixed-chunk \
--tensor-parallel-size 1 \
--enable-p2p-check \
--disable-shared-experts-fusion

示例:Qwen3.5-35B-A3B-FP8(FP8)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 下载模型
huggingface-cli download Qwen/Qwen3.5-35B-A3B-FP8 --local-dir /path/to/Qwen3.5-35B-A3B-FP8

# 启动服务
python -m sglang.launch_server \
--host 0.0.0.0 --port 30000 \
--model /path/to/Qwen3.5-35B-A3B-FP8 \
--kt-weight-path /path/to/Qwen3.5-35B-A3B-FP8 \
--kt-cpuinfer 16 \
--kt-threadpool-count 1 \
--kt-num-gpu-experts 2 \
--kt-method FP8 \
--kt-gpu-prefill-token-threshold 400 \
--attention-backend triton \
--trust-remote-code \
--mem-fraction-static 0.85 \
--chunked-prefill-size 4096 \
--max-running-requests 1 \
--max-total-tokens 32000 \
--enable-mixed-chunk \
--tensor-parallel-size 1 \
--disable-shared-experts-fusion

示例:Qwen3-30B-A3B-GPTQ-Int4(GPTQ_INT4)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 下载模型
huggingface-cli download Qwen/Qwen3-30B-A3B-GPTQ-Int4 --local-dir /path/to/Qwen3-30B-A3B-GPTQ-Int4

# 启动服务
python -m sglang.launch_server \
--host 0.0.0.0 --port 30000 \
--model /path/to/Qwen3-30B-A3B-GPTQ-Int4 \
--kt-weight-path /path/to/Qwen3-30B-A3B-GPTQ-Int4 \
--kt-cpuinfer 16 \
--kt-threadpool-count 1 \
--kt-num-gpu-experts 2 \
--kt-method GPTQ_INT4 \
--attention-backend triton \
--trust-remote-code \
--mem-fraction-static 0.85 \
--chunked-prefill-size 4096 \
--max-running-requests 1 \
--max-total-tokens 32000 \
--enable-mixed-chunk \
--tensor-parallel-size 1 \
--disable-shared-experts-fusion

示例:Kimi-K2.5(RAWINT4)

注意:以下命令针对 4x RTX PRO 6000 Blackwell(每张 96GB)+ AMD Threadripper PRO 5995WX(64 核、1 个 NUMA 节点)+ 256GB 内存优化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 下载模型
huggingface-cli download moonshotai/Kimi-K2.5 --local-dir /path/to/Kimi-K2.5

# 启动服务
python -m sglang.launch_server \
--host 0.0.0.0 --port 30000 \
--model /path/to/Kimi-K2.5 \
--kt-weight-path /path/to/Kimi-K2.5 \
--kt-cpuinfer 64 \
--kt-threadpool-count 1 \
--kt-num-gpu-experts 228 \
--kt-enable-dynamic-expert-update \
--kt-method RAWINT4 \
--attention-backend flashinfer \
--trust-remote-code \
--mem-fraction-static 0.95 \
--chunked-prefill-size 8192 \
--max-running-requests 4 \
--context-length 262144 \
--enable-mixed-chunk \
--tensor-parallel-size 4 \
--enable-p2p-check \
--disable-shared-experts-fusion

发送请求

1
2
3
4
5
6
7
# 交互式对话
kt chat

# OpenAI 兼容 API
curl http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"Qwen3","messages":[{"role":"user","content":"Hello"}],"stream":true}'

性能调优

  • --kt-cpuinfer:设为物理核心数
  • --kt-threadpool-count:设为 NUMA 节点数
  • --kt-num-gpu-experts:值越大 CPU 负载越低,但显存占用越高
  • 内存带宽往往是瓶颈;高频 DDR5 内存帮助明显

常见问题

GPU OOM

  • 减小 --kt-num-gpu-experts、--chunked-prefill-size、--max-total-tokens
  • 降低 --mem-fraction-static

更多问题见常见问题。

常见问题

1. SGLang 启动时出现 “Using default MoE kernel config” 警告

在 SGLang 里用 kt-kernel 时,可能会看到这样的警告:

1
2
[2026-05-15 20:31:38] Using default MoE kernel config. Performance might be sub-optimal!
Config file not found at .../fused_moe_triton/configs/...

这条警告在预期之内,可以直接忽略。kt-kernel 用自己的 CPU/GPU 混合调度替掉了 SGLang 内置的 MoE 实现,SGLang 那套 fused-MoE Triton kernel 配置根本用不上。警告是 SGLang 在 kt-kernel 接手 MoE 之前打出来的,不影响性能,也不影响正确性。

2. 在哪里可以获得更多帮助?

可以翻一翻已有的 issue,或者新开一个。

来自: Ktransformers 官方文档