Skip to main content
The complete Kimi-K3 LoRA RL implementation is open at the Miles pull request: radixark/miles#1825. The scripts and image below come from that branch. Results and background are in the LMSYS day-0 write-up.

1. Model Introduction

Kimi-K3 pairs two attention mechanisms in one stack, KDA and MLA chosen per layer, with an 896-expert latent MoE at top-16. The checkpoint ships in MXFP4. miles trains it with native LoRA adapters rather than full fine-tuning, which is what makes the recipe fit at all: the base weights stay frozen and only the adapters carry gradients. The adapters are implemented under TP, EP, PP and CP, with shared-A and per-expert-B factors across the 896 experts, and they are exported to the rollout engines as HF-named chunks over CUDA IPC. Key highlights:
  • Two attention types per layer: KDA and MLA, with an attention-residual snapshot bank.
  • 896-expert latent MoE, top-16, moe_latent_size=3584, plus a shared expert.
  • LoRA RL, not full fine-tuning. Rank 16 by default, 32 in the validated run.
  • Colocated rollout: trainer and SGLang share the GPUs, with adapters synced over CUDA IPC.
  • MXFP4 checkpoint upcast to BF16 once, offline.

2. Supported Variants

--model-variant selects between them and sets the matching checkpoint paths and megatron_model_type. Architecture, from scripts/models/kimi-k3.sh: hidden 7168, FFN 33792, 96 attention heads, kv_channels=256, MLA with q_lora_rank=1536 / kv_lora_rank=512 / qk_head_dim=128 / qk_pos_emb_head_dim=64 / v_head_dim=128, 896 experts at moe_ffn_hidden_size=3072, shared expert 6144, vocab 163840, no position embedding.

3. Environment Setup

Use the docker.io/radixark/miles:kimi-k3 image, which pins miles, SGLang (the sglang-miles-k3 branch) and flashinfer 0.6.15.post1 at the validated versions. On Hopper set SGLANG_K3_ATTN_RES_MODE=jit. The only external asset is the Kimi-K3 MXFP4 HF checkpoint. Everything else derives in-repo.

3.1 Data

3.2 MXFP4 to BF16

3.3 BF16 to torch_dist

Unlike the bridge-mode recipes, K3 needs an offline conversion. Run it on 32 ranks; the output re-shards at load, so the conversion layout does not have to match the training one:
Training then takes the MXFP4 directory as --hf-checkpoint and the converted torch_dist as --ref-load.

4. Launch

Validated on 16 nodes × 4 GPUs. One container per node; bring up a ray cluster across them, export MILES_SCRIPT_EXTERNAL_RAY=1, then:
--rollout-max-concurrency 8 is passed explicitly: the field default is 64, and the validated runs pin 8. For a single-node smoke test, drop to the default --model-variant 4layer.

5. Recipe Configuration

5.1 Parallelism

The resolved config at startup should show expert_model_parallel_size 8, max_tokens_per_gpu 8192, colocate_memory_peak_device gpu and lora_base_cpu_backup True. Checking those four lines is the fastest way to confirm the run came up in the intended shape.

5.2 LoRA

Rank 32 / alpha 64 in the validated run; the script defaults to 16 / 32. Adapters attach to attention output and both MLA down-projections, the dense MLP, and both expert projections:
The 896 experts share one A factor and carry per-expert B factors, which is what keeps the adapter count tractable at this expert width.

5.3 Rollout

Rollout is colocated: the trainer and SGLang share GPUs, and adapters sync over CUDA IPC as HF-named chunks. lora_base_cpu_backup keeps a host copy of the frozen base so the GPU copy can be reclaimed during rollout.

5.4 What a healthy run looks like

From the GB300 validation runs:
  • 11 to 13 minutes per rollout cycle
  • trainer allocated memory returns to about 91 GB after every weight sync
  • rollout/raw_reward between 0.5 and 0.75 from rollout 0
  • eval/aime 0.37 to 0.43 at eval@0 (that spread is temperature-0 nondeterminism), rising by at least 0.06 by eval@9; the measured run went 0.367 to 0.467
The memory figure is the one to watch. If allocated does not return to its baseline after a weight sync, the adapter export is leaking and the run will die later rather than sooner.

5.5 Notable quirks

  • The image preloads a small shm_unlink shim through /etc/ld.so.preload. It tolerates a benign PyTorch CUDA-IPC unlink race that otherwise aborts colocated weight sync at scale.
  • On Hopper, set SGLANG_K3_ATTN_RES_MODE=jit.
  • Weight conversion for K3 lives in miles/backends/megatron_utils/megatron_to_hf/kimi_k3.py, and the model itself in miles_plugins/models/kimi_k3/.

6. Pairs Well With