| 
							 | 
						 | 
					
					
						
						| 
							 | 
						import math | 
					
					
						
						| 
							 | 
						from typing import Any, List | 
					
					
						
						| 
							 | 
						import torch | 
					
					
						
						| 
							 | 
						from torch import nn | 
					
					
						
						| 
							 | 
						from torch.nn import functional as F | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						from detectron2.config import CfgNode | 
					
					
						
						| 
							 | 
						from detectron2.structures import Instances | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						from .. import DensePoseConfidenceModelConfig, DensePoseUVConfidenceType | 
					
					
						
						| 
							 | 
						from .chart import DensePoseChartLoss | 
					
					
						
						| 
							 | 
						from .registry import DENSEPOSE_LOSS_REGISTRY | 
					
					
						
						| 
							 | 
						from .utils import BilinearInterpolationHelper, LossDict | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						@DENSEPOSE_LOSS_REGISTRY.register() | 
					
					
						
						| 
							 | 
						class DensePoseChartWithConfidenceLoss(DensePoseChartLoss): | 
					
					
						
						| 
							 | 
						    """ """ | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def __init__(self, cfg: CfgNode): | 
					
					
						
						| 
							 | 
						        super().__init__(cfg) | 
					
					
						
						| 
							 | 
						        self.confidence_model_cfg = DensePoseConfidenceModelConfig.from_cfg(cfg) | 
					
					
						
						| 
							 | 
						        if self.confidence_model_cfg.uv_confidence.type == DensePoseUVConfidenceType.IID_ISO: | 
					
					
						
						| 
							 | 
						            self.uv_loss_with_confidences = IIDIsotropicGaussianUVLoss( | 
					
					
						
						| 
							 | 
						                self.confidence_model_cfg.uv_confidence.epsilon | 
					
					
						
						| 
							 | 
						            ) | 
					
					
						
						| 
							 | 
						        elif self.confidence_model_cfg.uv_confidence.type == DensePoseUVConfidenceType.INDEP_ANISO: | 
					
					
						
						| 
							 | 
						            self.uv_loss_with_confidences = IndepAnisotropicGaussianUVLoss( | 
					
					
						
						| 
							 | 
						                self.confidence_model_cfg.uv_confidence.epsilon | 
					
					
						
						| 
							 | 
						            ) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def produce_fake_densepose_losses_uv(self, densepose_predictor_outputs: Any) -> LossDict: | 
					
					
						
						| 
							 | 
						        """ | 
					
					
						
						| 
							 | 
						        Overrides fake losses for fine segmentation and U/V coordinates to | 
					
					
						
						| 
							 | 
						        include computation graphs for additional confidence parameters. | 
					
					
						
						| 
							 | 
						        These are used when no suitable ground truth data was found in a batch. | 
					
					
						
						| 
							 | 
						        The loss has a value 0 and is primarily used to construct the computation graph, | 
					
					
						
						| 
							 | 
						        so that `DistributedDataParallel` has similar graphs on all GPUs and can | 
					
					
						
						| 
							 | 
						        perform reduction properly. | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        Args: | 
					
					
						
						| 
							 | 
						            densepose_predictor_outputs: DensePose predictor outputs, an object | 
					
					
						
						| 
							 | 
						                of a dataclass that is assumed to have the following attributes: | 
					
					
						
						| 
							 | 
						             * fine_segm - fine segmentation estimates, tensor of shape [N, C, S, S] | 
					
					
						
						| 
							 | 
						             * u - U coordinate estimates per fine labels, tensor of shape [N, C, S, S] | 
					
					
						
						| 
							 | 
						             * v - V coordinate estimates per fine labels, tensor of shape [N, C, S, S] | 
					
					
						
						| 
							 | 
						        Return: | 
					
					
						
						| 
							 | 
						            dict: str -> tensor: dict of losses with the following entries: | 
					
					
						
						| 
							 | 
						             * `loss_densepose_U`: has value 0 | 
					
					
						
						| 
							 | 
						             * `loss_densepose_V`: has value 0 | 
					
					
						
						| 
							 | 
						             * `loss_densepose_I`: has value 0 | 
					
					
						
						| 
							 | 
						        """ | 
					
					
						
						| 
							 | 
						        conf_type = self.confidence_model_cfg.uv_confidence.type | 
					
					
						
						| 
							 | 
						        if self.confidence_model_cfg.uv_confidence.enabled: | 
					
					
						
						| 
							 | 
						            loss_uv = ( | 
					
					
						
						| 
							 | 
						                densepose_predictor_outputs.u.sum() + densepose_predictor_outputs.v.sum() | 
					
					
						
						| 
							 | 
						            ) * 0 | 
					
					
						
						| 
							 | 
						            if conf_type == DensePoseUVConfidenceType.IID_ISO: | 
					
					
						
						| 
							 | 
						                loss_uv += densepose_predictor_outputs.sigma_2.sum() * 0 | 
					
					
						
						| 
							 | 
						            elif conf_type == DensePoseUVConfidenceType.INDEP_ANISO: | 
					
					
						
						| 
							 | 
						                loss_uv += ( | 
					
					
						
						| 
							 | 
						                    densepose_predictor_outputs.sigma_2.sum() | 
					
					
						
						| 
							 | 
						                    + densepose_predictor_outputs.kappa_u.sum() | 
					
					
						
						| 
							 | 
						                    + densepose_predictor_outputs.kappa_v.sum() | 
					
					
						
						| 
							 | 
						                ) * 0 | 
					
					
						
						| 
							 | 
						            return {"loss_densepose_UV": loss_uv} | 
					
					
						
						| 
							 | 
						        else: | 
					
					
						
						| 
							 | 
						            return super().produce_fake_densepose_losses_uv(densepose_predictor_outputs) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def produce_densepose_losses_uv( | 
					
					
						
						| 
							 | 
						        self, | 
					
					
						
						| 
							 | 
						        proposals_with_gt: List[Instances], | 
					
					
						
						| 
							 | 
						        densepose_predictor_outputs: Any, | 
					
					
						
						| 
							 | 
						        packed_annotations: Any, | 
					
					
						
						| 
							 | 
						        interpolator: BilinearInterpolationHelper, | 
					
					
						
						| 
							 | 
						        j_valid_fg: torch.Tensor, | 
					
					
						
						| 
							 | 
						    ) -> LossDict: | 
					
					
						
						| 
							 | 
						        conf_type = self.confidence_model_cfg.uv_confidence.type | 
					
					
						
						| 
							 | 
						        if self.confidence_model_cfg.uv_confidence.enabled: | 
					
					
						
						| 
							 | 
						            u_gt = packed_annotations.u_gt[j_valid_fg] | 
					
					
						
						| 
							 | 
						            u_est = interpolator.extract_at_points(densepose_predictor_outputs.u)[j_valid_fg] | 
					
					
						
						| 
							 | 
						            v_gt = packed_annotations.v_gt[j_valid_fg] | 
					
					
						
						| 
							 | 
						            v_est = interpolator.extract_at_points(densepose_predictor_outputs.v)[j_valid_fg] | 
					
					
						
						| 
							 | 
						            sigma_2_est = interpolator.extract_at_points(densepose_predictor_outputs.sigma_2)[ | 
					
					
						
						| 
							 | 
						                j_valid_fg | 
					
					
						
						| 
							 | 
						            ] | 
					
					
						
						| 
							 | 
						            if conf_type == DensePoseUVConfidenceType.IID_ISO: | 
					
					
						
						| 
							 | 
						                return { | 
					
					
						
						| 
							 | 
						                    "loss_densepose_UV": ( | 
					
					
						
						| 
							 | 
						                        self.uv_loss_with_confidences(u_est, v_est, sigma_2_est, u_gt, v_gt) | 
					
					
						
						| 
							 | 
						                        * self.w_points | 
					
					
						
						| 
							 | 
						                    ) | 
					
					
						
						| 
							 | 
						                } | 
					
					
						
						| 
							 | 
						            elif conf_type in [DensePoseUVConfidenceType.INDEP_ANISO]: | 
					
					
						
						| 
							 | 
						                kappa_u_est = interpolator.extract_at_points(densepose_predictor_outputs.kappa_u)[ | 
					
					
						
						| 
							 | 
						                    j_valid_fg | 
					
					
						
						| 
							 | 
						                ] | 
					
					
						
						| 
							 | 
						                kappa_v_est = interpolator.extract_at_points(densepose_predictor_outputs.kappa_v)[ | 
					
					
						
						| 
							 | 
						                    j_valid_fg | 
					
					
						
						| 
							 | 
						                ] | 
					
					
						
						| 
							 | 
						                return { | 
					
					
						
						| 
							 | 
						                    "loss_densepose_UV": ( | 
					
					
						
						| 
							 | 
						                        self.uv_loss_with_confidences( | 
					
					
						
						| 
							 | 
						                            u_est, v_est, sigma_2_est, kappa_u_est, kappa_v_est, u_gt, v_gt | 
					
					
						
						| 
							 | 
						                        ) | 
					
					
						
						| 
							 | 
						                        * self.w_points | 
					
					
						
						| 
							 | 
						                    ) | 
					
					
						
						| 
							 | 
						                } | 
					
					
						
						| 
							 | 
						        return super().produce_densepose_losses_uv( | 
					
					
						
						| 
							 | 
						            proposals_with_gt, | 
					
					
						
						| 
							 | 
						            densepose_predictor_outputs, | 
					
					
						
						| 
							 | 
						            packed_annotations, | 
					
					
						
						| 
							 | 
						            interpolator, | 
					
					
						
						| 
							 | 
						            j_valid_fg, | 
					
					
						
						| 
							 | 
						        ) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						class IIDIsotropicGaussianUVLoss(nn.Module): | 
					
					
						
						| 
							 | 
						    """ | 
					
					
						
						| 
							 | 
						    Loss for the case of iid residuals with isotropic covariance: | 
					
					
						
						| 
							 | 
						    $Sigma_i = sigma_i^2 I$ | 
					
					
						
						| 
							 | 
						    The loss (negative log likelihood) is then: | 
					
					
						
						| 
							 | 
						    $1/2 sum_{i=1}^n (log(2 pi) + 2 log sigma_i^2 + ||delta_i||^2 / sigma_i^2)$, | 
					
					
						
						| 
							 | 
						    where $delta_i=(u - u', v - v')$ is a 2D vector containing UV coordinates | 
					
					
						
						| 
							 | 
						    difference between estimated and ground truth UV values | 
					
					
						
						| 
							 | 
						    For details, see: | 
					
					
						
						| 
							 | 
						    N. Neverova, D. Novotny, A. Vedaldi "Correlated Uncertainty for Learning | 
					
					
						
						| 
							 | 
						    Dense Correspondences from Noisy Labels", p. 918--926, in Proc. NIPS 2019 | 
					
					
						
						| 
							 | 
						    """ | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def __init__(self, sigma_lower_bound: float): | 
					
					
						
						| 
							 | 
						        super(IIDIsotropicGaussianUVLoss, self).__init__() | 
					
					
						
						| 
							 | 
						        self.sigma_lower_bound = sigma_lower_bound | 
					
					
						
						| 
							 | 
						        self.log2pi = math.log(2 * math.pi) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def forward( | 
					
					
						
						| 
							 | 
						        self, | 
					
					
						
						| 
							 | 
						        u: torch.Tensor, | 
					
					
						
						| 
							 | 
						        v: torch.Tensor, | 
					
					
						
						| 
							 | 
						        sigma_u: torch.Tensor, | 
					
					
						
						| 
							 | 
						        target_u: torch.Tensor, | 
					
					
						
						| 
							 | 
						        target_v: torch.Tensor, | 
					
					
						
						| 
							 | 
						    ): | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        sigma2 = F.softplus(sigma_u) + self.sigma_lower_bound | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        delta_t_delta = (u - target_u) ** 2 + (v - target_v) ** 2 | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        loss = 0.5 * (self.log2pi + 2 * torch.log(sigma2) + delta_t_delta / sigma2) | 
					
					
						
						| 
							 | 
						        return loss.sum() | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						class IndepAnisotropicGaussianUVLoss(nn.Module): | 
					
					
						
						| 
							 | 
						    """ | 
					
					
						
						| 
							 | 
						    Loss for the case of independent residuals with anisotropic covariances: | 
					
					
						
						| 
							 | 
						    $Sigma_i = sigma_i^2 I + r_i r_i^T$ | 
					
					
						
						| 
							 | 
						    The loss (negative log likelihood) is then: | 
					
					
						
						| 
							 | 
						    $1/2 sum_{i=1}^n (log(2 pi) | 
					
					
						
						| 
							 | 
						      + log sigma_i^2 (sigma_i^2 + ||r_i||^2) | 
					
					
						
						| 
							 | 
						      + ||delta_i||^2 / sigma_i^2 | 
					
					
						
						| 
							 | 
						      - <delta_i, r_i>^2 / (sigma_i^2 * (sigma_i^2 + ||r_i||^2)))$, | 
					
					
						
						| 
							 | 
						    where $delta_i=(u - u', v - v')$ is a 2D vector containing UV coordinates | 
					
					
						
						| 
							 | 
						    difference between estimated and ground truth UV values | 
					
					
						
						| 
							 | 
						    For details, see: | 
					
					
						
						| 
							 | 
						    N. Neverova, D. Novotny, A. Vedaldi "Correlated Uncertainty for Learning | 
					
					
						
						| 
							 | 
						    Dense Correspondences from Noisy Labels", p. 918--926, in Proc. NIPS 2019 | 
					
					
						
						| 
							 | 
						    """ | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def __init__(self, sigma_lower_bound: float): | 
					
					
						
						| 
							 | 
						        super(IndepAnisotropicGaussianUVLoss, self).__init__() | 
					
					
						
						| 
							 | 
						        self.sigma_lower_bound = sigma_lower_bound | 
					
					
						
						| 
							 | 
						        self.log2pi = math.log(2 * math.pi) | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    def forward( | 
					
					
						
						| 
							 | 
						        self, | 
					
					
						
						| 
							 | 
						        u: torch.Tensor, | 
					
					
						
						| 
							 | 
						        v: torch.Tensor, | 
					
					
						
						| 
							 | 
						        sigma_u: torch.Tensor, | 
					
					
						
						| 
							 | 
						        kappa_u_est: torch.Tensor, | 
					
					
						
						| 
							 | 
						        kappa_v_est: torch.Tensor, | 
					
					
						
						| 
							 | 
						        target_u: torch.Tensor, | 
					
					
						
						| 
							 | 
						        target_v: torch.Tensor, | 
					
					
						
						| 
							 | 
						    ): | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        sigma2 = F.softplus(sigma_u) + self.sigma_lower_bound | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        r_sqnorm2 = kappa_u_est**2 + kappa_v_est**2 | 
					
					
						
						| 
							 | 
						        delta_u = u - target_u | 
					
					
						
						| 
							 | 
						        delta_v = v - target_v | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        delta_sqnorm = delta_u**2 + delta_v**2 | 
					
					
						
						| 
							 | 
						        delta_u_r_u = delta_u * kappa_u_est | 
					
					
						
						| 
							 | 
						        delta_v_r_v = delta_v * kappa_v_est | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        delta_r = delta_u_r_u + delta_v_r_v | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						         | 
					
					
						
						| 
							 | 
						        delta_r_sqnorm = delta_r**2 | 
					
					
						
						| 
							 | 
						        denom2 = sigma2 * (sigma2 + r_sqnorm2) | 
					
					
						
						| 
							 | 
						        loss = 0.5 * ( | 
					
					
						
						| 
							 | 
						            self.log2pi + torch.log(denom2) + delta_sqnorm / sigma2 - delta_r_sqnorm / denom2 | 
					
					
						
						| 
							 | 
						        ) | 
					
					
						
						| 
							 | 
						        return loss.sum() | 
					
					
						
						| 
							 | 
						
 |