ktransformers

Framework

kvcache-ai/ktransformers

A flexible framework for heterogeneous LLM inference and fine-tuning.

Overview

KTransformers is a research project focused on efficient LLM inference and fine-tuning through CPU-GPU heterogeneous computing. It provides high-performance kernel operations and integration with LLaMA-Factory for fine-tuning, supporting MoE models and various quantization techniques.

README Preview

\n  \n\n\n    \n\n\n\n\n  A Flexible Framework for Experiencing Cutting-edge LLM Inference/Fine-tune Optimizations\n  🎯 Overview | 🚀 Inference | 🎓 SFT | 🔥 Citation | 🚀 Roadmap(2026Q2)  \n\n\n## 🎯 Overview\n\nKTransformers is a research project focused on efficient inference and fine-tuning of large language models through CPU-GPU heterogeneous computing. The project now exposes two user-facing capabilities from the kt-kernel source tree: [Inference](./kt-kernel/README.md) and [SFT](./doc/en/SFT/KTransformers-Fine-Tuning_Quick-Start.md).\n\n## 🔥 Updates\n* **June 21, 2026**: MiniMax-M3 Day0 Support! ([Tutorial](./doc/en/kt-kernel/MiniMax-M3-Tutorial.md))\n* **June 17, 2026**: GLM-5.2 Day0 Support! ([Tutorial](./doc/en/kt-kernel/GLM-5.2-Tutorial.md))\n* **May 6, 2026**: KTransformers at [GOSIM Paris 2026](https://paris2026.gosim.org/zh/schedule/) — "Agentic AI on Edge" track. We'll present KT's inference performance on consumer hardware.\n* **May 02, 2026**: DeepSeek-V4-Flash Support! ([Tutorial](./doc/en/DeepSeek-V4-Flash.md))\n* **Apr 30, 2026**: KTransformers v0.6.1 refreshes kt-kernel inference and SFT docs with separate [Inference](./kt-kernel/README.md) and [SFT Quick Start](./doc/en/SFT/KTransformers-Fine-Tuning_Quick-Start.md) entry points.\n* **Mar 26, 2026**: Support AVX2-only CPU backend for KT-Kernel inference. ([Tutorial](./doc/en/kt-kernel/AVX2-Tutorial.md))\n* **Feb 13, 2026**: MiniMax-M2.5 Day0 Support! ([Tutorial](./doc/en/MiniMax-M2.5.md))\n* **Feb 12, 2026**: GLM-5 Day0 Support! ([Tutorial](./doc/en/kt-kernel/GLM-5-Tutorial.md))\n* **Jan 27, 2026**: Kimi-K2.5 Day0 Support! ([Tutorial](./doc/en/Kimi-K2.5.md)) ([SFT Tutorial](./doc/en/SFT_Installation_Guide_KimiK2.5.md))\n* **Jan 22, 2026**: Support [CPU-GPU Expert Scheduling](./doc/en/kt-kernel/experts-sched-Tutorial.md), [Native BF16 and FP8 per channel Precision](./doc/en/kt-kernel/Native-Precision-Tutorial.md) and [AutoDL unified fine-tuning and inference](./doc/zh/【云端低价训推】%20KTransformers%

FAQ (5)

Troubleshooting
How to fix DeepSeek V4 Flash returning garbage output on Xeon Cascade Lake with AVX-512 but no AVX512BF16?

This is a regression from PR #2181: prepare_decode_down_input() in kt-kernel/operators/amx/fp4-moe.hpp uses the optimized MXFP4 decode path even when __AVX512BF16__ is unavailable. On non-BF16 CPUs, down_ba_ is never populated, so the down projection reads uninitialized memory and produces garbage.

Fix by updating to the build containing PR fix(kt-kernel): restore MXFP4 decode fallback without AVX512 BF16, or gate the optimized path with __AVX512BF16__:

void prepare_decode_down_input(int expert_idx, int qlen) {
#if defined(__AVX512BF16__)
  if (qlen != 1 || config_.quant_config.group_size != 32 ||
      config_.intermediate_size % 32 != 0) {
    Base::prepare_decode_down_input(expert_idx, qlen);
    return;
  }
  assert(down_ba_[expert_idx]->natural_order);
#else
  Base::prepare_decode_down_input(expert_idx, qlen);
#endif
}

Then rebuild the kernel. This restores the base fallback for CPUs such as Xeon Platinum 8268/Cascade Lake that support AVX512F/VNNI but lack AVX512BF16.

GitHub Issue #2192
Troubleshooting
How to fix IndexError in `MoELayer._compute_routing` when running LoRA SFT on DeepSeek-V2-Lite with ktransformers?

This occurs in ktransformers 0.6.4 when PEFT/LoRA replaces the DeepSeek MoE gate with an nn.Linear, but _compute_routing still enters the deepseek_gate branch and treats raw logits as a (topk_ids, topk_weights, aux_loss) tuple.

Apply this one-line fix in kt_kernel/sft/layer.py:

# Before
if self.router_type == "deepseek_gate":

# After
if self.router_type == "deepseek_gate" and self._original_router is None:

This lets replaced Linear routers use the existing _original_router routing path, which performs softmax scoring and greedy top-k selection for DeepSeek-V2-Lite.

Also avoid lora_target: all in the LLaMA-Factory YAML, because it wraps the MoE router itself. Use the explicit target set:

lora_target: q_proj,kv_a_proj_with_mqa,kv_b_proj,o_proj,gate_proj,up_proj,down_proj

After the patch and config change, DeepSeek-V2-Lite LoRA SFT proceeds normally; the fix was verified with a 20-step training run and successful adapter export.

GitHub Issue #2144
Troubleshooting
Why does GLM-4.5-Air output degrade, loop, or garble after about 4,000 tokens with transformers-kt 5.x, and how do I fix rope_theta being read as 10000?

The model's config.json stores the correct value under rope_parameters (1000000), but transformers-kt 5.x exposes no top-level rope_theta, so the loader falls back to the default 10000. The incorrect RoPE base frequency causes perplexity to explode after roughly 4k tokens.

Affected setup reported with sglang-kt 0.7.0.post4, kt-kernel 0.7.0.post4, and transformers-kt 5.6.0.post5.

Fix the config/RoPE initialization to read the nested value:

if getattr(config, "rope_parameters", None):
    rope_theta = config.rope_parameters.get(
        "rope_theta", getattr(config, "rope_theta", 10000)
    )
else:
    rope_theta = getattr(config, "rope_theta", 10000)

Use this rope_theta when constructing the rotary embedding, then restart the server. The effective value must be 1000000, not 10000.

As a temporary local workaround, add the top-level value to the model's config.json:

import json, pathlib
p = pathlib.Path("/path/to/model/config.json")
c = json.loads(p.read_text())
c["rope_theta"] = c["rope_parameters"]["rope_theta"]
p.write_text(json.dumps(c, indent=2))

After the fix, long-context perplexity should remain approximately flat instead of rising sharply at positions 4096 and beyond.

GitHub Issue #2214
Troubleshooting
How to fix 'Attempted to access the data pointer on an invalid python storage' when saving LoRA Experts with kt_use_lora_experts and FSDP2?

This affects kt-kernel 0.6.4. Under FSDP2, LoRA-Expert parameters are DTensor shards, but save_lora_experts_to_adapter calls .data.cpu().clone() directly. That does not gather the shards, so safetensors receives a tensor with invalid storage and crashes after training, leaving only the standard PEFT LoRA weights in adapter_model.safetensors.

Patch kt_kernel/sft/lora.py around lines 797–799 to gather DTensors before saving:

def _materialise_for_save(t):
    try:
        from torch.distributed.tensor import DTensor
    except ImportError:
        try:
            from torch.distributed._tensor import DTensor
        except ImportError:
            DTensor = ()

    if DTensor and isinstance(t, DTensor):
        t = t.full_tensor()  # collective: must run on every FSDP rank

    return t.detach().cpu().clone()

state_dict[f"{base_key}.le_gate.weight"] = _materialise_for_save(expert.le_gate.weight)
state_dict[f"{base_key}.le_up.weight"]   = _materialise_for_save(expert.le_up.weight)
state_dict[f"{base_key}.le_down.weight"] = _materialise_for_save(expert.le_down.weight)

Do not call full_tensor() only on rank 0; it is a distributed collective and must be entered by all ranks. You may still guard the actual safetensors.torch.save_file call so only the main process writes the checkpoint.

After the fix, verify that adapter_model.safetensors contains le_gate, le_up, and le_down tensors and is larger than a run without LoRA Experts. As a temporary workaround, either disable kt_use_lora_experts or use a non-FSDP2/DDP configuration.

GitHub Issue #2147
Troubleshooting
How to fix 'aten._foreach_mul_.Tensor: got mixed torch.Tensor and DTensor' in ktransformers FSDP2 LoRA SFT gradient clipping?

This occurs in ktransformers 0.6.4 with FSDP2 because FSDP2 wraps normal parameters as DTensor, while CPU-resident expert-LoRA parameters remain plain torch.Tensor. HF Trainer then passes a mixed list to _foreach_mul_. It happens in both real clipping (max_grad_norm > 0) and _get_grad_norm(), which calls clipping with inf just for logging, so setting max_grad_norm: 0.0 alone is insufficient.

Temporary workaround, with gradient clipping disabled:
1. In the training/YAML config, set:

max_grad_norm: 0.0

2. Patch the logging-only gradient-norm call before starting training:
from transformers import Trainer

_orig_get_grad_norm = Trainer._get_grad_norm

def _safe_get_grad_norm(self, model, grad_norm=None):
    try:
        return _orig_get_grad_norm(self, model, grad_norm)
    except RuntimeError as e:
        if "DTensor" in str(e):
            return None
        raise

Trainer._get_grad_norm = _safe_get_grad_norm

This allows LoRA SFT to run, but does not perform gradient clipping, so it is unsuitable for production-quality training.

Proper fix: register ktransformers expert-LoRA parameters as replicated DTensor parameters when FSDP2 is active, making model.parameters() type-homogeneous. Alternatively, exclude those expert-LoRA parameters from the Trainer/accelerate clipping list and clip them separately as plain tensors. Either approach handles both the clipping and gradient-norm logging call sites and restores max_grad_norm > 0.

GitHub Issue #2145