feat(sft): DSv4 Flash offline-packed SFT with THD + CP - #5126
Conversation
3138f2a to
fb283af
Compare
|
test line one |
Review SummaryThe change adds a contiguous context-parallel partition mode for packed THD batches (needed for DSv4 CSA hybrid attention), threads cp_partition_mode/cp_group/local_cp_size through to PackedSeqParams when the installed MCore supports them, and exposes a new deepseek_v4_flash_sft_openmath_thinking_packed_config recipe. Overall the direction is sound and the contiguous slicing math is careful. A few points to confirm: Correctness
Recipe
Tests
Suggested test cases
No perf/recipe performance configs are touched (scripts/performance/configs/ has no DeepSeek entries) — no perf tests impacted. |
| _SEQLEN_MAP = { | ||
| "cu_seqlens": cu_seqlens, # trimmed by _cu_seqlens_for_cp_partition | ||
| "cu_seqlens_q": batch.get("cu_seqlens_q"), | ||
| "cu_seqlens_kv": batch.get("cu_seqlens_kv"), | ||
| "cu_seqlens_unpadded": batch.get("cu_seqlens_unpadded"), | ||
| } | ||
| for key in seqlen_keys: | ||
| val = batch.get(key) | ||
| if val is None or "argmin" in key or key in {"max_seqlen", "max_seqlen_q", "max_seqlen_kv", "token_count"}: | ||
| continue | ||
| trimmed = _SEQLEN_MAP.get(key) | ||
| src = trimmed if trimmed is not None else val | ||
| clipped = (src.clamp(min=start, max=end) - start).to(val.dtype) | ||
| batch[key] = clipped |
There was a problem hiding this comment.
The comment says the sentinel-free trimmed version is used "to avoid clamping -1 padding to 0", but that only holds for the legacy cu_seqlens key — _SEQLEN_MAP["cu_seqlens"] points at the trimmed cu_seqlens local, whereas cu_seqlens_q, cu_seqlens_kv, and cu_seqlens_unpadded map to the raw batch.get(...) tensors, which are not trimmed. If any of those carry -1 sentinels, src.clamp(min=start) promotes -1 to start and the subsequent - start yields 0, i.e. the exact failure the comment claims to avoid. Please confirm the current-format cu_seqlens_q/kv batches never contain -1 padding in the contiguous path, or trim them like cu_seqlens.
There was a problem hiding this comment.
Good catch. For DSv4 offline SFT (the only contiguous-CP user today), batches always take the legacy cu_seqlens path so cu_seqlens_q/kv/unpadded are None and never processed. However the comment was misleading — updated it to clarify that cu_seqlens_q/kv/unpadded in the current format do not use -1 sentinels, so they are safe to clip directly without trimming.
| batch = _partition_packed_batch_for_cp(batch, pg_collection.cp) | ||
| _cp_mode = getattr(cfg.model, "cp_partition_mode", "zigzag") | ||
| batch = _partition_packed_batch_for_cp(batch, pg_collection.cp, cp_partition_mode=_cp_mode) | ||
| batch["cp_partition_mode"] = _cp_mode |
There was a problem hiding this comment.
batch["cp_partition_mode"] is set to a plain str here, and it flows into _packed_metadata_for_forward via _LEGACY_PACKED_SEQ_PARAM_KEYS → get_packed_seq_params. But cp_partition_mode is only added to _LEGACY_PACKED_SEQ_PARAM_KEYS, not _CURRENT_PACKED_SEQ_PARAM_KEYS. For current-format batches (those with cu_seqlens_q), the cp_partition_mode / cp_group / local_cp_size set on the batch will therefore never reach get_packed_seq_params, so the hasattr(PackedSeqParams, "cp_partition_mode") block in the cu_seqlens_q branch always falls back to "zigzag". If DSv4 contiguous CP is expected to run through the current-format path, this is a silent correctness gap. If DSv4 only uses the legacy cu_seqlens path, please confirm.
There was a problem hiding this comment.
Fixed — added cp_partition_mode, cp_group, local_cp_size to _CURRENT_PACKED_SEQ_PARAM_KEYS as well (a6cc865). For DSv4 offline SFT the legacy path is always taken, but this ensures correctness for current-format batches too.
a6cc865 to
29e64cb
Compare
| cfg.dataset = default_openmathinstruct2_thinking_config( | ||
| seq_length=cfg.model.seq_length, | ||
| enable_offline_packing=True, | ||
| pad_seq_to_mult=4, # 2 * cp_size when CP=2; divisible by any CP up to 4 |
There was a problem hiding this comment.
this should be dynamic to cfg.model.context_parallel_size
There was a problem hiding this comment.
good catch. forgot to set that after validation. resolving now
29e64cb to
2588a87
Compare
2588a87 to
1dcbc1b
Compare
cp_partition_mode=contiguous is DSv4-specific — MCore enforces this in TransformerConfig (dsv4_hybrid only). Move the contiguous batch partition logic out of generic gpt_step.py into a new model-specific step file. Changes: - gpt_step.py: _partition_packed_batch_for_cp reverted to zigzag-only; _forward_step_common gains optional _get_batch_fn override; inline _model_chunk_vp_stage helper (was get_model_chunk_vp_stage from flop_utils) - deepseek_v4_step.py (new): _partition_packed_batch_contiguous, DSv4-aware get_batch dispatching contiguous/zigzag, forward_step via _get_batch_fn - recipe_runner.py: register dsv4_step in STEP_FUNCTIONS - test_gpt_step.py: remove contiguous-mode tests (moved to deepseek_v4_step) - test_deepseek_v4_step.py (new): contiguous partition unit tests Use --step_func dsv4_step for DSv4 SFT/pretrain with CP > 1. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
dsv4_step is a text-modality step function (text LLM forward step, same as gpt_step/llm_step). recipe_steps_match must recognize it as compatible with llm_step so --step_func dsv4_step does not fail validation. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
deepseek_v4_flash_sft_openmath_thinking_packed_config was defined in deepseek_v4.py but not forwarded through deepseek/__init__.py so megatron.bridge.recipes could not find it. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
/ok to test 92b27ab |
|
/ok to test b44a2ab |
|
/ok to test 4d3c463 |
Adds offline-packed SFT support for DSv4-Flash with contiguous Context Parallel, required by the DSv4 CSA compressor which exchanges boundary hidden states between adjacent CP ranks. Extends
_partition_packed_batch_for_cpwith a contiguous mode that slices a consecutive token window per CP rank, clipscu_seqlensto the local window, and injectscp_partition_modeinto packed sequence metadata so MCore attention receives the correct partition mode. Also addsdeepseek_v4_flash_sft_openmath_thinking_packed_configfollowing the GPT-OSS two-step workflow (pre-pack withprepare_gpt_sft_packed_data.py, then train). All changes are gated behindhas_packed and cp_size > 1so existing users are unaffected.based on NVIDIA/Megatron-LM#6158