Wrappers¶
Metrics that wrap another metric and change how it is evaluated.
UncertaintyLoss
¶
Bases: Metric
Heteroscedastic-NLL data term for any pointwise base metric.
Multiplies the base's per-element error by exp(-log_var) (the
predicted precision, since precision = 1/variance =
exp(-log_var)). The result is the data term of the
heteroscedastic NLL:
::
UncertaintyLoss(..., log_var) = prefactor · base.pointwise(...) · exp(-log_var)
Its inputs are the base's, plus log_var (and y_mask, like
every pointwise metric): (x, y, log_var, y_mask) around L1 or MSE,
(x, log_var, y_mask) around a no-reference metric, the base's own
names around a custom one. Bind them on the UncertaintyLoss; the
base's own io is not consulted, since only its pointwise runs.
When is it a likelihood? base · exp(-log_var) + log_var is a
true negative log-likelihood when the base is a residual between a
prediction and a target: squared error gives the Gaussian, absolute
error the Laplacian (family sets the matching constant). Around any
other per-pixel term — a no-reference score, a weighted or perceptual
error — it is learned loss attenuation: the model learns where to
discount the term, paying log_var for it. A common and legitimate
use, just not a likelihood.
Note: the parameter is named log_var because that's
semantically what the network predicts — the log of the variance.
log_var = log(σ²), so exp(-log_var) = 1/σ².
The +log_var regularizer (the log-determinant of the Gaussian /
Laplacian density) is NOT included — pair this with a
:class:Regularizer (penalty="identity") on the same
log_var field in the same combiner. Splitting the data term
and the regularizer makes shared-uncertainty multi-task setups
composable without double-counting the regularizer when several
base metrics share one log_var.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_metric
|
Metric
|
Any :class: |
required |
family
|
str
|
Selects the NLL prefactor.
The prefactor is a multiplicative constant; it doesn't
change the optimum, only the numerical loss value. Pick
|
'laplace'
|
logvar_clamp
|
tuple
|
|
(-14.0, 14.0)
|
weight
|
float
|
Scalar weight passed to the base |
1.0
|
**kwargs
|
Any
|
Forwarded to the base |
{}
|
Example (YAML)::
loss:
_target: srforge.metrics.MetricCombiner
params:
losses:
- _target: srforge.metrics.wrappers.UncertaintyLoss
params:
base_metric: {_target: srforge.metrics.regression.MSE}
family: gauss
io: {inputs: {x: sr, y: hr, log_var: head_log_var}}
- _target: srforge.metrics.regularization.Regularizer
params: {penalty: identity}
io: {inputs: {x: head_log_var}}
pointwise(*args, **kwargs) -> torch.Tensor
¶
Per-pixel data term:
prefactor · base.pointwise(...) · exp(-log_var).
Takes the inputs :meth:_pointwise_parameters lists — the base's
plus log_var — positionally or by name.
log_var is clamped to :attr:logvar_clamp first (if
enabled) to prevent exp(-log_var) from over/underflowing.
The +log_var regularizer is NOT included — pair this with
a :class:Regularizer (penalty="identity") on the same
log_var field.
CorrectedLoss
¶
Bases: Metric
Shift- and photometrically-corrected wrapper around any base
:class:Metric.
Applies one base metric at every shift of the prediction within a
border-pixel window and keeps each pixel's best-aligned shift,
using :func:torch.Tensor.unfold for the shift extraction — no
Python-level for-loop, no intermediate torch.stack copy.
Per sample:
- Slice the central SR patch (
border-pixel margin on each spatial side). - Extract all
(2*border+1)²shifted HR patches via a single view-basedunfold. - Optional photometric correction:
b = mean(hr_patch - sr_patch)is added tosr_patchso per-shift intensity offset is normalised out. - Build a synthetic :class:
~srforge.data.Entrywith canonical field names (:data:_PRED_FIELD, :data:_TARGET_FIELD, :data:_MASK_FIELD) and call the base metric via its standard__call__/forwardpipeline. The base's own IO binding routes those fields to its parameters — no manual parameter-name resolution needed in this wrapper. - Pick per-pixel
min(ifbase.best_min) ormaxover shifts — i.e. each pixel gets credited for its best-aligned shift.
Two IO bindings, two roles:
- Outer
io(on :class:CorrectedLossitself) maps the caller's :class:Entryfields tox/y/y_mask— same as any other Metric. - Inner
io(onbase) maps the base's parameters to the canonical field names listed below. For bases with canonical(x, y, y_mask)parameter names, the default identity map suffices and no inneriois needed. For bases with custom parameter names, declare an innerioblock routing them to the canonical field names.
Example with a base that uses (sr, hr, mask) naming::
loss:
_target: srforge.metrics.wrappers.CorrectedLoss
params:
base_metric:
_target: my_module.MyLoss # params: (sr, hr, mask)
io:
inputs: # ← inner IO routes
sr: x # base params to
hr: y # canonical inner
mask: y_mask # field names
border: 3
io:
inputs: {x: pred_field, y: hr_field, y_mask: valid_mask}
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_metric
|
Metric
|
The base :class: |
required |
border
|
int
|
How many pixels on each spatial side define the
shift range. |
3
|
do_correction
|
bool
|
Apply the additive photometric bias before
the base-metric call. Default |
True
|