Skip to content

[dev] [DeepSeek-v4] Packed Sequence (THD) support for DSv4 Hybrid Attention - #5011

Merged
hxbai merged 13 commits into
NVIDIA:devfrom
hxbai:dsv4_thd
Jun 26, 2026
Merged

[dev] [DeepSeek-v4] Packed Sequence (THD) support for DSv4 Hybrid Attention#5011
hxbai merged 13 commits into
NVIDIA:devfrom
hxbai:dsv4_thd

Conversation

@hxbai

@hxbai hxbai commented May 27, 2026

Copy link
Copy Markdown
Contributor
  • I, the PR author, have personally reviewed every line of this PR.

What does this PR do ?

Add Packed Sequence (THD) support for DSv4 Hybrid Attention.

⚠️ For major changes (either in lines of code or in its impact), please make sure to first share a design doc with the team. If you're unsure what's the best way to do so, contact @NVIDIA/mcore-oncall.

Issue tracking

For PRs from open-source community contributors:

  • New features: a linked issue is required. Please open a feature request and reference it here before submitting the PR.
  • Small updates (bug fixes, minor improvements): a linked issue is recommended and will accelerate the PR review process.

Linked issue:

Contribution process

Pre-checks

  • I have added relevant unit tests
  • I have added relevant functional tests
  • I have added proper typing to my code Typing guidelines
  • I have added relevant documentation
  • I have run the autoformatter.sh on my PR

Code review

Feel free to message or comment @NVIDIA/mcore-oncall to help accelerate your merge into main. The less complex your PR is, the faster it will be approved and merged!

All PRs start as draft. If you open a non-draft PR, it will be automatically converted to draft.

Step 1: Mark PR as "Ready for Review"

  1. When your PR is ready, click Ready for Review.
  2. An oncall reviewer is auto-assigned and expert reviewers are notified based on your changes.
    • Some PRs may jump straight to step 2. This is determined by .github/CODEOWNERS.

⚠️ Only mark as ready once merge-conflicts are resolved and the CI is passing.
Final Review might get declined if these requirements are not fulfilled.

Step 2: Final Review

For PRs that change megatron/core, once all expert reviewers have approved, the Final Review label is applied automatically and final reviewers are assigned.

For PRs outside megatron/core, this step is skipped.

Step 3: Approved

Once all required reviewers have approved, the Approved label is applied automatically.

Merge

Any member of mcore-engineers will be able to merge your PR.

@copy-pr-bot

copy-pr-bot Bot commented May 27, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@hxbai
hxbai requested a review from kunlunl May 27, 2026 10:02
@yaox12 yaox12 mentioned this pull request May 28, 2026
18 tasks
@hxbai
hxbai marked this pull request as ready for review May 29, 2026 08:49
@hxbai
hxbai requested review from a team as code owners May 29, 2026 08:49
@hxbai
hxbai requested a review from yuzhongw-nvidia June 1, 2026 07:57
Meirtz added a commit to Meirtz/verl that referenced this pull request Jun 4, 2026
GSM8K SFT example for DeepSeek-V4-Flash via the Megatron-Bridge backend,
mirroring run_mimo_7b_mtp_megatron.sh. TP1/PP4/EP8 (32 GPU), THD packed
sequences, MTP enabled, unfused mHC/RoPE (apply_rope_fusion=False,
use_fused_mhc=False), vanilla_mbridge=False. Fetches the DSv4 deps not in
verl's pinned Megatron-Core (NVIDIA/Megatron-LM#5011 + NVIDIA-NeMo/Megatron-Bridge).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Lingrui Mei <lmei@nvidia.com>
Meirtz added a commit to Meirtz/verl that referenced this pull request Jun 4, 2026
GSM8K SFT example for DeepSeek-V4-Flash via the Megatron-Bridge backend,
mirroring run_mimo_7b_mtp_megatron.sh. TP1/PP4/EP8 (32 GPU), THD packed
sequences, MTP enabled, unfused mHC/RoPE (apply_rope_fusion=False,
use_fused_mhc=False), vanilla_mbridge=False. Fetches the DSv4 deps not in
verl's pinned Megatron-Core (NVIDIA/Megatron-LM#5011 + NVIDIA-NeMo/Megatron-Bridge).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Lingrui Mei <lmei@nvidia.com>
Meirtz added a commit to Meirtz/verl that referenced this pull request Jun 4, 2026
GSM8K SFT example for DeepSeek-V4-Flash via the Megatron-Bridge backend,
mirroring run_mimo_7b_mtp_megatron.sh. TP1/PP4/EP8 (32 GPU), THD packed
sequences, MTP enabled, unfused mHC/RoPE (apply_rope_fusion=False,
use_fused_mhc=False), vanilla_mbridge=False. Fetches the DSv4 deps not in
verl's pinned Megatron-Core (NVIDIA/Megatron-LM#5011 + NVIDIA-NeMo/Megatron-Bridge).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Lingrui Mei <lmei@nvidia.com>
Meirtz added a commit to Meirtz/verl that referenced this pull request Jun 4, 2026
GSM8K SFT example for DeepSeek-V4-Flash via the Megatron-Bridge backend,
mirroring run_mimo_7b_mtp_megatron.sh. TP1/PP4/EP8 (32 GPU), THD packed
sequences, MTP enabled, unfused mHC/RoPE (apply_rope_fusion=False,
use_fused_mhc=False), vanilla_mbridge=False. Fetches the DSv4 deps not in
verl's pinned Megatron-Core (NVIDIA/Megatron-LM#5011 + NVIDIA-NeMo/Megatron-Bridge).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Lingrui Mei <lmei@nvidia.com>
Meirtz added a commit to Meirtz/verl that referenced this pull request Jun 4, 2026
GSM8K SFT example for DeepSeek-V4-Flash via the Megatron-Bridge backend,
mirroring run_mimo_7b_mtp_megatron.sh. TP1/PP4/EP8 (32 GPU), THD packed
sequences, MTP enabled, unfused mHC/RoPE (apply_rope_fusion=False,
use_fused_mhc=False), vanilla_mbridge=False. Fetches the DSv4 deps not in
verl's pinned Megatron-Core (NVIDIA/Megatron-LM#5011 + NVIDIA-NeMo/Megatron-Bridge).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Lingrui Mei <lmei@nvidia.com>
Meirtz added a commit to Meirtz/verl that referenced this pull request Jun 4, 2026
GSM8K SFT example for DeepSeek-V4-Flash via the Megatron-Bridge backend,
mirroring run_mimo_7b_mtp_megatron.sh. TP1/PP4/EP8 (32 GPU), THD packed
sequences, MTP enabled, unfused mHC/RoPE (apply_rope_fusion=False,
use_fused_mhc=False), vanilla_mbridge=False. Fetches the DSv4 deps not in
verl's pinned Megatron-Core (NVIDIA/Megatron-LM#5011 + NVIDIA-NeMo/Megatron-Bridge).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Lingrui Mei <lmei@nvidia.com>
Meirtz added a commit to Meirtz/verl that referenced this pull request Jun 4, 2026
GSM8K SFT example for DeepSeek-V4-Flash via the Megatron-Bridge backend,
mirroring run_mimo_7b_mtp_megatron.sh. TP1/PP4/EP8 (32 GPU), THD packed
sequences, MTP enabled, unfused mHC/RoPE (apply_rope_fusion=False,
use_fused_mhc=False), vanilla_mbridge=False. Fetches the DSv4 deps not in
verl's pinned Megatron-Core (NVIDIA/Megatron-LM#5011 + NVIDIA-NeMo/Megatron-Bridge).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Lingrui Mei <lmei@nvidia.com>
@dingqingy-nv dingqingy-nv added the deepseekv4 DeepSeek V4 PRs label Jun 9, 2026
@dingqingy-nv dingqingy-nv removed the deepseekv4 DeepSeek V4 PRs label Jun 11, 2026
@hxbai
hxbai force-pushed the dsv4_thd branch 2 times, most recently from 1d5834c to b2cd4cc Compare June 17, 2026 01:50
@hxbai

hxbai commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

/claude strict-review

Comment on lines +1277 to +1280
if is_thd:
dense_bwd_kwargs = dict(
cu_seqlens_q=cu_seqlens_q, cu_seqlens_k=cu_seqlens_compressed_idx
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[IMPORTANT Correctness] Dense-loss backward for THD is missing max_seqlen_q and max_seqlen_k kwargs.

The forward path at lines 1185-1192 builds dense_attn_kwargs with all four cu_seqlens + max_seqlen fields and passes them to both _compute_dense_indexer_score and _compute_dense_attn_score. However, the backward's dense_bwd_kwargs here only passes cu_seqlens_q and cu_seqlens_k, omitting max_seqlen_q and max_seqlen_k.

cuDNN THD-mode wrappers typically require max_seqlen for internal tile sizing. If dense_indexer_backward_wrapper follows the same convention as the forward wrappers, this will either silently produce wrong gradients or raise at runtime.

Suggested fix:

if is_thd:
    dense_bwd_kwargs = dict(
        cu_seqlens_q=cu_seqlens_q,
        cu_seqlens_k=cu_seqlens_compressed_idx,
        max_seqlen_q=int(max_seqlen_q),
        max_seqlen_k=int(max_seqlen_compressed_idx),
    )

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines +1265 to +1268
if is_thd:
precomputed_grad_q_indexer = ig["d_index_q"].view(total_q, idx_nh, idx_hd)
precomputed_grad_k_indexer = ig["d_index_k"].view(total_comp_idx, idx_hd)
precomputed_grad_weights = ig["d_weights"].view(total_q, idx_nh)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[IMPORTANT Correctness] Sparse-loss backward: THD indexer gradient reshape relies on .view() to collapse the fake-BSHD B=1 dim returned by the cuDNN wrapper.

The cuDNN indexer_backward_wrapper was called with fake-BSHD inputs shaped (1, total_q, ...) (line 1238-1243), so ig["d_index_q"] is (1, total_q, idx_nh, idx_hd). The .view(total_q, idx_nh, idx_hd) here works because 1 * total_q == total_q, but it's semantically fragile — if the wrapper ever pads or returns a different leading dimension, .view() will silently reinterpret memory.

Consider using .squeeze(0) to explicitly remove the batch dimension, consistent with the pattern used elsewhere in this file (e.g., q_thd = q_indexer.squeeze(1) in csa.py):

precomputed_grad_q_indexer = ig["d_index_q"].squeeze(0)
precomputed_grad_k_indexer = ig["d_index_k"].squeeze(0)
precomputed_grad_weights = ig["d_weights"].squeeze(0)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modified

Comment on lines +321 to +327
dst_comp = (
cu_seqlens_kv_full[batch_of_comp]
+ kv_lens[batch_of_comp]
+ (src_comp - cu_seqlens_compressed[batch_of_comp])
)
dst_comp = torch.where(valid_comp, dst_comp, total_kv + src_comp)
out[dst_comp] = compressed_kv_thd

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[IMPORTANT Correctness] When total_comp_capacity > cu_seqlens_compressed[-1] (capacity-padded for CUDA graph capture), invalid compressed rows are routed to total_kv + src_comp (line 326). However, out is sized total_kv_full = total_kv + compressed_kv_thd.shape[0], so the maximum valid destination index is total_kv_full - 1.

For the last invalid compressed row, dst_comp = total_kv + (total_comp_capacity - 1), which equals total_kv_full - 1 — that's exactly in-bounds. But this only works because out is sized using compressed_kv_thd.shape[0] (capacity) rather than cu_seqlens_compressed[-1] (true count). This tight coupling between the out allocation at line 288 and this fallback logic is fragile.

Consider adding a bounds assertion:

assert (total_kv + src_comp.max().item()) < total_kv_full, "padding dest OOB"

Or document the invariant that out is always capacity-sized (not true-count-sized) explicitly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment to clarify

@ko3n1g

ko3n1g commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

/ok to test e979a98

hxbai added 10 commits June 24, 2026 14:46
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
@hxbai

hxbai commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 7f3c633

Comment thread megatron/core/transformer/multi_token_prediction.py Outdated
Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
@hxbai

hxbai commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 215de5e

@hxbai

hxbai commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 7e38374

@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/28212100264

Signed-off-by: Hongxiao Bai <hongxiaob@nvidia.com>
@hxbai

hxbai commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test e1bdccc

@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/28225017892

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants