def forward(self, features: torch.Tensor) -> torch.Tensor:
        """Compute KDE estimates for the input features.

        Args:
            features (torch.Tensor): Feature tensor of shape ``(N, D)`` where
                ``N`` is the number of samples and ``D`` is the dimension.

        Returns:
            torch.Tensor: Density estimates for each input sample, shape ``(N,)``.

        Example:
            >>> kde = GaussianKDE()
            >>> features = torch.randn(100, 10)
            >>> kde.fit(features)
            >>> estimates = kde(features)
            >>> estimates.shape
            torch.Size([100])
        """
        features = torch.matmul(features, self.bw_transform)

        estimate = torch.zeros(features.shape[0]).to(features.device)
        for i in range(features.shape[0]):
            embedding = ((self.dataset - features[i]) ** 2).sum(dim=1)
            embedding = torch.exp(-embedding / 2) * self.norm
            estimate[i] = torch.mean(embedding)

        return estimate
Compute KDE estimates for the input features.

        Args:
            features (torch.Tensor): Feature tensor of shape ``(N, D)`` where
                ``N`` is the number of samples and ``D`` is the dimension.

        Returns:
            torch.Tensor: Density estimates for each input sample, shape ``(N,)``.

        Example:
            >>> kde = GaussianKDE()
            >>> features = torch.randn(100, 10)
            >>> kde.fit(features)
            >>> estimates = kde(features)
            >>> estimates.shape
            torch.Size([100])
        
src/anomalib/models/components/stats/kde.py