def _m_step(self, data: torch.Tensor, resp: torch.Tensor) -> None:
        """Perform M-step to update GMM parameters.

        Args:
            data (torch.Tensor): Input data.
                Shape: ``(n_samples, n_features)``.
            resp (torch.Tensor): Responsibilities from E-step.
                Shape: ``(n_samples, n_components)``.
        """
        cluster_counts = resp.sum(axis=0)  # number of points in each cluster
        self.weights = resp.mean(axis=0)  # new weights
        self.means = (resp.T @ data) / cluster_counts[:, None]  # new means

        diff = data.unsqueeze(0) - self.means.unsqueeze(1)
        weighted_diff = diff * resp.T.unsqueeze(-1)
        covariances = torch.bmm(
            weighted_diff.transpose(-2, -1),
            diff,
        ) / cluster_counts.view(-1, 1, 1)
        # Add a small constant for numerical stability
        self.covariances = (
            covariances
            + torch.eye(
                data.shape[1],
                device=data.device,
            )
            * 1e-6
        )
Perform M-step to update GMM parameters.

        Args:
            data (torch.Tensor): Input data.
                Shape: ``(n_samples, n_features)``.
            resp (torch.Tensor): Responsibilities from E-step.
                Shape: ``(n_samples, n_components)``.
        
src/anomalib/models/components/cluster/gmm.py