[None][refactor] Unify sparse attention framework with clean backend interfaces - #12733
[None][refactor] Unify sparse attention framework with clean backend interfaces#12733lfr-0531 wants to merge 15 commits into
Conversation
a1e4402 to
eaab4c3
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #41657 [ run ] triggered by Bot. Commit: |
|
PR_Github #41657 [ run ] completed with state
|
6d89705 to
4004b1a
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #41813 [ run ] triggered by Bot. Commit: |
|
PR_Github #41813 [ run ] completed with state |
|
/bot run --disable-fail-fast |
|
PR_Github #41921 [ run ] triggered by Bot. Commit: |
|
PR_Github #41921 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #41962 [ run ] triggered by Bot. Commit: |
|
PR_Github #41962 [ run ] completed with state
|
|
|
||
| TLLM_CHECK(host_kv_cache_pool_mapping.has_value()); | ||
| int32_t const layer_num = host_kv_cache_pool_mapping.value().size(0); | ||
|
|
There was a problem hiding this comment.
We can add an assert sentence here to make sure sparse_mla_topk_value is a valid value
| tensorrt_llm/_torch/attention_backend/sparse/dsa.py | | ||
| tensorrt_llm/_torch/attention_backend/sparse/kernel.py | | ||
| tensorrt_llm/_torch/attention_backend/sparse/rocket.py | | ||
| tensorrt_llm/_torch/attention_backend/sparse/utils.py | |
There was a problem hiding this comment.
Why we just remove there files but not add new files?
There was a problem hiding this comment.
The removed files (dsa.py, kernel.py, rocket.py, utils.py) were in the legacy exclusion list because they had historical lint violations that were grandfathered in.
The new replacement files (dsa/backend.py, dsa/custom_ops.py, dsa/indexer.py, dsa/metadata.py, dsa/cache_manager.py, rocket/backend.py, skip_softmax/backend.py, params.py, etc.) are written from scratch and fully comply with current lint standards — ruff check passes on all of them without any exclusions. So they don't need to be added to the legacy list.
The same applies to legacy-files.txt, pyproject.toml, and ruff-legacy.toml — all four config files are auto-generated from legacy-files.txt via scripts/legacy_utils.py gen-configs.
79c8913 to
53a6ee5
Compare
|
PR_Github #61837 [ run ] triggered by Bot. Commit: |
|
/bot run --disable-fail-fast |
|
PR_Github #61843 [ run ] triggered by Bot. Commit: |
|
PR_Github #61837 [ run ] completed with state |
|
PR_Github #61843 [ run ] completed with state
|
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Define validated sparse-attention hooks shared by Attention and MLA while keeping algorithm-specific module behavior under each sparse backend. Simplify DSA and DeepSeek-V4 module integration, move Rocket kernels into its backend directory, and align the related architecture tests. Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Unify module-to-backend and backend-to-attention-op sparse runtime arguments. Split DeepSeek-V4 indexer, metadata, and parameter definitions, and route DSA prediction through the backend while preserving shared TopK buffer lifetime. Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Allocate a single mixed-batch TopK buffer only when the model contains shared indexer layers. Reuse per-layer indexer routing to derive the metadata requirement and keep the buffer address stable across steps. Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Keep split DSA indexer test paths under inference mode, matching the original integrated Indexer.forward contract. Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Restore the shared lint configuration to match main and format the split sparse attention modules with Ruff. Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Group all accepted module hook signatures under one contract table and document the lifecycle of each sparse attention hook. Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Document that the model-specific integration is a compatibility exception and should not be used as the pattern for new sparse attention algorithms. Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
|
/bot run --disable-fail-fast |
|
PR_Github #61912 [ run ] triggered by Bot. Commit: |
|
PR_Github #61912 [ run ] completed with state
|
Signed-off-by: Fanrong Li <23290157+lfr-0531@users.noreply.github.com>
|
/bot run --disable-fail-fast |
|
PR_Github #62059 [ run ] triggered by Bot. Commit: |
|
Changes related to Skip Softmax Attention look nice. |
| self.aux_stream = aux_stream | ||
| self.ln_events = [torch.cuda.Event(), torch.cuda.Event()] | ||
| self.kv_a_layernorm = RMSNorm(hidden_size=self.kv_lora_rank, dtype=dtype, eps=rms_norm_eps) | ||
| self.kv_b_proj = Linear( |
There was a problem hiding this comment.
Blocking: this unconditionally constructs kv_b_proj (and later v_b_proj, o_proj, and the
dense MHA backend) before the sparse hook is initialized. The DeepSeek-V4 hook then deletes
these modules.
This is not only an abstraction issue: skip_create_weights_in_init defaults to false, so the
unused weights are actually allocated. With the dimensions used by the DeepSeek-V4 test, the
three deleted BF16 parameters alone account for roughly 84.5 MiB of transient allocation per
layer; larger production configurations can be substantially worse. Depending on the default
device used during model construction, this can increase host memory or GPU memory peaks and
potentially cause initialization OOMs.
The pre-refactor implementation explicitly avoided constructing these modules for DeepSeek-V4.
Please resolve the algorithm-specific build requirements before constructing the common MLA
modules, e.g. through a declarative build spec/capability object or an algorithm-specific
component factory, rather than constructing and deleting unused modules.
| _ATTENTION_HOOKS[algorithm] = hooks | ||
|
|
||
|
|
||
| @lru_cache(maxsize=None) |
There was a problem hiding this comment.
Major: this makes the public registration API ineffective for a new algorithm. Even after
register_mla_sparse_hooks("new_algo", NewHooks) succeeds, this lookup returns None unless
"new_algo" is also added to the private _MLA_HOOK_MODULE_PATHS map.
The same issue exists in the Attention hook getter. The getter should first consult the hook
registry and use the module-path map only to lazily import built-in algorithms. Please also
add a test that registers an arbitrary algorithm name and retrieves its hook without modifying
a central built-in map.
If external registration is intentionally unsupported, the register_* functions should not
be exported as public extension points.
|
|
||
|
|
||
| @lru_cache(maxsize=None) | ||
| def _get_sparse_mla_hooks_for_algorithm(algorithm: str) -> Optional[MLASparseHooks]: |
There was a problem hiding this comment.
Major: this cache stores the instantiated hook object, so every layer and every model using
the same algorithm shares one global adapter instance.
The current adapters happen to be stateless, but neither the interface nor the type system
enforces that constraint. A future hook that stores initialization or layer-specific state on
self would silently leak state across layers or model instances.
Please cache only the lazy-import or hook class resolution and instantiate the adapter per
owning MLA/Attention module. A state-isolation test with two module instances would help
protect this contract.
| @abstractmethod | ||
| def initialize( | ||
| self, | ||
| mla: "MLA", |
There was a problem hiding this comment.
Major architectural concern: although this adapter is typed, passing the concrete MLA object
gives each sparse algorithm unrestricted access to the entire module implementation. The
current implementations directly inspect, replace, and delete MLA attributes, so any internal
MLA refactor can break an algorithm at runtime.
Moreover, most of the actual algorithm logic is delegated to free functions whose self
parameter is untyped, which means the typed adapter does not provide meaningful static
checking for those internal dependencies.
Please consider modeling the sparse implementation as a composed SparseMLAComponent that
owns its algorithm-specific weights and state, and pass it a narrow, stable context/services
interface instead of the full MLA object. At minimum, the set of MLA fields available to hooks
should be explicitly defined and contract-tested.
| sparse_attn_offsets: Optional[torch.Tensor] = None | ||
| sparse_attn_indices_block_size: int = 0 | ||
| # DeepSeek-V4 compressed-cache inputs. | ||
| sparse_mla_topk_lens: Optional[torch.Tensor] = None |
There was a problem hiding this comment.
Major extensibility concern: this supposedly shared runtime contract already mixes generic
sparse-index fields with DeepSeek-V4-specific cache inputs and SkipSoftmax-specific
thresholds.
With this design, every new algorithm-specific runtime value requires modifying the common
dataclass and likely the shared THOP/C++ attention ABI, causing unrelated algorithms and
backends to depend on fields they never use.
Please keep only genuinely algorithm-independent indexing data in SparseRuntimeParams.
Algorithm-specific values should remain in a typed/discriminated payload and be lowered by the
selected backend at the THOP boundary. This would prevent the common carrier from growing into
a sparse-attention parameter bag.
Dev Engineer Review
SparseBackendForwardArgsandSparseRuntimeParams, removingSparsePredictionand replacingSkipSoftmaxKernelParamsusage with runtime fields.tensorrt_llm/_torch/attention_backend/sparse/hooks.py, and rewired MLA/attention execution to route sparse execution through hooks and consume predicted indices fromforward_args.sparse_runtime_params.*.tensorrt_llm/_torch/attention_backend/sparse/<algorithm>/:sparse/dsa/package (backend, indexer, kernels, metadata, cache manager, custom CUDA-graph-friendly ops, params).sparse/deepseek_v4/package (runtime-only metadata, backend/indexer/kernels/compressor, params).sparse/rocket.pytosparse/rocket/package; the monolithicrocket.pywas deleted and replaced by package modules (backend/cache_manager/kernels/metadata/params).SparseRuntimeParamsacross multiple backends and FMHA fallbacks, including SkipSoftmax threshold scaling fields..pre-commit-config.yaml,legacy-files.txt,pyproject.toml,ruff-legacy.toml.tok < 0, page-range check), not necessarily on all negative/out-of-range intermediates—verify assumptions aboutblock_table/pool-page validity.on_update_kv_lens()and CUDA-graph capture paths via custom ops; ensure buffer object identity/stability and cache revalidation are consistent.sparse/rocket/package and that any stale references to the removedrocket.pyare gone.forward_args.sparse_runtime_params(not legacy prediction/kernel-param paths), especially where multiple FMHA/FlashInfer/MSA backends branch on “sparse vs dense plan” decisions.QA Engineer Review
No test changes (no
tests/,tests/integration/test_lists/,test-db/,qa/, orwaives.txtmodifications detected in the diff evidence available here).Description
TensorRT-LLM already provides a sparse-attention framework for DSA, DeepSeek-V4,
RocketKV, and SkipSoftmax, but algorithm-specific module, backend, prediction,
metadata, cache, and kernel logic had become mixed across the common Attention
and MLA paths. That made the extension boundary inconsistent and required
changes to shared modules when adding or maintaining an algorithm.
This PR refactors sparse attention around explicit module and backend contracts:
optional sparse-attention hooks for module initialization, weights, forward,
custom-op execution, and output projection.
_torch/attention_backend/sparse/<algorithm>/.SparseBackendForwardArgscarries sparse inputs from Attention/MLA to theselected backend, while
SparseRuntimeParamscarries prediction andSkipSoftmax runtime inputs from the backend to the attention op.
the hooks it needs.
module.py,backend.py,params.py,metadata.py, cache/indexer helpers,and algorithm-owned kernels. SkipSoftmax keeps its existing FMHA integration
through the shared runtime parameters.
The refactor preserves dense MLA fallback behavior, DSA cross-layer indexer
sharing and piecewise CUDA graph support, DeepSeek-V4 compressed-cache paths,
RocketKV, MiniMax-M3 integration, and SkipSoftmax.
Test Coverage
main; a native rebuild is not required forthis refactor.
pre-commiton all files changed by this PR.70 passed.
worktree.
PR Checklist
Please review the following before submitting your PR:
PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.
Test cases are provided for new code paths (see test instructions)
If PR introduces API changes, an appropriate PR label is added - either
api-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin the PR title.Any new dependencies have been scanned for license and vulnerabilities
CODEOWNERS updated if ownership changes
Documentation updated as needed
Update tava architecture diagram if there is a significant design change in PR.
The reviewers assigned automatically/manually are appropriate for the PR.
Please check this after reviewing the above items as appropriate for this PR.
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.