def _local_loss(
        self,
        global_view_features: Sequence[Tuple[Tensor, Tensor]],
        global_view_grids: Sequence[Tensor],
        local_view_features: Optional[Sequence[Tuple[Tensor, Tensor]]] = None,
        local_view_grids: Optional[Sequence[Tensor]] = None,
    ) -> Tensor:
        """Returns loss from local features based on nearest neighbor matching.

        Note: Our nearest neighbor implementation returns the selected features sorted
        by increasing matching distance, whereas the implementation by the VICRegL
        authors returns features in a different order [1]. This results in slight
        differences of the final local loss. The difference results from feature
        centering which depends on the order.

        Note: Nearest neighbor matching slightly differs between the paper [0] and the
        original implementation of the authors [1]. The paper mentions that
        num_matches is set to 20 for global views and 4 for local views. The code
        uses 20 matches for the first NN search and 4 matches for the second search,
        regardless of global or local views:
        https://github.com/facebookresearch/VICRegL/blob/803ae4c8cd1649a820f03afb4793763e95317620/main_vicregl.py#L329-L334
        Our implementation follows the original code and ignores view type.

        Args:
            global_view_features:
                Sequence of (global_features, local_features) tuples from the global crop views.
            global_view_grids:
                Sequence of grid tensors from the global crop views.
            local_view_features:
                Sequence of (global_features,local_features) tuples from the local crop views.
            local_view_grids:
                Sequence of grid tensors from the local crop views.

        Returns:
            The computed loss from local features based on nearest neighbor matching.
        """
        loss = torch.tensor(0.0)
        loss_count = torch.tensor(0)

        # Compute the loss for global views
        for (_, z_a_local_features), grid_a in zip(
            global_view_features, global_view_grids
        ):
            for (_, z_b_local_features), grid_b in zip(
                global_view_features, global_view_grids
            ):
                if z_a_local_features is not z_b_local_features:
                    loss += self._local_l2_loss(
                        z_a=z_a_local_features,
                        z_b=z_b_local_features,
                    )
                    loss += self._local_location_loss(
                        z_a=z_a_local_features,
                        z_b=z_b_local_features,
                        grid_a=grid_a,
                        grid_b=grid_b,
                    )
                    loss_count += 1

            # Compute the loss for local views
            if local_view_features is not None and local_view_grids is not None:
                for (_, z_b_local_features), grid_b in zip(
                    local_view_features, local_view_grids
                ):
                    loss += self._local_l2_loss(
                        z_a=z_a_local_features,
                        z_b=z_b_local_features,
                    )
                    loss += self._local_location_loss(
                        z_a=z_a_local_features,
                        z_b=z_b_local_features,
                        grid_a=grid_a,
                        grid_b=grid_b,
                    )
                    loss_count += 1
        return loss / loss_count
Returns loss from local features based on nearest neighbor matching.

        Note: Our nearest neighbor implementation returns the selected features sorted
        by increasing matching distance, whereas the implementation by the VICRegL
        authors returns features in a different order [1]. This results in slight
        differences of the final local loss. The difference results from feature
        centering which depends on the order.

        Note: Nearest neighbor matching slightly differs between the paper [0] and the
        original implementation of the authors [1]. The paper mentions that
        num_matches is set to 20 for global views and 4 for local views. The code
        uses 20 matches for the first NN search and 4 matches for the second search,
        regardless of global or local views:
        https://github.com/facebookresearch/VICRegL/blob/803ae4c8cd1649a820f03afb4793763e95317620/main_vicregl.py#L329-L334
        Our implementation follows the original code and ignores view type.

        Args:
            global_view_features:
                Sequence of (global_features, local_features) tuples from the global crop views.
            global_view_grids:
                Sequence of grid tensors from the global crop views.
            local_view_features:
                Sequence of (global_features,local_features) tuples from the local crop views.
            local_view_grids:
                Sequence of grid tensors from the local crop views.

        Returns:
            The computed loss from local features based on nearest neighbor matching.
        
lightly/loss/vicregl_loss.py