Protein sequence and inverse folding
Rotary positions for queries and keys
ESM-2ESM-CProGen2
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Rotate an even-width prefix of query and key channels using their own positions. Return rotated queries and keys while preserving the unrotated suffix exactly.
Function signature
rotary_position_embedding(
q: torch.Tensor,
k: torch.Tensor,
q_positions: torch.Tensor,
k_positions: torch.Tensor,
inverse_frequency: torch.Tensor,
options: dict,
) -> tuple[torch.Tensor, torch.Tensor]Worked example
Quarter-turn, half-turn, and unchanged suffix
The first query pair [1,2] rotates by pi/2 to [-2,1]; the second [3,4] rotates by pi to [-3,-4]. Its final channel remains 9. Key position 0 produces zero angles, so every key channel is unchanged.
import torch
q = torch.tensor([[[[1.0, 2.0, 3.0, 4.0, 9.0]]]], dtype=torch.float64, requires_grad=True)
k = torch.tensor([[[[2.0, 1.0, 4.0, 3.0, 8.0]]]], dtype=torch.float64, requires_grad=True)
q_positions = torch.tensor([[1]], dtype=torch.int64)
k_positions = torch.tensor([[0]], dtype=torch.int64)
inverse_frequency = torch.tensor([1.5707963267948966, 3.141592653589793], dtype=torch.float64, requires_grad=True)
options = {
'rotary_dim': 4,
'convention': 'adjacent',
}
result = rotary_position_embedding(q=q, k=k, q_positions=q_positions, k_positions=k_positions, inverse_frequency=inverse_frequency, options=options)Expected return
(torch.tensor([[[[-2.0, 1.0000000000000002, -3.0000000000000004, -3.9999999999999996, 9.0]]]], dtype=torch.float64), torch.tensor([[[[2.0, 1.0, 4.0, 3.0, 8.0]]]], dtype=torch.float64))Parameters
| Parameter | Shape and meaning |
|---|---|
qtorch.Tensor | [B, H, \mathrm{Lq}, D]Query features, already projected into heads. |
ktorch.Tensor | [B, H, \mathrm{Lk}, D]Key features, already projected into heads. |
q_positionstorch.Tensor | [B, \mathrm{Lq}]Positions, possibly repeated or offset. |
k_positionstorch.Tensor | [B, \mathrm{Lk}]Positions, possibly repeated or offset. |
inverse_frequencytorch.Tensor | [R/2]Frequencies, shared by q and k. |
optionsdict | Scalar settings. Omitted keys use the defaults below. |
Return
tuple[torch.Tensor, torch.Tensor]
Return these tensors in the stated order.
Required behavior
- Rotate the first
Rfeatures ofq[B,H,L_q,D]andk[B,H,L_k,D]without changing the suffix.B,H,L_q,L_k\,\ge \,1. Positions are supplied separately as integerq_positions[B,L_q]andk_positions[B,L_k]; different lengths and offsets model cached keys. inverse_frequency[R/2]is supplied, shared by both tensors, and has their floating dtype/device. All tensor values are finite. Config:rotary_dimRdefaults toDand must be even with2\,\le \,R\,\le \,D;conventionis'half_split'(default) or'adjacent'. There are no otheroptions.- For pair
r,\theta[b,t,r]\,=\,\mathrm{positions}[b,t]\,\cdot \,\mathrm{inverse\_frequency}[r]. Half-split pairs coordinates(r,\,r+R/2); adjacent pairs(2r,\,2r+1). - In either
convention,(a,b)\,\mapsto \,(a\cdot \cos(\theta)-b\cdot \sin(\theta),\,a\cdot \sin(\theta)+b\cdot \cos(\theta)). Do not mix the two pair layouts or reverse the sine sign. Angles broadcast overH, not across positions or batches. - The suffix x[..., R:] is unchanged.
Why this matters
RoPE turns position into an angle and rotates feature pairs. Queries and keys can have different lengths and positions; the shared frequencies determine how quickly each pair rotates.
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 rotary_position_embedding(
q: torch.Tensor, # (B, H, Lq, D)
k: torch.Tensor, # (B, H, Lk, D)
q_positions: torch.Tensor, # (B, Lq)
k_positions: torch.Tensor, # (B, Lk)
inverse_frequency: torch.Tensor, # (R/2)
options: dict,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Return tuple[torch.Tensor, torch.Tensor]:
q_rotated: (B, H, Lq, D).
k_rotated: (B, H, Lk, D)."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement rotary_position_embedding")
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.