Skip to main content

seapig

PyPI Conda Version Codecov test MIT DOI


seapig provides uncertainty-based selective inference for deep learning models. Its main focus currently lies on analyzing latent representations. The library implements a small set of lightweight, composable uncertainty scores that are used to decide whether to accept or reject an individual query sample at prediction time. Thresholds are calibrated on an independent validation set. It provides a wrapper for torchmetrics that allows evaluating the performance of a selective inference system on a test set, and a PyTorch Lightning task for seamless integration into training and evaluation pipelines.

Installation

seapig is available on PyPI and can be installed with pip. For the latest features, install from the GitHub repository. We recommend using a virtual environment to avoid dependency conflicts. The package has a small set of core dependencies, and optional extras for suggested features, development, and documentation. See the installation instructions below.

# minimal installation
pip install seapig
# including optional features
pip install seapig[suggested]

# for contributors / developers (tests, linters, type-checkers)
pip install seapig[dev]
# for building documentation (quarto-cli, great-docs, others)
pip install seapig[docs]
# or, if you need everything:
pip install seapig[all]

seapig is also available on the conda-forge channel and can be installed with conda:

conda install -c conda-forge seapig

or with mamba:

mamba install -c conda-forge seapig

Why selective prediction?

  • Machine learning models often fail silently on out-of-distribution inputs.
  • Selective prediction lets a system abstain from predicting when the input is considered unreliable.
  • seapig uses internal model representations (embeddings) to detect such atypical inputs with interpretable, fast-to-compute scores.

The core idea is to compute a representation for each input, score how similar the representation is to training representations, and reject inputs whose score indicates low support.

From uncertainty scores to selective inference

All uncertainty scores produce a scalar score $s(x)$ for each query $x$. Given a threshold $\lambda$, we derive a binary selection function indicating which samples to accept. For example, accepting samples with score below $\lambda$:

$$g_{\lambda}(x) = \mathbf{1}{s(x) \le \lambda}.$$

We recommend calibrating $\lambda$ on an independent calibration set to fix a desired coverage level (fraction of accepted samples) and compute the correspoding empirical quantile $q$ of the calibration scores:

$$\lambda_{q} = Q_q(s_1^{cal}, s_2^{cal}, \dots, s_m^{cal}),$$

where $s_i^{cal}$ are the scores of the calibration samples. The decision function $g_{\lambda}(x)$ can then be applied at inference time to accept or reject predictions. We obtain a selective predictor, $h(x)$, that either produces an output or abstains from prediction, depending on the score of the input:

$$h(x) = \begin{cases} f(x), & \text{if} g(x)=1,\ \varnothing, & \text{if } g(x)=0. \end{cases}$$

How to use seapig

The code snippets show a typical use of distance-based scores: (1) compute or provide embeddings, (2) fit a confidence score, (3) calibrate a threshold on validation data, and (4) accept/reject predictions at inference time. These are illustrative examples that are intentionally minimal so the flow is clear. For a more complete example, see the “Getting Started” tutorial in the documentation.

Precomputed embeddings

If you have precomputed embeddings for your reference, validation, and query sets, you can fit a score directly on the tensors. The example below uses random tensors to illustrate the API.

import torch
from seapig.scores import EuclideanScore
from seapig.utils.progress import disable

disable()  # disables  seapig progress bars for quickstart example
torch.manual_seed(0)
# latent representations a torch.Tensor of shapes (N, D), (M, D), (Q, D)
ref_emb, cal_emb, query_emb = (
    torch.randn(1000, 32),
    torch.randn(200, 32),
    torch.randn(10, 32),
)

score = EuclideanScore(k=5, stat="mean")
score.fit(ref=ref_emb, cal=cal_emb)
score.set_threshold(q=0.90)  # keep ~90% coverage on validation set
sel = score.select(query=query_emb)
print(sel)
{'score': tensor([6.2651, 5.5944, 6.0226, 5.8903, 6.2928, 4.8388, 5.7290, 5.3641, 5.6599,
        5.9143]), 'selected': tensor([ True,  True,  True,  True, False,  True,  True,  True,  True,  True])}

On-the-fly embedding extraction

If you have a model that can compute embeddings on the fly, you can fit a score with the model and loaders API. This requires the model to expose an .extract() method returning a dictionary with the relevant keys. The example below uses a dummy model and random data to illustrate the API.

from torch.utils.data import TensorDataset, DataLoader

ds_train = TensorDataset(torch.randn(1000, 32), torch.randint(0, 2, (1000,)))
ds_val = TensorDataset(torch.randn(200, 32), torch.randint(0, 2, (200,)))
ds_test = TensorDataset(torch.randn(10, 32), torch.randint(0, 2, (10,)))
train_loader = DataLoader(ds_train, batch_size=64)
val_loader = DataLoader(ds_val, batch_size=64)
test_loader = DataLoader(ds_test, batch_size=64)


class Model(torch.nn.Module):
    def forward(self, batch: tuple[torch.Tensor, torch.Tensor]) -> torch.Tensor:
        image, label = batch
        return torch.rand(image.shape[0])

    def extract(self, batch: tuple[torch.Tensor, torch.Tensor]):
        preds = self.forward(batch)
        embs = torch.randn(preds.shape[0], 32)
        return {"prediction": preds, "embedding": embs}


model = Model()

score = EuclideanScore(k=3)
score.fit(model=model, loaders={"train": train_loader, "cal": val_loader})
score.set_threshold(q=0.80)  # keep ~80% coverage on validation set

sel = score.select(model=model, loader=test_loader)
print(sel)
{'score': tensor([5.6522, 6.6245, 5.5196, 5.1725, 5.8717, 5.6051, 5.3821, 5.2224, 5.0285,
        5.8041]), 'selected': tensor([ True, False,  True,  True,  True,  True,  True,  True,  True,  True])}

Using SelectiveInferenceTask with a lightning module

When working with lightning modules, you can wrap the model and score into a SelectiveInferenceTask for evaluation and prediction purposes. This allows you to seamlessly integrate selective inference into your training and evaluation pipelines, and compute metrics for the full, selected, and rejected samples. The example below uses a dummy model and random data to illustrate the API.

from seapig import SelectiveInferenceTask
from lightning import Trainer, LightningModule
from torchmetrics import Accuracy


# minimal LightningModule
class Model(LightningModule):
    def __init__(self, model: torch.nn.Module):
        super().__init__()
        self.model = model
        self.test_metrics = Accuracy("binary")

    def forward(self, batch: tuple[torch.Tensor, torch.Tensor]):
        return self.model(batch)

    def extract(self, batch: tuple[torch.Tensor, torch.Tensor]):
        outputs = self.model.extract(batch)
        return {"label": batch[1]} | outputs


trainer = Trainer(accelerator="cpu")
task = Model(model=model)
# trainer.fit(...) and score.fit(...) are expected to have been called already
sel_task = SelectiveInferenceTask(task=task, score=score)
# evaluate on test set, will return metrics for the full, selected, and rejected samples
metrics = trainer.test(sel_task, dataloaders=test_loader)
# or for prediction, will return a dict with keys "predictions", "selected", and "score" for each sample
preds = trainer.predict(sel_task, dataloaders=test_loader)
print(preds)
Output()
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃        Test metric        ┃       DataLoader 0        ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│    full/BinaryAccuracy    │            0.5            │
│  rejected/BinaryAccuracy  │            0.0            │
│  selected/BinaryAccuracy  │    0.5555555820465088     │
└───────────────────────────┴───────────────────────────┘

Output()

[{'prediction': tensor([0.3412, 0.6198, 0.8258, 0.8317, 0.8443, 0.0064, 0.4464, 0.5923, 0.1485,
        0.4144]), 'score': tensor([5.0690, 5.0864, 6.4270, 5.6630, 5.2806, 5.5488, 5.2757, 5.8282, 5.4030,
        5.9053]), 'selected': tensor([ True,  True, False,  True,  True,  True,  True,  True,  True,  True])}]

Available scores

  • KNN-distances: EuclideanScore, CosineScore, MahalanobisScore
  • Logit-based scores: EnergyScore, EntropyScore, LogitScore, MarginScore, SoftmaxScore
  • PCA-based reconstruction: PCAScore
  • PyOD detectors: PyODScore
  • Random baseline: RandomScore

Further reading

Code of Conduct

This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.

License

Funding

This research was funded in the course of TRR 391 Spatio-temporal Statistics for the Transition of Energy and Transport (520388526) by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation).

Metadata

Release files for seapig 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for seapig 0.3.0
File Size Uploaded
seapig-0.3.0.tar.gz 101.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for seapig 0.3.0
File Interpreter ABI Platform
seapig-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 163.2 kB

Release files / seapig-0.3.0.tar.gz

Download URL seapig-0.3.0.tar.gz
Size 101.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e31abf6b7d307e0aef7081848374d210dbf9a932d6fab58eb06cd70b267ef56b
BLAKE2b-256 checksum
How to use checksums
c2533d2fe4d65e71e3112386aa4d02435b765b06b08a91bbe2741c59f2ff5997
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 22, 2026.

Transparency log

Release files / seapig-0.3.0-py3-none-any.whl

Download URL seapig-0.3.0-py3-none-any.whl
Size 61.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f07c0260daf2490eea4436b6772f288fd2e01212bcaa963d3086e1f31e2d395b
BLAKE2b-256 checksum
How to use checksums
16a037637daa8c3f7b05120fed750969e4b70653d623e41e6a220d17cbabce31
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 22, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page