class_docstr: A class to train PLDA model from embeddings.
  
  The input is in speechbrain.utils.StatObject_SB format.
  Trains a simplified PLDA model no within-class covariance matrix but full residual covariance matrix.
  
  Arguments
  ---------
  mean : tensor
      Mean of the vectors.
  F : tensor
      Eigenvoice matrix.
  Sigma : tensor
      Residual matrix.
  
  Example
  -------
  >>> from speechbrain.processing.PLDA_LDA import *
  >>> import random, numpy
  >>> dim, N = 10, 100
  >>> n_spkrs = 10
  >>> train_xv = numpy.random.rand(N, dim)
  >>> md = ['md'+str(random.randrange(1,n_spkrs,1)) for i in range(N)]
  >>> modelset = numpy.array(md, dtype="|O")
  >>> sg = ['sg'+str(i) for i in range(N)]
  >>> segset = numpy.array(sg, dtype="|O")
  >>> s = numpy.array([None] * N)
  >>> stat0 = numpy.array([[1.0]]* N)
  >>> xvectors_stat = StatObject_SB(modelset=modelset, segset=segset, start=s, stop=s, stat0=stat0, stat1=train_xv)
  >>> # Training PLDA model: M ~ (mean, F, Sigma)
  >>> plda = PLDA(rank_f=5)
  >>> plda.plda(xvectors_stat)
  >>> print (plda.mean.shape)
  (10,)
  >>> print (plda.F.shape)
  (10, 5)
  >>> print (plda.Sigma.shape)
  (10, 10)
  >>> # Enrollment (20 utts), Test (30 utts)
  >>> en_N = 20
  >>> en_xv = numpy.random.rand(en_N, dim)
  >>> en_sgs = ['en'+str(i) for i in range(en_N)]
  >>> en_sets = numpy.array(en_sgs, dtype="|O")
  >>> en_s = numpy.array([None] * en_N)
  >>> en_stat0 = numpy.array([[1.0]]* en_N)
  >>> en_stat = StatObject_SB(modelset=en_sets, segset=en_sets, start=en_s, stop=en_s, stat0=en_stat0, stat1=en_xv)
  >>> te_N = 30
  >>> te_xv = numpy.random.rand(te_N, dim)
  >>> te_sgs = ['te'+str(i) for i in range(te_N)]
  >>> te_sets = numpy.array(te_sgs, dtype="|O")
  >>> te_s = numpy.array([None] * te_N)
  >>> te_stat0 = numpy.array([[1.0]]* te_N)
  >>> te_stat = StatObject_SB(modelset=te_sets, segset=te_sets, start=te_s, stop=te_s, stat0=te_stat0, stat1=te_xv)
  >>> ndx = Ndx(models=en_sets, testsegs=te_sets)
  >>> # PLDA Scoring
  >>> scores_plda = fast_PLDA_scoring(en_stat, te_stat, ndx, plda.mean, plda.F, plda.Sigma)
  >>> print (scores_plda.scoremat.shape)
  (20, 30)
docstr: Trains PLDA model with no within class covariance matrix but full residual covariance matrix.
  
  Arguments
  ---------
  stat_server : speechbrain.processing.PLDA_LDA.StatObject_SB
      Contains vectors and meta-information to perform PLDA
  rank_f : int
      Rank of the between-class covariance matrix.
  nb_iter : int
      Number of iterations to run.
  scaling_factor : float
      Scaling factor to downscale statistics (value between 0 and 1).
  output_file_name : str
      Name of the output file where to store PLDA model.
docstr_tok: ["Trains","PLDA","model","with","no","within","class","covariance","matrix","but","full","residual","covariance","matrix",".","Arguments","--","--","--","--","-","stat_server",":","speechbrain.processing.PLDA_LDA.StatObject_SB","Contains","vectors","and","meta-information","to","perform","PLDA","rank_f",":","int","Rank","of","the","between-class","covariance","matrix",".","nb_iter",":","int","Number","of","iterations","to","run",".","scaling_factor",":","float","Scaling","factor","to","downscale","statistics","(","value","between","0","and","1",")",".","output_file_name",":","str","Name","of","the","output","file","where","to","store","PLDA","model","."]
code: def plda(
      self,
      stat_server=None,
      output_file_name=None,
      whiten=False,
      w_stat_server=None,
  ):
      """Trains PLDA model with no within class covariance matrix but full residual covariance matrix.
  
      Arguments
      ---------
      stat_server : speechbrain.processing.PLDA_LDA.StatObject_SB
          Contains vectors and meta-information to perform PLDA
      rank_f : int
          Rank of the between-class covariance matrix.
      nb_iter : int
          Number of iterations to run.
      scaling_factor : float
          Scaling factor to downscale statistics (value between 0 and 1).
      output_file_name : str
          Name of the output file where to store PLDA model.
      """
  
      # Dimension of the vector (x-vectors stored in stat1)
      vect_size = stat_server.stat1.shape[1]  # noqa F841
  
      # Whitening (Optional)
      if whiten is True:
          w_mean = w_stat_server.get_mean_stat1()
          w_Sigma = w_stat_server.get_total_covariance_stat1()
          stat_server.whiten_stat1(w_mean, w_Sigma)
  
      # Initialize mean and residual covariance from the training data
      self.mean = stat_server.get_mean_stat1()
      self.Sigma = stat_server.get_total_covariance_stat1()
  
      # Sum stat0 and stat1 for each speaker model
      (
          model_shifted_stat,
          session_per_model,
      ) = stat_server.sum_stat_per_model()
  
      # Number of speakers (classes) in training set
      class_nb = model_shifted_stat.modelset.shape[0]
  
      # Multiply statistics by scaling_factor
      model_shifted_stat.stat0 *= self.scaling_factor
      model_shifted_stat.stat1 *= self.scaling_factor
      session_per_model *= self.scaling_factor
  
      # Covariance for stat1
      sigma_obs = stat_server.get_total_covariance_stat1()
      evals, evecs = linalg.eigh(sigma_obs)
  
      # Initial F (eigen voice matrix) from rank
      idx = numpy.argsort(evals)[::-1]
      evecs = evecs.real[:, idx[: self.rank_f]]
      self.F = evecs[:, : self.rank_f]
  
      # Estimate PLDA model by iterating the EM algorithm
      for it in range(self.nb_iter):
          # E-step
          # print(
          #    f"E-step: Estimate between class covariance, it {it+1} / {nb_iter}"
          # )
  
          # Copy stats as they will be whitened with a different Sigma for each iteration
          local_stat = copy.deepcopy(model_shifted_stat)
  
          # Whiten statistics (with the new mean and Sigma)
          local_stat.whiten_stat1(self.mean, self.Sigma)
  
          # Whiten the EigenVoice matrix
          eigen_values, eigen_vectors = linalg.eigh(self.Sigma)
          ind = eigen_values.real.argsort()[::-1]
          eigen_values = eigen_values.real[ind]
          eigen_vectors = eigen_vectors.real[:, ind]
          sqr_inv_eval_sigma = 1 / numpy.sqrt(eigen_values.real)
          sqr_inv_sigma = numpy.dot(
              eigen_vectors, numpy.diag(sqr_inv_eval_sigma)
          )
          self.F = sqr_inv_sigma.T.dot(self.F)
  
          # Replicate self.stat0
          index_map = numpy.zeros(vect_size, dtype=int)
          _stat0 = local_stat.stat0[:, index_map]
  
          e_h = numpy.zeros((class_nb, self.rank_f))
          e_hh = numpy.zeros((class_nb, self.rank_f, self.rank_f))
  
          # loop on model id's
          fa_model_loop(
              batch_start=0,
              mini_batch_indices=numpy.arange(class_nb),
              factor_analyser=self,
              stat0=_stat0,
              stat1=local_stat.stat1,
              e_h=e_h,
              e_hh=e_hh,
          )
  
          # Accumulate for minimum divergence step
          _R = numpy.sum(e_hh, axis=0) / session_per_model.shape[0]
  
          _C = e_h.T.dot(local_stat.stat1).dot(
              linalg.inv(sqr_inv_sigma)
          )
          _A = numpy.einsum(
              "ijk,i->jk", e_hh, local_stat.stat0.squeeze()
          )
  
          # M-step
          # print("M-step")
          self.F = linalg.solve(_A, _C).T
  
          # Update the residual covariance
          self.Sigma = (
              sigma_obs - self.F.dot(_C) / session_per_model.sum()
          )
  
          # Minimum Divergence step
          self.F = self.F.dot(linalg.cholesky(_R))
  
imports: import numpy
  import copy
  import pickle
  from scipy import linalg
label_desc: Use image node_id 2 for calling the PLDA obj's underlying member method code with example usage: obj.plda(stat_server, output_file_name, whiten, w_stat_server) without return types