def forward(self, pred, gt, weight, mask, penalize_ratio=0.9, detach=False, occlusion_aware=True):
        """

        :param pred: [N_pts, Npx, 3]
        :param gt: [N_pts, Npx, 3]
        :param weight: [N_pts]
        :param mask: [N_pts]
        :return:
        """

        if detach:
            weight = weight.detach()

        if self.type == 'l1':
            error = torch.abs(pred - gt).mean(dim=-1, keepdim=False).sum(dim=-1, keepdim=False)  # [N_pts]
        elif self.type == 'ncc':
            error = 1 - self.ncc(pred[:, None, :, :], gt)[:, 0]  # ncc 1 positive, -1 negative
            error, indices = torch.sort(error)
            mask = torch.index_select(mask, 0, index=indices)
            mask[int(penalize_ratio * mask.shape[0]):] = False  # can help boundaries
        elif self.type == 'ssd':
            error = ((pred - gt) ** 2).mean(dim=-1, keepdim=False).sum(dim=-1, keepdims=False)

        error = error[mask]
        if not (self.occlusion_aware and occlusion_aware):
            return torch.mean(error), torch.mean(error), 0.

        # * weight adjuster
        beta = self.adjuster(weight.mean())

        # weight = weight[mask]
        weight = weight.clamp(0.0, 1.0)

        term1 = self.alpha * torch.mean(weight[mask] * error)
        term2 = beta * torch.log(1 - weight + self.eps).mean()
        term3 = self.gama * torch.log(weight + self.eps).mean()

        return term1 + term2 + term3, term1, beta


        :param pred: [N_pts, Npx, 3]
        :param gt: [N_pts, Npx, 3]
        :param weight: [N_pts]
        :param mask: [N_pts]
        :return:
        
mv-diffusion/One-2-3-45-by-view/reconstruction/loss/color_loss.py