specsr.training.ztransform¶
Redshift normalisation and bounded decoding.
The redshift head does not regress z directly. Training normalises z to
zero mean and unit variance using statistics from the training split only, and
the head’s raw output is squashed through a sigmoid onto the observed redshift
range before the loss is applied.
The sigmoid bound matters: an unbounded head can emit redshifts far outside the range the data covers, and the heteroscedastic likelihood will happily trade a wild prediction against a large predicted variance. Bounding the mean keeps the uncertainty interpretable. It also keeps gradients alive at the extremes, which a hard clamp would not.
Collecting this in one object matters because the same transform must be applied identically at training, inference and evaluation time. When it lived inline in four copies of the training script, a divergence would have shown up as a subtle redshift bias rather than as an error.
Classes
|
Affine normalisation plus a sigmoid bound on the decoded mean. |
- class specsr.training.ztransform.RedshiftTransform(mean, std, z_min_n, z_max_n)[source]¶
Bases:
objectAffine normalisation plus a sigmoid bound on the decoded mean.
- Variables:
- Parameters:
- classmethod from_training_redshifts(z_train, pad=0.0)[source]¶
Fit the transform to the training-split redshifts.
padoptionally widens the bounds by a fraction of the range, giving the sigmoid a little headroom at the extremes.- Parameters:
pad (float)
- Return type:
- normalize(z)[source]¶
Physical redshift -> normalised units.
- Parameters:
z (torch.Tensor)
- Return type:
- denormalize(z_n)[source]¶
Normalised units -> physical redshift.
- Parameters:
z_n (torch.Tensor)
- Return type:
- decode_mean(mu_raw, bounded=True)[source]¶
Squash a raw head output onto the observed range, in normalised units.
bounded=Falsepasses the value through untouched, for heads whose estimate is already in normalised redshift units and already inside the range – the classification head reads its estimate off a grid, so squashing it a second time would compress it towards the range centre. Passzhead.bounded_meanrather than deciding per call site.- Parameters:
mu_raw (torch.Tensor)
bounded (bool)
- Return type:
- decode_sigma(log_var, var_floor=1e-06)[source]¶
Predicted log-variance (normalised) -> physical 1-sigma uncertainty.
- Parameters:
log_var (torch.Tensor)
var_floor (float)
- Return type:
- predict(mu_raw, log_var, var_floor=1e-06, bounded=True)[source]¶
Raw head outputs -> physical
(z, sigma_z).log_varis clamped before exponentiation; without it an early, overconfident-in-the-wrong-direction update can sendexp(log_var)to infinity and take the loss with it.- Parameters:
mu_raw (torch.Tensor)
log_var (torch.Tensor)
var_floor (float)
bounded (bool)
- Return type: