Foundations · INTEGRATION
Stable categorical and binary classification losses
OpenFoldESM-2DNABERTESM-1b
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Compute categorical or binary cross-entropy directly from logits. Apply the supplied masks and weights, then return per-target losses, their sum, or their globally weighted mean.
Function signature
stable_classification_loss(
logits: torch.Tensor,
targets: torch.Tensor,
mask: torch.Tensor | None = None,
weights: torch.Tensor | None = None,
variant: str = 'categorical',
reduction: str = 'mean',
dim: int = -1,
eps: float = 1e-08,
ignore_index: int = -100,
) -> torch.TensorWorked example
A correct target with probability three quarters
Categorical mode: logits=[[0,log(3)]], targets=[1], reduction="none", with mask/weights omitted, returns [−log(3/4)] ≈ [0.287682]. Binary mode: logits=[log(3),log(3)], targets=[1,0], reduction="none" returns approximately [0.287682,1.386294]. Categorical classes compete in one softmax; binary entries are independent sigmoid predictions. eps changes only a mean denominator, so it does not enter either calculation.
Parameters
| Parameter | Shape and meaning |
|---|---|
logitstorch.Tensor | Categorical: any shape with class axis dim of size C \ge 1. Binary: exactly targets.shape.Unnormalized class scores, or one score per binary target. |
targetstorch.Tensor | Categorical: logits.shape with the class axis removed. Binary: exactly logits.shape.Class indices for categorical loss; target probabilities for binary loss. |
masktorch.Tensor | NoneDefault None | Any shape broadcastable to targets.shape.Optional validity mask; omission includes every target. |
weightstorch.Tensor | NoneDefault None | Any shape broadcastable to targets.shape.Optional nonnegative importance per target; omission uses one. |
variantstrDefault 'categorical' | Choose "categorical" for integer class labels or "binary" for floating targets in [0,1]. |
reductionstrDefault 'mean' | Choose "none" for targets-shaped losses, "sum" for one scalar sum, or "mean" for one globally weighted scalar mean. |
dimintDefault -1 | Categorical class axis only. Removing this axis gives the target shape; binary mode treats each logit as one target. |
epsfloatDefault 1e-08 | Nonnegative offset added once to the total included weight for a mean reduction. It does not modify logits, probabilities, or individual losses. |
ignore_indexintDefault -100 | Categorical target value excluded from both loss and mean denominator, independently of the supplied mask. |
Return
torch.Tensor · Exactly targets.shape for reduction="none"; scalar tensor [] for "sum" or "mean".
Return Weighted per-example tensor for reduction='none'; scalar weighted sum or guarded weighted mean otherwise.
Required behavior
- Implement stable categorical cross-entropy and binary cross-entropy from
logits, with optional masks and differentiable sampleweights. variantis 'categorical' (default) or 'binary'.- In categorical mode
logitshas rankR\ge 1withC\ge 1categories ondim(integer, default-1; negative axes count from the end).int64targetshas logits.shape with that axis removed and stores a class in[0,C)on valid positions.ignore_indexdefaults to-100and always excludes that target. - Optional bool
maskbroadcasts to targets.shape;Truemeans valid. Validity ismaskAND\mathrm{target}\ne \mathrm{ignore\_index}. Masked/ignored labels may be arbitrary integers, including out-of-range padding: replace them safely before any gather. - Per-valid-example
lossis\mathrm{ell}=\operatorname{log}(\sum_{c} \operatorname{exp}(z_{c}))-z_{\mathrm{target}}, evaluated through shiftedlogitsfor stability. AllCcategories participate for a valid example; there is no classmask, class weighting, label smoothing or causal shift in this primitive. - In binary mode
logitsand floatingtargetshave the SAME arbitrary shape, including scalar tensors or zero-length batch dimensions; targettlies in[0,1]at valid entries, including soft labels. dim andignore_indexdo not apply. Optional boolmaskbroadcasts to that shape. - Per-valid-element
lossis\mathrm{ell}=\operatorname{max}(z,0)-z\cdot t+\operatorname{log}(1+\operatorname{exp}(-\left|z\right|)). Do not log a sigmoid: confident incorrectlogitsmust have finite losses and nonvanishing gradients. The mathematical derivative atz=0is0.5-t. - Masked
logits/targetsmay contain arbitrary finite padding, and must contribute neitherlossnor gradients. - In either mode optional
weightsis nonnegative, floating, shareslogitsdtype/device, and broadcasts to targets.shape (not the categorical class axis); omittedweightsmeans one, omittedmaskmeans allTrue. Floatinglogits/targets/weightsshare dtype/device and all required outputs must be representable. - Define
v_ias final validity,q_{i}=v_{i}\cdot w_{i}\cdot \mathrm{ell\_i},S=\sum_{i} q_{i},D=\sum_{i}(v_{i}\cdot w_{i}).reductionis 'none', 'sum', or 'mean' (default). - Return the targets-shaped tensor
qfor none, scalarSfor sum, or scalarS/(D+\varepsilon)for mean whenD>0and an exact zero scalar whenD=0. The scalar reductions are GLOBAL over every example axis, not an average of example means. epsdefaults to10^{-8}, is finite and\ge 0, and is added once after summingweightsonly in the mean denominator; it does not modifylogits, probabilities or any unreducedloss. All-masked/ignored batches return zero with zero gradients.- Zero-length example axes are permitted in either variant: none returns the empty target shape, and
\sum/\operatorname{mean}return zero. The mean'sD=0branch is constant zero. Support noncontiguous layouts, broadcasting and singleton categories, and never modify inputs.
Why this matters
Working in logit space avoids saturated probabilities and preserves useful gradients even for confident incorrect predictions.
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 stable_classification_loss(
logits: torch.Tensor, # Categorical: any shape with class axis dim of size C >= 1. Binary: exactly targets.shape.
targets: torch.Tensor, # Categorical: logits.shape with the class axis removed. Binary: exactly logits.shape.
mask: torch.Tensor | None = None, # Any shape broadcastable to targets.shape.
weights: torch.Tensor | None = None, # Any shape broadcastable to targets.shape.
variant: str = 'categorical',
reduction: str = 'mean',
dim: int = -1,
eps: float = 1e-08,
ignore_index: int = -100,
) -> torch.Tensor:
"""Return a tensor with shape targets.shape for reduction="none"; scalar tensor () for
"sum" or "mean"."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement stable_classification_loss")
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.
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.