[All] Refactor fused attention APIs with cuDNN-frontend support checks and opaque config/params handles - #2964
Conversation
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
for more information, see https://pre-commit.ci
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
for more information, see https://pre-commit.ci
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
for more information, see https://pre-commit.ci
|
/te-ci L1 |
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
for more information, see https://pre-commit.ci
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
for more information, see https://pre-commit.ci
|
/te-ci L0 L1 L2 L3 |
Conflict in dot_product_attention.py: NVIDIA#3476 respelled the attention_params_kwargs dict() call as a dict literal, which rewrote every line of a block this branch had also edited. Resolved to main's literal syntax carrying this branch's semantics: the four added keys (num_tokens_q, num_tokens_kv, cp_size_a2a, softmax_scale) and the tightened alibi_slopes_shape and core_attention_bias_requires_grad guards. Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
c2f0137 to
2ea91aa
Compare
|
/te-ci L0 L1 L2 L3 |
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
|
/te-ci L0 L1 L2 L3 |
KshitijLakhani
left a comment
There was a problem hiding this comment.
nit: So the fact that we use an adjusted window size for CP in one of our primitives which is different than the global window size is not something this PR introduces, however, I'm wondering ff the caching becomes less efficient because of this ?
workspace query with global window
→ build/cache global-window graph in the thread-local cache
runtime with adjusted CP window
→ different descriptor
→ cache miss
→ build/cache adjusted-window graph
it's a minor penalty I suppose, but I do not think we need to worry about it - thoughts ?
Done. I added a helper function to get the effective window size for CP + Ring + Striped + THD + SWA. Looking through other CP variants, it seems that they are already passing the exact config that the execution will run, during the probing/support query stage. Thanks. |
|
/te-ci L0 L1 L2 L3 |
The FFI fwd/bwd paths queried the backend and then populated the RNG state
and the aux tensor pack unconditionally. With NVTE_No_Backend that walked
the FP8 branch of PopulateRngStateAsync, advanced the global RNG offset and
launched a kernel for an attention that never runs, and the rejection
message was discarded, so the failure only surfaced later from
nvte_fused_attn_{fwd,bwd}_v2 without the diagnostic.
Check the backend right after the query and surface the message.
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
GetFusedAttnBackendImpl took 36 positional arguments, including runs of same-typed heads, head dims and sequence lengths that could be transposed at a call site and still compile. Have each of the three call sites build a FusedAttnConfigWrapper with its named setters instead, and reduce GetFusedAttnBackendImpl to the query itself. The wrapper already names every field and owns the defaults, so it supplies the anti-swap property without a second struct mirroring FusedAttnConfig. The pybind entry point now reads like its PyTorch counterpart, and the two FFI handlers build the config in FUSED_ATTN_IMPL_COMMON_BLOCK, which already decodes the rest of the arguments they share, so the config cannot drift from the values it is derived from. GetFusedAttnBackendImpl stays separate from the pybind GetFusedAttnBackend because the FFI handlers run without the GIL and have no params object to pass. Their query is not a repeat of the one the Python layer ran: batch size is the segment count, which for ragged input is only resolved inside the handler. No behavior change: the fields the FFI paths never set are pinned to the values they previously picked up as struct defaults. return_max_logit is pinned to false, which is what the backward pass always passed, and the forward pass overrides it before querying. Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
The three production call sites passed the first sixteen fields positionally, including the is_training/batch_size and q_num_heads/kv_num_heads/q_max_seqlen/ kv_max_seqlen runs, where a transposition type-checks and yields a plausible backend answer rather than an error. Name them, convert the one remaining positional construction under tests/jax, and mark the dataclass kw_only so the convention cannot drift back. Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
The positional index into the recorded FusedAttnHelper arguments had to move from 3 to 4 when batch_size was added. Now that the call site passes keywords, read qkv_layout out of the recorded kwargs instead. Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
The fwd/bwd lowerings substitute cp_striped_window_size for the global window (CP + Ring P2P + THD + SWA), but the backend probe and the workspace-size query in abstract kept using config.window_size. The probe therefore validated, and the graph cache retained, a descriptor that never executes, while the executing descriptor was never checked. Add _FusedAttnConfig.effective_window_size and use it in both places, which also collapses the branch that was duplicated in the two lowerings. Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
|
/te-ci L0 L1 L2 L3 |
for more information, see https://pre-commit.ci
|
/te-ci L0 L1 L2 L3 |
|
L1 and L2 jax distributed tests have some hangs but fused_attn related tests have run and passed. |
Three conflicts, all two sides adding different things at the same line. tests/pytorch/utils.py: NVIDIA#2964 adds bottom_right_diagonal to ModelConfig and to the AttentionParams call where this branch adds softcap. AttentionParams carries both fields, so both are kept. dot_product_attention.py: the attention_params_kwargs dict. NVIDIA#2964 tightens the alibi_slopes_shape guard to require core_attention_bias_type == "alibi". Kept that and kept the "softcap" key, which get_attention_backend needs to see in order to disqualify the backends that cannot honour a cap. Dropping it here would leave softcap silently ignored during backend selection with no test failure, which is how it was lost in an earlier merge on this branch. Signed-off-by: Nitin Vegesna <nvegesna@nvidia.com>
Description
TE currently hand-maintains the fused-attention backend-selection logic in
nvte_get_fused_attn_backend, duplicating cuDNN's support rules. This list drifts out of sync as cuDNN evolves, and the support check can disagree with what actually runs.This PR replaces that logic with cuDNN-frontend's production-grade support checks. The new
nvte_get_fused_attn_backend_v2builds the same graph cuDNN executes at runtime, so the probe and execution can no longer diverge. It caches the graph on success and returns a diagnostic message on failure, giving users actionable guidance (e.g. adjust the config, GPU architecture, or cuDNN version).This PR also reworks
nvte_fused_attn_fwd/nvte_fused_attn_bwdintonvte_fused_attn_fwd_v2/nvte_fused_attn_bwd_v2, which take opaque, attribute-based config/params handles instead of long flat argument lists — improving TE's API and ABI stability.Legacy APIs are retained as deprecated shims that route through the v2 APIs, so existing callers keep working.
Type of change
Changes
API rework (opaque config/params + v2 entry points)
common/fused_attn/config_and_params.{h,cpp},common/include/transformer_engine/fused_attn.h): newNVTEFusedAttnConfig/NVTEFusedAttnFwdParams/NVTEFusedAttnBwdParamswithcreate/destroy/get/setattribute accessors, for better API/ABI stability. The cache key, probe, and execution now all originate from one place viamake_config/derive/make_cache_key.common/fused_attn/fused_attn*.{cpp,cu}):nvte_get_fused_attn_backend_v2,nvte_fused_attn_fwd_v2, andnvte_fused_attn_bwd_v2, taking the opaque handles above in place of flat argument lists.common/fused_attn/fused_attn_f16_arbitrary_seqlen.cu,fused_attn_fp8.cu,graph_cache.h): graph building moved out offused_attn_*_{fwd,bwd}_implintocreate_graph_{f16,fp8}_{fwd,bwd}(const FusedAttnConfig &); the*_implbodies now only fetch the graph, finish its plans, and bind the variant pack. The probe (support_verdict_*) and execution reach that builder through the sameget_graph<Backend, Pass, create_graph_*>and cache, so they can't diverge;build_plans()is deferred so a probe-only miss doesn't pay for it.nvte_get_fused_attn_backend/nvte_fused_attn_fwd/nvte_fused_attn_bwdare retained, routed through the v2 APIs.csrc/extensions/attention.cpp) and JAX (jax/csrc/extensions/attention.cpp).Correctness & backend selection
cp_per_step_configsprobes each context-parallel step instead of only the global, non-CP config.log2(0)guard: avoids UB when casting-inftosize_tinget_max_batch_size/get_max_tokens.Diagnostics
NVTE_DEBUG/NVTE_DEBUG_LEVELfor JAX (parity with PyTorch): level 1 reports the selected backend; level 2 adds a diagnostic message explaining why fused attention was rejected.NVTE_FUSED_ATTN_CACHE_DEBUG=<level>[:<ranks>]: opt-in instrumentation that reports cuDNN graph build-vs-execution counts and per-stage cudnn-frontend build timings, so cache hit/miss/build/exec behaviors and graph build time can be inspected. Off by default;[:<ranks>]specifies select ranks for diagnostics; available for both PyTorch and Jax.Cleanup / removals
NVTE_FUSED_ATTN_BACKEND— the two remaining backends (F16, FP8) are mutually exclusive now that max512 is gone.Q_ID/.../MASK_VAL_IDmacros (used only by the max512 backend).cudnn_frontend::xxxutility functions (used only byfp8_impl_v0and max512).fused_attn/headers.Tests
test_fused_attn_graph_cacheto test graph cache's behavior withNVTE_FUSED_ATTN_CACHE_DEBUG=2on, andtest_fused_attn_backend_messageto test the surfacing of TE-specific or cuDNN-related error messages to users.Checklist: