Skip to main content

1. Model Introduction

DeepSeek-V3 is a large-scale Mixture-of-Experts language model from DeepSeek. Key highlights:
  • Fine-grained MoE architecture: 671 B total / 37 B active per token, 256 routed experts with top-8 plus 1 shared expert, sigmoid router with bias.
  • MLA attention: Multi-head Latent Attention with q-LoRA rank 1536, keeping the KV cache compact under long contexts.
  • Long-context capability: trained at 32 K response length in this recipe; supports extended reasoning and agent-style workflows.

2. Supported Variants

Passing a --model-name that contains <N>layer (for example DeepSeek-V3-0324-5layer) selects a layer-pruned checkpoint from the fzyzcjy org and the matching deepseek-v3-<N>layer Megatron definition — the single-node smoke-test path.

3. Launch

scripts/run_deepseek.py splits the pipeline across three commands:
  • prepare — HF download, FP8 → BF16 cast, HF → Megatron torch_dist conversion.
  • train — the train.py submission; each trainer pod first rsyncs both model directories to node-local storage.
  • full-train — prepare followed by train, which is the whole pipeline in one invocation.
Single-node smoke test on a pruned checkpoint:
Directories default to --model-dir /root/models (shared FS), --data-dir /root/datasets, and --model-local-dir /root/local_data (node-local copy the training job reads from). --task selects dapo_aime (default) or gsm8k; --mode debug_minimal shortens responses and drops dynamic sampling and eval.

Multi-node fan-out

The torch_dist conversion and the node-local rsync fan out across every node of the Ray cluster, so a multi-node run needs the whole cluster joined before the launcher starts, and the launcher must be told not to replace it. Bring up the head, join the workers, then run with MILES_SCRIPT_EXTERNAL_RAY=1:
With an MPI-style hostfile (each line ip slot=8), fan the workers out from node 0:
Without MILES_SCRIPT_EXTERNAL_RAY=1 the launcher runs ray stop --force and starts its own single-node head, which is what the single-node invocation above relies on — the conversion then runs on that one node.

4. Checkpoint conversion

prepare, and therefore full-train, performs the two conversion steps for you; the equivalent manual commands are below. The HF checkpoint ships in block-quantized FP8 — first cast it to BF16:
Then convert BF16 HF → Megatron torch_dist. Run on 4 separate nodes (NODE_RANK=0..3); MASTER_ADDR is the IP of node 0:

5. Recipe Configuration

All values below come straight from scripts/run_deepseek.py.

5.1 Parallelism

The layout is chosen from --num-nodes: Recomputation is full / uniform / 1 layer, with --use-dynamic-batch-size and --max-tokens-per-gpu 2048.
--max-tokens-per-gpu 2048 is a deliberately tiny placeholder in the current script (the production value is 16384). Raise it before you read any throughput number off this recipe.
DeepSeek-V3 has 61 layers, which doesn’t divide evenly into PP=4 — --decoder-last-pipeline-num-layers 13 puts the extra layers on the last stage. With --use-dynamic-batch-size, miles packs samples up to --max-tokens-per-gpu; under CP=4, a CP group shares a CP × max-tokens-per-gpu budget. miles always trains with data packing and per-token loss, so dynamic batch size doesn’t change the loss.

5.2 Algorithm

GRPO with DAPO-style dynamic sampling:
--use-kl-loss is absent, so the reference model is never loaded and the zero KL coefficient costs nothing. --over-sampling-batch-size 256 paired with check_reward_nonzero_std is the DAPO-style setup: oversample, then drop prompts whose reward distribution has zero variance. The two dynamic-sampling flags and the whole eval block are skipped under --mode debug_minimal.

5.3 Rollout & SGLang

The engine world size follows the node count: 4 GPUs per engine up to 4 nodes, 64 beyond that, with attention DP 1 and 8 respectively.
--rollout-num-gpus-per-engine corresponds to SGLang’s tp_size. To exploit large-EP inference, the recipe sets EP64, DP-attention with DP8, and DeepEP low_latency. --sglang-server-concurrency is a miles-specific knob to keep the SGLang HTTP server from being swamped — default 512, raised to 1024 here so each of the 8 DP ranks gets 128 concurrent requests. SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK is exported to match --sglang-cuda-graph-max-bs-decode.

5.4 Optimizer

CPU offload (--optimizer-cpu-offload --overlap-cpu-optimizer-d2h-h2d --use-precision-aware-optimizer) is available but commented out in the script. Enabling it puts the Adam state on host RAM (~1.4–1.5 TB / 8-GPU node); if a node runs out of host memory, add more nodes to widen parallelism rather than swapping.

5.5 Notable quirks

  • Online FP8 quantization against the HF config: --hf-checkpoint points at the FP8 HF directory (also where the tokenizer is read from). miles applies the quantization config from the HF checkpoint, so weights are block-wise quantized before being passed to SGLang. The BF16 directory produced by the cast is used only as the conversion input.
  • --decoder-last-pipeline-num-layers 13 is mandatory under PP=4 (61 layers don’t divide evenly), and is skipped for layer-pruned variants.
  • Node-local reads: training reads --hf-checkpoint and --ref-load out of --model-local-dir, which train populates by rsync from the shared --model-dir.
  • --colocate runs actor and rollout on the same GPUs (--actor-num-nodes × --actor-num-gpus-per-node).
  • --attention-backend flash is deliberately unset — MLA models need the default backend.

6. Pairs Well With