Skip to content
Open

Dsv4 #1937

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
31fb6fc
[Docs] Fix sphinx build with packaging.Version and add MTP design docs
HAOCHENYE May 19, 2026
383ed8c
[Feature] Support sqrtsoftplus scoring in NoAuxRouter
HAOCHENYE May 19, 2026
2b0ec9e
[Feature] Support dual rope (compress_rope_theta + compress_ratios) f…
HAOCHENYE May 19, 2026
bb541f1
[Feature] Add KVCompressor for DeepSeek-V4 sparse attention
HAOCHENYE May 19, 2026
ae944b8
[Feature] Add Indexer + sparse_attn reference for DeepSeek-V4 DSA
HAOCHENYE May 19, 2026
344fca3
[Feature] Add DeepSeek-V4 DSA attention with grouped O-LoRA + attn_sink
HAOCHENYE May 19, 2026
6bdf8a2
[Feature] Add HashRouter for DeepSeek-V4 hash-routing layers
HAOCHENYE May 19, 2026
a1b103e
[Feature] Add Hyper-Connections decoder wrapper for DeepSeek-V4
HAOCHENYE May 19, 2026
69e4c2d
[Feature] Add DeepSeekV4 model + config + entry-point for DeepSeek-V4…
HAOCHENYE May 19, 2026
713dc95
[Fix] DSA accepts full-head-dim cos/sin from XTuner RotaryEmbedding
HAOCHENYE May 19, 2026
d54aee2
[Config] Add ci/config/deepseek_v4_flash.py for DeepSeek-V4-Flash tra…
HAOCHENYE May 19, 2026
fbd602f
[WIP] DSA varlen + bf16 fp32-upcast opts + V4 wave-1 glue
HAOCHENYE May 21, 2026
b838a2e
[Feature] Add varlen Triton kernel for the V4 Indexer top-k path
HAOCHENYE May 21, 2026
57eebda
[Perf] Indexer triton kernel: tensor-core scoring + single-pass topk
HAOCHENYE May 21, 2026
186a170
[Perf] Re-enable V4 EP compile + default Indexer to triton + compile …
HAOCHENYE May 21, 2026
65355d7
[Perf] Wrap Indexer call in torch.no_grad at DSA.forward
HAOCHENYE May 21, 2026
395db1e
[Refactor] Consolidate V4 decoder into a single V4DecoderLayer class
HAOCHENYE May 21, 2026
9a74631
[Fix] sparse_attn: avoid expand+gather pattern that inductor balloons…
HAOCHENYE May 21, 2026
0b8809d
[Fix] DSA: bind sparse-attn backend statically at __init__, no runtim…
HAOCHENYE May 21, 2026
eb928d1
[Fix] DSA: HCA (compress_ratio=128) layers must use native, not flash…
HAOCHENYE May 21, 2026
2947e6c
[Perf] hc_post: replace cuBLAS bmm(K=4) with broadcast+sum that induc…
HAOCHENYE May 21, 2026
b39fe53
[Test] Add decoder-layer parity scaffold vs HF transformers 5.9.0
HAOCHENYE May 21, 2026
08300b5
[Test] Decoder-layer parity: pass causal+sliding mask to HF eager att…
HAOCHENYE May 21, 2026
8853318
[Fix] V4: switch RoPE to interleaved convention to match HF / V4-ref
HAOCHENYE May 22, 2026
d8facf4
[Test] Sub-component probe: locate first divergence in V4 layer forward
HAOCHENYE May 22, 2026
71b9d13
[Fix] V4: align numerics with HF — q_b_norm/hc_pre/hc_post + router s…
HAOCHENYE May 22, 2026
5783aa5
[Test] V4: add HF-fallback test anchors for CSA/HCA decoder layers
HAOCHENYE May 22, 2026
6f7c12a
[Test] V4: add full-layer HF fallback for atol=0 sanity baseline
HAOCHENYE May 22, 2026
212c6c7
Revert "[Test] V4: add full-layer HF fallback for atol=0 sanity basel…
HAOCHENYE May 22, 2026
bd78b0b
[Fix] V4 parity at atol=0 with attention+MoE anchors
HAOCHENYE May 22, 2026
4efd1d9
[Fix] V4: derive num_hash_layers from mlp_layer_types for transformer…
HAOCHENYE May 23, 2026
d0707c5
[Fix] V4: precompute D-dim signed RoPE, flip-based rotation to fix co…
HAOCHENYE May 23, 2026
4e60861
[Fix] V4 hc_post: bf16-round + fp32-accumulator broadcast+sum, bit-ma…
HAOCHENYE May 23, 2026
fd94d7e
[Perf] DSA HCA: pad topk_idxs to FlashMLA's 128-alignment via pre-all…
HAOCHENYE May 23, 2026
7b28884
[Perf] V4: mark HC params as fp32 / ignored by FSDP to skip per-forwa…
HAOCHENYE May 23, 2026
b089255
[Perf] Wrap torch.compile targets with profiler record_function ranges
HAOCHENYE May 23, 2026
b5aaed5
[Config] V4 ci config: wire moe_cfg.attention.pack_max_length so HCA …
HAOCHENYE May 23, 2026
e54bb8e
[Perf] V4 hc_pre: bf16 Linear + F.rms_norm + drop redundant fp32 cast…
HAOCHENYE May 23, 2026
45be0e4
[Feature] V4 hc_pre: add XTUNER_V4_HF_PARITY env var for fp32 bit-ide…
HAOCHENYE May 23, 2026
24198a1
[Feature] V4 Domino-EP: layer-internal wave pipeline (FSDP-correct)
HAOCHENYE May 23, 2026
62929d0
[Perf] V4 hc_post: fused Triton kernel for the K=4 stream mix
HAOCHENYE May 24, 2026
e98fe9b
[Perf] V4 DSA/HC: quack RMSNorm + fused Triton rope-split kernel
HAOCHENYE May 26, 2026
2ef38fe
[Config] V4 ci config: disable MTP loss ctx, raise pack/micro-batch, …
HAOCHENYE May 26, 2026
6349339
[Refactor] V4 DSA: split dsa.py rope/topk ops into sibling modules
HAOCHENYE May 26, 2026
22c72e7
[Refactor] V4: move V4DecoderLayer/V4FFNState into module/decoder_layer
HAOCHENYE May 26, 2026
80af71b
[Refactor] MoE: template-method seams for _forward; drop V4/qwen3vl c…
HAOCHENYE May 26, 2026
08bc534
[Refactor] V4 mb_forward: route tail through the shared MoE seams
HAOCHENYE May 26, 2026
8ad3228
[Refactor] MoE: split mb_forward into dense/moe phases; V4 reuses the…
HAOCHENYE May 26, 2026
b755bfd
[Refactor] MoE: unify offload ctx + extract MTP forward to slim the f…
HAOCHENYE May 27, 2026
5651e7f
[Perf] V4 KVCompressor: drop the .item() D2H sync via cu_seq_lens CPU…
HAOCHENYE Jun 16, 2026
a28a569
[Fix] SequenceContext: default-derive cu_seq_lens_*_cpu mirrors inste…
HAOCHENYE Jun 16, 2026
1878200
[Feature] V4: integrate DeepSeek TileKernels mhc backend
HAOCHENYE Jun 22, 2026
ee40256
[Perf] V4 Indexer: stream per-horizon top-K to shrink the topk width
HAOCHENYE Jun 25, 2026
3d40e13
[Feature] V4 KVCompressor: compressed-kv RoPE + per-ratio cu_seq_lens…
HAOCHENYE Jun 27, 2026
aed2d71
[Perf] AdamWConfig: enable fused AdamW kernel
HAOCHENYE Jun 27, 2026
effd8cc
[CI] deepseek_v4_flash: run the full stack — triton indexer, compile,…
HAOCHENYE Jun 27, 2026
e964e4a
[Refactor] DSA: gather the compressor/indexer/sparse-attn stack into …
HAOCHENYE Jun 29, 2026
0b4966c
[Refactor] V4 decoder layer: gather the layer + HC helpers into a dec…
HAOCHENYE Jun 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions ci/config/deepseek_v4_flash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import os

# Replace the env's broken Triton-3.4-targeted MoE expert GEMM kernel
# (`m_grouped_gemm_TMA_triton3_4.py` PassManager::run failure under Triton 3.5.1)
# with the `grouped_gemm` PyPI CUTLASS backend, which is compile-friendly via the
# `moe::gmm` torch.library.custom_op shim in `group_gemm_cutlass.py`.
# os.environ.setdefault("XTUNER_USE_CUTLASS_GROUP_GEMM", "1")
# Stage each decoder layer's HC-expanded activation on CPU during the forward,
# fetch back on the backward. Halves peak HBM at the cost of D2H/H2D bandwidth;
# with 4× HC expansion this is the main lever that lets the full 256-expert /
# pack_max_length=32768 setup fit on 8× H200.
# os.environ.setdefault("XTUNER_ACTIVATION_OFFLOAD", "1")

from xtuner.v1.config import AdamWConfig, FSDPConfig, LRConfig
from xtuner.v1.datasets import FTDPTokenizeFnConfig
from xtuner.v1.datasets.config import DataloaderConfig, DatasetConfig
from xtuner.v1.loss.ce_loss import CELossConfig
from xtuner.v1.model.moe.deepseek_v4 import DeepSeekV4Config
from xtuner.v1.train import TrainerConfig


# DEEPSEEK_V4_PATH should point at a directory that holds the BF16 DeepSeek-V4-Flash
# release plus its tokenizer files. The BF16 dequant of the 46-shard FP4/FP8 release
# lives at /mnt/shared-storage-user/llmrazor-share/yehaochen/model/DeepSeek-V4-Flash
# on the shared storage (109 safetensor shards, 542 GB). `from_hf` reads the local
# `config.json` to recover the 44-entry `compress_ratios` list and all V4 hyper-params.
DEEPSEEK_V4_PATH = os.environ["DEEPSEEK_V4_PATH"]
ALPACA_PATH = os.environ["ALPACA_PATH"]
pack_max_length = 24576 // 2
#

# pack_max_length = 16384
# Use `from_hf` rather than the default-arg constructor so the per-layer
# `compress_ratios` (length = num_hidden_layers + 1) and other release-specific
# fields (num_hash_layers, swiglu_limit, attn_sink dims) are picked up from the
# checkpoint instead of relying on the Config defaults.
moe_cfg = DeepSeekV4Config.from_hf(DEEPSEEK_V4_PATH)
# moe_cfg.num_hidden_layers = 4
# V4 MTP forward is not wired yet (DeepSeekV4.build_mtp_block returns None), but
# from_hf sets mtp_config from the release's num_nextn_predict_layers=1. Left as-is,
# MoE.build_loss_ctx_batch keys off `mtp_config is not None` and builds MTP loss
# contexts every step — `roll_packed_tensor` loops over every packed sub-sequence
# with 2 `.item()` D2H syncs each (~450 syncs/step at pack=8192), then the result is
# silently dropped because the model has no MTP block. Disable it until MTP lands.
moe_cfg.mtp_config = None
# # 256 experts at 2048 inter × 4096 hidden × 3 (w1/w2/w3) × 2 bytes ≈ 12.6 GB per
# # layer, and we keep a fp32 master copy → 25 GB per layer. With 2 layers and HC's
# # 5D residual mix tensor (~8 GB per packed sequence) plus master weights, even
# # 140 GB H200 is tight. Cut experts to 16 to leave headroom.
# moe_cfg.n_routed_experts = 16
# Honor the release config's `num_hash_layers` (3 in the BF16 dequant). With
# `num_hidden_layers=2` both layers fall under `layer_idx < num_hash_layers`
# → both are hash-routed (matching the ckpt's `tid2eid` and absent
# `e_score_correction_bias` for these layers). The all-hash side effect — no
# layer accumulating routing stats — is handled inside `DeepSeekV4._forward`
# (skips `aux_loss.finalize` when `num_hash_layers >= num_hidden_layers`).

# EP works now that MoE.fully_shard patches nn.Linear.forward + nn.Embedding.forward
# to .to_local() the weight when it's a Replicate-on-ep DTensor (created by
# _replicate_other_params), plus DSA's raw .weight accesses (attn_sink, wo_a.weight)
# do the unwrap inline. Bumping ep_size from 1 → 2 cuts per-rank expert memory in
# half (256 experts → 128 owned per ep group), trading off for an all2all dispatcher
# on the MoE forward.
# EP sweep on this 8× H200 / 2-layer toy:
# ep=1 pack=8192 → 62.50 GB max_mem, 11.0 s/step ← works for multi-step
# ep=2 pack=4096 → 29.55 GB max_mem, but only HALF the ranks complete
# step 1's clip_grad_norm; the other half hangs in
# cal_grad_norm's `dist.all_reduce` on a 2D-composed
# (Replicate-on-ep × Shard-on-fsdp) DTensor placement
# that splits the all_reduce group asymmetrically. The
# "Training finished" we previously saw at ep=2 was
# torchrun killing the stuck half after the other half
# exited debug_skip_save. EP needs cal_grad_norm + the
# patched_linear_forward grad path to be EP-aware
# (tracked as known issue).
# Until EP desync is fixed, run with ep=1 so multi-step (step 2+) actually
# completes on all ranks.
moe_cfg.ep_size = 8
moe_cfg.dispatcher = "deepep"
# DSA backend selector for the per-layer ``sparse_attn`` call (see
# ``DSAConfig.backend``):
# * "native" — pure-PyTorch reference (default, always works)
# * "flash_mla" — Phase-1: FlashMLA forward + native-recompute backward
# * "cudnn" — Phase-2: FlashMLA forward + cudnn SparseAttentionBackward
moe_cfg.attention.backend = "cudnn"
# Tell DSA the static upper bound on packed query length. HCA
# (compress_ratio=128) layers use it to size a pre-allocated ``-1`` pad
# buffer that brings ``topk_idxs.size(-1)`` up to a multiple of FlashMLA's
# 128-alignment. Without this set, HCA layers fall back to native sparse_attn
# (slower; see DSA._resolve_sparse_attn_fn). Must match the DataloaderConfig
# pack_max_length below.
moe_cfg.attention.pack_max_length = pack_max_length
moe_cfg.attention.indexer_backend = "triton"
# Compile is now safe — cutlass group_gemm is annotated with @torch.library.custom_op
# (compile-friendly), and HC + DSA helpers are pure-Tensor.
# Temporarily disabled: under pack=8192 + intra_layer_micro_batch=1 +
# recompute_ratio=1.0 some backward path allocates a 130 GiB fp32 tensor.
# The 06:00 run with compile_cfg=False reached step 50 at max_mem 114 GB so
# the baseline fits — debug what compile_cfg=True is changing in the eager
# code path that adds 130 GB on top.
moe_cfg.compile_cfg = True

optim_cfg = AdamWConfig(lr=6e-05,)
lr_cfg = LRConfig(lr_type="cosine", lr_min=1e-6)
fsdp_cfg = FSDPConfig(
# `FSDPConfig.torch_compile` is deprecated (1.1.0) and now acts as a master
# OFF switch — setting it to False overrides `moe_cfg.compile_cfg` and
# disables compile entirely. Omit it (defaults to True so the model-level
# `compile_cfg` controls the actual targets).
cpu_offload=False,
ep_size=moe_cfg.ep_size,
# Activation checkpointing on. Together with XTUNER_ACTIVATION_OFFLOAD this
# gives recompute-on-backward + CPU-resident inter-layer hidden states.
recompute_ratio=1.0,
)

dataset_config = [
{
"dataset": DatasetConfig(name="alpaca", anno_path=ALPACA_PATH, sample_ratio=1.0),
# `chat_template="internlm2"` is the default — it wraps each turn with
# `<|im_start|>role\n...<|im_end|>` markers. DeepSeek-V4's tokenizer has
# no such tokens, so applying the InternLM2 template causes the markers
# to fall back to per-byte tokens that V4's embed/lm_head never saw
# → per-token CE > ln(vocab) (worse than random init), ~22 instead of
# the ~12 expected from-scratch initial loss. Use the matching DeepSeek
# family template instead (V4 reuses V3's chat schema).
"tokenize_fn": FTDPTokenizeFnConfig(max_length=4096, chat_template="deepseekv3"),
},
]

# With recompute_ratio=1.0, every backward recomputes the full forward of a
# layer — that re-allocates the HC 5D mix tensor (~4 GB at pack=32768 × hc_mult=4
# × hidden=4096 bf16), plus DSA grads, plus per-expert grads, simultaneously on
# top of the 137 GB of params/fp32-master/Adam states already resident. 32768
# OOMs on 140 GB. 8192 leaves ~30 GB headroom for the recompute peak.
# XTUNER_ACTIVATION_OFFLOAD additionally stages the inter-layer hidden state on
# CPU during the original forward, so the next layer's recompute sees a clean
# slate when it starts.
dataloader_config = DataloaderConfig(pack_max_length=pack_max_length, num_workers=4)

loss_cfg = CELossConfig(mode="chunk")


trainer = TrainerConfig(
load_from=DEEPSEEK_V4_PATH,
model_cfg=moe_cfg,
optim_cfg=optim_cfg,
fsdp_cfg=fsdp_cfg,
dataset_cfg=dataset_config,
dataloader_cfg=dataloader_config,
lr_cfg=lr_cfg,
loss_cfg=loss_cfg,
tokenizer_path=DEEPSEEK_V4_PATH,
global_batch_size=128,
work_dir="/mnt/shared-storage-user/yehaochen/tmp",
seed=0,
strict_load=False,
# Force at least 2 training steps. `total_epoch=1` over alpaca_tiny (20 tiny
# samples, ~1864 tokens) only yields 1 packed batch per rank → default
# `total_step = len(dataloader) * total_epoch = 1`. Set explicitly to 2 so
# `_data_iter`'s `while cur_step < total_step` keeps yielding; on StopIteration
# it bumps epoch and re-iterates the same data (so step 2 trains on the same
# sequence).
total_step=10000,
total_epoch=None,
# Smoke-test V4 `_micro_batch_forward`: list-input path is taken when > 1.
# Sequential per-layer per-MB loop (see DeepSeekV4._micro_batch_forward).
intra_layer_micro_batch=2,
# debug_skip_save left off — ep=1 save path is collective-safe (it was only
# broken under ep_size>1 where the fsdp_mesh got split into ep groups).
# Memory profiling: dumps `rank{r}_memory_snapshot.pickle` under work_dir/profile/
# for the listed step. Load in PyTorch's https://pytorch.org/memory_viz to see
# the timeline of allocations. profile_time also writes a trace per step.
# trainer._cur_step is 0-indexed at check time (incremented AFTER the step),
# so profile_step=0 fires on the first step.
# Profile step 3 (steady-state — step 1 is compile warmup, step 2 may still
# see specialization recompile). Drops a per-rank ``rank{r}_trace.json``
# under ``work_dir/profiling_time/`` viewable in chrome://tracing or
# https://ui.perfetto.dev/. profile_time defaults to True.
# Profile step 0 (== first training step) so we can read peak memory even
# when the rest of the run OOMs before reaching steady state. ``profile_memory``
# dumps ``rank{r}_memory_snapshot.pickle`` under ``work_dir/profiling_memory/step-0/``,
# viewable at https://pytorch.org/memory_viz.
profile_step=14,
profile_memory=True,
)
Loading
Loading