Plot2Eq / src /plot2eq /data_utils /augmentation.py
YauheniShe's picture
Переименовал папку
d38b6f8
Raw History Blame Contribute Delete
4.01 kB
import torch
import torch.nn.functional as F
class HandDrawnAugmentation:
def __init__(self, max_drift_scale=0.05, max_wobble_scale=0.01, p=0.8):
"""
:param max_drift_scale: Максимальное плавное искажение
:param max_wobble_scale: Максимальные мелкие неровности
:param p: Вероятность применения аугментации (иногда полезно видеть идеальные данные)
"""
self.max_drift_scale = max_drift_scale
self.max_wobble_scale = max_wobble_scale
self.p = p
def __call__(self, points: torch.Tensor) -> torch.Tensor:
if torch.rand(1).item() > self.p:
return points
y = points[0:1, :].clone()
mask = points[1:2, :].clone()
seq_len = y.size(1)
device = y.device
min_strength = 0.5
drift_strength = (
torch.empty(1, device=device).uniform_(min_strength, 1.0).item()
)
wobble_strength = (
torch.empty(1, device=device).uniform_(min_strength, 1.0).item()
)
current_drift = self.max_drift_scale * drift_strength
current_wobble = self.max_wobble_scale * wobble_strength
drift_freq = torch.randint(2, 6, (1,)).item()
wobble_freq = torch.randint(10, 30, (1,)).item()
low_freq_noise = torch.randn(1, 1, 1, drift_freq, device=device) # type: ignore
drift = F.interpolate(
low_freq_noise, size=(1, seq_len), mode="bicubic", align_corners=True
).view(1, seq_len)
mid_freq_noise = torch.randn(1, 1, 1, wobble_freq, device=device) # type: ignore
wobble = F.interpolate(
mid_freq_noise, size=(1, seq_len), mode="bicubic", align_corners=True
).view(1, seq_len)
total_distortion = (drift * current_drift) + (wobble * current_wobble)
y = y + total_distortion * mask
x_freq = torch.randint(5, 15, (1,)).item()
x_noise = torch.randn(1, 1, 1, x_freq, device=device) # type: ignore
x_drift = F.interpolate(
x_noise, size=(1, seq_len), mode="bicubic", align_corners=True
).view(seq_len)
envelope = F.interpolate(
torch.rand(1, 1, 1, 3, device=device),
size=(1, seq_len),
mode="bicubic",
align_corners=True,
).view(seq_len)
x_drift = x_drift * envelope
x_shift_amplitude = torch.rand(1, device=device).item() * 3.0 + 1.0
new_indices = (
torch.arange(seq_len, device=device).float() + x_drift * x_shift_amplitude
)
new_indices = torch.clamp(new_indices, 0, seq_len - 1)
idx_floor = new_indices.long()
idx_ceil = torch.clamp(idx_floor + 1, 0, seq_len - 1)
weight = new_indices - idx_floor.float()
mask_floor = mask[:, idx_floor]
mask_ceil = mask[:, idx_ceil]
valid_transition = mask_floor * mask_ceil
idx_nearest = torch.round(new_indices).long()
y_nearest = y[:, idx_nearest]
y_interp = y[:, idx_floor] * (1.0 - weight) + y[:, idx_ceil] * weight
y = torch.where(valid_transition == 1.0, y_interp, y_nearest)
mask = mask[:, idx_nearest]
if torch.rand(1).item() > 0.5:
shear_factor = (torch.rand(1, device=device) - 0.5) * 0.1
tiling = torch.linspace(-1, 1, seq_len, device=device) * shear_factor
y = y + tiling * mask
y_valid_mask = mask.bool().squeeze(0)
if y_valid_mask.any():
y_valid_points = y[0, y_valid_mask]
min_val = torch.min(y_valid_points)
max_val = torch.max(y_valid_points)
if max_val > min_val:
y[0, y_valid_mask] = (y[0, y_valid_mask] - min_val) / (
max_val - min_val
)
else:
y[0, y_valid_mask] = 0.5
return torch.cat((y, mask), dim=0)