Source code for core.transforms.augmentations
"""Array augmentation primitives, shared by unit-feature models.
Covers waveforms, ACGs and ISI histograms. The per-model recipes that compose them live
with their model.
"""
import numpy as np
from scipy.ndimage import gaussian_filter
[docs]
class RandomApply:
"""Apply a transform with probability p."""
def __init__(self, transform, p: float = 0.5):
self.transform = transform
self.p = p
def __call__(self, x):
if np.random.random() < self.p:
return self.transform(x)
return x
[docs]
class AmplitudeScaling:
"""Rescales amplitude by a small random factor."""
def __init__(self, lo: float = 0.9, hi: float = 1.1):
self.lo = lo
self.hi = hi
def __call__(self, x: np.ndarray) -> np.ndarray:
return x * np.random.uniform(self.lo, self.hi)
[docs]
class GaussianNoise:
"""Adds Gaussian noise scaled to the input std."""
def __init__(self, std: float = 0.1):
self.std = std
def __call__(self, x: np.ndarray) -> np.ndarray:
noise = np.random.normal(0, self.std * np.std(x), size=x.shape)
return x + noise
[docs]
class TemporalGaussianSmoothing:
"""Gaussian smoothing along the temporal (last) axis only."""
def __init__(self, sigma: int = 2):
self.sigma = sigma
def __call__(self, x: np.ndarray) -> np.ndarray:
return gaussian_filter(x, sigma=(0, self.sigma))
[docs]
class TemporalJittering:
"""Random row-wise circular shift along the temporal axis."""
def __init__(self, max_jitter: int = 3):
self.max_jitter = max_jitter
def __call__(self, x: np.ndarray) -> np.ndarray:
num_rows, num_cols = x.shape
jitters = np.random.randint(-self.max_jitter, self.max_jitter + 1, size=num_rows)
col_indices = (np.arange(num_cols) - jitters[:, np.newaxis]) % num_cols
return x[np.arange(num_rows)[:, np.newaxis], col_indices]
[docs]
class AdditiveGaussianNoise:
"""Adds Gaussian noise scaled to the input max, clipped at 0."""
def __init__(self, mean: float = 0.0, std: float = 0.1):
self.mean = mean
self.std = std
def __call__(self, x: np.ndarray) -> np.ndarray:
noise = np.random.normal(self.mean, self.std * np.max(x), size=x.shape)
return np.clip(x + noise, 0, np.inf)
[docs]
class AdditivePepperNoise:
"""Randomly zeros out bins."""
def __init__(self, pepper_prob: float = 0.05):
self.pepper_prob = pepper_prob
def __call__(self, x: np.ndarray) -> np.ndarray:
noisy = np.copy(x)
noisy[np.random.random(x.shape) < self.pepper_prob] = 0.0
return noisy