PldaUnsupervisedAdaptor Class Reference

This class takes unlabeled iVectors from the domain of interest and uses their mean and variance to adapt your PLDA matrices to a new domain. More...

#include <plda.h>

Collaboration diagram for PldaUnsupervisedAdaptor:

Public Member Functions

 PldaUnsupervisedAdaptor ()
 
void AddStats (double weight, const Vector< double > &ivector)
 
void AddStats (double weight, const Vector< float > &ivector)
 
void UpdatePlda (const PldaUnsupervisedAdaptorConfig &config, Plda *plda) const
 

Private Attributes

double tot_weight_
 
Vector< double > mean_stats_
 
SpMatrix< double > variance_stats_
 

Detailed Description

This class takes unlabeled iVectors from the domain of interest and uses their mean and variance to adapt your PLDA matrices to a new domain.

This class also stores stats for this form of adaptation.

Definition at line 319 of file plda.h.

Constructor & Destructor Documentation

◆ PldaUnsupervisedAdaptor()

Definition at line 321 of file plda.h.

321 : tot_weight_(0.0) { }

Member Function Documentation

◆ AddStats() [1/2]

void AddStats ( double  weight,
const Vector< double > &  ivector 
)

Definition at line 595 of file plda.cc.

References VectorBase< Real >::Dim(), and KALDI_ASSERT.

Referenced by main().

596  {
597  if (mean_stats_.Dim() == 0) {
598  mean_stats_.Resize(ivector.Dim());
599  variance_stats_.Resize(ivector.Dim());
600  }
601  KALDI_ASSERT(weight >= 0.0);
602  tot_weight_ += weight;
603  mean_stats_.AddVec(weight, ivector);
604  variance_stats_.AddVec2(weight, ivector);
605 }
Vector< double > mean_stats_
Definition: plda.h:332
void Resize(MatrixIndexT length, MatrixResizeType resize_type=kSetZero)
Set vector to a specified size (can be zero).
SpMatrix< double > variance_stats_
Definition: plda.h:333
void AddVec2(const Real alpha, const VectorBase< OtherReal > &v)
rank-one update, this <– this + alpha v v&#39;
Definition: sp-matrix.cc:946
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void Resize(MatrixIndexT nRows, MatrixResizeType resize_type=kSetZero)
Definition: sp-matrix.h:81
void AddVec(const Real alpha, const VectorBase< OtherReal > &v)
Add vector : *this = *this + alpha * rv (with casting between floats and doubles) ...

◆ AddStats() [2/2]

void AddStats ( double  weight,
const Vector< float > &  ivector 
)

Definition at line 607 of file plda.cc.

608  {
609  Vector<double> ivector_dbl(ivector);
610  this->AddStats(weight, ivector_dbl);
611 }
void AddStats(double weight, const Vector< double > &ivector)
Definition: plda.cc:595

◆ UpdatePlda()

void UpdatePlda ( const PldaUnsupervisedAdaptorConfig config,
Plda plda 
) const

Definition at line 613 of file plda.cc.

References SpMatrix< Real >::AddMat2Sp(), MatrixBase< Real >::AddMatMat(), MatrixBase< Real >::AddMatTp(), SpMatrix< Real >::AddTp2Sp(), VectorBase< Real >::AddVec(), SpMatrix< Real >::AddVec2(), PldaUnsupervisedAdaptorConfig::between_covar_scale, TpMatrix< Real >::Cholesky(), MatrixBase< Real >::CopyFromMat(), VectorBase< Real >::CopyFromVec(), Plda::Dim(), SpMatrix< Real >::Eig(), rnnlm::i, TpMatrix< Real >::Invert(), MatrixBase< Real >::Invert(), KALDI_ASSERT, KALDI_LOG, kaldi::kNoTrans, kaldi::kTrans, Plda::mean_, PldaUnsupervisedAdaptorConfig::mean_diff_scale, Plda::psi_, MatrixBase< Real >::Row(), PackedMatrix< Real >::Scale(), kaldi::SortSvd(), Plda::transform_, and PldaUnsupervisedAdaptorConfig::within_covar_scale.

Referenced by main().

614  {
615  KALDI_ASSERT(tot_weight_ > 0.0);
616  int32 dim = mean_stats_.Dim();
617  KALDI_ASSERT(dim == plda->Dim());
618  Vector<double> mean(mean_stats_);
619  mean.Scale(1.0 / tot_weight_);
620  SpMatrix<double> variance(variance_stats_);
621  variance.Scale(1.0 / tot_weight_);
622  variance.AddVec2(-1.0, mean); // Make it the uncentered variance.
623 
624  // mean_diff of the adaptation data from the training data. We optionally add
625  // this to our total covariance matrix
626  Vector<double> mean_diff(mean);
627  mean_diff.AddVec(-1.0, plda->mean_);
628  KALDI_ASSERT(config.mean_diff_scale >= 0.0);
629  variance.AddVec2(config.mean_diff_scale, mean_diff);
630 
631  // update the plda's mean data-member with our adaptation-data mean.
632  plda->mean_.CopyFromVec(mean);
633 
634 
635  // transform_model_ is a row-scaled version of plda->transform_ that
636  // transforms into the space where the total covariance is 1.0. Because
637  // plda->transform_ transforms into a space where the within-class covar is
638  // 1.0 and the the between-class covar is diag(plda->psi_), we need to scale
639  // each dimension i by 1.0 / sqrt(1.0 + plda->psi_(i))
640 
641  Matrix<double> transform_mod(plda->transform_);
642  for (int32 i = 0; i < dim; i++)
643  transform_mod.Row(i).Scale(1.0 / sqrt(1.0 + plda->psi_(i)));
644 
645  // project the variance of the adaptation set into this space where
646  // the total covariance is unit.
647  SpMatrix<double> variance_proj(dim);
648  variance_proj.AddMat2Sp(1.0, transform_mod, kNoTrans,
649  variance, 0.0);
650 
651  // Do eigenvalue decomposition of variance_proj; this will tell us the
652  // directions in which the adaptation-data covariance is more than
653  // the training-data covariance.
654  Matrix<double> P(dim, dim);
655  Vector<double> s(dim);
656  variance_proj.Eig(&s, &P);
657  SortSvd(&s, &P);
658  KALDI_LOG << "Eigenvalues of adaptation-data total-covariance in space where "
659  << "training-data total-covariance is unit, is: " << s;
660 
661  // W, B are the (within,between)-class covars in the space transformed by
662  // transform_mod.
663  SpMatrix<double> W(dim), B(dim);
664  for (int32 i = 0; i < dim; i++) {
665  W(i, i) = 1.0 / (1.0 + plda->psi_(i)),
666  B(i, i) = plda->psi_(i) / (1.0 + plda->psi_(i));
667  }
668 
669  // OK, so variance_proj (projected by transform_mod) is P diag(s) P^T.
670  // Suppose that after transform_mod we project by P^T. Then the adaptation-data's
671  // variance would be P^T P diag(s) P^T P = diag(s), and the PLDA model's
672  // within class variance would be P^T W P and its between-class variance would be
673  // P^T B P. We'd still have that W+B = I in this space.
674  // First let's compute these projected variances... we call the "proj2" because
675  // it's after the data has been projected twice (actually, transformed, as there is no
676  // dimension loss), by transform_mod and then P^T.
677 
678  SpMatrix<double> Wproj2(dim), Bproj2(dim);
679  Wproj2.AddMat2Sp(1.0, P, kTrans, W, 0.0);
680  Bproj2.AddMat2Sp(1.0, P, kTrans, B, 0.0);
681 
682  Matrix<double> Ptrans(P, kTrans);
683 
684  SpMatrix<double> Wproj2mod(Wproj2), Bproj2mod(Bproj2);
685 
686  for (int32 i = 0; i < dim; i++) {
687  // For this eigenvalue, compute the within-class covar projected with this direction,
688  // and the same for between.
689  BaseFloat within = Wproj2(i, i),
690  between = Bproj2(i, i);
691  KALDI_LOG << "For " << i << "'th eigenvalue, value is " << s(i)
692  << ", within-class covar in this direction is " << within
693  << ", between-class is " << between;
694  if (s(i) > 1.0) {
695  double excess_eig = s(i) - 1.0;
696  double excess_within_covar = excess_eig * config.within_covar_scale,
697  excess_between_covar = excess_eig * config.between_covar_scale;
698  Wproj2mod(i, i) += excess_within_covar;
699  Bproj2mod(i, i) += excess_between_covar;
700  } /*
701  Below I was considering a method like below, to try to scale up
702  the dimensions that had less variance than expected in our sample..
703  this didn't help, and actually when I set that power to +0.2 instead
704  of -0.5 it gave me an improvement on sre08. But I'm not sure
705  about this.. it just doesn't seem right.
706  else {
707  BaseFloat scale = pow(std::max(1.0e-10, s(i)), -0.5);
708  BaseFloat max_scale = 10.0; // I'll make this configurable later.
709  scale = std::min(scale, max_scale);
710  Ptrans.Row(i).Scale(scale);
711  } */
712  }
713 
714  // combined transform "transform_mod" and then P^T that takes us to the space
715  // where {W,B}proj2{,mod} are.
716  Matrix<double> combined_trans(dim, dim);
717  combined_trans.AddMatMat(1.0, Ptrans, kNoTrans,
718  transform_mod, kNoTrans, 0.0);
719  Matrix<double> combined_trans_inv(combined_trans); // ... and its inverse.
720  combined_trans_inv.Invert();
721 
722  // Wmod and Bmod are as Wproj2 and Bproj2 but taken back into the original
723  // iVector space.
724  SpMatrix<double> Wmod(dim), Bmod(dim);
725  Wmod.AddMat2Sp(1.0, combined_trans_inv, kNoTrans, Wproj2mod, 0.0);
726  Bmod.AddMat2Sp(1.0, combined_trans_inv, kNoTrans, Bproj2mod, 0.0);
727 
728  TpMatrix<double> C(dim);
729  // Do Cholesky Wmod = C C^T. Now if we use C^{-1} as a transform, we have
730  // C^{-1} W C^{-T} = I, so it makes the within-class covar unit.
731  C.Cholesky(Wmod);
732  TpMatrix<double> Cinv(C);
733  Cinv.Invert();
734 
735  // Bmod_proj is Bmod projected by Cinv.
736  SpMatrix<double> Bmod_proj(dim);
737  Bmod_proj.AddTp2Sp(1.0, Cinv, kNoTrans, Bmod, 0.0);
738  Vector<double> psi_new(dim);
739  Matrix<double> Q(dim, dim);
740  // Do symmetric eigenvalue decomposition of Bmod_proj, so
741  // Bmod_proj = Q diag(psi_new) Q^T
742  Bmod_proj.Eig(&psi_new, &Q);
743  SortSvd(&psi_new, &Q);
744  // This means that if we use Q^T as a transform, then Q^T Bmod_proj Q =
745  // diag(psi_new), hence Q^T diagonalizes Bmod_proj (while leaving the
746  // within-covar unit).
747  // The final transform we want, that projects from our original
748  // space to our newly normalized space, is:
749  // first Cinv, then Q^T, i.e. the
750  // matrix Q^T Cinv.
751  Matrix<double> final_transform(dim, dim);
752  final_transform.AddMatTp(1.0, Q, kTrans, Cinv, kNoTrans, 0.0);
753 
754  KALDI_LOG << "Old diagonal of between-class covar was: "
755  << plda->psi_ << ", new diagonal is "
756  << psi_new;
757  plda->transform_.CopyFromMat(final_transform);
758  plda->psi_.CopyFromVec(psi_new);
759 }
Vector< double > mean_stats_
Definition: plda.h:332
kaldi::int32 int32
SpMatrix< double > variance_stats_
Definition: plda.h:333
float BaseFloat
Definition: kaldi-types.h:29
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_LOG
Definition: kaldi-error.h:153
void SortSvd(VectorBase< Real > *s, MatrixBase< Real > *U, MatrixBase< Real > *Vt, bool sort_on_absolute_value)
Function to ensure that SVD is sorted.

Member Data Documentation

◆ mean_stats_

Vector<double> mean_stats_
private

Definition at line 332 of file plda.h.

◆ tot_weight_

double tot_weight_
private

Definition at line 331 of file plda.h.

◆ variance_stats_

SpMatrix<double> variance_stats_
private

Definition at line 333 of file plda.h.


The documentation for this class was generated from the following files: