Loss functions (spec layer) #
This file defines a small collection of common losses (and their gradients) in a way that is:
- shape-generic: a loss takes
Tensor α sand reduces it to a scalarα, - explicit about reduction: most losses here are "mean over all elements",
- easy to line up with PyTorch terminology when you read training code.
In PyTorch you'll often see two layers:
- a low-level, elementwise loss (for example, Huber loss),
- plus a reduction (
meanorsum).
TorchLean's spec layer mirrors that idea: most definitions are written as an elementwise formula followed by a global mean over the shape.
The teacher-logit gradient uses logit differences, centering, and a residual correction as in Barron, Gnanapragasam and Tschannen, "A Fix for Softmax and Cross-Entropy" (https://arxiv.org/abs/2610.31642). Its near-field expression retains small gradients that would be lost by subtracting two separately rounded probability vectors.
Weight a difference, distributing the multiplication when subtraction overflows. Ordinary finite differences keep their evaluation order. For opposite-sign finite operands, weighting each operand first can keep the result representable without halving small tangents.
Instances For
Totalized denominator for a mean over slices orthogonal to axis.
Classification losses sum along the selected class dimension and average over every other
dimension. Thus a class vector has one slice, a matrix of shape (batch, classes) with class
dimension 1 has batch slices, and a tensor may instead place its class dimension anywhere in
the shape. The shared meanDenominator supplies the empty-slice convention.
Instances For
Divide a classification loss by the number of slices orthogonal to axis.
Instances For
Mean squared error: average of $(\mathtt{predicted}-\mathtt{target})^2$.
Instances For
Derivative of mseSpec with respect to predicted.
Instances For
Mean absolute error: average of |predicted - target|.
Instances For
Derivative of maeSpec w.r.t. predicted (subgradient via sign).
Instances For
Huber loss with transition parameter delta.
Elementwise, for residual $d=\mathtt{pred}-\mathtt{target}$:
- if $\lvert d\rvert<\delta$: $\tfrac12d^2$
- otherwise: $\delta(\lvert d\rvert-\tfrac12\delta)$
Then we take a mean over all elements.
This is PyTorch's HuberLoss convention. It differs from SmoothL1Loss by a factor of delta.
The Huber interpretation requires delta > 0.
The quadratic branch halves before squaring. If a finite prediction and target have an overflowing difference, the linear branch instead weights both operands before subtraction. Nonfinite inputs and genuinely unrepresentable losses or reductions can still overflow.
Instances For
Derivative of huberSpec w.r.t. predicted.
Instances For
Cross-entropy between distributions (probabilities).
This is closest to PyTorch when you already have probabilities q (e.g. after a softmax) and a
probability target p (e.g. one-hot or label-smoothed), and you want:
$$ \operatorname{CE}(p,q) =-\operatorname{mean}_r\sum_c p_{rc}\log q_{rc}, $$
where c ranges along the selected class dimension and r ranges over all remaining dimensions.
A lone class vector is one distribution and is not divided by its number of classes.
Each predicted probability is clamped to [epsilon, 1 - epsilon] before the logarithm. A one-hot
prediction that exactly matches a one-hot target therefore has loss -log(1 - epsilon), which is
small but not 0.
PyTorch's F.cross_entropy typically takes logits and does log_softmax + NLLLoss; that is a
different API surface than this "probabilities in, scalar out" spec.
Instances For
Derivative of crossEntropySpec w.r.t. predicted.
Instances For
Weighted log-probabilities for one class vector. Keep the original logits available to reconstruct a weighted term when the unweighted log-probability overflows.
Instances For
Apply the weighted-log-probability calculation independently to each final-axis vector.
Instances For
Weighted log-probabilities along axis, restored to the original tensor layout before
the loss reduction. This preserves the existing accumulation order for non-trailing axes.
Instances For
Cross-entropy on logits, retaining the original logits when a weighted term needs rescaling.
This matches the common PyTorch decomposition:
$$ \operatorname{cross\_entropy}(\mathtt{logits},\mathtt{target}) =-\operatorname{mean}_r\sum_c \mathtt{target}_{rc}\operatorname{logsoftmax}(\mathtt{logits})_{rc}, $$
where the dimension selected by axis contains classes and r ranges over the remaining
dimensions. This is PyTorch's reduction="mean" convention for one-hot or soft distribution
targets.
Unlike crossEntropySpec, this takes logits and uses Activation.logSoftmaxSpec. Ordinary
finite log-probabilities are multiplied as usual. When a log-probability is nonfinite, its
weighted term is reconstructed from the shifted normalizer and a rescaled logit difference.
Thus zero or small weights need not multiply an overflowing unweighted difference. No target
mask discards target derivatives. Nonfinite inputs or overflowing reductions can still yield NaN.
Probability targets usually sum to one along axis, as in one-hot or label-smoothed targets.
The same formula also accepts arbitrary target weights. Their sum scales the contribution of
that slice; the mean still divides by the number of slices, not by the total target weight.
Set mean := false to sum the contributions without averaging.
Instances For
Derivative of crossEntropyLogitsSpec with respect to the logits.
For each class slice, differentiating the log-normalizer contributes
softmax(logits) * sum(target). The direct logit term contributes -target. Keeping that
slice sum makes the derivative agree with the loss for weighted, unnormalized, and zero targets.
For a probability target, its sum is one and the familiar softmax(logits) - target follows.
Evaluation uses the shared log-softmax VJP rather than forming this difference directly;
the pivot's complementary probability is retained when its exponential rounds to one.
The reduction drops the class axis and then restores that exact axis. Ordinary trailing-axis broadcasting would mix slices when classes occupy an outer or middle dimension. Empty class axes use the same zero-sum convention as the loss.
Instances For
Target-weight derivative of logits cross-entropy, multiplied by an upstream scalar seed. Reconstructing the weighted log-probability before reduction also handles zero or small seeds without first materializing a possibly overflowing unweighted target derivative.
Instances For
Cross-entropy against a fixed teacher's logits, averaged over class slices.
Unlike probability targets, teacher logits retain the information needed to compute small student–teacher gradient differences. Zero teacher weights contribute zero even when a student log-probability overflows to negative infinity. The teacher is held fixed during differentiation.
Instances For
Student gradient of distillSpec, evaluated from logit differences.
Center the difference under the teacher distribution, then compute its log-normalizer with
expm1 and log1p. Near equal logits this avoids subtracting rounded probabilities. Coordinates
far from the teacher use the ordinary probability difference instead, avoiding 0 * ∞ in a
small teacher weight times a large exponential. The final correction removes reduction residuals.
The mean uses the same class-slice denominator as crossEntropyLogitsSpec.
Instances For
Hinge loss (binary margin loss), elementwise then mean-reduced:
$\operatorname{hinge}(x,y)=\operatorname{mean}_i\max(0,1-y_i x_i)$.
This matches the usual SVM-style hinge loss. (PyTorch exposes similar behavior via margin-style
losses such as HingeEmbeddingLoss / MultiMarginLoss, but the exact signature differs.)
Instances For
Derivative/subgradient of hingeSpec w.r.t. predicted.
Instances For
Poisson negative log-likelihood (log-input form), elementwise then mean-reduced:
If predicted represents log(rate) and target is a nonnegative count,
then (up to an additive constant that does not affect gradients):
$\operatorname{loss}_i=\exp(\mathtt{pred}_i)-\mathtt{target}_i\mathtt{pred}_i$.
This corresponds to PyTorch's PoissonNLLLoss(log_input=true, full=false) at the math level.
Instances For
Derivative of poissonSpec w.r.t. predicted.
Instances For
Scale and scaled, epsilon-clipped norm. For positive epsilon over the reals, both are positive and their product is the clipped L2 norm. Numerical callers divide by them separately.
Instances For
Cosine similarity loss: 1 - cos(predicted, target) (reduced-to-scalar).
Normalize each tensor before the dot product, using a shared scale before squaring. This avoids
forming raw dot products or products of large norms. The norm floor remains epsilon, not an
additive regularizer. Pass a positive, finite epsilon representable in the scalar type.
Nonfinite inputs and an overflowing scaled reduction can still produce nonfinite results.
Instances For
Derivative of cosineSimilaritySpec w.r.t. predicted.
If $\cos=(p\mathbin{\cdot}t)/(\lVert p\rVert\lVert t\rVert)$ and $\operatorname{loss}=1-\cos$, then (for nonzero norms):
$$ \frac{\partial\operatorname{loss}}{\partial p} =\frac{p\mathbin{\cdot}t}{\lVert p\rVert^3\lVert t\rVert}p -\frac{1}{\lVert p\rVert\lVert t\rVert}t. $$
The shared scaled norms avoid forming the fourth-degree denominator in this expression.
When the predicted norm is at or below epsilon, its clipped denominator is held constant
and the radial term is zero. The same positive, finite epsilon requirement applies as above.
Instances For
Log-cosh loss (reduced-to-scalar): log(cosh(predicted - target)).
Instances For
Derivative of logCoshSpec w.r.t. predicted.
Instances For
Binary cross-entropy on scalars (probabilities), with clipping to avoid log(0).
This matches the core formula behind PyTorch's BCELoss when predicted is already a probability
(not a logit):
$$ \operatorname{BCE}(p,y) =-\left(y\log p+(1-y)\log(1-p)\right). $$
Assumption: target is in [0, 1]. We do not clip the target; we only clip predicted.
The safeguard must remain positive in the chosen scalar type. At the upper clamp, retain it
directly as the complementary probability: subtracting 1 - epsilon from one could otherwise
produce zero when the upper clamp rounds to one. Inside the interval, log1p (-p) retains the
negative-class loss when 1 - p would round to one.
Instances For
Selected derivative of binaryCrossEntropySpec w.r.t. predicted.
The clipped forward function is not differentiable at epsilon or 1 - epsilon; this definition
chooses zero at those two kinks and on the clipped exterior branches.
Instances For
Tensor BCE (probabilities), elementwise then mean-reduced.
Instances For
Derivative of binaryCrossEntropyTensorSpec w.r.t. predicted.