Protein sequence and inverse folding

Rotary positions for queries and keys

MediumRaw PyTorchAbout 20 min2 public examples plus private tests

ESM-2ESM-CProGen2

Write and run your solution Sign in

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

ParameterShape 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.
optionsdictScalar 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 R features of q[B,H,L_q,D] and k[B,H,L_k,D] without changing the suffix. B,H,L_q,L_k\,\ge \,1. Positions are supplied separately as integer q_positions[B,L_q] and k_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_dim R defaults to D and must be even with 2\,\le \,R\,\le \,D; convention is 'half_split' (default) or 'adjacent'. There are no other options.
  • 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 over H, 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.

Write and run your solution Sign in

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.