def forward(
        self,
        features: torch.Tensor,
        mask: torch.Tensor,
        labels: torch.Tensor,
    ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
        """Generate anomaly on features using thresholded perlin noise and Gaussian noise.

        Also update GT masks and labels with new anomaly information.

        Args:
            features (torch.Tensor): input features.
            mask (torch.Tensor): GT masks.
            labels (torch.Tensor): GT labels.

        Returns:
            perturbed features, updated GT masks and labels.
        """
        b, _, h, w = features.shape

        # duplicate
        features = torch.cat((features, features))
        mask = torch.cat((mask, mask))
        labels = torch.cat((labels, labels))

        noise = torch.normal(
            mean=self.noise_mean,
            std=self.noise_std,
            size=features.shape,
            device=features.device,
            requires_grad=False,
        )

        # mask indicating which regions will have noise applied
        # [B * 2, 1, H, W] initial all masked as anomalous
        noise_mask = torch.ones(
            b * 2,
            1,
            h,
            w,
            device=features.device,
            requires_grad=False,
        )

        # no overlap: don't apply to already anomalous regions (mask=1 -> bad)
        noise_mask = noise_mask * (1 - mask)

        # shape of noise is [B * 2, 1, H, W]
        perlin_mask = self.generate_perlin(b * 2, h, w).to(features.device)
        # only apply where perlin mask is 1
        noise_mask = noise_mask * perlin_mask

        # update gt mask
        mask = mask + noise_mask
        # binarize
        mask = torch.where(mask > 0, torch.ones_like(mask), torch.zeros_like(mask))

        # make new labels. 1 if any part of mask is 1, 0 otherwise
        new_anomalous = noise_mask.reshape(b * 2, -1).any(dim=1).type(torch.float32)
        labels = labels + new_anomalous
        # binarize
        labels = torch.where(labels > 0, torch.ones_like(labels), torch.zeros_like(labels))

        # apply masked noise
        perturbed = features + noise * noise_mask

        return perturbed, mask, labels
Generate anomaly on features using thresholded perlin noise and Gaussian noise.

        Also update GT masks and labels with new anomaly information.

        Args:
            features (torch.Tensor): input features.
            mask (torch.Tensor): GT masks.
            labels (torch.Tensor): GT labels.

        Returns:
            perturbed features, updated GT masks and labels.
        
src/anomalib/models/image/supersimplenet/anomaly_generator.py