AnomVidGen / src /image2d /diffusion2d.py
Kartikeya Mishra
Initial AnomVidGen Docker Space
de24669
Raw
History Blame Contribute Delete
2.91 kB
import torch
import torch.nn.functional as F
class GaussianDiffusion2D:
def __init__(self, timesteps=1000, beta_start=1e-4, beta_end=2e-2, device="cpu"):
self.timesteps = timesteps
self.device = torch.device(device)
betas = torch.linspace(beta_start, beta_end, timesteps, device=self.device)
alphas = 1.0 - betas
alpha_bars = torch.cumprod(alphas, dim=0)
self.betas = betas
self.alphas = alphas
self.alpha_bars = alpha_bars
self.sqrt_alpha_bars = torch.sqrt(alpha_bars)
self.sqrt_one_minus_alpha_bars = torch.sqrt(1.0 - alpha_bars)
def _extract(self, arr, t, x_shape):
out = arr.gather(0, t)
return out.view(t.shape[0], *([1] * (len(x_shape) - 1)))
def q_sample(self, x_start, t, noise=None):
if noise is None:
noise = torch.randn_like(x_start)
sqrt_ab = self._extract(self.sqrt_alpha_bars, t, x_start.shape)
sqrt_omab = self._extract(self.sqrt_one_minus_alpha_bars, t, x_start.shape)
return sqrt_ab * x_start + sqrt_omab * noise
def p_losses(self, model, x_start, t, y):
noise = torch.randn_like(x_start)
x_noisy = self.q_sample(x_start, t, noise)
noise_pred = model(x_noisy, t, y)
return F.mse_loss(noise_pred, noise)
@torch.no_grad()
def predict_eps(self, model, x, t, y, guidance_scale=1.0):
if guidance_scale <= 1.0:
return model(x, t, y)
eps_cond = model(x, t, y)
eps_uncond = model(x, t, torch.zeros_like(y))
return eps_uncond + guidance_scale * (eps_cond - eps_uncond)
@torch.no_grad()
def sample(self, model, shape, y, sampling_steps=100, guidance_scale=1.0):
model.eval()
x = torch.randn(shape, device=self.device)
if sampling_steps >= self.timesteps:
steps = torch.arange(self.timesteps - 1, -1, -1, device=self.device).long()
else:
steps = torch.linspace(self.timesteps - 1, 0, sampling_steps, device=self.device).long()
for i, step in enumerate(steps):
t = torch.full((shape[0],), int(step.item()), device=self.device, dtype=torch.long)
eps = self.predict_eps(model, x, t, y, guidance_scale=guidance_scale)
alpha_bar_t = self._extract(self.alpha_bars, t, x.shape)
x0_pred = (x - torch.sqrt(1.0 - alpha_bar_t) * eps) / torch.sqrt(alpha_bar_t)
x0_pred = x0_pred.clamp(-1.0, 1.0)
if i == len(steps) - 1:
x = x0_pred
break
prev_step = steps[i + 1]
prev_t = torch.full((shape[0],), int(prev_step.item()), device=self.device, dtype=torch.long)
alpha_bar_prev = self._extract(self.alpha_bars, prev_t, x.shape)
x = torch.sqrt(alpha_bar_prev) * x0_pred + torch.sqrt(1.0 - alpha_bar_prev) * eps
return x.clamp(-1.0, 1.0)