Skip to content

Add GDN dynamic inference - #6499

Merged
anlthms merged 1 commit into
NVIDIA:mainfrom
anlthms:gdn_inference_take2
Aug 21, 2026
Merged

Add GDN dynamic inference#6499
anlthms merged 1 commit into
NVIDIA:mainfrom
anlthms:gdn_inference_take2

Conversation

@anlthms

@anlthms anlthms commented Aug 13, 2026

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

What does this PR do?

This implementation adds GDN prefill and single-token decode to the dynamic inference engine. It reuses the generic recurrent-mixer control flow introduced by PR #5382 and uses the inference kernels from flash-linear-attention (FLA) 0.5.1.

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

Notes

For a detailed description of the changes, please see Gated DeltaNet Dynamic Inference (internal document)

@copy-pr-bot

copy-pr-bot Bot commented Aug 13, 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.

@anlthms
anlthms force-pushed the gdn_inference_take2 branch from 952025b to 3c93c80 Compare August 14, 2026 14:39
@anlthms

anlthms commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 3c93c80

@anlthms
anlthms marked this pull request as ready for review August 14, 2026 21:12
@anlthms
anlthms requested review from a team as code owners August 14, 2026 21:12
Comment on lines +441 to +452
# Mamba and GDN use the same slot-indexed recurrent-state cache contract. Build
# one map in global layer order; independently generated per-symbol maps both
# start at zero and would alias if they were simply unioned.
attention_layer_map, dsa_layer_map = operator.itemgetter(
Symbols.ATTENTION, Symbols.DS_ATTENTION
)(get_layer_maps_from_layer_type_list(mamba_inference_state_config.layer_type_list))
recurrent_layer_map = {}
for global_layer_idx, layer_type in enumerate(
mamba_inference_state_config.layer_type_list
):
if layer_type in (Symbols.MAMBA, Symbols.GDN):
recurrent_layer_map[global_layer_idx] = len(recurrent_layer_map)

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.

Not really related to this PR, but I'm curious why GDN has a specific layer type but GDP did not - should we be unifying all of these linear attention variants under a single layer type?

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.

good question! I don’t know why GDP doesn’t have its own symbol. Symbol.GDN was already there and being used, so it made sense to just follow the pattern for this work. GDP piggybacks on Symbol.Mamba, I think.

Comment thread tests/unit_tests/inference/engines/test_dynamic_engine.py
Comment thread tests/unit_tests/ssm/conftest.py
@@ -0,0 +1,180 @@
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

"""Focused kernel and CUDA-graph tests for Gated DeltaNet dynamic inference."""

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.

Is cuda graph functionality intended to work out of the box? For Mamba2 at least we needed to modify the kernel to support masking computation when we pass -1 values in the batch_indices tensor, do the GDN kernels already support this?

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.

writes use tensor_masked_update, which explicitly ignores -1.

for reads, there is a call to batch_indices.clamp(min=0) before gathering. this is present for both ssm_decode() and ssm_prefill() inside gdn.py.

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.

I see, so this is basically relying on the fact that multiple readers of the value at index 0 is safe as long as we don't have multiple writers. I think that's ok for now, but we should maybe document this 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.

as long as we don't have multiple writers

@santhnm2, to clarify: writes go through tensor_masked_update, which in turn calls _tensor_masked_update_kernel_2d (or 3d/4d). these kernels ignore an index of -1 with an explicit return.

    if target_idx == -1:
        return

(it is possible I misunderstood your comment)

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.

Sorry let me clarify - my understanding is the clamp on batch_indices is basically forcing all padding entries to read from slot 0 and then do some dummy computation based on that value, but the result of the dummy computation is not written back to slot 0 because tensor_masked_update prevents writes on -1 slots. So what I meant by not having multiple writers is slot 0 will have a max of 1 writer (i.e., a real request mapped to slot 0) so this is safe.

The semantics for Mamba2 (and eventually GDP) are that within the kernel itself we skip computation for the -1 indices and directly write out 0 values rather than proceeding with the dummy computation. But the end result is effectively the same other than the output activation tensor having nonzero values in the padding slots. These padding slot outputs are ignored anyway so there should be no downstream effect.

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.

I get it now. the way Mamba2 handles padding sounds cleaner. probably worth changing this in another PR.

Comment thread pyproject.toml

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.

Was this change intentional?

@anlthms anlthms Aug 17, 2026

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.

intentional. FLA was previously a dev dependency. that seemed wrong as it is a requirement for GDN (just like causal-conv1d, which was already under the ssm section). but let me know if you think FLA belongs in dev.

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.

It seems like we should bump this, but maybe @NVIDIA/mcore-oncall has thoughts here?

Integrate GDN with the shared recurrent-state cache and FLA kernels
for packed prefill and decode. Add configuration validation plus
state-continuity coverage.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Anil Thomas <anthomas@nvidia.com>
@anlthms
anlthms force-pushed the gdn_inference_take2 branch from 3c93c80 to b6ff5f4 Compare August 20, 2026 17:17
@svcnvidia-nemo-ci svcnvidia-nemo-ci added the Approved All necessary approvals have been made label Aug 20, 2026
@anlthms

anlthms commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test b6ff5f4

@nemo-automation-bot

Copy link
Copy Markdown

🔄 Merge queue validation started!

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

@nemo-automation-bot

Copy link
Copy Markdown

🔄 Merge queue validation started!

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

Merged via the queue into NVIDIA:main with commit 606b9f4 Aug 21, 2026
92 checks passed
@anlthms
anlthms deleted the gdn_inference_take2 branch August 21, 2026 03:35
dimapihtar pushed a commit to dimapihtar/Megatron-LM that referenced this pull request Aug 21, 2026
Signed-off-by: Anil Thomas <anthomas@nvidia.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Dmytro Pykhtar <dpykhtar@nvidia.com>
devnkong pushed a commit to devnkong/Megatron-LM that referenced this pull request Aug 22, 2026
Signed-off-by: Anil Thomas <anthomas@nvidia.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Kezhi Kong <kezhik@kezhik-mlt.client.nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Approved All necessary approvals have been made complexity: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants