Source code for pypielm.data.adapters.torch_adapter

"""PyTorch Dataset / DataLoader adapter.

Wraps a standard ``torch.utils.data.Dataset`` to produce a
:class:`~pypielm.data.dataset.PIELMDataset`.
"""

from __future__ import annotations

from typing import Any

import torch
import torch.utils.data

from pypielm.data.dataset import PIELMDataset

_VALID_ROLES = {"colloc", "bc", "ic", "data"}


[docs] class TorchDatasetAdapter: """Convert a :class:`torch.utils.data.Dataset` into a :class:`~pypielm.data.dataset.PIELMDataset`. The ``torch.utils.data.Dataset`` must return ``(x, y)`` tuples where *x* are spatial coordinates and *y* are target values. All items are loaded eagerly into memory. Args: dataset: Source PyTorch dataset returning ``(x, y)`` pairs. role: Determines which field of :class:`~pypielm.data.dataset.PIELMDataset` the loaded points populate. One of ``'colloc'``, ``'bc'``, ``'ic'``, ``'data'``. dtype: Tensor dtype. device: Target device. """ def __init__( self, dataset: torch.utils.data.Dataset, role: str = "data", dtype: torch.dtype = torch.float64, device: str | torch.device = "cpu", ) -> None: if role not in _VALID_ROLES: raise ValueError( f"role must be one of {sorted(_VALID_ROLES)}, got '{role}'." ) self.dataset = dataset self.role = role self.dtype = dtype self.device = device
[docs] def load(self) -> PIELMDataset: """Eagerly load all items and return a :class:`~pypielm.data.dataset.PIELMDataset`.""" xs: list[torch.Tensor] = [] ys: list[torch.Tensor] = [] for item in self.dataset: # type: ignore[attr-defined] if not (isinstance(item, (tuple, list)) and len(item) == 2): raise ValueError( "Each item from the dataset must be a (x, y) tuple." ) x, y = item xs.append(torch.as_tensor(x, dtype=self.dtype)) ys.append(torch.as_tensor(y, dtype=self.dtype)) if not xs: raise ValueError("Dataset is empty.") X = torch.stack(xs).to(self.device) Y = torch.stack(ys).to(self.device) if X.ndim == 1: X = X.unsqueeze(1) if Y.ndim == 1: Y = Y.unsqueeze(1) kwargs: dict[str, Any] = {} if self.role == "colloc": kwargs = {"X_colloc": X} elif self.role == "bc": kwargs = {"X_colloc": X, "X_bc": X, "y_bc": Y} elif self.role == "ic": kwargs = {"X_colloc": X, "X_ic": X, "y_ic": Y} else: # "data" kwargs = {"X_colloc": X, "y_data": Y} return PIELMDataset(**kwargs)