| import abc
|
|
|
| import torch
|
| import numpy as np
|
|
|
| from sgmse.util.registry import Registry
|
|
|
|
|
| PredictorRegistry = Registry("Predictor")
|
|
|
|
|
| class Predictor(abc.ABC):
|
| """The abstract class for a predictor algorithm."""
|
|
|
| def __init__(self, sde, score_fn, probability_flow=False):
|
| super().__init__()
|
| self.sde = sde
|
| self.rsde = sde.reverse(score_fn)
|
| self.score_fn = score_fn
|
| self.probability_flow = probability_flow
|
|
|
| @abc.abstractmethod
|
| def update_fn(self, x, t, *args):
|
| """One update of the predictor.
|
|
|
| Args:
|
| x: A PyTorch tensor representing the current state
|
| t: A Pytorch tensor representing the current time step.
|
| *args: Possibly additional arguments, in particular `y` for OU processes
|
|
|
| Returns:
|
| x: A PyTorch tensor of the next state.
|
| x_mean: A PyTorch tensor. The next state without random noise. Useful for denoising.
|
| """
|
| pass
|
|
|
| def debug_update_fn(self, x, t, *args):
|
| raise NotImplementedError(f"Debug update function not implemented for predictor {self}.")
|
|
|
|
|
| @PredictorRegistry.register('euler_maruyama')
|
| class EulerMaruyamaPredictor(Predictor):
|
| def __init__(self, sde, score_fn, probability_flow=False):
|
| super().__init__(sde, score_fn, probability_flow=probability_flow)
|
|
|
| def update_fn(self, x, y, t, *args):
|
| dt = -1. / self.rsde.N
|
| z = torch.randn_like(x)
|
| f, g = self.rsde.sde(x, y, t, *args)
|
| x_mean = x + f * dt
|
| x = x_mean + g[:, None, None, None] * np.sqrt(-dt) * z
|
| return x, x_mean
|
|
|
|
|
| @PredictorRegistry.register('reverse_diffusion')
|
| class ReverseDiffusionPredictor(Predictor):
|
| def __init__(self, sde, score_fn, probability_flow=False):
|
| super().__init__(sde, score_fn, probability_flow=probability_flow)
|
|
|
| def update_fn(self, x, y, t, stepsize):
|
| f, g = self.rsde.discretize(x, y, t, stepsize)
|
| z = torch.randn_like(x)
|
| x_mean = x - f
|
| x = x_mean + g[:, None, None, None] * z
|
| return x, x_mean
|
|
|
|
|
| @PredictorRegistry.register('none')
|
| class NonePredictor(Predictor):
|
| """An empty predictor that does nothing."""
|
|
|
| def __init__(self, *args, **kwargs):
|
| pass
|
|
|
| def update_fn(self, x, y, t, *args):
|
| return x, x
|
|
|