All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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: