Foundations

Masked Softmax

EasyRaw PyTorchAbout 10 min2 public examples plus private tests

OpenFoldESM-2ESM-1v

Write and run your solution Sign in

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

Your task

Turn each set of included scores along dim into probabilities: exponentiate the scores and divide by the sum of their included exponential weights. Each output entry is that score’s share of the total; excluded entries are zero.

Function signature

masked_softmax(
    logits: torch.Tensor,
    mask: torch.Tensor,
    dim: int = -1,
) -> torch.Tensor

Worked example

Unequal included scores

Take logits=[0,1,100], mask=[True,True,False] and dim=0. Only exponential weights 1 and e participate; the masked score 100 is excluded even from the denominator. The probabilities are [1/(1+e), e/(1+e), 0] ≈ [0.268941, 0.731059, 0]. They add to one over the included entries.

Parameters

ParameterShape and meaning
logitstorch.Tensor[\mathrm{d0}, \ldots, d(R-1)]Finite scores to normalize.
masktorch.TensorAny shape broadcastable to logits.shape.True includes a score; False excludes it from the numerator and denominator.
dimintDefault -1One integer normalization axis; negative indices count from the end.

Return

torch.Tensor · Exactly logits.shape.

A tensor with exactly logits.shape. Each slice along dim contains normalized probabilities at included entries and zero at excluded entries; an entirely masked slice is all zero.

Required behavior

  • logits has rank at least one; mask is Boolean and must broadcast to exactly logits.shape. True includes a score. dim is one integer axis (default -1); negative axes count from the end. A slice fixes every index except dim.
  • For a nonempty included set V, let a be its largest score and Z = sum(exp(logits[i]-a) for i in V). Subtract this included maximum before exponentiating; masked scores contribute neither exponential weight nor normalizer.
  • Return exp(logits[i]-a)/Z at included entries and exact zero elsewhere. An all-masked slice is all zero. A zero-length normalization axis returns an empty tensor with logits.shape.
  • Use no epsilon, probability clipping or probability floor. Empty-support outputs have zero gradients. Preserve the shared CPU float32/float64 dtype and device, accept noncontiguous inputs, and do not mutate inputs.
  • 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

Subtracting a valid maximum controls exponent size; an explicit empty-row branch prevents an all-masked input from becoming NaN or a uniform distribution.

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 masked_softmax(
    logits: torch.Tensor,  # (d0, ..., d(R-1))
    mask: torch.Tensor,  # Any shape broadcastable to logits.shape.
    dim: int = -1,
) -> torch.Tensor:
    """Return a tensor with shape logits.shape."""
    # Implement the operation. Inputs and test setup are supplied by BioTorch.
    raise NotImplementedError("Implement masked_softmax")

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.