1. Model Introduction
Kimi-K3.1 is Kimi-K3 with a DSA lightning indexer on each of its 24 MLA layers. miles trains a rank-32 LoRA on its text decoder with RL, on 4 × 8 H200 or 2 × 8 B300, half the GPUs of the K3 recipe. Key highlights:- K3’s backbone: 93 layers that mix KDA (69) and MLA (24) attention, and an 896-expert latent MoE at top-16 with a shared expert.
- DSA indexer on every MLA layer: each query attends its top 2048 keys, picked by 32 index heads of width 128 with LayerNorm keys and no RoPE. The indexer stays frozen.
- MXFP4 routed experts: the checkpoint is compressed-tensors MXFP4 (1.5 TB), and both the trainer and the rollout read it as published, with no BF16 copy and no
torch_distconversion. - W4A16 LoRA: the trainer keeps the frozen experts as MXFP4 bytes and dequantizes them per layer; only a BF16 adapter trains, and a weight sync sends only the adapter.
2. Supported Variants
The vision tower stays in the checkpoint but is not trained (text-only RL). One launcher per hardware trains it, both sharing the workload, loss and checks in
scripts/kimi_k31_w4a16_lora_common.py:
3. Environment Setup
3.1 Image and storage
/root/miles from radixark/miles#4667, which adds these recipes on top of the Kimi-K3.1 model support in radixark/miles#4666; Megatron-LM (radixark/Megatron-LM miles-main at eb547f33e); and the SGLang branch of section 3.3 at /sgl-workspace/sglang/python.
--model-dir must hold the checkpoint at the same path on every node, on shared storage or as one copy per node. --save-dir must be shared by all nodes: every training rank writes its own adapter shard into the directory rank 0 creates.
3.2 Download
prepare-download downloads the release to <model-dir>/Kimi-K3.1 and dapo-math-17k plus AIME-2024 to <data-dir>:
--hf-checkpoint and --ref-load both point at it), and the engine serves it on SGLang’s Marlin MXFP4 MoE runner.
3.3 SGLang
The image carries thesglang-miles-kimi-k31 branch (at 35708f7), which adds Kimi-K3.1 support and the rollout changes this recipe relies on:
- a BF16 KV cache for K3.1’s DSA attention;
- MoE LoRA on the Marlin MXFP4 runner under expert parallelism, with each rank keeping only its own experts’ rows of a streamed adapter;
- LoRA under attention DP with attention TP above 1;
- the DSA top-k broadcast (
SGLANG_DSA_TOPK_BROADCAST); - the DSA prefill padding-row fix.
sglang-miles yet.
4. Launch
4.1 32 × H200
Start one Ray cluster across the 4 nodes, then launch from node 0:train/grad_norm stays around 0.011, with isolated spikes (0.026, and 0.49 once). rollout/raw_reward rises from 0.61 (mean of steps 0–4) to 0.74 (steps 39–43) while the mean response shortens from 1890 to 1370 tokens and truncation falls from 36% to 18%; deepscaler scores a truncated response 0 in practice, so part of the gain is fewer truncations. GPU memory peaks at 130 GiB per card and host memory at 1483 GB per node.
4.2 16 × B300
Start one Ray cluster across the 2 nodes as above, then launch from node 0. With the checkpoint on node-local disks, runprepare-download on every node:
train/train_rollout_logprob_abs_diff 0.014–0.015 and train/train_rollout_kl 3.6e-4–3.8e-4, in the H200 range; the current 16-prompt version has not run.
4.3 Save and resume
Every 5 rollouts and after the last, the run saves the adapter shards andadapter_config.json under <save-dir>/<run-id> (48 GB each at rank 32), without the Adam state (about 294 GB); --skip-saving turns saving off. To continue from a save, pass a directory holding that save’s adapter_config.json and adapter_megatron_rank*.pt:
5. Recipe Configuration
5.1 Parallelism
--sequence-parallel, THD packing (--use-dynamic-batch-size) and full recomputation are on. The 8 ranks of a pipeline stage (TP4 × CP2) form its EP8 group.
5.2 Algorithm
Score centering (--loss-type score_centering) on the sampler’s top-128 candidates (--rollout-top-logprobs-num 128), with per-token loss, no std normalization and no KL or entropy term. Sampling is unfiltered (temperature 1, top-p 1), which miles maps to the “selected” candidate mode, and the rollout log-probs replace the trainer’s forward-only pass (--use-rollout-logprobs).
--rm-type deepscaler rewards dapo-math-17k answers, with responses up to 3072 tokens (--rollout-max-response-len) and the tokenizer’s default (max) thinking effort. Each rollout feeds one optimizer step:
The filter drops a group whose 16 rewards are all equal and draws new prompts until 16 groups remain;
rollout/raw_reward_unfiltered keeps the mean reward before the filter.
R3 (--use-rollout-routing-replay) is on; indexer replay is off, and the trainer selects the DSA top-k from its own indexer scores.
5.3 Rollout & SGLang
One engine spans all the GPUs, colocated with the trainer, with up to 256 concurrent requests:--lora-base-cpu-backup), so a sync sends only the adapter: about 46 GiB at rank 32 in 2 GiB buckets, 99% of it the per-expert factors, of which each engine rank keeps only its own experts’ rows. On B300 the base is re-sent at every sync as well.
5.4 Optimizer
Adam at--lr 1e-5, constant, with weight decay 0.1 and betas 0.9 / 0.98. 80% of the optimizer state lives on the CPU:
5.5 LoRA
Rank 32 and alpha 64 onall-linear, which selects K3’s HF defaults: the MLA query and KV down projections, the attention output projections, the dense and shared MLPs, and the routed experts. The experts share their outer factors (--experts-shared-outer-loras).
The frozen base would need about 180 GB per GPU in BF16 on 32 H200. The trainer instead keeps every routed expert as the checkpoint’s MXFP4 bytes (weight_packed plus weight_scale, 0.53 B per parameter, about 47 GB per GPU) and dequantizes them exactly into BF16 inside the grouped GEMM, so a layer’s BF16 experts live only through its forward and recompute.
5.6 Notable quirks
--check-lora-weight-equalis off: it hashes every adapter tensor on the CPU, on the trainer and again on every engine rank, about 167 s of each 187 s sync. Pass it through--extra-argsfor a checked run.NCCL_RAS_ENABLE=0: with NCCL 2.30.7, the RAS thread segfaulted on every node right after the engine first released its memory.- DSA top-k broadcast: with attention DP the launcher sets
SGLANG_DSA_TOPK_BROADCAST=1, so every attention-TP rank of a DP group attends rank 0’s DSA top-k; without it the ranks can pick different keys beyond the first 2048. - No dp-aware router: the engine spreads requests over its DP groups (
--sglang-load-balance-method total_requests).sglang-router0.3.2 reads the engine’sdp_size, which attention DP reports as 1, and would send every request to DP group 0. - Per-group KV budget: under attention DP,
--sglang-max-total-tokensis per DP group, while running requests, mamba slots and chunked prefill are engine-wide and split over the groups. - Indexer replay is off: shipping 196 KB of top-k per token cost about 30 minutes a step after the rollout.
- InfiniBand port down: a port going down mid-run kills it with
IBV_WC_RETRY_EXC_ERR; leave the port out with--extra-env-vars "NCCL_IB_HCA=^<hca>"before resuming.

