test(pp): add deepseek_v4 PP and EP parity tests [2/4] - #3613
Open
athitten wants to merge 2 commits into
Open
Conversation
DeepSeek-V4 owns get_pipeline_stage_metas, so it carries hyper-connection streams across a pipeline stage boundary rather than just hidden states, and it is the main expert-parallel recipe. Neither contract had a GitHub-CI test. Add two parity tests that train a shrunk DeepSeek-V4 proxy twice with the same seed and data order and fail when the loss or gradient-norm trajectories disagree: PP2 against a single-rank baseline, and EP2 against a 2-rank data-parallel reference so both legs are FSDP-wrapped identically. The proxy generates its own synthetic token sequences, so this stages no tokenizer or dataset in TEST_DATA_DIR or HF_CACHE. Raise the gemma4 PP2 test's global_batch_size to 4 so it accumulates two micro-batches, and assert positively that stage shapes were precomputed -- the pre-existing negative grep cannot catch the precompute being skipped outright, because then the fallback log line is not emitted either. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Abhishree <abhishreetm@gmail.com>
`experts: torch_mm` is what the shipped recipe uses and it runs on the CI runners, so the proxy no longer substitutes `torch` for it. `attn` stays sdpa because tilelang JIT-compiles its kernels on every run, and `dispatcher` stays torch because hybridep is not installed in the CI container. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Abhishree <abhishreetm@gmail.com>
Contributor
Author
|
/ok to test f6f9ceb |
athitten
marked this pull request as ready for review
August 21, 2026 22:23
athitten
enabled auto-merge (squash)
August 21, 2026 22:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
L2_Parallelism_DeepSeekV4_PP2_Parity.shL2_Parallelism_DeepSeekV4_EP2_Parity.shdeepseek_v4_proxy.yamldeepseek_v4_flash_hellaswag.yaml(6 layers, ~20M params) keeping every field the parallelism code branches on.Also raises the gemma4 PP2 test's
global_batch_size2 → 4 so it accumulates two micro-batches.Why
#2983 broke every pipeline-parallel recipe while GitHub CI stayed green, because no test ran a real recipe topology twice and compared the numbers. #3529 covered gemma4. DeepSeek-V4 is the next one that matters: it owns
get_pipeline_stage_metas, so it carries hyper-connection streams across the stage boundary rather than just hidden states, and it is the main expert-parallel recipe.Loss on its own is a weak detector; gradient norm is the sensitive one. Both tests assert on it, and the comparison script fails if a log has no
grad_norm.No new CI assets
The proxy generates its own fixed-length synthetic token sequences (
llm.mock.build_unpacked_dataset,std_len: 0) — no tokenizer, no dataset to stage. Same pattern asbaichuan_2_7b_mock_fp8.yaml.Three things the proxy has to copy from the shipped recipe
Each was found by running the test, not by reading it:
patch_inner_model/patch_causal_lm_model: false— as in every shipped deepseek recipe. At theirtruedefault,patch_hf_model_for_ppreplaces DeepSeek-V4's own PP-awareforwardwith the generic CausalLM one, which skips the[B,S,dim] → [B,S,hc_mult,dim]expansion and dies inDeepseekV4HyperConnection.pp_size=2a hash-routing layer lands on stage 1, getsinput_ids=None, and takes its score-based-topk fallback, routing differently from the baseline. The shipped 43-layer/pp4 recipe keeps all 3 hash layers on stage 0.fake_balanced_gate—model.py:181only installs the hash gate when it is off, so it disabled the routingnum_hash_layers: 3is there to exercise.Measured
PP's loss bound is 0.10 because at a loss of ~10.9 in bf16 the representable resolution is already ~0.04. EP is 50x tighter because both its legs are 2-rank and FSDP-wrapped identically — which is also the control proving the PP gap is the wrapped/unwrapped asymmetry, not pipeline parallelism.
CI cost:
L2_Parallelismgoes ~4m42s → ~9min against a 40-minute timeout, and finishes ~8 minutes before the critical-path job. No change to total pipeline wall-time.Backends
experts: torch_mmmatches the shipped recipe. Two differ:attnissdpa, nottilelang— tilelang JIT-compiles its kernels on every run (~1min for this suite), and the parity numbers are identical either way.dispatcheristorch, nothybridep— hybridep is not installed in the CI container, and atworld_size == 1the deepep/hybridep path falls back toGroupedExperts(layers.py:771), so the PP test's single-rank baseline would run a different expert implementation than its pp2 leg.Neither changes what EP shards:
apply_ep→ExpertParalleldistributes the expert weights on the expert axis in every case.Also
Both PP scripts now assert positively that
"Precomputed pipeline stage shapes"appears. The pre-existing negative grep cannot catch_precompute_stage_shapesbeing skipped outright, since the fallback line disappears with it — the exact function #2983 broke.Known gap: the EP test catches EP changing the numbers, but not EP silently never being applied — that would make both legs identical and pass. PP closes the equivalent hole via the log line;
apply_ephas none to grep. Documented in the script header.🤖 Generated with Claude Code