Skip to content

Backend API

This section documents the backend components of OKAPI, which handle tensor operations.

Backend Interface

The abstract interface that all backend implementations must follow.

from okapi.backend.backend_interface import BackendInterface

Abstract interface for tensor backends used by OKAPI.

This interface defines the tensor operations required by OKAPI, allowing for different backend implementations (e.g., NumPy, PyTorch) to be used interchangeably. Each backend must implement all these methods to provide a consistent interface for tensor operations.

Source code in okapi/backend/backend_interface.py
class BackendInterface:
    """
    Abstract interface for tensor backends used by OKAPI.

    This interface defines the tensor operations required by OKAPI, allowing
    for different backend implementations (e.g., NumPy, PyTorch) to be used
    interchangeably. Each backend must implement all these methods to provide
    a consistent interface for tensor operations.
    """

    @staticmethod
    def tensor(x):
        raise NotImplementedError()

    @staticmethod
    def concat(tensors, axis=0):
        raise NotImplementedError()

    @staticmethod
    def mean(x, axis=None):
        raise NotImplementedError()

    @staticmethod
    def max(x, axis=None):
        raise NotImplementedError()

    @staticmethod
    def min(x, axis=None):
        raise NotImplementedError()

    @staticmethod
    def sum(x, axis=None):
        raise NotImplementedError()

    @staticmethod
    def argmax(x, axis=None):
        raise NotImplementedError()

    @staticmethod
    def argmin(x, axis=None):
        raise NotImplementedError()

    @staticmethod
    def to_numpy(x) -> np.ndarray:
        raise NotImplementedError()

    @staticmethod
    def clip(x, min, max):
        raise NotImplementedError()

    @staticmethod
    def log(x):
        raise NotImplementedError()

    @staticmethod
    def to_float(x):
        raise NotImplementedError()

    @staticmethod
    def shape(x):
        raise NotImplementedError()

    @staticmethod
    def reshape(x, *args, **kwargs):
        raise NotImplementedError()

    @staticmethod
    def squeeze(x):
        raise NotImplementedError()

    @staticmethod
    def unsqueeze(x, axis):
        raise NotImplementedError()

    @staticmethod
    def load(path, device=None):
        raise NotImplementedError()

Backend Factory

Factory class for managing tensor backends.

from okapi.backend.backend import Backend

Factory class for managing tensor backends in OKAPI.

This class provides a centralized way to set and retrieve the tensor backend implementation (NumPy or PyTorch) used throughout the OKAPI library.

Important: The backend should only be set at the beginning of the program, before any OKAPI instances are initialized or predictions are loaded.

Source code in okapi/backend/backend.py
class Backend:
    """
    Factory class for managing tensor backends in OKAPI.

    This class provides a centralized way to set and retrieve the tensor backend
    implementation (NumPy or PyTorch) used throughout the OKAPI library.

    Important: The backend should only be set at the beginning of the program,
    before any OKAPI instances are initialized or predictions are loaded.
    """

    _current_backend: Type[BackendInterface] = NumpyBackend

    @classmethod
    def set_backend(cls, backend_name: str):  # TODO: Add option to set backend by providing class instead
        """
        Set the active tensor backend by name.

        Available backends:
        - 'numpy': Uses NumPyBackend for tensor operations
        - 'torch' or 'pytorch': Uses PyTorchBackend for tensor operations

        Args:
            backend_name: String identifier for the backend

        Raises:
            ValueError: If the backend name is not recognized
        """
        logger.info(f"Setting tensor backend to '{backend_name}'")
        if backend_name == "torch" or backend_name == "pytorch":
            from okapi.backend.pytorch import PyTorchBackend

            cls._current_backend = PyTorchBackend
            logger.debug("PyTorch backend initialized successfully")
        elif backend_name == "numpy":
            cls._current_backend = NumpyBackend
            logger.debug("NumPy backend initialized successfully")
        else:
            logger.error(f"Invalid backend: {backend_name}")
            raise ValueError(f"Invalid backend: {backend_name}")

    @classmethod
    def get_backend(cls) -> Type[BackendInterface]:
        """
        Get the current tensor backend.

        Returns:
            The current backend implementation class (NumpyBackend or PyTorchBackend)
        """
        logger.trace(f"Getting current backend: {cls._current_backend.__name__}")
        return cls._current_backend

    def __init__(self):
        pass

    def __getattr__(self, name):
        return getattr(Backend._current_backend, name)

get_backend() classmethod

Get the current tensor backend.

Returns:

Type Description
Type[BackendInterface]

The current backend implementation class (NumpyBackend or PyTorchBackend)

Source code in okapi/backend/backend.py
@classmethod
def get_backend(cls) -> Type[BackendInterface]:
    """
    Get the current tensor backend.

    Returns:
        The current backend implementation class (NumpyBackend or PyTorchBackend)
    """
    logger.trace(f"Getting current backend: {cls._current_backend.__name__}")
    return cls._current_backend

set_backend(backend_name) classmethod

Set the active tensor backend by name.

Available backends: - 'numpy': Uses NumPyBackend for tensor operations - 'torch' or 'pytorch': Uses PyTorchBackend for tensor operations

Parameters:

Name Type Description Default
backend_name str

String identifier for the backend

required

Raises:

Type Description
ValueError

If the backend name is not recognized

Source code in okapi/backend/backend.py
@classmethod
def set_backend(cls, backend_name: str):  # TODO: Add option to set backend by providing class instead
    """
    Set the active tensor backend by name.

    Available backends:
    - 'numpy': Uses NumPyBackend for tensor operations
    - 'torch' or 'pytorch': Uses PyTorchBackend for tensor operations

    Args:
        backend_name: String identifier for the backend

    Raises:
        ValueError: If the backend name is not recognized
    """
    logger.info(f"Setting tensor backend to '{backend_name}'")
    if backend_name == "torch" or backend_name == "pytorch":
        from okapi.backend.pytorch import PyTorchBackend

        cls._current_backend = PyTorchBackend
        logger.debug("PyTorch backend initialized successfully")
    elif backend_name == "numpy":
        cls._current_backend = NumpyBackend
        logger.debug("NumPy backend initialized successfully")
    else:
        logger.error(f"Invalid backend: {backend_name}")
        raise ValueError(f"Invalid backend: {backend_name}")

Global Backend Configuration

Functions and variables for configuring the backend.

from okapi.globals import BACKEND, set_backend, get_backend, DEVICE

BACKEND = Backend() module-attribute

DEVICE = os.environ.get('DEVICE', None) module-attribute

set_backend(backend_name)

Set the tensor backend to use.

Parameters:

Name Type Description Default
backend_name

Name of the backend to use ('numpy' or 'pytorch')

required
Source code in okapi/globals.py
def set_backend(backend_name):
    """
    Set the tensor backend to use.

    Args:
        backend_name: Name of the backend to use ('numpy' or 'pytorch')
    """
    global Backend
    logger.info(f"Setting tensor backend to: {backend_name}")
    Backend.set_backend(backend_name)

get_backend()

Get the current tensor backend.

Returns:

Type Description

The current backend interface class

Source code in okapi/globals.py
def get_backend():
    """
    Get the current tensor backend.

    Returns:
        The current backend interface class
    """
    global Backend
    backend = Backend.get_backend()
    logger.debug(f"Retrieved current backend: {backend.__name__}")
    return backend