PepGLAD / models /LDM /diffusion /transition.py
Irwiny123's picture
添加PepGLAD初始代码
52007f8
Raw
History Blame Contribute Delete
5.43 kB
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
def construct_transition(_type, num_steps, opt):
if _type == 'Diffusion':
return ContinuousTransition(num_steps, opt)
elif _type == 'FlowMatching':
return FlowMatchingTransition(num_steps, opt)
else:
raise NotImplementedError(f'transition type {_type} not implemented')
class VarianceSchedule(nn.Module):
def __init__(self, num_steps=100, s=0.01):
super().__init__()
T = num_steps
t = torch.arange(0, num_steps+1, dtype=torch.float)
f_t = torch.cos( (np.pi / 2) * ((t/T) + s) / (1 + s) ) ** 2
alpha_bars = f_t / f_t[0]
betas = 1 - (alpha_bars[1:] / alpha_bars[:-1])
betas = torch.cat([torch.zeros([1]), betas], dim=0)
betas = betas.clamp_max(0.999)
sigmas = torch.zeros_like(betas)
for i in range(1, betas.size(0)):
sigmas[i] = ((1 - alpha_bars[i-1]) / (1 - alpha_bars[i])) * betas[i]
sigmas = torch.sqrt(sigmas)
self.register_buffer('betas', betas)
self.register_buffer('alpha_bars', alpha_bars)
self.register_buffer('alphas', 1 - betas)
self.register_buffer('sigmas', sigmas)
class ContinuousTransition(nn.Module):
def __init__(self, num_steps, var_sched_opt={}):
super().__init__()
self.var_sched = VarianceSchedule(num_steps, **var_sched_opt)
def get_timestamp(self, t):
# use beta as timestamp
return self.var_sched.betas[t]
def add_noise(self, p_0, mask_generate, batch_ids, t):
"""
Args:
p_0: [N, ...]
mask_generate: [N]
batch_ids: [N]
t: [batch_size]
"""
expand_shape = [p_0.shape[0]] + [1 for _ in p_0.shape[1:]]
mask_generate = mask_generate.view(*expand_shape)
alpha_bar = self.var_sched.alpha_bars[t] # [batch_size]
alpha_bar = alpha_bar[batch_ids] # [N]
c0 = torch.sqrt(alpha_bar).view(*expand_shape)
c1 = torch.sqrt(1 - alpha_bar).view(*expand_shape)
e_rand = torch.randn_like(p_0) # [N, 14, 3]
supervise_e_rand = e_rand.clone()
p_noisy = c0*p_0 + c1*e_rand
p_noisy = torch.where(mask_generate.expand_as(p_0), p_noisy, p_0)
return p_noisy, supervise_e_rand
def denoise(self, p_t, eps_p, mask_generate, batch_ids, t, guidance=None, guidance_weight=1.0):
# IMPORTANT:
# clampping alpha is to fix the instability issue at the first step (t=T)
# it seems like a problem with the ``improved ddpm''.
expand_shape = [p_t.shape[0]] + [1 for _ in p_t.shape[1:]]
mask_generate = mask_generate.view(*expand_shape)
alpha = self.var_sched.alphas[t].clamp_min(
self.var_sched.alphas[-2]
)[batch_ids]
alpha_bar = self.var_sched.alpha_bars[t][batch_ids]
sigma = self.var_sched.sigmas[t][batch_ids].view(*expand_shape)
c0 = ( 1.0 / torch.sqrt(alpha + 1e-8) ).view(*expand_shape)
c1 = ( (1 - alpha) / torch.sqrt(1 - alpha_bar + 1e-8) ).view(*expand_shape)
z = torch.where(
(t > 1).view(*expand_shape).expand_as(p_t),
torch.randn_like(p_t),
torch.zeros_like(p_t),
)
if guidance is not None:
eps_p = eps_p - torch.sqrt(1 - alpha_bar).view(*expand_shape) * guidance
# if guidance is not None:
# p_next = c0 * (p_t - c1 * eps_p) + sigma * z + sigma * sigma * guidance_weight * guidance
# else:
# p_next = c0 * (p_t - c1 * eps_p) + sigma * z
p_next = c0 * (p_t - c1 * eps_p) + sigma * z
p_next = torch.where(mask_generate.expand_as(p_t), p_next, p_t)
return p_next
# TODO: flow matching (uniform or OT), not done yet
class FlowMatchingTransition(nn.Module):
def __init__(self, num_steps, opt={}):
super().__init__()
self.num_steps = num_steps
# TODO: number of steps T or T + 1
c1 = torch.arange(0, num_steps + 1).float() / num_steps
c0 = 1 - c1
self.register_buffer('c0', c0)
self.register_buffer('c1', c1)
def get_timestamp(self, t):
# use c1 as timestamp
return self.c1[t]
def add_noise(self, p_0, mask_generate, batch_ids, t):
"""
Args:
p_0: [N, ...]
mask_generate: [N]
batch_ids: [N]
t: [batch_size]
"""
expand_shape = [p_0.shape[0]] + [1 for _ in p_0.shape[1:]]
mask_generate = mask_generate.view(*expand_shape)
c0 = self.c0[t][batch_ids].view(*expand_shape)
c1 = self.c1[t][batch_ids].view(*expand_shape)
e_rand = torch.randn_like(p_0) # [N, 14, 3]
p_noisy = c0*p_0 + c1*e_rand
p_noisy = torch.where(mask_generate.expand_as(p_0), p_noisy, p_0)
return p_noisy, (e_rand - p_0)
def denoise(self, p_t, eps_p, mask_generate, batch_ids, t):
# IMPORTANT:
# clampping alpha is to fix the instability issue at the first step (t=T)
# it seems like a problem with the ``improved ddpm''.
expand_shape = [p_t.shape[0]] + [1 for _ in p_t.shape[1:]]
mask_generate = mask_generate.view(*expand_shape)
p_next = p_t - eps_p / self.num_steps
p_next = torch.where(mask_generate.expand_as(p_t), p_next, p_t)
return p_next