Files
2026-07-13 12:31:40 +08:00

99 lines
3.0 KiB
Python

from abc import ABC, abstractmethod
import torch
class DenoisingLoss(ABC):
@abstractmethod
def __call__(
self, x: torch.Tensor, x_pred: torch.Tensor,
noise: torch.Tensor, noise_pred: torch.Tensor,
alphas_cumprod: torch.Tensor,
timestep: torch.Tensor,
gradient_mask: torch.Tensor = None,
**kwargs
) -> torch.Tensor:
"""
Base class for denoising loss.
Input:
- x: the clean data with shape [B, F, C, H, W]
- x_pred: the predicted clean data with shape [B, F, C, H, W]
- noise: the noise with shape [B, F, C, H, W]
- noise_pred: the predicted noise with shape [B, F, C, H, W]
- alphas_cumprod: the cumulative product of alphas (defining the noise schedule) with shape [T]
- timestep: the current timestep with shape [B, F]
"""
pass
class X0PredLoss(DenoisingLoss):
def __call__(
self, x: torch.Tensor, x_pred: torch.Tensor,
noise: torch.Tensor, noise_pred: torch.Tensor,
alphas_cumprod: torch.Tensor,
timestep: torch.Tensor,
gradient_mask: torch.Tensor = None,
**kwargs
) -> torch.Tensor:
err = (x - x_pred) ** 2
if gradient_mask is not None:
return err[gradient_mask].mean()
return err.mean()
class VPredLoss(DenoisingLoss):
def __call__(
self, x: torch.Tensor, x_pred: torch.Tensor,
noise: torch.Tensor, noise_pred: torch.Tensor,
alphas_cumprod: torch.Tensor,
timestep: torch.Tensor,
gradient_mask: torch.Tensor = None,
**kwargs
) -> torch.Tensor:
weights = 1 / (1 - alphas_cumprod[timestep].reshape(*timestep.shape, 1, 1, 1))
err = weights * (x - x_pred) ** 2
if gradient_mask is not None:
return err[gradient_mask].mean()
return err.mean()
class NoisePredLoss(DenoisingLoss):
def __call__(
self, x: torch.Tensor, x_pred: torch.Tensor,
noise: torch.Tensor, noise_pred: torch.Tensor,
alphas_cumprod: torch.Tensor,
timestep: torch.Tensor,
gradient_mask: torch.Tensor = None,
**kwargs
) -> torch.Tensor:
err = (noise - noise_pred) ** 2
if gradient_mask is not None:
return err[gradient_mask].mean()
return err.mean()
class FlowPredLoss(DenoisingLoss):
def __call__(
self, x: torch.Tensor, x_pred: torch.Tensor,
noise: torch.Tensor, noise_pred: torch.Tensor,
alphas_cumprod: torch.Tensor,
timestep: torch.Tensor,
gradient_mask: torch.Tensor = None,
**kwargs
) -> torch.Tensor:
err = (kwargs["flow_pred"] - (noise - x)) ** 2
if gradient_mask is not None:
return err[gradient_mask].mean()
return err.mean()
NAME_TO_CLASS = {
"x0": X0PredLoss,
"v": VPredLoss,
"noise": NoisePredLoss,
"flow": FlowPredLoss
}
def get_denoising_loss(loss_type: str) -> DenoisingLoss:
return NAME_TO_CLASS[loss_type]