class_docstr: Torch implementation of the CFA Model.
  
  Args:
      input_size: (tuple[int, int]): Input size of the image tensor.
      backbone (str): Backbone CNN network.
      gamma_c (int): gamma_c parameter from the paper.
      gamma_d (int): gamma_d parameter from the paper.
      num_nearest_neighbors (int): Number of nearest neighbors.
      num_hard_negative_features (int): Number of hard negative features.
      radius (float): Radius of the hypersphere to search the soft boundary.
class_docstr_tok: ["Torch","implementation","of","the","CFA","Model",".","Args",":","input_size",":","(","tuple","[","int",",","int","]",")",":","Input","size","of","the","image","tensor",".","backbone","(","str",")",":","Backbone","CNN","network",".","gamma_c","(","int",")",":","gamma_c","parameter","from","the","paper",".","gamma_d","(","int",")",":","gamma_d","parameter","from","the","paper",".","num_nearest_neighbors","(","int",")",":","Number","of","nearest","neighbors",".","num_hard_negative_features","(","int",")",":","Number","of","hard","negative","features",".","radius","(","float",")",":","Radius","of","the","hypersphere","to","search","the","soft","boundary","."]
code: def __init__(
      self,
      input_size: tuple[int, int],
      backbone: str,
      gamma_c: int,
      gamma_d: int,
      num_nearest_neighbors: int,
      num_hard_negative_features: int,
      radius: float,
  ) -> None:
      super().__init__()
      self.input_size = torch.Size(input_size)
      self.gamma_c = gamma_c
      self.gamma_d = gamma_d
  
      self.num_nearest_neighbors = num_nearest_neighbors
      self.num_hard_negative_features = num_hard_negative_features
  
      self.register_buffer("memory_bank", torch.tensor(0.0))
      self.memory_bank: Tensor
  
      return_nodes = get_return_nodes(backbone)
      self.feature_extractor = get_feature_extractor(
          backbone, return_nodes
      )
      feature_map_metadata = dryrun_find_featuremap_dims(
          feature_extractor=self.feature_extractor,
          input_size=input_size,
          layers=return_nodes,
      )
      # Scale is to get the largest feature map dimensions of different layers
      # of the feature extractor. In a typical feature extractor, the first
      # layer has the highest resolution.
      resolution = list(feature_map_metadata.values())[0]["resolution"]
      if isinstance(resolution, int):
          self.scale = (resolution,) * 2
      elif isinstance(resolution, tuple):
          self.scale = resolution
      else:
          raise ValueError(
              f"Unknown type {type(resolution)} for `resolution`. Expected types are either int or tuple[int, int]."
          )
  
      self.descriptor = Descriptor(self.gamma_d, backbone)
      self.radius = torch.ones(1, requires_grad=True) * radius
  
      self.anomaly_map_generator = AnomalyMapGenerator(
          image_size=input_size,
          num_nearest_neighbors=num_nearest_neighbors,
      )
  
imports: from __future__ import annotations
  import torch
  import torch.nn.functional
  import torchvision
  from einops import rearrange
  from sklearn.cluster import KMeans
  from torch import Tensor, nn
  from torch.fx.graph_module import GraphModule
  from torch.nn.common_types import _size_2_t
  from torch.utils.data import DataLoader
  from torchvision.models.feature_extraction import create_feature_extractor
  from tqdm import tqdm
  from anomalib.models.cfa.anomaly_map import AnomalyMapGenerator
  from anomalib.models.components import DynamicBufferModule
  from anomalib.models.components.feature_extractors import dryrun_find_featuremap_dims
label_desc: Use image node_id 1 to create a new CfaModel object from inherited base classes: DynamicBufferModule with example: obj = CfaModel(input_size, backbone, gamma_c, gamma_d, num_nearest_neighbors, num_hard_negative_features, radius)