def forward(self, input_tensor: torch.Tensor) -> torch.Tensor | InferenceBatch:
        """Process input tensor through the model.

        During training, returns embeddings extracted from the input. During
        inference, returns anomaly maps and scores computed by comparing input
        embeddings against the memory bank.

        Args:
            input_tensor (torch.Tensor): Input images of shape
                ``(batch_size, channels, height, width)``.

        Returns:
            torch.Tensor | InferenceBatch: During training, returns embeddings.
                During inference, returns ``InferenceBatch`` containing anomaly
                maps and scores.

        Example:
            >>> model = PatchcoreModel(layers=["layer1"])
            >>> input_tensor = torch.randn(32, 3, 224, 224)
            >>> output = model(input_tensor)
            >>> if model.training:
            ...     assert isinstance(output, torch.Tensor)
            ... else:
            ...     assert isinstance(output, InferenceBatch)
        """
        output_size = input_tensor.shape[-2:]
        if self.tiler:
            input_tensor = self.tiler.tile(input_tensor)

        with torch.no_grad():
            features = self.feature_extractor(input_tensor)

        features = {layer: self.feature_pooler(feature) for layer, feature in features.items()}
        embedding = self.generate_embedding(features)

        if self.tiler:
            embedding = self.tiler.untile(embedding)

        batch_size, _, width, height = embedding.shape
        embedding = self.reshape_embedding(embedding)

        if self.training:
            return embedding
        # apply nearest neighbor search
        patch_scores, locations = self.nearest_neighbors(embedding=embedding, n_neighbors=1)
        # reshape to batch dimension
        patch_scores = patch_scores.reshape((batch_size, -1))
        locations = locations.reshape((batch_size, -1))
        # compute anomaly score
        pred_score = self.compute_anomaly_score(patch_scores, locations, embedding)
        # reshape to w, h
        patch_scores = patch_scores.reshape((batch_size, 1, width, height))
        # get anomaly map
        anomaly_map = self.anomaly_map_generator(patch_scores, output_size)

        return InferenceBatch(pred_score=pred_score, anomaly_map=anomaly_map)
Process input tensor through the model.

        During training, returns embeddings extracted from the input. During
        inference, returns anomaly maps and scores computed by comparing input
        embeddings against the memory bank.

        Args:
            input_tensor (torch.Tensor): Input images of shape
                ``(batch_size, channels, height, width)``.

        Returns:
            torch.Tensor | InferenceBatch: During training, returns embeddings.
                During inference, returns ``InferenceBatch`` containing anomaly
                maps and scores.

        Example:
            >>> model = PatchcoreModel(layers=["layer1"])
            >>> input_tensor = torch.randn(32, 3, 224, 224)
            >>> output = model(input_tensor)
            >>> if model.training:
            ...     assert isinstance(output, torch.Tensor)
            ... else:
            ...     assert isinstance(output, InferenceBatch)
        
src/anomalib/models/image/patchcore/torch_model.py