RosettaCommons / RosettaCommons/foundry

[BUG] function get_sparse_attention_indices_with_inter_chain in RFD3

Open
#176 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug RFdiffusion3
Dominant language
Python
Stars
966
Forks
181
Avg merge
4d 4h
Merged PRs (30d)
2

Description

Hi all,

I was using the code with LOW_MEMOY_MODE activated when I think I have spotted a bug in how the attention indices for the inter-chain atoms are determined. As a context, I am generating a protein with Icosahedral symmetry where each Asymmetric Subunit (chain) has 40 AA. There are a total of 60 symmetrical chains in the Icosahedral symmetry

Currently, the function get_sparse_attention_indices_with_inter_chain inside models/rfd3/src/rfd3/model/layers/block_utils.py does

for c in unique_chains: 
    query_chain = chain_id[c]
    other_chain_mask = (chain_id != query_chain) & base_mask[c, :]

So the bug is:

  • Loop iterates over chain IDs (0, 1, 2, ..., 59)
  • Uses those as atom indices (chain_id[c], base_mask[c, :])
  • Only atoms 0-59 get inter-chain neighbors computed
  • Atoms 60-33599 are never processed by this loop, so they get zeros in their inter-chain slots

Therefore, I think the loop should iterate over all query atoms (0 to L-1), not over chain IDs.

My proposed fix for this whole function is the following:

@torch.no_grad()
def get_sparse_attention_indices_with_inter_chain(
    tok_idx, D_LL, n_seq_neighbours, k_intra, k_inter, chain_id, base_mask
):
    """
    Create attention indices that guarantee inter-chain interactions for clash avoidance.

    Args:
        tok_idx: atom to token mapping [L]
        D_LL: pairwise distances [B, L, L]
        n_seq_neighbours: number of sequence neighbors
        k_intra: number of intra-chain attention keys
        k_inter: number of inter-chain attention keys
        chain_id: chain IDs for each atom [L]
        base_mask: base mask for valid pairs [L, L]

    Returns:
        attn_indices: [B, L, k_total] where k_total = k_intra + k_inter
    """
    B, L, _ = D_LL.shape
    device = D_LL.device

    # Get regular intra-chain indices (limited to k_intra)
    intra_indices = get_sparse_attention_indices(
        tok_idx, D_LL, n_seq_neighbours, k_intra, chain_id, base_mask
    )  # [B, L, k_intra]

    # Get inter-chain indices for clash avoidance - VECTORIZED
    inter_indices = torch.zeros(B, L, k_inter, dtype=torch.long, device=device)

    for b in range(B):
        # Build inter-chain mask for ALL query atoms at once: [L, L]
        # other_chain_mask[q, j] = True if chain_id[j] != chain_id[q] AND base_mask[q, j]
        same_chain = chain_id[:, None] == chain_id[None, :]  # [L, L]
        other_chain_mask = ~same_chain & base_mask  # [L, L]

        # Set distances for same-chain (and disallowed) pairs to inf
        D_inter = D_LL[b].clone()  # [L, L]
        D_inter[~other_chain_mask] = float('inf')

        # Get k_inter closest atoms from other chains for ALL atoms
        # torch.topk with largest=False gets the k smallest values
        _, inter_idx = torch.topk(D_inter, k_inter, dim=-1, largest=False)  # [L, k_inter]
        
        inter_indices[b] = inter_idx

    # Combine intra and inter chain indices
    combined_indices = torch.cat(
        [intra_indices, inter_indices], dim=-1
    )  # [B, L, k_total]

    return combined_indices

It would be great if someone could have a look at this and let me know what they think!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in models/rfd3/src/rfd3/model/layers/block_utils.py at get_sparse_attention_indices_with_inter_chain and trace how chain_id, base_mask, and D_LL define the returned indices. Reproduce the low-memory icosahedral case with 60 chains of 40 residues each, then verify that inter-chain slots are populated for all query atoms rather than only the first chain IDs.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, pytorch
Domain
machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.