def generate_perlin(self, batches: int, height: int, width: int) -> torch.Tensor:
        """Generate 2d perlin noise masks with dims [b, 1, h, w].

        Args:
            batches (int): number of batches (different masks)
            height (int): height of features
            width (int): width of features

        Returns:
            tensor with b perlin binarized masks
        """
        perlin = []
        for _ in range(batches):
            perlin_height = self.next_power_2(height)
            perlin_width = self.next_power_2(width)

            # keep power of 2 here for reproduction purpose, although this function supports power2 internally
            perlin_noise = generate_perlin_noise(height=perlin_height, width=perlin_width)

            # original is power of 2 scale, so fit to our size
            perlin_noise = F.interpolate(
                perlin_noise.reshape(1, 1, perlin_height, perlin_width),
                size=(height, width),
                mode="bilinear",
            )
            # binarize
            thresholded_perlin = torch.where(perlin_noise > self.threshold, 1, 0)

            # 50% of anomaly
            if torch.rand(1).item() > 0.5:
                thresholded_perlin = torch.zeros_like(thresholded_perlin)

            perlin.append(thresholded_perlin)
        return torch.cat(perlin)
Generate 2d perlin noise masks with dims [b, 1, h, w].

        Args:
            batches (int): number of batches (different masks)
            height (int): height of features
            width (int): width of features

        Returns:
            tensor with b perlin binarized masks
        
src/anomalib/models/image/supersimplenet/anomaly_generator.py