Quickstart
1. Get model outputs and labels
You need two things from a held-out, labelled calibration set (see Concepts for why it must be held out):
predictions: the model output, shape(B, C, *spatial)with the class axis at dimension 1 (e.g.(B, C, H, W)in 2D);targets: integer labels, shape(B, *spatial).
import torch
import torch.nn.functional as F
from fiducio import TemperatureScaling, negative_log_likelihood, expected_calibration_error
# Stand-in for your model's outputs on the calibration set.
torch.manual_seed(0)
logits = torch.randn(8, 4, 64, 64)
labels = torch.randint(0, 4, (8, 64, 64))
2. Fit a calibrator
3. Apply it to new predictions
new_logits = torch.randn(2, 4, 64, 64)
calibrated = calibrator.transform(new_logits) # calibrated probabilities (B, C, H, W)
transform returns probabilities that sum to 1 at valid voxels.
predict_proba is an alias, and fit_transform(logits, labels) does both steps.
Evaluate on separate data rather than the output of fit_transform.
If you need calibrated logits instead, use decision_function(new_logits)
(softmax of its output equals transform); see
Concepts.
4. Measure the effect
# Separate test data, never used for fitting or model selection:
test_logits = torch.randn(8, 4, 64, 64)
test_labels = torch.randint(0, 4, (8, 64, 64))
raw = F.softmax(test_logits, dim=1)
calibrated_test = calibrator.transform(test_logits)
print(
"NLL",
negative_log_likelihood(raw, test_labels),
"->",
negative_log_likelihood(calibrated_test, test_labels),
)
print(
"ECE",
expected_calibration_error(raw, test_labels),
"->",
expected_calibration_error(calibrated_test, test_labels),
)
Metrics take probabilities, not logits. These random tensors show the API; improvement on unseen data is not guaranteed. To inspect where predictions are over- or under-confident, see the reliability-diagram examples.
5. Save and reload
from fiducio import load_calibrator
calibrator.save("calibrator.pt")
calibrator = load_calibrator("calibrator.pt") # loads on CPU by default
Mask padding or select a region
Pass a boolean mask with the same shape as the labels. Use it consistently when fitting, transforming and evaluating:
fit_mask = torch.ones_like(labels, dtype=torch.bool)
fit_mask[:, :4] = False # example padding rows
calibrator.fit(logits, labels, mask=fit_mask)
test_mask = torch.ones_like(test_labels, dtype=torch.bool)
test_mask[:, :4] = False
calibrated_test = calibrator.transform(test_logits, mask=test_mask)
ece = expected_calibration_error(calibrated_test, test_labels, mask=test_mask)
Masked output probabilities are all zero, so pass the same mask to metrics.
For missing hard labels, ignore_index=-100 is available as well. For soft
targets, use a mask; see multi-rater calibration.
Logits or probabilities?
Set input_type to match what you pass in:
TemperatureScaling(input_type="logits") # raw scores (default)
TemperatureScaling(input_type="probs") # probabilities that sum to 1
Keep logits when available: converting to probabilities can round small values
to zero. Use the same input_type for fitting and inference. See
Concepts.
Accepted tensor shapes
The class axis is always dimension 1, and the same code handles 2D, 3D and
per-pixel inputs. Binary segmentation is provided as two channels (C = 2). See
Concepts for the full convention and
the single-channel conversion.