Skip to content

torch_vn_algebra.cost

Source: torch_vn_algebra/cost.py. Signatures and docstrings as in the source.

Module documentation

Safeguards against unexpectedly long or memory-hungry computations.

* Time: batch-separable kernels (eigh, SVD, QR, matrix exponentials) are routed through
  `batched_call`. For large problems it first runs the kernel on a small slice of the batch,
  extrapolates the time for the whole batch and issues a CostWarning with the estimate when
  it exceeds `warn_seconds`. The result is identical to a single call.
* Memory: `check_memory` compares the estimated size of a large allocation with the memory
  available on the device; above `warn_memory_fraction` it warns, above `max_memory_fraction`
  it raises InsufficientMemoryError (instead of an out-of-memory crash halfway through).
* Integrators (dynamics.rk4 and everything built on it) warn with an ETA after the first step
  and can show a progress bar.

    import torch_vn_algebra as tv
    tv.cost.set_limits(warn_seconds=30)          # thresholds
    with tv.cost.disabled():                     # switch the checks off locally
        ...
    import warnings; warnings.simplefilter('ignore', tv.cost.CostWarning)   # silence warnings only

CostWarning

class CostWarning()
A computation is expected to take long or to use a large share of the memory.

InsufficientMemoryError

class InsufficientMemoryError()
The estimated memory of an operation exceeds what is available on the device.

set_limits

def set_limits(**kwargs)
Change thresholds: warn_seconds, warn_memory_fraction, max_memory_fraction, probe_items,
probe_flops, enabled.

get_limits

def get_limits() -> dict

disabled

def disabled()
Temporarily switch all cost checks off.

available_memory

def available_memory(device) -> Optional[int]
Free memory on `device` in bytes (CUDA: mem_get_info; CPU: MemAvailable on Linux, psutil otherwise).

check_memory

def check_memory(nbytes: float, device, what: str)
Warn or raise if an allocation of about `nbytes` is large compared with the free memory.

itemsize

def itemsize(dtype: torch.dtype) -> int
Bytes per entry of `dtype` (torch.dtype.itemsize exists only from PyTorch 2.1).

abs_max

def abs_max(x: torch.Tensor, dim=None) -> torch.Tensor
max |x_i| over `dim` (all axes by default). On PyTorch versions whose complex |z| overflows for large
entries, max(|Re|, |Im|) instead (within a factor sqrt(2) of max |x_i|, never overflows).

tensor_bytes

def tensor_bytes(shape, dtype) -> int

kernel_flops

def kernel_flops(kind: str, k: int, complex_: bool) -> float
Rough flop count of one k x k kernel (only used to skip probing of small problems).

batched_call

def batched_call(fn: Callable, x: torch.Tensor, what: str, kind: str='eigh')
fn(x) for a function acting independently on the items x[0], x[1], ... (leading dimension). The first large
problem of a kind (same fn, block shape, dtype and device) is timed on slices of the batch (from 8 items on a
CPU, 1/16 of the batch on a GPU, where small slices do not fill the device) and the cost per item is remembered;
a CostWarning reports the expected time if it exceeds warn_seconds. A call has a fixed cost (dispatch, workspace;
milliseconds for batched LAPACK kernels) that is not proportional to the number of items: it is measured on one
item and subtracted, and the slice is enlarged (x4) until the per-item part dominates or the time it implies
for the whole batch is below warn_seconds. Later calls cost nothing extra. The result is fn(x), computed in one
call.

StepTimer

class StepTimer(total_steps: int, what: str, progress: bool=False)
ETA warning (and optional progress bar) for loops with a known number of equal steps.

StepTimer.step

def step(self, device=None)

StepTimer.close

def close(self)