This release is a pre-release and may not be stable for production use.
exacta
Metrics and differentiable losses for 2D and 3D medical-image segmentation, on CPU and GPU. Exacta provides reusable implementations of Dice, HD95, surface distances, lesion scores, probability metrics and training objectives, with explicit mathematical conventions.
CPU operations use C++ kernels where implemented; CUDA paths use Triton or native PyTorch. Definitions are checked against independent references such as SciPy, MONAI, MedPy, DeepMind's surface-distance, MeshMetrics, SimpleITK, Panoptica and the BraTS 2023 evaluation code. Where conventions differ, parameters select the intended definition.
Version: 0.0.1a5 (alpha). Documentation · Source · Issues
Installation
Exacta requires Python 3.10+, PyTorch 2.4+ and NumPy 1.22+. Install PyTorch for your CPU or CUDA environment, then install Exacta:
python -m pip install exacta==0.0.1a5
Binary wheels target Linux x86-64 with glibc 2.28 or newer: Python 3.10 and 3.11 wheels, plus a Python 3.12 stable-ABI wheel for Python 3.12 and newer. Other platforms install from source and require a C++17 compiler and Python development headers; OpenMP is optional. SciPy is an optional dependency for Hungarian lesion matching.
For distributed CPU evaluation with Gloo, use PyTorch 2.8+ to avoid an older process-group teardown deadlock. Multi-GPU NCCL support remains experimental.
Quickstart
Train with logits and evaluate hard labels. This synthetic 3D example runs on the available CPU or CUDA device; it demonstrates the API, not model accuracy:
import torch
import exacta.functional as EF
from exacta.losses import DiceCELoss
rng = torch.Generator().manual_seed(7)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
logits = torch.randn((2, 3, 16, 24, 24), generator=rng).to(device).requires_grad_()
target = torch.zeros((2, 16, 24, 24), dtype=torch.long, device=device)
target[:, 3:8, 4:12, 5:13] = 1
target[:, 9:13, 12:20, 12:20] = 2
loss = DiceCELoss(include_background=False)(logits, target)
loss.backward()
prediction = logits.detach().argmax(dim=1)
scores = EF.evaluate(
prediction, target, num_classes=3, include_background=False,
spacing=(1.5, 0.8, 0.8), # spatial-axis order, in mm
metrics={"dice": {}, "hd95": {}, "nsd": {"tolerance": 1.0}},
)
print("Loss:", loss.item())
print("Dice per case/class:", scores["dice"]) # shape (2, 2)
print("HD95 in mm:", scores["hd95"])
For 2D images, use logits (B,C,H,W), integer targets (B,H,W) and two-axis spacing.
For independent overlapping labels, supported losses use activation="sigmoid" and
target_format="one-hot" with same-shaped binary targets. The
2D medical-segmentation guide
includes binary, multiclass and multilabel examples.
Metrics
Stateless functions live in exacta.functional. Their stateful counterparts in
exacta.metrics accumulate across batches and support distributed evaluation.
| Category | Metrics |
|---|---|
| Overlap | Dice / voxel F1; IoU / Jaccard |
| Classification rates | Sensitivity / recall; precision; specificity |
| Relative size | Volume similarity; signed or absolute relative volume difference |
| Physical size | Predicted/target 3D volume and error in mm³ or mL; 2D area and error in mm² or cm² |
| Boundaries | Hausdorff distance with configurable percentile; HD95; ASSD; normalized surface Dice (NSD) |
| Centreline | Hard-skeleton clDice |
| Probability quality | Brier score; negative log-likelihood (NLL) |
| Calibration | Expected calibration error (ECE); reliability diagrams |
| Voxel ranking | Average precision (AP); AUROC; precision–recall and ROC curves, exact or approximately binned |
| Lesion matching | Lesion TP/FP/FN, precision, recall, F1, segmentation quality and panoptic quality |
| Lesion segmentation | Lesion-wise Dice and HD95; BraTS 2023 evaluation conventions |
| Confidence-ranked detection | Lesion AP and FROC curves |
Use exacta.lesions.evaluate for lesion matching and exacta.detection.LesionDetection
for confidence-ranked detection. Connected-component labeling, largest-component selection
and small-component removal are available in exacta.components.
functional.evaluate and MetricCollection share confusion counts and compatible surface
distances when evaluating multiple metrics. For accumulation across validation batches:
from exacta.metrics import MetricCollection
metrics = MetricCollection(
metrics={"dice": {}, "hd95": {}}, num_classes=3, include_background=False,
)
metrics.update(prediction, target, spacing=(1.5, 0.8, 0.8))
result = metrics.compute()["dice"]
print(result.per_case, result.per_class, result.mean)
metrics.reset()
Functional APIs accept PyTorch, NumPy, CuPy and JAX arrays and return the prediction's array type. Stateful APIs use PyTorch. See Metrics and Lesion evaluation for arguments, formulas and matching protocols.
Training losses
Losses are PyTorch modules in exacta.losses. Choose the objective and target representation
explicitly; different loss definitions produce different gradients.
| Category | Classes |
|---|---|
| Overlap | DiceLoss, GeneralizedDiceLoss, TverskyLoss, FocalTverskyLoss |
| Class-confusion costs | GeneralizedWassersteinDiceLoss |
| Voxel classification | FocalLoss, TopKCELoss |
| Combined objectives | DiceCELoss, DiceFocalLoss, GeneralizedDiceCELoss, DiceTopKCELoss |
| IoU surrogates | LovaszSoftmaxLoss, LovaszHingeLoss |
| Boundary objectives | BoundaryLoss, HausdorffDTLoss |
| Soft centreline objective | SoftClDiceLoss |
DeepSupervisionLoss combines a loss across explicitly paired prediction/target resolutions.
DiceLoss(squared_pred=True) uses a squared denominator; Dice–CE, Dice–focal and Dice–top-k CE
support the same option. Generalized Dice supports inverse-square, inverse-volume and uniform
class weights. Standard cross-entropy and binary cross-entropy remain available in PyTorch.
Wasserstein Dice accepts integer labels and a symmetric, nonnegative class-cost matrix with
zero diagonal and a positive maximum. The matrix is normalized by that maximum. Default
weighting requires maximal background/foreground costs; weighting_mode="GDL" uses inverse
observed class counts. These costs describe label confusion, not spatial distance.
HausdorffDTLoss is a distance-transform training surrogate, not HD95. Soft-clDice uses a
finite-iteration soft skeleton and differs from the hard clDice evaluation metric. Geometry
and topology objectives require complete target geometry; combine them with regional
supervision where appropriate. See Losses
for equations, smoothing, reductions, target formats and derivative support.
Partial annotations and probability channels
Overlap, area and volume metrics accept shared boolean voxel masks and index-target
ignore_index. Excluded voxels contribute to none of TP, FP, FN or TN:
partial_target = target.clone()
partial_target[:, :2] = -1
observed_dice = EF.dice(
prediction, partial_target, num_classes=3, include_background=False, ignore_index=-1,
)
Surface and hard-clDice metrics require complete segmentations: removing voxels would change boundaries or topology. Loss masking follows each objective's documented rules.
Brier, NLL, ECE, reliability diagrams and voxel rankings support multilabel=True for
independent probability channels with same-shaped binary targets. Logit inputs then use
independent sigmoids. Shared or per-label masks and explicit macro/micro reductions are
available where documented.
Mathematical conventions
Specify the definition as part of your evaluation protocol. Empty inputs, aggregation and surface representations can change reported values even for identical segmentations.
| Choice | Default and options |
|---|---|
| Hard labels | Index maps with num_classes, or binary channels with input_format="one-hot"; overlapping channels are allowed. |
| Background | Channel/class zero is included unless include_background=False. |
| Spacing | Spatial-axis order of the array; physical area/volume inputs use millimetres. |
| Surfaces | Boundary voxel centres by default; surface="surfels" uses physical length/area weights, and "mesh" uses contour/triangle geometry. |
| HD95 | Maximum of the two directed 95th percentiles; combine="pooled" instead pools distances before the percentile. |
| ASSD | Pooled surface-element mean; combine="mean" averages the two directed means. |
| Empty masks | Dice/IoU return NaN when both are empty; distance metrics default to infinity when exactly one is empty, except NSD, which returns zero. Parameters make these policies explicit. |
| Case aggregation | Stateful per-case metrics skip NaNs, average cases per class, then average class means. |
| Pooled evaluation | Calibration pools voxel bins; VoxelRanking pools voxel rankings. Case averages and pooled scores are different quantities. |
| AP | Non-interpolated sum of recall increments times precision, not trapezoidal PR area. No-positive AP and single-outcome AUROC are NaN. |
For distributed evaluation, every rank must participate in compute(), including ranks with
no local cases. Avoid samplers that duplicate cases through padding. See
Conventions for full definitions,
reference-library variants and empty-input behavior.
Performance
Backend choice depends on shape, class count, dtype and hardware. Supported metric passes use
C++/OpenMP on CPU and Triton on CUDA. Training losses use native PyTorch and, for supported
objectives, fused Triton forward/backward. torch.compile can improve native PyTorch paths;
measure complete forward/backward cost and account for compilation startup.
Mesh distances and hard skeletonization run on CPU, including transfers for CUDA inputs. Lesion matching uses CPU lesion tables. The CPU extension is independent of the PyTorch binary version. See Performance for measured workloads, memory behavior and backend limitations.
License
Apache License 2.0; see the license, notices and third-party licenses.
Metadata
Release files for exacta 0.0.1a5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| exacta-0.0.1a5.tar.gz | 139.6 kB | With provenance | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| exacta-0.0.1a5-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
| exacta-0.0.1a5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| exacta-0.0.1a5-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.10 | CPython 3.10 | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
Total release size: 1.3 MB
Release files / exacta-0.0.1a5.tar.gz
| Download URL | exacta-0.0.1a5.tar.gz |
|---|---|
| Size | 139.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cbfc503cbfc7cb6d7276ca45ed9fa660c86c7c82d9830f5b1321a2b79a2b388f
|
|
BLAKE2b-256 checksum How to use checksums |
03ef876e9abc75e439abe334c2522f0758eb8a9087a47330db1e90675788354e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / exacta-0.0.1a5-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | exacta-0.0.1a5-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 396.6 kB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
723b4d61ead1c744b9995bcb4fdbf24ef8623ed3694133254323b58f99d74ccb
|
|
BLAKE2b-256 checksum How to use checksums |
dbae9c67cd338c5947586f131d80d55cb8468e0906355d0c359db92f55e7bd43
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / exacta-0.0.1a5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | exacta-0.0.1a5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 400.6 kB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
c1f080a186e1457c08c626ee0984c5f90a81426b1aad3d30cc3a21b6beb143de
|
|
BLAKE2b-256 checksum How to use checksums |
cfcaef1ca579f3c9c0e6539bfc70bb21978748dd50cfe8d4aa9f5fb3ad1b2722
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / exacta-0.0.1a5-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | exacta-0.0.1a5-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 400.9 kB |
| Tags | CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
2e97ba2a7bb45dfae448984602755b4733782bc1266dffef076db4c5837562c9
|
|
BLAKE2b-256 checksum How to use checksums |
4c81575056c74fa51672708843718643570bdda86fd9a33c2068c9f2a4c8b347
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logSecurity for exacta 0.0.1a5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 4 files in this release have been uploaded with provenance metadata.
Attestation for exacta-0.0.1a5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.