def loss_by_feat(self,
                     cls_scores: Sequence[Tensor],
                     bbox_preds: Sequence[Tensor],
                     objectnesses: Sequence[Tensor],
                     kpt_preds: Sequence[Tensor],
                     vis_preds: Sequence[Tensor],
                     batch_gt_instances: Sequence[InstanceData],
                     batch_img_metas: Sequence[dict],
                     batch_gt_instances_ignore: OptInstanceList = None
                     ) -> dict:
        """Calculate the loss based on the features extracted by the detection
        head.

        In addition to the base class method, keypoint losses are also
        calculated in this method.
        """

        self._clear()

        # collect keypoints coordinates and visibility from model predictions
        kpt_preds = torch.cat([
            kpt_pred.flatten(2).permute(0, 2, 1).contiguous()
            for kpt_pred in kpt_preds
        ],
                              dim=1)

        featmap_sizes = [cls_score.shape[2:] for cls_score in cls_scores]
        mlvl_priors = self.prior_generator.grid_priors(
            featmap_sizes,
            dtype=cls_scores[0].dtype,
            device=cls_scores[0].device,
            with_stride=True)
        grid_priors = torch.cat(mlvl_priors)

        flatten_kpts = self.decode_pose(grid_priors[..., :2], kpt_preds,
                                        grid_priors[..., 2])

        vis_preds = torch.cat([
            vis_pred.flatten(2).permute(0, 2, 1).contiguous()
            for vis_pred in vis_preds
        ],
                              dim=1)

        # compute detection losses and collect targets for keypoints
        # predictions simultaneously
        self._log['pred_keypoints'] = list(flatten_kpts.detach().split(
            1, dim=0))
        self._log['pred_keypoints_vis'] = list(vis_preds.detach().split(
            1, dim=0))

        losses = super().loss_by_feat(cls_scores, bbox_preds, objectnesses,
                                      batch_gt_instances, batch_img_metas,
                                      batch_gt_instances_ignore)

        kpt_targets, vis_targets = [], []
        sampling_results = self.sampler.log['sample']
        sampling_result_idx = 0
        for gt_instances in batch_gt_instances:
            if len(gt_instances) > 0:
                sampling_result = sampling_results[sampling_result_idx]
                kpt_target = gt_instances['keypoints'][
                    sampling_result.pos_assigned_gt_inds]
                vis_target = gt_instances['keypoints_visible'][
                    sampling_result.pos_assigned_gt_inds]
                sampling_result_idx += 1
                kpt_targets.append(kpt_target)
                vis_targets.append(vis_target)

        if len(kpt_targets) > 0:
            kpt_targets = torch.cat(kpt_targets, 0)
            vis_targets = torch.cat(vis_targets, 0)

        # compute keypoint losses
        if len(kpt_targets) > 0:
            vis_targets = (vis_targets > 0).float()
            pos_masks = torch.cat(self._log['foreground_mask'], 0)
            bbox_targets = torch.cat(self._log['bbox_target'], 0)
            loss_kpt = self.loss_pose(
                flatten_kpts.view(-1, self.num_keypoints, 2)[pos_masks],
                kpt_targets, vis_targets, bbox_targets)
            loss_vis = self.loss_cls(
                vis_preds.view(-1, self.num_keypoints)[pos_masks],
                vis_targets) / vis_targets.sum()
        else:
            loss_kpt = kpt_preds.sum() * 0
            loss_vis = vis_preds.sum() * 0

        losses.update(dict(loss_kpt=loss_kpt, loss_vis=loss_vis))

        self._clear()
        return losses
Calculate the loss based on the features extracted by the detection
        head.

        In addition to the base class method, keypoint losses are also
        calculated in this method.
        
mmpose/projects/yolox_pose/models/yolox_pose_head.py