Protein sequence and inverse folding
Constrained categorical sampling with tied positions
ProteinMPNNESM3Evo 1ProGen2
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Select one consistent token identity for each tied-position group under supplied class restrictions. Apply the configured filters and temperature, then return sampled tokens and their probability diagnostics.
Function signature
constrained_categorical_sampling(
logits: torch.Tensor,
temperature: torch.Tensor,
uniform: torch.Tensor,
tokens: torch.Tensor,
group_ids: torch.Tensor,
allowed: torch.Tensor,
parameters: dict,
masks: dict,
top_k: int = 0,
top_p: float = 1.0,
filter_order: str = 'before_temperature',
nucleus_rule: str = 'standard',
) -> dict[str, torch.Tensor]Worked example
Unequal member weights and intersected legal classes
Two editable positions belong to group 0. Class 1 is forbidden by the first member, leaving classes 0 and 2. Each member gives class 2 score \log3, and their weights are 1 and 3. Divide the weighted sum by two active members: class 2’s group score is (\log3+3\log3)/2=\log9; class 0’s is zero. Temperature 1 gives probabilities [0.1, 0, 0.9]. Uniform 0.75 passes class 0’s cumulative 0.1 and crosses at class 2, so both tokens become 2 and log_probability is \log0.9.
Parameters
| Parameter | Shape and meaning |
|---|---|
logitstorch.Tensor | [B, L, V]Unnormalized vocabulary scores for every sequence position. |
temperaturetorch.Tensor | [B, G]Nonnegative floating [B,G]; \mathrm{zero}=\mathrm{greedy}. |
uniformtorch.Tensor | [B, G]Supplied floating [B,G] in [0,1), discrete random variates. |
tokenstorch.Tensor | [B, L]Integer current [B,L]. |
group_idstorch.Tensor | [B, L]Only valid-position IDs must be in range. |
allowedtorch.Tensor | [B, L, V]True means legal class. |
parametersdict | Supplied model parameters, keyed as shown below. |
masksdict | Supplied masks. Each field below defines what True includes or permits. |
top_kintDefault 0 | Keep at most this many allowed classes by stable score rank. Zero disables top-k; a positive value must not exceed vocabulary size. |
top_pfloatDefault 1.0 | Nucleus probability threshold in (0,1]. One disables nucleus truncation; apply it after any top-k restriction. |
filter_orderstrDefault 'before_temperature' | Choose "before_temperature" to filter original group scores or "after_temperature" to filter temperature-scaled scores. |
nucleus_rulestrDefault 'standard' | "standard" keeps the first class crossing the threshold; "esm3" keeps only classes whose cumulative mass is at most the threshold, always retaining the top class. |
Return
dict[str, torch.Tensor]
Return exactly the named fields applicable to this operation.
Required behavior
logitsandbiasare finite floating[B,L,V],\mathrm{weights}[B,L]\ge 0,\mathrm{temperature}[B,G]\ge 0;B,G\ge 1,L\ge 0,V\ge 2.uniform[B,G]is supplied in[0,1), never drawn internally. All floats share dtype/device; all scaled scores/differences must be representable.group_ids[B,L]is in[0,G)on valid positions (arbitrary integers on padding).valid_mask,update_maskare bool[B,L];allowed[B,L,V]usesTruemeans legal class.tokens[B,L]are current integers: valid non-updatedpositions must have IDs in[0,V), while update/padding slots may carry arbitrary placeholders.- For group
g, members are valid positions with that group ID and active members additionally haveupdate_mask=True. Group scorez_vis the SUM over active members of\mathrm{weights\_i}\cdot (\mathrm{logits\_iv}+\mathrm{bias\_iv}), divided by the NUMBER of active members, not\sum(\mathrm{weights}). - Thus tied all-active positions with unit
weightsaverage theirlogits/biases. Legal classes are the INTERSECTION ofallowedsets over ALL members. - Every fixed (valid non-
updated) member additionally forces its current identity, so consistent fixed ties force a one-hot outcome; contradictory fixed identities or forbidden fixed identities leave empty support. Groups with no active members also have empty support. Configtop_kis0(default, no top-k) or an integer1..V. - Rank legal classes by descending score with smaller class ID breaking ties and retain
kif enabled. Configtop_pis in(0,1], default1. - If
\mathrm{top\_p}<1, softmax the FILTER scores on the top-k-retained support and applynucleus_rule: 'standard' (default) keeps each class whose cumulative mass before it is< p, including the first crossing class; 'esm3' keeps classes whose cumulative mass THROUGH them is\le pand always keeps the highest-ranked legal class, thus normally excluding the first crossing class. - For
p=1neither rule filters. Empty support stays empty under both rules. Configfilter_orderis 'before_temperature' (default, filterz) or 'after_temperature' (filterz/T). top-kalways precedes nucleus filtering. - For
T=0, usezfor filtering. After filtering,T>0yields\operatorname{softmax}(z/T);T=0yields a one-hot at the highest retainedz, ties to smaller ID. These are allkeys. - For
T>0, sample the first class in ORIGINAL ascending vocabulary order whose cumulative final probability is STRICTLY greater thanuniform. If roundoff leaves no crossing, choose the last positive-probability class. - Return
sampled[B,G](-1for empty support),probabilities[B,G,V],group_valid[B,G],\mathrm{log\_probability}[B,G]=\operatorname{log}(probability ofsampledclass) or0if empty, andupdated\mathrm{tokens}[B,L]/\mathrm{updated}[B,L]. - Only active positions in valid groups change; invalid groups leave
tokensunchanged, and all fixed/padding positions are preserved. Invalid-groupprobabilitiesare exactly zero. No in-place mutation. This is one categorical update from suppliedlogits, not a neural decoder or a source-specific random-number stream.
Why this matters
Tied positions share a decision, so their logits and allowed classes must be resolved at group level before a supplied random number selects a class.
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 constrained_categorical_sampling(
logits: torch.Tensor, # (B, L, V)
temperature: torch.Tensor, # (B, G)
uniform: torch.Tensor, # (B, G)
tokens: torch.Tensor, # (B, L)
group_ids: torch.Tensor, # (B, L)
allowed: torch.Tensor, # (B, L, V)
parameters: dict,
masks: dict,
top_k: int = 0,
top_p: float = 1.0,
filter_order: str = 'before_temperature',
nucleus_rule: str = 'standard',
) -> dict[str, torch.Tensor]:
"""Return dict[str, torch.Tensor]:
tokens: (B, L).
updated: (B, L).
sampled: (B, G).
group_valid: (B, G).
probabilities: (B, G, V).
log_probability: (B, G)."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement constrained_categorical_sampling")
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.