MSA and pair representations

Noisy Atom Pair Features

HardRaw PyTorchAbout 30 min1 public example plus private tests

AlphaFold3

Write and run your solution Sign in

Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.

Your task

Build reference-space conditioning for each query atom and supplied key slot, then separately add the projected noisy coordinates to the returned atom features. The noisy branch changes atom_features; query_condition, key_condition, and pair features retain their reference-conditioning values. Return pair vectors before and after the residual MLP with these diagnostics.

Function signature

af3_noisy_atom_pair_features(
    activations: dict,
    parameters: dict,
    masks: dict,
    structure: dict,
) -> dict[str, torch.Tensor]

Worked example

Worked example

Reference-space pair features are [[6, 6], [7, 9]] before the residual MLP. Three half-scale projections add one eighth of each positive pair feature. Noisy positions change atom_features to [1.5, 3], while query_condition remains [1, 2].

import torch

activations = {
    'x': torch.tensor([[[1.0], [2.0]]], dtype=torch.float64, requires_grad=True),
}
parameters = {
    'row_weight': torch.tensor([[1.0]], dtype=torch.float64, requires_grad=True),
    'col_weight': torch.tensor([[2.0]], dtype=torch.float64, requires_grad=True),
    'offset_weight': torch.tensor([[1.0], [0.0], [0.0]], dtype=torch.float64, requires_grad=True),
    'distance_weight': torch.tensor([[2.0]], dtype=torch.float64, requires_grad=True),
    'valid_weight': torch.tensor([[1.0]], dtype=torch.float64, requires_grad=True),
    'pair_mlp_weight': torch.tensor([[[0.5]], [[0.5]], [[0.5]]], dtype=torch.float64, requires_grad=True),
    'noisy_weight': torch.tensor([[0.5], [0.0], [0.0]], dtype=torch.float64, requires_grad=True),
}
masks = {
    'mask': torch.tensor([[True, True]], dtype=torch.bool),
    'window_mask': torch.tensor([[[True, True], [True, True]]], dtype=torch.bool),
}
structure = {
    'ref_positions': torch.tensor([[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]]], dtype=torch.float64, requires_grad=True),
    'ref_space_uid': torch.tensor([[0, 0]], dtype=torch.int64),
    'key_index': torch.tensor([[[0, 1], [0, 1]]], dtype=torch.int64),
    'noisy_positions': torch.tensor([[[1.0, 0.0, 0.0], [2.0, 0.0, 0.0]]], dtype=torch.float64, requires_grad=True),
}

result = af3_noisy_atom_pair_features(activations=activations, parameters=parameters, masks=masks, structure=structure)

Expected return

{
    'query_condition': torch.tensor([[[1.0], [2.0]]], dtype=torch.float64),
    'key_condition': torch.tensor([[[[1.0], [2.0]], [[1.0], [2.0]]]], dtype=torch.float64),
    'atom_features': torch.tensor([[[1.5], [3.0]]], dtype=torch.float64),
    'offset_mask': torch.tensor([[[True, True], [True, True]]], dtype=torch.bool),
    'pair_features': torch.tensor([[[[6.0], [6.0]], [[7.0], [9.0]]]], dtype=torch.float64),
    'output': torch.tensor([[[[6.75], [6.75]], [[7.875], [10.125]]]], dtype=torch.float64),
}

Parameters

ParameterShape and meaning
activationsdictSupplied intermediate tensors.
parametersdictSupplied model parameters, keyed as shown below.
masksdictSupplied masks. Each field below defines what True includes or permits.
structuredictFields supplied together in this dictionary.

Return

dict[str, torch.Tensor]

Return exactly the named fields applicable to this operation.

Required behavior

  • x is [B,A,C]; mask marks valid atoms. key_index [B,A,K] chooses atom slots per query, and window_mask marks allowed slots. A slot requires valid query/key atoms, an in-range index, and window_mask=True; repeated keys stay repeated.
  • Begin with cleaned x as query_condition.
  • Gather key_condition at each slot. Initial pair features are ReLU(query_condition) @ row_weight plus ReLU(key_condition) @ col_weight.
  • Offsets point from key to query: r_i-r_j. Add offset @ offset_weight plus 1/(1+\|offset\|^2) @ distance_weight only when the allowed atoms share ref_space_uid. Also add offset_mask (as a scalar feature) @ valid_weight.
  • Pass pair_features through three consecutive ReLU-then-matrix-product stages using pair_mlp_weight[0], [1], [2], then add this result to pair_features as a residual. No stage has a bias.
  • Return zero key_condition/pair_features/output for disallowed slots, zero atom_features for invalid atoms, and boolean offset_mask. query_condition is the cleaned atom condition.
  • atom_features adds noisy_positions @ noisy_weight to query_condition after cleaning invalid noisy coordinates. This addition does not change query_condition, key_condition, or pair features.
  • Use CPU float32/float64 tensors with one shared floating dtype/device. Preserve strided layouts and do not mutate supplied tensors.
  • Use raw tensor operations, not a ready-made implementation of the requested primitive. Supplied parameters and random variates must not be reinitialized.

Why this matters

AF3 combines atom conditions with geometry only when reference coordinates share a common space. Noisy coordinates update atom features separately, so pair conditioning stays tied to the reference conformer.

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 af3_noisy_atom_pair_features(
    activations: dict,
    parameters: dict,
    masks: dict,
    structure: dict,
) -> dict[str, torch.Tensor]:
    """Return dict[str, torch.Tensor]:
    
    pair_features: (B,A,K,P).
    output: (B,A,K,P).
    query_condition: (B, A, C).
    key_condition: (B, A, K, C).
    offset_mask: (B, A, K).
    atom_features: (B, A, C)."""
    # Implement the operation. Inputs and test setup are supplied by BioTorch.
    raise NotImplementedError("Implement af3_noisy_atom_pair_features")

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.

Related exercises

Sources and further reading

A primitive exercise, not an end-to-end reproduction of the named models. No affiliation or endorsement is implied.