Protein sequence and inverse folding
Autoregressive KV-cache append and causal attention
Evo 1ProGen2
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Append the supplied keys and values to each cache, then compute one value-weighted context for every valid query in the new chunk. Query t can use the old prefix and newly appended positions through t, so later new tokens cannot affect earlier contexts. Return the entire updated caches, their valid lengths, attention weights, and contexts.
Function signature
kv_cache_attention_step(
query: torch.Tensor,
new_key: torch.Tensor,
new_value: torch.Tensor,
key_cache: torch.Tensor,
value_cache: torch.Tensor,
lengths: torch.Tensor,
append_mask: torch.Tensor,
options: dict,
) -> dict[str, torch.Tensor]Worked example
Two queries see different prefixes
Use one batch and one query/KV head, scalar keys and values, capacity 4, old length 1, and queries [1,1]. Old key/value caches are [0,99,99,99] and [2,99,99,99]. Append keys [log(3),log(2)] and values [6,10], with both append slots True and scale 1. Updated caches are [0,log(3),log(2),99] and [2,6,10,99], with length 3. Query 0 has weights [1/4,3/4,0,0], so context is 5. Query 1 has weights [1/6,3/6,2/6,0], so context is 20/3 ≈ 6.666667. The stored tail value 99 affects neither query.
Parameters
| Parameter | Shape and meaning |
|---|---|
querytorch.Tensor | [B, \mathrm{Hq}, Q, D]Features at the positions requesting information. |
new_keytorch.Tensor | [B, \mathrm{Hk}, Q, D]Projected keys for the chunk being appended. |
new_valuetorch.Tensor | [B, \mathrm{Hk}, Q, \mathrm{Dv}]Projected values for the chunk being appended. |
key_cachetorch.Tensor | [B, \mathrm{Hk}, M, D]Previous key storage, with the active prefix specified by lengths. |
value_cachetorch.Tensor | [B, \mathrm{Hk}, M, \mathrm{Dv}]Previous value storage, with the active prefix specified by lengths. |
lengthstorch.Tensor | [B]Integer [B], old valid prefix. |
append_masktorch.Tensor | [B, Q]Contiguous True prefix per row. |
optionsdict | Scalar settings. Omitted keys use the defaults below. |
Return
dict[str, torch.Tensor]
Return exactly the named fields applicable to this operation.
Required behavior
query[B,H_q,Q,D],new_key[B,H_k,Q,D],new_value[B,H_k,Q,D_v],key_cache[B,H_k,M,D],value_cache[B,H_k,M,D_v]are finite floating with matching dtype/device.B,H_q,H_k,D,D_v,M\ge 1,Q\ge 0;H_qmust be a multiple ofH_k.- Query head
huses KV head\operatorname{floor}(h/(H_q/H_k));H_q=H_kis ordinary MHA. Inputs are already projected and, if required by the model, position-rotated. No projections or RoPE are performed here.lengths[B]integers specify the old valid cache prefix,0\le \mathrm{length}\le M. append_mask[B,Q]is bool and each row must be a prefix ofTruevalues followed byFalse. Its countnmust satisfy\mathrm{length}+n\le M. Writenew_key/value at positions\mathrm{length}+tonly forTrueappend slotst.- Return the entire updated cache, preserving every unwritten entry exactly (including unused tail storage); never modify inputs. Updated lengths are
\mathrm{length}+n.Avalid querytmay attend only cache slotsj\le \mathrm{old\_length}+tandj<\mathrm{new\_length}. Invalid query rows return zero attention/context. - Compute
\mathrm{scores}(q,k)=\mathrm{scale}\cdot \operatorname{dot}(q,k), with positive scale default1/\sqrt{D}, and a stable softmax on allowed keys. Returnattention[B,H_q,Q,M]andcontext[B,H_q,Q,D_v]=\mathrm{attention}\,\mathrm{updated\_values}. - Cache-tail values and future tokens cannot influence earlier query context even though the returned cache transports unused tail entries.
Q=0or rows withn=0preserve their cache/lengths and return empty/zero query outputs. scale is the onlykey. - No dropout, eviction, output projection or neural-model invocation is included; capacity overflow and non-prefix append masks are outside this contract.
Why this matters
Each batch item can have a different existing cache length. New queries see the old prefix and only the new entries up to their own step; grouped query heads share the corresponding key/value head.
Starter code
You write the body of this function in the BioTorch workspace. Your code runs in an isolated PyTorch sandbox; Run checks the public examples and Submit grades the full test suite, including gradients.
import torch
def kv_cache_attention_step(
query: torch.Tensor, # (B, Hq, Q, D)
new_key: torch.Tensor, # (B, Hk, Q, D)
new_value: torch.Tensor, # (B, Hk, Q, Dv)
key_cache: torch.Tensor, # (B, Hk, M, D)
value_cache: torch.Tensor, # (B, Hk, M, Dv)
lengths: torch.Tensor, # (B,)
append_mask: torch.Tensor, # (B, Q)
options: dict,
) -> dict[str, torch.Tensor]:
"""Return dict[str, torch.Tensor]:
key_cache: (B, Hk, M, D).
value_cache: (B, Hk, M, Dv).
lengths: (B,).
attention: (B, Hq, Q, M).
context: (B, Hq, Q, Dv)."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement kv_cache_attention_step")
Ready to implement it?
3 progressive hints, a solution walkthrough, and grading that checks values, shapes and gradients are waiting in the workspace.
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Sources and further reading
A primitive exercise, not an end-to-end reproduction of the named models. No affiliation or endorsement is implied.