Source code for neural_lam.utils.buffer_list

"""Module wrapper exposing a list of tensors as registered buffers."""

# Standard library
from typing import Iterator, overload

# Third-party
import torch
from torch import nn


[docs] class BufferList(nn.Module): """ A list of torch buffer tensors that sit together as a Module with no parameters and only buffers. This should be replaced by a native torch BufferList once implemented. See: https://github.com/pytorch/pytorch/issues/37386 """ def __init__( self, buffer_tensors: list[torch.Tensor], persistent: bool = True ) -> None: """ Register a collection of tensors as buffers inside a module. Parameters ---------- buffer_tensors : Sequence[torch.Tensor] Buffers to register in the order they should be indexed. persistent : bool, optional If ``True``, buffers are saved in checkpoints. Default ``True``. """ super().__init__() self.n_buffers = len(buffer_tensors) for buffer_i, tensor in enumerate(buffer_tensors): self.register_buffer(f"b{buffer_i}", tensor, persistent=persistent) @overload def __getitem__(self, key: int) -> torch.Tensor: """Integer-indexed access overload; see the implementation below.""" @overload def __getitem__(self, key: slice) -> list[torch.Tensor]: """Slice-indexed access overload; see the implementation below.""" def __getitem__( self, key: int | slice ) -> torch.Tensor | list[torch.Tensor]: """Return the buffer(s) at ``key``. Supports integer indexing (with Python-style negative indices) and slice indexing (which returns a list of tensors). Raises ------ IndexError If ``key`` is an out-of-range integer. """ # Unpack slice indices and call recursively for each position if isinstance(key, slice): return [self[i] for i in range(*key.indices(len(self)))] # Support negative indexing (e.g. buffer_list[-1] -> last element) if key < 0: key += len(self) if not (0 <= key < len(self)): raise IndexError( f"index {key} out of range for BufferList of length {len(self)}" ) return getattr(self, f"b{key}") def __len__(self) -> int: """Return the number of registered buffers.""" return self.n_buffers def __iter__(self) -> Iterator[torch.Tensor]: """Iterate over the registered buffers in ascending index order.""" return (self[i] for i in range(len(self))) def __itruediv__(self, other: float | torch.Tensor) -> "BufferList": """ Divide each element in list with other. Parameters ---------- other : float or torch.Tensor The value to divide by. Returns ------- BufferList The modified BufferList. """ return self.__imul__(1.0 / other) def __imul__(self, other: float | torch.Tensor) -> "BufferList": """ Multiply each element in list with other. Parameters ---------- other : float or torch.Tensor The value to multiply by. Returns ------- BufferList The modified BufferList. """ for buffer_tensor in self: buffer_tensor *= other return self