Regression¶
Metrics that compare two tensors of any shape, element by element or as a whole: images, signals, volumes, feature vectors alike.
MSE
¶
Bases: Metric
Mean Squared Error. Per-pixel (y - x)**2 averaged over
non-batch dims, honouring optional y_mask. Inherits the
default calculate_score — only overrides pointwise.
PSNR
¶
Bases: Metric
Peak Signal-to-Noise Ratio. Higher is better.
Level-1 (structural), deliberately. PSNR has no meaningful
per-pixel form, so it does not implement :meth:pointwise and cannot
be wrapped by modifiers like :class:UncertaintyLoss — attempting it
raises at construction with a message pointing at :class:MSE.
The reason is in the definition::
PSNR = 10 · log10(MAX² / MSE) MSE is a *mean*
The logarithm sits outside the average, and log is concave, so
mean(log(...)) ≠ log(mean(...)): no per-pixel value averages back
to PSNR. Worse, a per-pixel PSNR is +inf wherever two pixels match
exactly, which is routine in quantised data. Forcing it with a clamp
measured 6.9 dB above the true PSNR on a test image — more than
three times the improvement a typical SR milestone asks for — and the
answer moved by 1.5 dB across plausible clamp values. A number you can
tune by choosing an epsilon is not a metric.
Earlier versions inherited from :class:MSE and therefore exposed its
pointwise, which made UncertaintyLoss(PSNR()) construct happily
and silently compute UncertaintyLoss(MSE()) — the log10 is
applied after reduction and simply vanished. That was documented rather
than prevented; it is now prevented. Use UncertaintyLoss(MSE()) if
that is what you meant.
Masking is unaffected: :meth:reduce applies y_mask to the squared
error before the transform, which is the only order that makes sense.
Micro (aggregate="micro") pools the squared error first and takes
the log once: 10·log10(MAX² / MSE_pooled). Macro averages per-image
PSNRs, and because log is concave the two differ — by over 10 dB on
SR data, where a few near-perfect images dominate a mean of logs.