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","."]
docstr: Initialize the Centroid of the Memory Bank.
  
  Args:
      data_loader (DataLoader):  Train Dataloader.
  
  Returns:
      Tensor: Memory Bank.
docstr_tok: ["Initialize","the","Centroid","of","the","Memory","Bank",".","Args",":","data_loader","(","DataLoader",")",":","Train","Dataloader",".","Returns",":","Tensor",":","Memory","Bank","."]
code: def initialize_centroid(self, data_loader: DataLoader) -> None:
      """Initialize the Centroid of the Memory Bank.
  
      Args:
          data_loader (DataLoader):  Train Dataloader.
  
      Returns:
          Tensor: Memory Bank.
      """
      device = next(self.feature_extractor.parameters()).device
      with torch.no_grad():
          for i, data in enumerate(tqdm(data_loader)):
              batch = data["image"].to(device)
              features = self.feature_extractor(batch)
              features = list(features.values())
              target_features = self.descriptor(features)
              self.memory_bank = (
                  (self.memory_bank * i)
                  + target_features.mean(dim=0, keepdim=True)
              ) / (i + 1)
  
      self.memory_bank = rearrange(
          self.memory_bank, "b c h w -> (b h w) c"
      )
  
      if self.gamma_c > 1:
          # TODO: Create PyTorch KMeans class.
          k_means = KMeans(
              n_clusters=(self.scale[0] * self.scale[1])
              // self.gamma_c,
              max_iter=3000,
          )
          cluster_centers = k_means.fit(
              self.memory_bank.cpu()
          ).cluster_centers_
          self.memory_bank = torch.tensor(
              cluster_centers, requires_grad=False
          ).to(device)
  
      self.memory_bank = rearrange(self.memory_bank, "h w -> w h")
  
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 2 for calling the CfaModel obj's underlying member method code with example usage: obj.initialize_centroid(data_loader) without return types