Skip to content

API: Persistence

Fiducio saves a single torch.save payload containing format metadata, the Fiducio version, a stable calibrator id, the constructor configuration and the learned state. Loading resolves the id through an internal controlled registry and never imports an arbitrary module path stored in the file. By default files are read with weights_only=True and onto CPU.

Warning

Only load calibrator files from sources you trust. See the project security policy.

save_calibrator

save_calibrator(calibrator: Calibrator, path: PathLike) -> None

Serialize calibrator to path.

Parameters:

Name Type Description Default
calibrator Calibrator

A fitted (or at least constructed) :class:fiducio.Calibrator.

required
path PathLike

Destination file. The .pt extension is conventional.

required
Source code in src/fiducio/persistence.py
def save_calibrator(calibrator: Calibrator, path: PathLike) -> None:
    """Serialize ``calibrator`` to ``path``.

    Parameters
    ----------
    calibrator:
        A fitted (or at least constructed) :class:`fiducio.Calibrator`.
    path:
        Destination file. The ``.pt`` extension is conventional.
    """
    if not getattr(calibrator, "calibrator_id", ""):
        raise ValueError(
            f"{type(calibrator).__name__} has no registered calibrator_id and cannot be saved"
        )
    path = os.fspath(path)
    if os.path.isdir(path):
        raise ValueError(f"calibrator path is a directory: {path}")
    directory = os.path.dirname(path)
    if directory:
        os.makedirs(directory, exist_ok=True)

    payload: dict[str, Any] = {
        "format": FORMAT_NAME,
        "format_version": FORMAT_VERSION,
        "fiducio_version": _fiducio_version(),
        "calibrator_id": calibrator.calibrator_id,
        "config": calibrator.get_config(),
        "num_classes": calibrator.num_classes,
        "fitted": calibrator.is_fitted,
        "state": _to_cpu(calibrator._get_state()),
    }
    # A unique, exclusively created name keeps concurrent saves from colliding.
    tmp_path = f"{path}.{os.getpid()}.{uuid.uuid4().hex}.tmp"
    try:
        with open(tmp_path, "xb") as handle:
            torch.save(payload, handle)
            handle.flush()
            os.fsync(handle.fileno())
        os.replace(tmp_path, path)
    finally:
        if os.path.exists(tmp_path):
            os.remove(tmp_path)

load_calibrator

load_calibrator(path: PathLike, map_location: MapLocation | None = 'cpu') -> Calibrator

Load a calibrator previously written by :func:save_calibrator.

Parameters:

Name Type Description Default
path PathLike

File to load.

required
map_location MapLocation | None

Device for the loaded tensors and the reconstructed calibrator. Defaults to "cpu"; the device saved on the original calibrator is not forced. Pass "cuda" to load onto a GPU.

'cpu'
Notes

The payload is read exclusively with weights_only=True, which restricts deserialization to tensors and basic Python types. Only load files you trust.

Source code in src/fiducio/persistence.py
def load_calibrator(
    path: PathLike,
    map_location: MapLocation | None = "cpu",
) -> Calibrator:
    """Load a calibrator previously written by :func:`save_calibrator`.

    Parameters
    ----------
    path:
        File to load.
    map_location:
        Device for the loaded tensors and the reconstructed calibrator. Defaults
        to ``"cpu"``; the device saved on the original calibrator is **not**
        forced. Pass ``"cuda"`` to load onto a GPU.

    Notes
    -----
    The payload is read exclusively with ``weights_only=True``, which restricts
    deserialization to tensors and basic Python types. Only load files you trust.
    """
    if not os.path.exists(path):
        raise FileNotFoundError(f"calibrator file not found: {path}")
    if not os.path.isfile(path):
        raise ValueError(f"calibrator path is not a file: {path}")

    location: MapLocation = "cpu" if map_location is None else map_location
    if not isinstance(location, (str, torch.device)):
        raise TypeError("map_location must be a device string or torch.device")
    try:
        device = torch.device(location)
    except RuntimeError as exc:
        raise ValueError(
            f"map_location must name a supported device ('cpu' or 'cuda'); got {location!r}"
        ) from exc
    if device.type not in {"cpu", "cuda"}:
        raise ValueError(
            "map_location must be 'cpu' or 'cuda' (optionally with an index); "
            f"got {str(location)!r}"
        )
    if device.type == "cuda" and not torch.cuda.is_available():
        raise RuntimeError(f"map_location={location!r} but CUDA is not available")
    try:
        payload = torch.load(os.fspath(path), map_location=location, weights_only=True)
    except (pickle.UnpicklingError, EOFError, IndexError, RuntimeError) as exc:
        raise ValueError(f"could not read Fiducio calibrator file: {path}") from exc

    if not isinstance(payload, dict) or payload.get("format") != FORMAT_NAME:
        raise ValueError(f"{path} is not a Fiducio calibrator file")

    if (
        type(payload.get("format_version")) is not int
        or payload["format_version"] != FORMAT_VERSION
    ):
        raise ValueError("unsupported or missing Fiducio format_version")
    required = {"fiducio_version", "calibrator_id", "config", "num_classes", "fitted", "state"}
    if not required <= payload.keys():
        raise ValueError("missing required Fiducio payload fields")
    if not isinstance(payload["calibrator_id"], str) or not isinstance(
        payload["fiducio_version"], str
    ):
        raise ValueError("invalid calibrator id or package version")
    if not isinstance(payload["config"], dict) or not isinstance(payload["state"], dict):
        raise ValueError("config and state must be dictionaries")
    fitted, classes = payload["fitted"], payload["num_classes"]
    if type(fitted) is not bool or (fitted and (type(classes) is not int or classes < 2)):
        raise ValueError("invalid fitted status or number of classes")
    if not fitted and classes is not None:
        raise ValueError("an unfitted calibrator must have num_classes=None")

    saved_version = payload["fiducio_version"]
    current_version = _fiducio_version()
    saved_major, current_major = _major(saved_version), _major(current_version)
    if saved_major is not None and current_major is not None and saved_major != current_major:
        _logger.warning(
            "calibrator was saved with fiducio %s but the installed version is %s; "
            "loading may not be fully compatible",
            saved_version,
            current_version,
        )

    calibrator_id = payload["calibrator_id"]
    try:
        cls = get_calibrator_class(calibrator_id)
    except KeyError as exc:
        raise ValueError(f"unsupported calibrator id {calibrator_id!r}") from exc

    config = payload["config"]
    if "device" in config:
        raise ValueError("saved config must not override map_location")
    try:
        calibrator = cls(device=device, **config)
    except (TypeError, ValueError, OverflowError) as exc:
        raise ValueError(f"invalid saved calibrator configuration: {exc}") from exc
    _validate_state(calibrator, payload["state"], classes, fitted)
    calibrator._num_classes = classes
    calibrator._set_state(payload["state"])
    calibrator._fitted = fitted
    return calibrator

Registry

registered_ids

registered_ids() -> list[str]

Return the sorted list of registered calibrator ids.

Source code in src/fiducio/registry.py
def registered_ids() -> list[str]:
    """Return the sorted list of registered calibrator ids."""
    return sorted(_REGISTRY)

get_calibrator_class

get_calibrator_class(calibrator_id: str) -> type[Calibrator]

Return the calibrator class registered under calibrator_id.

Source code in src/fiducio/registry.py
def get_calibrator_class(calibrator_id: str) -> type[Calibrator]:
    """Return the calibrator class registered under ``calibrator_id``."""
    try:
        return _REGISTRY[calibrator_id]
    except KeyError:
        raise KeyError(
            f"unknown calibrator id {calibrator_id!r}; known ids: {sorted(_REGISTRY)}"
        ) from None

register_calibrator

register_calibrator(calibrator_id: str) -> Callable[[T], T]

Class decorator that registers a calibrator under a stable id.

Parameters:

Name Type Description Default
calibrator_id str

Stable, unique identifier persisted in saved files. Changing it breaks backward compatibility of previously saved calibrators.

required
Source code in src/fiducio/registry.py
def register_calibrator(calibrator_id: str) -> Callable[[T], T]:
    """Class decorator that registers a calibrator under a stable id.

    Parameters
    ----------
    calibrator_id:
        Stable, unique identifier persisted in saved files. Changing it breaks
        backward compatibility of previously saved calibrators.
    """

    def decorator(cls: T) -> T:
        if calibrator_id in _REGISTRY and _REGISTRY[calibrator_id] is not cls:
            raise ValueError(f"calibrator id {calibrator_id!r} is already registered")
        cls.calibrator_id = calibrator_id
        _REGISTRY[calibrator_id] = cls
        return cls

    return decorator