Skip to content

Add functional update_and_attend KV-cache op + reference cache#21112

Merged
kiymetakdemir merged 5 commits into
pytorch:mainfrom
kiymetakdemir:update-and-attend-op-phase1
Jul 23, 2026
Merged

Add functional update_and_attend KV-cache op + reference cache#21112
kiymetakdemir merged 5 commits into
pytorch:mainfrom
kiymetakdemir:update-and-attend-op-phase1

Conversation

@kiymetakdemir

Copy link
Copy Markdown
Contributor

Summary
Adds a neutral kvcache::update_and_attend custom op for KV-cache attention. The op is functional to the tracer with the cache held off-graph via a process-global registry, so the exported .pte does not bake in cache size etc. Ships an eager reference cache (ContiguousReferenceCache) with runtime-selectable static/dynamic sizing and a hard capacity bound.

  • op_update_and_attend.py (new) — the kvcache::update_and_attend custom op and the off-graph cache registry
    (install_cache/set_active/uninstall_cache).
  • op_update_and_attend_reference.py (new) — CacheConfig/AttendSpec and ContiguousReferenceCache (update_and_fetch, static/dynamic sizing, hard capacity) plus the neutral attend SDPA mechanism.
  • test_update_and_attend.py (new) — functional-graph + prefill/decode parity tests across static and dynamic sizing.
  • targets.bzl (modified) — adds the update_and_attend_py python_library.
  • BUCK (modified) — adds the test_update_and_attend python_test.

Test plan
pytest -v extension/llm/custom_ops/test_update_and_attend.py
Verifies the exported graph is functional (no buffer inputs/mutations, one op call per layer) and that outputs match cacheless causal attention for prefill and incremental decode under both static and dynamic sizing.

@pytorch-bot

pytorch-bot Bot commented Jul 22, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21112

Note: Links to docs will display an error until the docs builds have been completed.

❗ 1 Active SEVs

There are 1 currently active SEVs. If your PR is affected, please view them below:

✅ No Failures

As of commit 265ed7d with merge base 3ba685e (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 22, 2026
@github-actions

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

Comment thread extension/llm/custom_ops/op_update_and_attend_reference.py Outdated
Comment thread extension/llm/custom_ops/BUCK Outdated
],
)

fbcode_target(_kind = runtime.python_binary,

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.

Looks like you need to rebase?

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.

Fixed this.

from executorch.extension.llm.custom_ops.op_update_and_attend_reference import attend

_REGISTRY: Dict[str, object] = {}
_CURRENT_KEY: Optional[str] = None

@metascroy metascroy Jul 22, 2026

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 know this is just a python reference, but maybe wrap this in a CacheRegistry class for neatness?

scale: float,
out_dtype: torch.dtype,
) -> torch.Tensor:
return torch.empty_like(q, dtype=out_dtype)

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 this the right shape? Shouldn't final dim be based on v? See https://docs.pytorch.org/docs/2.13/generated/torch.nn.functional.scaled_dot_product_attention.html

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.

You are right, attn_weight is [B, H, q_len, k_len] and value is [B, H, k_len, D_v], so attn_weight @ value is [B, H, q_len, D_v].



@torch.library.custom_op("kvcache::update_and_attend", mutates_args=())
def update_and_attend(

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.

Can we have a doc string describing shape of each arg?

For example, the op should natively handle GQA, so make sure q/k/v shapes are described as such

k = k.repeat_interleave(rep, dim=1)
v = v.repeat_interleave(rep, dim=1)

qf = q.to(torch.float32)

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.

Why not use F.scaled_dot_product_attention?

Comment thread extension/llm/cache/test_update_and_attend.py
def _export(self, seq_len):
x = torch.randn(1, seq_len, self.hidden)
pos = _positions(0, seq_len)
idx = torch.arange(seq_len, dtype=torch.long)

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.

Can we run functionalization on the graph? Sometimes export succeeds where functionalization fails (as an aside, ET always runs functionalization):

ep = ep.run_decompositions({})

with self.subTest(sizing=sizing):
cache = ContiguousReferenceCache(self._config(sizing, cap))
install_cache(self.cache_key, cache)
set_active(self.cache_key)

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.

What is difference between set_active and install?

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.

install registers a cache under a key once (at creation), while active selects which installed cache the op uses for a given forward. They look identical with one cache, but distinct with multi-sequence, where we install each once and switch active per step.

@@ -0,0 +1,224 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.

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.

Make sure this is run by the unittest job in CI (look at raw logs to confirm)

@@ -0,0 +1,167 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.

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 take it this is just an example implementation?

At runtime we do not have to use things like AttendSpec for implementation?

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.

Correct, and for the contiguous cases here the mask is always causal so it is not really functional now, I put it to use later for explicit but I can drop it for simplicity.

@kiymetakdemir
kiymetakdemir force-pushed the update-and-attend-op-phase1 branch from c47a9f3 to 8c72c6b Compare July 22, 2026 17:52
@metascroy

Copy link
Copy Markdown
Contributor

Looks good! Thinking ahead to where c++ stuff will live, maybe it's better to move these files to a dedicated export/llm/cache folder.

Also mark as experimental

@kiymetakdemir
kiymetakdemir merged commit 3389d51 into pytorch:main Jul 23, 2026
297 of 298 checks passed
@kiymetakdemir
kiymetakdemir deleted the update-and-attend-op-phase1 branch July 23, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants