anilegin's picture
Upload inference-only latent diffusion model
a04730e verified
Raw
History Blame Contribute Delete
5.29 kB
from __future__ import annotations
import torch
from src.diffusion.noise_schedule import NoiseSchedule, extract
def predict_x0_from_eps(
z_t: torch.Tensor,
t: torch.Tensor,
eps: torch.Tensor,
schedule: NoiseSchedule,
) -> torch.Tensor:
"""
Recover clean latent z_0 from epsilon prediction
"""
sqrt_recip_alpha_bar = extract(
schedule.sqrt_recip_alphas_cumprod,
t,
z_t.shape,
)
sqrt_recipm1_alpha_bar = extract(
schedule.sqrt_recipm1_alphas_cumprod,
t,
z_t.shape,
)
return sqrt_recip_alpha_bar * z_t - sqrt_recipm1_alpha_bar * eps
def predict_eps_from_x0(
z_t: torch.Tensor,
t: torch.Tensor,
z_0: torch.Tensor,
schedule: NoiseSchedule,
) -> torch.Tensor:
"""
Recover epsilon from clean latent z_0 and noisy latent z_t.
eps = (z_t - sqrt(alpha_bar_t) * z_0)
/ sqrt(1 - alpha_bar_t)
"""
sqrt_alpha_bar = extract(
schedule.sqrt_alphas_cumprod,
t,
z_t.shape,
)
sqrt_one_minus_alpha_bar = extract(
schedule.sqrt_one_minus_alphas_cumprod,
t,
z_t.shape,
)
return (z_t - sqrt_alpha_bar * z_0) / sqrt_one_minus_alpha_bar
def get_v_target(
z_0: torch.Tensor,
eps: torch.Tensor,
t: torch.Tensor,
schedule: NoiseSchedule,
) -> torch.Tensor:
"""
Compute v-prediction target.
v-prediction target:
v = sqrt(alpha_bar_t) * eps
- sqrt(1 - alpha_bar_t) * z_0
"""
sqrt_alpha_bar = extract(
schedule.sqrt_alphas_cumprod,
t,
z_0.shape,
)
sqrt_one_minus_alpha_bar = extract(
schedule.sqrt_one_minus_alphas_cumprod,
t,
z_0.shape,
)
v = sqrt_alpha_bar * eps - sqrt_one_minus_alpha_bar * z_0
return v
def predict_x0_from_v(
z_t: torch.Tensor,
t: torch.Tensor,
v: torch.Tensor,
schedule: NoiseSchedule,
) -> torch.Tensor:
"""
Recover clean latent z_0 from v prediction
defs:
z_t = a * z_0 + b * eps
v = a * eps - b * z_0
a = sqrt(alpha_bar_t)
b = sqrt(1 - alpha_bar_t)
it gives
z_0 = a * z_t - b * v
"""
sqrt_alpha_bar = extract(
schedule.sqrt_alphas_cumprod,
t,
z_t.shape,
)
sqrt_one_minus_alpha_bar = extract(
schedule.sqrt_one_minus_alphas_cumprod,
t,
z_t.shape,
)
z_0 = sqrt_alpha_bar * z_t - sqrt_one_minus_alpha_bar * v
return z_0
def predict_eps_from_v(
z_t: torch.Tensor,
t: torch.Tensor,
v: torch.Tensor,
schedule: NoiseSchedule,
) -> torch.Tensor:
"""
Recover epsilon from v prediction
defs:
z_t = a * z_0 + b * eps
v = a * eps - b * z_0
it gives
eps = b * z_t + a * v
"""
sqrt_alpha_bar = extract(
schedule.sqrt_alphas_cumprod,
t,
z_t.shape,
)
sqrt_one_minus_alpha_bar = extract(
schedule.sqrt_one_minus_alphas_cumprod,
t,
z_t.shape,
)
eps = sqrt_one_minus_alpha_bar * z_t + sqrt_alpha_bar * v
return eps
def model_output_to_x0_and_eps(
model_output: torch.Tensor,
z_t: torch.Tensor,
t: torch.Tensor,
schedule: NoiseSchedule,
prediction_type: str = "v",
) -> tuple[torch.Tensor, torch.Tensor]:
"""
Convert model output into both:
z_0 prediction
epsilon prediction
"""
prediction_type = prediction_type.lower()
if prediction_type in {"v", "v_prediction"}:
z_0 = predict_x0_from_v(
z_t=z_t,
t=t,
v=model_output,
schedule=schedule,
)
eps = predict_eps_from_v(
z_t=z_t,
t=t,
v=model_output,
schedule=schedule,
)
elif prediction_type in {"eps", "epsilon"}:
eps = model_output
z_0 = predict_x0_from_eps(
z_t=z_t,
t=t,
eps=eps,
schedule=schedule,
)
elif prediction_type in {"x0", "sample"}:
z_0 = model_output
eps = predict_eps_from_x0(
z_t=z_t,
t=t,
z_0=z_0,
schedule=schedule,
)
else:
raise ValueError(
f"Unknown prediction_type={prediction_type}. "
"Use 'v', 'eps', or 'x0'."
)
return z_0, eps
def get_training_target(
z_0: torch.Tensor,
eps: torch.Tensor,
t: torch.Tensor,
schedule: NoiseSchedule,
prediction_type: str = "v",
) -> torch.Tensor:
"""
Return the target the U-Net should learn
For our project, default is:
prediction_type = "v"
Then target is:
v = sqrt(alpha_bar_t) * eps
- sqrt(1 - alpha_bar_t) * z_0
"""
prediction_type = prediction_type.lower()
if prediction_type in {"v", "v_prediction"}:
return get_v_target(
z_0=z_0,
eps=eps,
t=t,
schedule=schedule,
)
if prediction_type in {"eps", "epsilon"}:
return eps
if prediction_type in {"x0", "sample"}:
return z_0
raise ValueError(
f"Unknown prediction_type={prediction_type}. "
"Use 'v', 'eps', or 'x0'."
)