Repository navigation
[dev] Make fused CSA Top-K deterministic across no-grad and grad forwards #7169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
20cbd65
6e5d9ce
4edec16
92473a3
c78fef6
f6802bc
e79f16f
6fc209b
003e334
da81780
b57ad25
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ | |
| BSHDCompactIndexerWorkspace, | ||
| FusedCSAIndexerSparseAttnFromTopkFunc, | ||
| THDCompactIndexerWorkspace, | ||
| _compact_flat_topk_idxs, | ||
| batch_of_row, | ||
| bshd_compact_indexer_available, | ||
| build_flat_topk_idxs, | ||
|
|
@@ -2238,8 +2239,13 @@ def _forward_fused_indexer_inference( | |
| deterministic=self.config.deterministic_mode, | ||
| ) | ||
| compress_topk_idxs = torch.where(topk_indices_cmp >= 0, topk_indices_cmp + offset, -1) | ||
| # Same lowering as ``FusedCSAIndexerSparseAttnFunc.forward`` (the | ||
| # grad-enabled path): compressed ids, then window ids, globalized and | ||
| # compacted. FlashMLA's online softmax accumulates in key order, so a | ||
| # forward-only pass reproduces the training forward only if it hands | ||
| # the kernel the same id sequence. | ||
| flat_idxs, flat_tlen = build_flat_topk_idxs( | ||
| window_idxs, compress_topk_idxs, batch_size=b, compact=True | ||
| compress_topk_idxs, window_idxs, batch_size=b, compact=True | ||
| ) | ||
| nvtx_range_pop("compressed_indices") | ||
|
|
||
|
|
@@ -2692,6 +2698,17 @@ def _forward_fused_indexer_inference_thd( | |
| deterministic=self.config.deterministic_mode, | ||
| ) | ||
|
|
||
| # ``build_attention_indices`` has two output layouts. Its default puts | ||
| # window ids first and returns the list already compacted with a | ||
| # ``topk_length``. Its indexer-loss layout puts the compressed ids | ||
| # first at fixed positions (so the grad-enabled path can slice the | ||
| # window segment for the dense teacher) and leaves compaction to the | ||
| # caller, returning ``None`` for the length. The grad-enabled path in | ||
| # ``FusedCSAIndexerSparseAttnFunc.forward`` uses the latter; take the | ||
| # same layout here and compact it ourselves so both forwards hand | ||
| # FlashMLA an identical id sequence. With no compressed ids the two | ||
| # layouts coincide, so keep the default and its precomputed length. | ||
| compressed_first = topk_indices_cmp.shape[-1] > 0 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question as above @hxbai
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some history from the tree while waiting for @hxbai: window-first goes back to #4894 (Part 4: Fusion Kernels). The eager reference there did |
||
| flat_idxs, flat_tlen, _, _ = thd_layout_kernels.build_attention_indices( | ||
| cu_seqlens_q, | ||
| 0, | ||
|
|
@@ -2702,11 +2719,14 @@ def _forward_fused_indexer_inference_thd( | |
| topk_indices_cmp.shape[-1], | ||
| topk_indices_cmp, | ||
| cu_seqlens_compressed=cu_seqlens_compressed, | ||
| for_indexer_loss=compressed_first, | ||
| compressed_base=compressed_base, | ||
| compressed_rows=compressed_rows, | ||
| compressed_is_sequence_major=True, | ||
| output_alignment=get_flash_mla_topk_alignment(), | ||
| ) | ||
| if compressed_first: | ||
| flat_idxs, flat_tlen = _compact_flat_topk_idxs(flat_idxs) | ||
| output = csa_sparse_attn( | ||
| query, | ||
| kv_full_thd, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hxbai Do you remember why the no-grad path originally placed window indices before compressed indices, while the training path used the opposite order? Was there a specific reason or constraint behind that difference that we should consider before aligning them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some history from the tree while waiting for @hxbai: window-first goes back to #4894 (Part 4: Fusion Kernels). The eager reference there did
torch.cat([window_idxs, compress_topk_idxs]), and the fused inference path passed the same order tobuild_flat_topk_idxs(window_idxs, compress_topk_idxs); for the eager/dense reference the order is immaterial, so nothing there depended on it. Compressed-first on the grad path comes from the indexer loss:FusedCSAIndexerSparseAttnFunc.forwardneeds the compressed ids at fixed positions (for_indexer_loss=True) so it can slice that segment for the dense teacher. I found no comment or commit message treating window-first as a constraint; the only observable effect of the difference is FlashMLA's accumulation order, which is what this PR aligns.