class_docstr: Fits and applies PCA whitening
code: def fit(self, X: Union[np.ndarray, torch.Tensor]):
      if isinstance(X, torch.Tensor):
          X = X.numpy()
  
      mean = X.mean(axis=0)
      X -= mean
      self.mean = torch.from_numpy(mean).view(1, -1)
      Xcov = np.dot(X.T, X)
      d, V = np.linalg.eigh(Xcov)
  
      eps = d.max() * 1e-5
      n_0 = (d < eps).sum()
      if n_0 > 0:
          logging.info(f"{n_0} / {d.size} singular values are 0")
          d[d < eps] = eps
      if self.n_components > 0:
          # if we want to retain all components, n_components = -1
          idx = np.argsort(d)[::-1][: self.n_components]
      else:
          idx = np.argsort(d)[::-1]
      d = d[idx]
      V = V[:, idx]
  
      D = np.diag(1.0 / np.sqrt(d))
      self.DVt = torch.from_numpy(np.dot(D, V.T))
  
file_path: vissl/vissl/utils/pca.py
imports: import logging
  from typing import Union
  import numpy
  import torch
  from vissl.utils.io import load_file, save_file
label_desc: Use image node_id 2 for calling the PCA obj's underlying member method code with example usage: obj.fit(X) without return types