Skip to content

[DSV4][ROCm] Reuse C4 and native quantization for separate Indexer compression (task 20) - #624

Open
inaniloquentee wants to merge 3 commits into
dsv4-rocmfrom
feat/dsv4-indexer-c4-bi
Open

inaniloquentee wants to merge 3 commits into
dsv4-rocmfrom
feat/dsv4-indexer-c4-bi

Conversation

@inaniloquentee

Copy link
Copy Markdown
Collaborator

Roadmap task 20 ??separate Indexer C4 compression

Dependency: stacked on task 19 / #618 at 879305251c37e1b8bb0cb44409f1762752d03561. Merge #618 first. The target remains dsv4-rocm as requested. The task-20-only change is commit e61f5eeaff5f46042b381657abe0a5dd213154c9; until #618 merges, the base diff also includes that prerequisite.

Reuse instead of another compressor implementation

  • Reuse the shared C4 grouping, global positions, CP final-token ownership, paged output mapping, mutation/version checks and RLK canonical backward session.
  • Add an independent typed 128-dimensional Indexer profile; main-KV remains 512-dimensional. Misused contracts, parameters and bound data are rejected; gradient namespaces are distinct even with the same caller layer ID.
  • Call existing aiter flydsl_fused_compress_attn and native rotate_activation, aiter MXFP4 quantization, and vLLM power-of-two FNUZ FP8 quantization. No new numerical GPU kernel or generic-matmul Hadamard fallback.
  • Pad both native Hadamard buffers to eight physical rows to respect the installed gfx942 kernel's tail-access behavior. Trim logical rows afterwards; dedicated canary/live-output tests cover tails.
  • Training and rollout return identical BF16 values, quantized bytes and scales. Quantization is explicitly detached, not an implicit STE; the full quantized Indexer VJP is task 26.

MI300X acceptance

Fresh member environment: Torch 2.11.0+gitd0c8b1f, HIP 7.2.53211, Triton 3.6.0, aiter 0.1.16.post3, FlyDSL 0.2.0, vLLM 0.26.0+rocm723.

  • 296 passed twice, zero failures/errors/skips (57.56s with coverage; independent repeat 44.91s).
  • 25 item-20 CPU tests, 44 real GPU tests, 85 main-C4 regressions and 142 existing operator-contract tests.
  • Exact bytes across batching/chunks/permutations/padding/CP materializations, train/rollout, page boundaries and fresh processes.
  • Actual native H-transpose + mLite VJP, exact microbatch/reverse-order gradient comparisons, genuine FP64 reference and parameter finite differences.
  • Main/Indexer state and gradient isolation, streams, inference/empty inputs, mutation/Graph rejection, native tail allocation safety.
  • Fifty repeated calls: live GPU allocation unchanged. Lint/format passed.
  • Python statement coverage 463/505 (91.68%), branches 82/92 (89.13%); native instruction coverage is not claimed.

Documentation: docs/models/deepseek_v4/indexer-compressor-c4.md.
Full report and synchronized benchmark: reports/indexer-compressor-c4-mi300x-20261029.md.

Explicit limits

No live cache lifecycle/commit (task 22), quantized STE/full Indexer training chain (task 26), Graph/runtime integration (task 27), actual RCCL/multi-GPU CP, multi-node or full-model acceptance is claimed. These opt-in framework adapters expose a common operator boundary, not complete model registration. No end-to-end speedup claim.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1fd3a0e4-e244-4969-aa1d-cd74d9113a02

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

🔍 OpenCodeReview found 8 issue(s) in this PR.

  • ✅ Successfully posted inline: 3 comment(s)
  • 📋 Routed to summary by policy: 5 comment(s)

⚠️ 4 warning(s) occurred during review.


maintainability · medium

📄 rl_engine/models/deepseek_v4/indexer_compressor_c4.py (L63-L64)

⚠️ GitHub could not post this as an inline comment: Routed to summary (severity medium · category maintainability)

The non-fp4 branch is treated as implicit "fp8", but the contract (IndexerC4Contract) separates precision from layout and only validates precision in ("mxfp4", "fp8"). Using precision == "mxfp4" as the discriminator for width/dtype means any future precision added to the contract (or a subclass relaxing it) silently falls into the FP8 branch and fails the shape/dtype require with a confusing message. Prefer an explicit if precision == "mxfp4" / elif precision == "fp8" / else: raise mapping so the layout assumption is stated and unsupported precisions fail with a precise diagnostic instead of a layout mismatch.


bug · medium

📄 rl_engine/backends/rocm/attention/kv_compressor_c4.py (L89-L89)

⚠️ GitHub could not post this as an inline comment: Routed to summary (severity medium · category bug)

The cache is allocated with torch.empty and only the slots addressed by bound.cache_slots_host are written by the kernel; torch.stack([cache[block, slot] ...]) then reads those slots. There is no assertion that every (block, slot) is within blocks and was actually written by the kernel, nor that block_table bounds match blocks. Reading unwritten slots returns uninitialized GPU memory and yields nondeterministic forward output. Either assert the slot invariants or zero-initialize the cache so unwritten slot reads are deterministic.


bug · low

📄 rl_engine/backends/rocm/attention/kv_compressor_c4.py (L84-L88)

⚠️ GitHub could not post this as an inline comment: Routed to summary (severity low · category bug)

The early-out only checks groups, but subsequent logic (max(... default=-1) + 1 and torch.stack over bound.cache_slots_host) requires cache_slots_host to be non-empty and aligned with logical_keys. If logical_keys is non-empty while cache_slots_host is empty, blocks becomes 0, torch.empty((0, 64, dim)) is allocated, and torch.stack([]) raises. Consider guarding on/validating cache_slots_host cardinality here.


maintainability · medium

📄 rl_engine/backends/rocm/attention/indexer_compressor_c4.py (L65-L65)

⚠️ GitHub could not post this as an inline comment: Routed to summary (severity medium · category maintainability)

_rotate hard-codes 128 both here and implicitly via source[:rows].copy_(values) (which requires values.shape[1] == 128). Any compressed tensor from super().forward with a different feature extent will fail the copy with a shape error, and there is no assertion documenting the invariant. Please assert values.shape[1] == 128 (or derive the width from values.shape[1]) so the failure mode is explicit rather than a broadcast/copy error.


bug · low

📄 rl_engine/backends/rocm/attention/indexer_compressor_c4.py (L38-L39)

⚠️ GitHub could not post this as an inline comment: Routed to summary (severity low · category bug)

Priming the native kernel via self._rotate(dummy) relies on self.rotate_activation having the (dest, src) argument order, which is never validated (only callable/attribute existence is implicitly assumed via import). If the installed aiter ABI changes the signature, priming either no-ops or compiles a wrong specialization while the provenance hash is still computed, defeating the stated "priming before fingerprint" guarantee. At minimum verify the call succeeded produces a numerically expected result, or validate the entrypoint signature before priming.


⚠️ Warnings:

  • rl_engine/models/deepseek_v4/indexer_compressor_c4.py,rl_engine/models/deepseek_v4/kv_compressor_c4.py (review_limit_reached): reached the aggregate token budget before finishing; the grace round did not complete the task
  • rl_engine/contracts/operators/indexer_compressor_c4.py,rl_engine/contracts/operators/kv_compressor_c4.py (review_limit_reached): reached the aggregate token budget before finishing; the grace round completed the task
  • rl_engine/integrations/common/indexer_compressor_c4.py (token_budget_reached): stopped dispatch: used 648393 tokens + group estimate 45320 = projected 693713 exceeds budget 500000
  • rl_engine/backends/rocm/attention/indexer_compressor_c4.py,rl_engine/backends/rocm/attention/kv_compressor_c4.py (review_limit_reached): reached the aggregate token budget before finishing; the grace round did not complete the task


def vjp(self, bound, ape, norm, cos, sin, grad, contract):
contributions, ape_rows, norm_rows = [], [], []
cache = torch.cat((cos, sin), dim=-1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · high
cos/sin are produced for the forward path, where the kernel consumes them via cos_cache/sin_cache. Reusing them here concatenated on the last dim and passing to the pinned functional assumes an exact layout (cat vs interleave) that is not validated anywhere. If the functional expects interleaved RoPE (or a different concat order), the VJP silently computes gradients for the wrong rotation basis while forward remains correct, producing a wrong-but-plausible backward. Please confirm the expected cache layout from the pinned compressed_compact_graph signature and assert it here.

eps=contract.rms_eps,
)
if group > 0:
grad_out = torch.cat((torch.zeros_like(y[:1]), grad[index : index + 1].float()))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · high
The cotangent layout is built by hard-coded concatenation: for group > 0 a single zero row is prepended and one grad row is passed, while for group == 0 the prefix is context[:4] and the zero padding is 4 rows. Neither the number of rows produced by functional nor the prefix extent is checked against group/ratio/contract, so any mismatch (e.g. a different prefix width or a functional returning group rows instead of group+1) yields a shape error or, worse, a silently misaligned gradient. Add an explicit assertion on y.shape[0] (and on len(grad) == len(bound.logical_keys)) before building grad_out.

Comment on lines +163 to +169
if group > 0 and (request, group - 1) not in complete:
incomplete.append(key)
continue
if entries[3][1] != rank:
unowned.append(key)
continue
selected.append(key)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · high
The predecessor-completeness check uses complete (offset completeness only), while ownership is checked separately only for the current group. With cp_size>1, a group whose predecessor is complete but owned by another rank passes this check and is selected; its previous context indices are then taken from complete[(request, group-1)][offset][0] (lines 187-191), i.e. physical rows that belong to a different rank's shard. In the distributed path this silently reads unmaterialized/garbage rows (or rows that do not exist on this rank) and produces wrong overlap state for every group that follows an unowned group. The ownership test should also be applied to the predecessor before allowing selection (e.g. require entries[3][1] == rank for (request, group-1) too, otherwise treat the group as unowned/not selectable so it is emitted later by the owning rank once its context is available).

@github-actions

Copy link
Copy Markdown

@inaniloquentee The automated OCR review has completed.

Please review and address all automated review bot findings, then push your updates. Maintainers will begin manual review after the bot findings have been addressed.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant