Source code for deepqmc.loss.clip

from typing import Protocol, Union

import jax
import jax.numpy as jnp

from ..parallel import all_device_mean, all_device_median, all_device_quantile
from ..types import Energy
from ..utils import log_squeeze

__all__ = [
    "median_clip_and_mask",
    "median_log_squeeze_and_mask",
    "clip_local_energy",
    "clip_psi_ratio",
    "psi_ratio_clip_and_mask",
]


class LocalEnergyClipAndMaskFn(Protocol):
    r"""Protocol for functions masking a single electron batch of local energies."""

    def __call__(self, __local_energy: Energy) -> tuple[Energy, jax.Array]: ...


class PsiRatioClipAndMaskFn(Protocol):
    r"""Protocol for functions masking a single electron batch of WF ratios."""

    def __call__(self, psi_ratio: jax.Array) -> tuple[jax.Array, jax.Array]: ...


[docs] def clip_local_energy( clip_mask_fn: LocalEnergyClipAndMaskFn, local_energy: Energy ) -> tuple[Energy, jax.Array]: r"""Apply a clipping function to the local energies. The clipping function is twice ``vmapped``: over the molecule batch, and electronic state dimensions. Args: clip_mask_fn (~collections.abc.Callable[[~jax.Array], tuple[~deepqmc.types.Energy, ~jax.Array]]): function taking as input an electron batch of local energies and returning a tuple of the clipped local energies and an identically shaped boolean mask array to be applied to the gradients. local_energy (~jax.Array): the electron batch of local energies, shape: ``[mol_batch_size, electronic_states, electron_batch_size // device_count]``. """ return jax.vmap(jax.vmap(clip_mask_fn))(local_energy)
[docs] def clip_psi_ratio( clip_mask_fn: PsiRatioClipAndMaskFn, psi_ratio: jax.Array ) -> tuple[jax.Array, jax.Array]: r"""Apply a clipping function to the wave function ratios. The clipping function is thrice ``vmapped``: over the molecule batch, and the two electronic state dimensions of the wave function ratio array: :math:`\text{ratio}[i,\,j,\,:]=\frac{\Psi_i(r\sim\Psi^2_j)}{\Psi_j(r\sim\Psi^2_j)}`. Args: clip_mask_fn (~collections.abc.Callable[[~jax.Array], tuple[~jax.Array, ~jax.Array]]): function taking as input an electron batch of ratios and returning a tuple of the clipped ratios and an identically shaped boolean mask array to be applied to the gradients. psi_ratio (~jax.Array): the electron batch of psi_ratios, shape: ``[mol_batch_size, electronic_states, electronic_states, electron_batch_size // device_count]``. Returns: tuple[~jax.Array, ~jax.Array]: the clipped WF ratios and gradient mask. """ return jax.vmap(jax.vmap(jax.vmap(clip_mask_fn)))(psi_ratio)
[docs] def median_clip_and_mask( x: jax.Array, clip_width: float, median_center: bool, exclude_width: float = jnp.inf ) -> tuple[jax.Array, jax.Array]: r"""Hard-clip values to a multiple of the mean absolute deviation from the center. Args: x (~jax.Array): values to clip, shape ``[electron_batch_size]``. clip_width (float): number of mean absolute deviations (MADs) around the center within which values are kept; values outside this range are clipped to the boundary. median_center (bool): if ``True``, use the median as the center; if ``False``, use the mean. exclude_width (float): deviation threshold in MADs above which samples are excluded from gradient computation (gradient mask set to ``False``). Defaults to :data:`jnp.inf` (no exclusion). Returns: tuple[~jax.Array, ~jax.Array]: the clipped values and a boolean gradient mask of the same shape, where ``False`` marks excluded outliers. """ clip_center = all_device_median(x) if median_center else all_device_mean(x) abs_diff = jnp.abs(x - clip_center) mad = all_device_mean(abs_diff) x_clip = jnp.clip(x, clip_center - clip_width * mad, clip_center + clip_width * mad) gradient_mask = abs_diff < exclude_width return x_clip, gradient_mask
[docs] def median_log_squeeze_and_mask( x: jax.Array, clip_width: float = 1.0, quantile: Union[float, jax.Array] = 0.95, exclude_width: float = jnp.inf, ) -> tuple[jax.Array, jax.Array]: r"""Softly squeeze values toward the median using a log-squeeze function. Values far from the median are continuously compressed rather than hard-clipped. The clipping scale is set to ``clip_width`` times the ``quantile``-th quantile of absolute deviations from the median. Formally, the squeezed value is .. math:: \tilde{x}_i = \bar{x} + 2w\,\operatorname{log\_squeeze}\!\left(\frac{x_i - \bar{x}}{2w}\right), where :math:`\bar{x}` is the median and :math:`w = \texttt{clip\_width}\times Q_q(|x-\bar{x}|)`. For :math:`|x_i - \bar{x}| \ll w` the squeezed value is close to :math:`x_i`; for large outliers it saturates at :math:`\bar{x} \pm 2w`. Args: x (~jax.Array): values to squeeze, shape ``[electron_batch_size]``. clip_width (float): multiplier applied to the quantile to obtain the half-width :math:`w` of the squeeze window. quantile (float): quantile of the absolute deviations used to set the natural scale of the distribution; default ``0.95``. exclude_width (float): deviation threshold in quantile units above which samples are excluded from gradient computation (gradient mask set to ``False``). Defaults to :data:`jnp.inf` (no exclusion). Returns: tuple[~jax.Array, ~jax.Array]: the squeezed values and a boolean gradient mask of the same shape, where ``False`` marks excluded outliers. """ x_median = all_device_median(x) x_diff = x - x_median x_abs_diff = jnp.abs(x_diff) quantile = all_device_quantile(x_abs_diff, quantile) width = clip_width * quantile x_clip = x_median + 2 * width * log_squeeze(x_diff / (2 * width)) gradient_mask = x_abs_diff / quantile < exclude_width return x_clip, gradient_mask
[docs] def psi_ratio_clip_and_mask( psi_ratio: jax.Array, *, clip_width: float = 10.0, exclude_width: float = jnp.inf, ) -> tuple[jax.Array, jax.Array]: r"""Clips WF ratios of a single batch of electron position samples. Args: psi_ratio (~jax.Array): ratio of log WF values, shape ``[electron_batch_size]``: :math:`\frac{\Psi_i({\bf r}_j)}{\Psi_j({\bf r}_j)}`. clip_width (float): clip width to use when clipping ratio. exclude_width (float): default: :data:`jnp.inf`, deviation threshold above which outlier ratios are excluded from the overlap gradient computation. Returns: tuple[~jax.Array, ~jax.Array]: the clipped WF ratios and gradient mask. """ clip_center = all_device_median(psi_ratio) deviation = jnp.abs(psi_ratio - clip_center) # TODO: check if using MAD to compute sigma (like in energy clipping) # would also work sigma = all_device_median(deviation) clipped_ratio = jnp.clip( psi_ratio, clip_center - clip_width * sigma, clip_center + clip_width * sigma, ) ratio_gradient_mask = jnp.abs(psi_ratio - clip_center) < exclude_width return clipped_ratio, ratio_gradient_mask