MleAmSgmm2Updater Class Reference

#include <estimate-am-sgmm2.h>

Collaboration diagram for MleAmSgmm2Updater:

Public Member Functions

 MleAmSgmm2Updater (const MleAmSgmm2Options &options)
 
void Reconfigure (const MleAmSgmm2Options &options)
 
void Update (const MleAmSgmm2Accs &accs, AmSgmm2 *model, SgmmUpdateFlagsType flags)
 

Private Member Functions

void UpdatePhoneVectorsInternal (const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &H, const std::vector< Matrix< double > > &log_a, AmSgmm2 *model, double *auxf_impr, int32 num_threads, int32 thread_id) const
 
double UpdatePhoneVectors (const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &H, const std::vector< Matrix< double > > &log_a, AmSgmm2 *model) const
 In this update, smoothing terms are not supported. More...
 
double UpdateM (const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &Q, const Vector< double > &gamma_i, AmSgmm2 *model)
 
void RenormalizeV (const MleAmSgmm2Accs &accs, AmSgmm2 *model, const Vector< double > &gamma_i, const std::vector< SpMatrix< double > > &H)
 
double UpdateN (const MleAmSgmm2Accs &accs, const Vector< double > &gamma_i, AmSgmm2 *model)
 
void RenormalizeN (const MleAmSgmm2Accs &accs, const Vector< double > &gamma_i, AmSgmm2 *model)
 
double UpdateVars (const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &S_means, const Vector< double > &gamma_i, AmSgmm2 *model)
 
double UpdateW (const MleAmSgmm2Accs &accs, const std::vector< Matrix< double > > &log_a, const Vector< double > &gamma_i, AmSgmm2 *model)
 
double UpdateU (const MleAmSgmm2Accs &accs, const Vector< double > &gamma_i, AmSgmm2 *model)
 
double UpdateSubstateWeights (const MleAmSgmm2Accs &accs, AmSgmm2 *model)
 
void ComputeMPrior (AmSgmm2 *model)
 
double MapUpdateM (const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &Q, const Vector< double > &gamma_i, AmSgmm2 *model)
 
 KALDI_DISALLOW_COPY_AND_ASSIGN (MleAmSgmm2Updater)
 
 MleAmSgmm2Updater ()
 

Static Private Member Functions

static void ComputeQ (const MleAmSgmm2Accs &accs, const AmSgmm2 &model, std::vector< SpMatrix< double > > *Q)
 Compute the Q_i quantities (Eq. 64). More...
 
static void ComputeSMeans (const MleAmSgmm2Accs &accs, const AmSgmm2 &model, std::vector< SpMatrix< double > > *S_means)
 Compute the S_means quantities, minus sum: (Y_i M_i^T + M_i Y_I^T). More...
 
static void UpdateWGetStats (const MleAmSgmm2Accs &accs, const AmSgmm2 &model, const Matrix< double > &w, const std::vector< Matrix< double > > &log_a, Matrix< double > *F_i, Matrix< double > *g_i, double *tot_like, int32 num_threads, int32 thread_id)
 Called, multithreaded, inside UpdateW. More...
 
static void ComputeLogA (const MleAmSgmm2Accs &accs, std::vector< Matrix< double > > *log_a)
 

Private Attributes

MleAmSgmm2Options options_
 

Friends

class UpdateWClass
 
class UpdatePhoneVectorsClass
 
class EbwEstimateAmSgmm2
 
class EbwAmSgmm2Updater
 

Detailed Description

Definition at line 246 of file estimate-am-sgmm2.h.

Constructor & Destructor Documentation

◆ MleAmSgmm2Updater() [1/2]

MleAmSgmm2Updater ( const MleAmSgmm2Options options)
inlineexplicit

Definition at line 248 of file estimate-am-sgmm2.h.

249  : options_(options) {}
MleAmSgmm2Options options_

◆ MleAmSgmm2Updater() [2/2]

MleAmSgmm2Updater ( )
inlineprivate

Definition at line 341 of file estimate-am-sgmm2.h.

341 {} // Prevent unconfigured updater.

Member Function Documentation

◆ ComputeLogA()

void ComputeLogA ( const MleAmSgmm2Accs accs,
std::vector< Matrix< double > > *  log_a 
)
staticprivate

Definition at line 806 of file estimate-am-sgmm2.cc.

References MleAmSgmm2Accs::a_, MleAmSgmm2Accs::gamma_, KALDI_ASSERT, KALDI_WARN, MleAmSgmm2Accs::num_gaussians_, and MleAmSgmm2Accs::num_groups_.

Referenced by EbwAmSgmm2Updater::UpdateW().

807  {
808  // This computes the logarithm of the statistics a_{jmi} defined
809  // in Eq. 40 of the SSGMM techreport. Although the log of a_{jmi} never
810  // explicitly appears in the techreport, it happens to be more convenient
811  // in the code to use the log of it.
812  // Note: because of the way a is computed, for each (j,m) the
813  // entries over i should always be all zero or all nonzero.
814  int32 num_zeros = 0;
815  KALDI_ASSERT(accs.a_.size() == accs.num_groups_);
816  log_a->resize(accs.num_groups_);
817  for (int32 j1 = 0; j1 < accs.num_groups_; j1++) {
818  int32 num_substates = accs.a_[j1].NumRows();
819  KALDI_ASSERT(num_substates > 0);
820  (*log_a)[j1].Resize(num_substates, accs.num_gaussians_);
821  for (int32 m = 0; m < num_substates; m++) {
822  if (accs.a_[j1](m, 0) == 0.0) { // Zero accs.
823  num_zeros++;
824  if (accs.gamma_[j1].Row(m).Sum() != 0.0)
825  KALDI_WARN << "Inconsistency between a and gamma stats. [BAD!]";
826  // leave the row zero. This means the sub-state saw no stats.
827  } else {
828  (*log_a)[j1].Row(m).CopyFromVec(accs.a_[j1].Row(m));
829  (*log_a)[j1].Row(m).ApplyLog();
830  }
831  }
832  }
833  if (num_zeros != 0)
834  KALDI_WARN << num_zeros
835  << " sub-states with zero \"a\" (and presumably gamma) stats.";
836 }
kaldi::int32 int32
#define KALDI_WARN
Definition: kaldi-error.h:150
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ ComputeMPrior()

void ComputeMPrior ( AmSgmm2 model)
private

Definition at line 1086 of file estimate-am-sgmm2.cc.

References MatrixBase< Real >::AddMat(), SpMatrix< Real >::AddMat2Sp(), AmSgmm2::col_cov_inv_, MatrixBase< Real >::CopyFromMat(), AmSgmm2::FeatureDim(), rnnlm::i, KALDI_ASSERT, KALDI_LOG, kaldi::kNoTrans, kaldi::kTrans, kaldi::Log(), AmSgmm2::M_, M_PI, AmSgmm2::M_prior_, AmSgmm2::NumGauss(), AmSgmm2::PhoneSpaceDim(), AmSgmm2::row_cov_inv_, MatrixBase< Real >::Scale(), and kaldi::TraceSpSp().

1086  {
1088  int32 Ddim = model->FeatureDim();
1089  int32 Sdim = model->PhoneSpaceDim();
1090  int32 nGaussians = model->NumGauss();
1091 
1092  // inverse variance of the columns of M: dim is # of rows
1093  model->col_cov_inv_.Resize(Ddim);
1094  // inverse covariance of the rows of M: dim is # of columns
1095  model->row_cov_inv_.Resize(Sdim);
1096 
1097  model->col_cov_inv_.SetUnit();
1098  model->row_cov_inv_.SetUnit();
1099 
1100  if (model->M_prior_.size() == 0) {
1101  model->M_prior_.resize(nGaussians);
1102  for (int32 i = 0; i < nGaussians; i++) {
1103  model->M_prior_[i].Resize(Ddim, Sdim);
1104  model->M_prior_[i].CopyFromMat(model->M_[i]); // We initialize Mpri as this
1105  }
1106  }
1107 
1109  Matrix<double> avg_M(Ddim, Sdim); // average of the Gaussian prior means
1110  for (int32 i = 0; i < nGaussians; i++)
1111  avg_M.AddMat(1.0, Matrix<double>(model->M_prior_[i]));
1112  avg_M.Scale(1.0 / nGaussians);
1113 
1114  Matrix<double> MDiff(Ddim, Sdim);
1115  for (int32 iter = 0; iter < options_.map_M_prior_iters; iter++) {
1116  { // diagnostic block.
1117  double prior_like = -0.5 * nGaussians * (Ddim * Sdim * Log(2 * M_PI)
1118  + Sdim * (-model->row_cov_inv_.LogPosDefDet())
1119  + Ddim * (-model->col_cov_inv_.LogPosDefDet()));
1120  for (int32 i = 0; i < nGaussians; i++) {
1121  MDiff.CopyFromMat(Matrix<double>(model->M_prior_[i]));
1122  MDiff.AddMat(-1.0, avg_M); // MDiff = M_{i} - avg(M)
1123  SpMatrix<double> tmp(Ddim);
1124  // tmp = MDiff.Omega_r^{-1}*MDiff^T.
1125  tmp.AddMat2Sp(1.0, MDiff, kNoTrans,
1126  SpMatrix<double>(model->row_cov_inv_), 0.0);
1127  prior_like -= 0.5 * TraceSpSp(tmp, SpMatrix<double>(model->col_cov_inv_));
1128  }
1129  KALDI_LOG << "Before iteration " << iter
1130  << " of updating prior over M, log like per dimension modeled is "
1131  << prior_like / (nGaussians * Ddim * Sdim);
1132  }
1133 
1134  // First estimate the column covariances (\Omega_r in paper)
1135  if (options_.full_col_cov) {
1136  size_t limited;
1137  model->col_cov_inv_.SetZero();
1138  for (int32 i = 0; i < nGaussians; i++) {
1139  MDiff.CopyFromMat(Matrix<double>(model->M_prior_[i]));
1140  MDiff.AddMat(-1.0, avg_M); // MDiff = M_{i} - avg(M)
1141  // Omega_r += 1/(D*I) * Mdiff * Omega_c^{-1} * Mdiff^T
1142  model->col_cov_inv_.AddMat2Sp(1.0 / (Ddim * nGaussians),
1143  Matrix<BaseFloat>(MDiff), kNoTrans,
1144  model->row_cov_inv_, 1.0);
1145  }
1146  model->col_cov_inv_.PrintEigs("col_cov");
1147  limited = model->col_cov_inv_.LimitCond(options_.max_cond,
1148  true /*invert the matrix*/);
1149  if (limited != 0) {
1150  KALDI_LOG << "Computing column covariances for M: limited " << limited
1151  << " singular values, max condition is "
1152  << options_.max_cond;
1153  }
1154  }
1155 
1156  // Now estimate the row covariances (\Omega_c in paper)
1157  if (options_.full_row_cov) {
1158  size_t limited;
1159  model->row_cov_inv_.SetZero();
1160  for (int32 i = 0; i < nGaussians; i++) {
1161  MDiff.CopyFromMat(Matrix<double>(model->M_prior_[i]));
1162  MDiff.AddMat(-1.0, avg_M); // MDiff = M_{i} - avg(M)
1163  // Omega_c += 1/(S*I) * Mdiff^T * Omega_r^{-1} * Mdiff.
1164  model->row_cov_inv_.AddMat2Sp(1.0 / (Sdim * nGaussians),
1165  Matrix<BaseFloat>(MDiff), kTrans,
1166  model->col_cov_inv_, 1.0);
1167  }
1168  model->row_cov_inv_.PrintEigs("row_cov");
1169  limited = model->row_cov_inv_.LimitCond(options_.max_cond,
1170  true /*invert the matrix*/);
1171  if (limited != 0) {
1172  KALDI_LOG << "Computing row covariances for M: limited " << limited
1173  << " singular values, max condition is "
1174  << options_.max_cond;
1175  }
1176  }
1177  } // end iterations
1178  }
1179 }
int map_M_prior_iters
num of iterations to update the prior of M
#define M_PI
Definition: kaldi-math.h:44
kaldi::int32 int32
bool full_row_cov
Estimate row covariance instead of using I.
MleAmSgmm2Options options_
bool full_col_cov
Estimate col covariance instead of using I.
double Log(double x)
Definition: kaldi-math.h:100
double TraceSpSp(const SpMatrix< double > &A, const SpMatrix< double > &B)
Definition: sp-matrix.cc:326
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ ComputeQ()

void ComputeQ ( const MleAmSgmm2Accs accs,
const AmSgmm2 model,
std::vector< SpMatrix< double > > *  Q 
)
staticprivate

Compute the Q_i quantities (Eq. 64).

Definition at line 686 of file estimate-am-sgmm2.cc.

References MleAmSgmm2Accs::gamma_, rnnlm::i, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::num_groups_, AmSgmm2::NumSubstatesForGroup(), MleAmSgmm2Accs::phn_space_dim_, and AmSgmm2::v_.

Referenced by EbwAmSgmm2Updater::Update().

688  {
689  Q->resize(accs.num_gaussians_);
690  for (int32 i = 0; i < accs.num_gaussians_; i++) {
691  (*Q)[i].Resize(accs.phn_space_dim_);
692  for (int32 j1 = 0; j1 < accs.num_groups_; j1++) {
693  for (int32 m = 0; m < model.NumSubstatesForGroup(j1); m++) {
694  if (accs.gamma_[j1](m, i) > 0.0) {
695  (*Q)[i].AddVec2(static_cast<BaseFloat>(accs.gamma_[j1](m, i)),
696  model.v_[j1].Row(m));
697  }
698  }
699  }
700  }
701 }
kaldi::int32 int32

◆ ComputeSMeans()

void ComputeSMeans ( const MleAmSgmm2Accs accs,
const AmSgmm2 model,
std::vector< SpMatrix< double > > *  S_means 
)
staticprivate

Compute the S_means quantities, minus sum: (Y_i M_i^T + M_i Y_I^T).

Definition at line 706 of file estimate-am-sgmm2.cc.

References MatrixBase< Real >::AddMat(), MatrixBase< Real >::AddMatMat(), VectorBase< Real >::AddMatVec(), MleAmSgmm2Accs::feature_dim_, MleAmSgmm2Accs::gamma_, rnnlm::i, KALDI_ASSERT, kaldi::kNoTrans, kaldi::kTrans, kaldi::kUndefined, AmSgmm2::M_, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::num_groups_, AmSgmm2::NumSubstatesForGroup(), AmSgmm2::v_, and MleAmSgmm2Accs::Y_.

Referenced by EbwAmSgmm2Updater::Update().

708  {
709  S_means->resize(accs.num_gaussians_);
710  Matrix<double> YM_MY(accs.feature_dim_, accs.feature_dim_);
711  Vector<BaseFloat> mu_jmi(accs.feature_dim_);
712  for (int32 i = 0; i < accs.num_gaussians_; i++) {
713  // YM_MY = - (Y_{i} M_{i}^T)
714  YM_MY.AddMatMat(-1.0, accs.Y_[i], kNoTrans,
715  Matrix<double>(model.M_[i]), kTrans, 0.0);
716  // Add its own transpose: YM_MY = - (Y_{i} M_{i}^T + M_{i} Y_{i}^T)
717  {
718  Matrix<double> M(YM_MY, kTrans);
719  YM_MY.AddMat(1.0, M);
720  }
721  (*S_means)[i].Resize(accs.feature_dim_, kUndefined);
722  (*S_means)[i].CopyFromMat(YM_MY); // Sigma_{i} = -(YM' + MY')
723 
724  for (int32 j1 = 0; j1 < accs.num_groups_; j1++) {
725  for (int32 m = 0; m < model.NumSubstatesForGroup(j1); m++) {
726  if (accs.gamma_[j1](m, i) != 0.0) {
727  // Sigma_{i} += gamma_{jmi} * mu_{jmi}*mu_{jmi}^T
728  mu_jmi.AddMatVec(1.0, model.M_[i], kNoTrans, model.v_[j1].Row(m), 0.0);
729  (*S_means)[i].AddVec2(static_cast<BaseFloat>(accs.gamma_[j1](m, i)), mu_jmi);
730  }
731  }
732  }
733  KALDI_ASSERT(1.0 / (*S_means)[i](0, 0) != 0.0);
734  }
735 }
kaldi::int32 int32
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ KALDI_DISALLOW_COPY_AND_ASSIGN()

KALDI_DISALLOW_COPY_AND_ASSIGN ( MleAmSgmm2Updater  )
private

◆ MapUpdateM()

double MapUpdateM ( const MleAmSgmm2Accs accs,
const std::vector< SpMatrix< double > > &  Q,
const Vector< double > &  gamma_i,
AmSgmm2 model 
)
private

Definition at line 1183 of file estimate-am-sgmm2.cc.

References MatrixBase< Real >::AddMat(), MatrixBase< Real >::AddMatSp(), MatrixBase< Real >::AddSpMat(), AmSgmm2::col_cov_inv_, MatrixBase< Real >::CopyFromMat(), SolverOptions::eps, MleAmSgmm2Accs::feature_dim_, AmSgmm2::FeatureDim(), rnnlm::i, SolverOptions::K, KALDI_LOG, KALDI_WARN, kaldi::kNoTrans, kaldi::kSetZero, AmSgmm2::M_, AmSgmm2::M_prior_, SolverOptions::name, AmSgmm2::NumGauss(), AmSgmm2::PhoneSpaceDim(), AmSgmm2::row_cov_inv_, PackedMatrix< Real >::Scale(), AmSgmm2::SigmaInv_, kaldi::SolveDoubleQuadraticMatrixProblem(), and MleAmSgmm2Accs::Y_.

1186  {
1187  int32 Ddim = model->FeatureDim();
1188  int32 Sdim = model->PhoneSpaceDim();
1189  int32 nGaussians = model->NumGauss();
1190 
1191  KALDI_LOG << "Prior smoothing parameter: Tau = " << options_.tau_map_M;
1192  if (model->M_prior_.size() == 0 || model->col_cov_inv_.NumRows() == 0
1193  || model->row_cov_inv_.NumRows() == 0) {
1194  KALDI_LOG << "Computing the prior first";
1195  ComputeMPrior(model);
1196  }
1197 
1198  Matrix<double> G(Ddim, Sdim);
1199  // \tau \Omega_c^{-1} avg(M) \Omega_r^{-1}, depends on Gaussian index
1200  Matrix<double> prior_term_i(Ddim, Sdim);
1201  SpMatrix<double> P2(model->col_cov_inv_);
1202  SpMatrix<double> Q2(model->row_cov_inv_);
1203  Q2.Scale(options_.tau_map_M);
1204 
1205  double totcount = 0.0, tot_like_impr = 0.0;
1206  for (int32 i = 0; i < nGaussians; ++i) {
1207  if (gamma_i(i) < accs.feature_dim_) {
1208  KALDI_WARN << "For component " << i << ": not updating M due to very "
1209  << "small count (=" << gamma_i(i) << ").";
1210  continue;
1211  }
1212 
1213  Matrix<double> tmp(Ddim, Sdim, kSetZero);
1214  tmp.AddSpMat(1.0, SpMatrix<double>(model->col_cov_inv_),
1215  Matrix<double>(model->M_prior_[i]), kNoTrans, 0.0);
1216  prior_term_i.AddMatSp(options_.tau_map_M, tmp, kNoTrans,
1217  SpMatrix<double>(model->row_cov_inv_), 0.0);
1218 
1219  Matrix<double> SigmaY(Ddim, Sdim, kSetZero);
1220  SigmaY.AddSpMat(1.0, SpMatrix<double>(model->SigmaInv_[i]), accs.Y_[i],
1221  kNoTrans, 0.0);
1222  G.CopyFromMat(SigmaY); // G = \Sigma_{i}^{-1} Y_{i}
1223  G.AddMat(1.0, prior_term_i); // G += \tau \Omega_c^{-1} avg(M) \Omega_r^{-1}
1224  SpMatrix<double> P1(model->SigmaInv_[i]);
1225  Matrix<double> Mi(model->M_[i]);
1226 
1227  SolverOptions opts;
1228  opts.name = "M";
1229  opts.K = options_.max_cond;
1230  opts.eps = options_.epsilon;
1231  double impr =
1232  SolveDoubleQuadraticMatrixProblem(G, P1, P2, Q[i], Q2, opts, &Mi);
1233  model->M_[i].CopyFromMat(Mi);
1234  if (i < 10) {
1235  KALDI_LOG << "Objf impr for projection M for i = " << i << ", is "
1236  << (impr / (gamma_i(i) + 1.0e-20)) << " over " << gamma_i(i)
1237  << " frames";
1238  }
1239  totcount += gamma_i(i);
1240  tot_like_impr += impr;
1241  }
1242  tot_like_impr /= (totcount + 1.0e-20);
1243  KALDI_LOG << "Overall objective function improvement for model projections "
1244  << "M is " << tot_like_impr << " over " << totcount << " frames";
1245  return tot_like_impr;
1246 }
kaldi::int32 int32
BaseFloat epsilon
very small value used to prevent SVD crashing.
Real SolveDoubleQuadraticMatrixProblem(const MatrixBase< Real > &G, const SpMatrix< Real > &P1, const SpMatrix< Real > &P2, const SpMatrix< Real > &Q1, const SpMatrix< Real > &Q2, const SolverOptions &opts, MatrixBase< Real > *M)
Maximizes the auxiliary function : Encountered in matrix update with a prior.
Definition: sp-matrix.cc:827
MleAmSgmm2Options options_
#define KALDI_WARN
Definition: kaldi-error.h:150
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
BaseFloat tau_map_M
For MAP update of the phonetic subspace M.
#define KALDI_LOG
Definition: kaldi-error.h:153
void ComputeMPrior(AmSgmm2 *model)

◆ Reconfigure()

void Reconfigure ( const MleAmSgmm2Options options)
inline

Definition at line 250 of file estimate-am-sgmm2.h.

250  {
251  options_ = options;
252  }
MleAmSgmm2Options options_

◆ RenormalizeN()

void RenormalizeN ( const MleAmSgmm2Accs accs,
const Vector< double > &  gamma_i,
AmSgmm2 model 
)
private

Definition at line 1525 of file estimate-am-sgmm2.cc.

References MatrixBase< Real >::AddMatMat(), SpMatrix< Real >::AddSp(), MleAmSgmm2Accs::feature_dim_, rnnlm::i, KALDI_ASSERT, KALDI_LOG, KALDI_WARN, kaldi::kNoTrans, MatrixBase< Real >::MulColsVec(), AmSgmm2::N_, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::R_, PackedMatrix< Real >::Scale(), MleAmSgmm2Accs::spk_space_dim_, VectorBase< Real >::Sum(), and SpMatrix< Real >::SymPosSemiDefEig().

1527  {
1528  KALDI_ASSERT(accs.R_.size() != 0);
1529  double tot_count = gamma_i.Sum();
1530  if (tot_count == 0) {
1531  KALDI_WARN << "Not renormalizing N, since there are no counts.";
1532  return;
1533  }
1534 
1535  SpMatrix<double> RTot(accs.spk_space_dim_);
1536  // for (int32 i = 0; i < accs.num_gaussians_; i++) {
1537  // RTot.AddSp(1.0, accs.R_[i]);
1538  // }
1539  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1540  RTot.AddSp(gamma_i(i), accs.R_[i]);
1541  }
1542  RTot.Scale(1.0 / tot_count);
1543  Matrix<double> U(accs.spk_space_dim_, accs.spk_space_dim_);
1544  Vector<double> eigs(accs.spk_space_dim_);
1545  RTot.SymPosSemiDefEig(&eigs, &U);
1546  KALDI_LOG << "Renormalizing N, eigs are: " << (eigs);
1547  Vector<double> sqrteigs(accs.spk_space_dim_);
1548  for (int32 t = 0; t < accs.spk_space_dim_; t++) {
1549  sqrteigs(t) = sqrt(eigs(t));
1550  }
1551  // e.g. diag(eigs)^{-0.5} * U' * RTot * U * diag(eigs)^{-0.5} = 1
1552  // But inverse transpose of this transformation needs to take place on R,
1553  // i.e. not (on left: diag(eigs)^{-0.5} * U')
1554  // but: (inverse it: U . diag(eigs)^{0.5},
1555  // transpose it: diag(eigs)^{0.5} U^T. Need to do this on the right to N
1556  // (because N has the spk vecs on the right), so N := N U diag(eigs)^{0.5}
1557  U.MulColsVec(sqrteigs);
1558  Matrix<double> Ntmp(accs.feature_dim_, accs.spk_space_dim_);
1559  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1560  Ntmp.AddMatMat(1.0, Matrix<double>(model->N_[i]), kNoTrans, U, kNoTrans, 0.0);
1561  model->N_[i].CopyFromMat(Ntmp);
1562  }
1563 }
kaldi::int32 int32
#define KALDI_WARN
Definition: kaldi-error.h:150
Real Sum() const
Returns sum of the elements.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ RenormalizeV()

void RenormalizeV ( const MleAmSgmm2Accs accs,
AmSgmm2 model,
const Vector< double > &  gamma_i,
const std::vector< SpMatrix< double > > &  H 
)
private

Definition at line 944 of file estimate-am-sgmm2.cc.

References SpMatrix< Real >::AddMat2Sp(), MatrixBase< Real >::AddMatMat(), VectorBase< Real >::AddMatVec(), SpMatrix< Real >::AddSp(), SpMatrix< Real >::AddVec2(), TpMatrix< Real >::Cholesky(), MatrixBase< Real >::CopyFromTp(), count, MleAmSgmm2Accs::feature_dim_, rnnlm::i, TpMatrix< Real >::Invert(), MatrixBase< Real >::Invert(), SpMatrix< Real >::IsDiagonal(), SpMatrix< Real >::IsPosDef(), SpMatrix< Real >::IsUnit(), KALDI_ASSERT, KALDI_LOG, kaldi::kNoTrans, kaldi::kTrans, AmSgmm2::M_, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::num_groups_, AmSgmm2::NumSubstatesForGroup(), MleAmSgmm2Accs::phn_space_dim_, SpMatrix< Real >::PrintEigs(), MatrixBase< Real >::Row(), PackedMatrix< Real >::Scale(), VectorBase< Real >::Sum(), SpMatrix< Real >::SymPosSemiDefEig(), AmSgmm2::v_, and AmSgmm2::w_.

947  {
948  // Compute H^{(sm)}, the "smoothing" matrix-- average of H's.
949  SpMatrix<double> H_sm(accs.phn_space_dim_);
950  for (int32 i = 0; i < accs.num_gaussians_; i++)
951  H_sm.AddSp(gamma_i(i), H[i]);
952  KALDI_ASSERT(gamma_i.Sum() > 0.0);
953  H_sm.Scale(1.0 / gamma_i.Sum());
954 
955  SpMatrix<double> Sigma(accs.phn_space_dim_);
956  int32 count = 0;
957  for (int32 j1 = 0; j1 < accs.num_groups_; j1++) {
958  for (int32 m = 0; m < model->NumSubstatesForGroup(j1); m++) {
959  count++;
960  Sigma.AddVec2(static_cast<BaseFloat>(1.0), model->v_[j1].Row(m));
961  }
962  }
963  if (!Sigma.IsPosDef()) {
964  KALDI_LOG << "Not renormalizing v because scatter is not positive definite"
965  << " -- maybe first iter?";
966  return;
967  }
968  Sigma.Scale(1.0 / count);
969  KALDI_LOG << "Scatter of vectors v is : ";
970  Sigma.PrintEigs("Sigma");
971 
972  // Want to make variance of v unit and H_sm (like precision matrix) diagonal.
973  TpMatrix<double> L(accs.phn_space_dim_);
974  L.Cholesky(Sigma);
975  TpMatrix<double> LInv(L);
976  LInv.Invert();
977 
978  Matrix<double> tmpL(accs.phn_space_dim_, accs.phn_space_dim_);
979  tmpL.CopyFromTp(L);
980 
981  SpMatrix<double> H_sm_proj(accs.phn_space_dim_);
982  H_sm_proj.AddMat2Sp(1.0, tmpL, kTrans, H_sm, 0.0);
983  // H_sm_proj := L^{T} * H_sm * L.
984  // This is right because we would transform the vectors themselves
985  // by L^{-1}, and H_sm is like the inverse of the vectors,
986  // so it's {L^{-1}}^{-T} = L^T.
987 
988  Matrix<double> U(accs.phn_space_dim_, accs.phn_space_dim_);
989  Vector<double> eigs(accs.phn_space_dim_);
990  H_sm_proj.SymPosSemiDefEig(&eigs, &U, 1.0); // 1.0 means no checking +ve def -> faster
991  KALDI_LOG << "Note on the next diagnostic: the first number is generally not "
992  << "that meaningful as it relates to the static offset";
993  H_sm_proj.PrintEigs("H_sm_proj (Significance of dims in vector space.. note)");
994 
995  // Transform on vectors is U^T L^{-1}.
996  // Why? Because transform on H_sm is T =U^T L^T
997  // and we want T^{-T} by normal rules of vector/covector and we
998  // have (U^T L^T)^{-T} = (L U)^{-1} = U^T L^{-1}.
999  Matrix<double> Trans(accs.phn_space_dim_, accs.phn_space_dim_); // T^{-T}
1000  Matrix<double> tmpLInv(accs.phn_space_dim_, accs.phn_space_dim_);
1001  tmpLInv.CopyFromTp(LInv);
1002  Trans.AddMatMat(1.0, U, kTrans, tmpLInv, kNoTrans, 0.0);
1003  Matrix<double> TransInv(Trans);
1004  TransInv.Invert(); // T in above...
1005 
1006 #ifdef KALDI_PARANOID
1007  {
1008  SpMatrix<double> H_sm_tmp(accs.phn_space_dim_);
1009  H_sm_tmp.AddMat2Sp(1.0, TransInv, kTrans, H_sm, 0.0);
1010  KALDI_ASSERT(H_sm_tmp.IsDiagonal(0.1));
1011  }
1012  {
1013  SpMatrix<double> Sigma_tmp(accs.phn_space_dim_);
1014  Sigma_tmp.AddMat2Sp(1.0, Trans, kNoTrans, Sigma, 0.0);
1015  KALDI_ASSERT(Sigma_tmp.IsUnit(0.1));
1016  }
1017 #endif
1018 
1019  for (int32 j1 = 0; j1 < accs.num_groups_; j1++) {
1020  for (int32 m = 0; m < model->NumSubstatesForGroup(j1); m++) {
1021  Vector<double> tmp(accs.phn_space_dim_);
1022  tmp.AddMatVec(1.0, Trans, kNoTrans, Vector<double>(model->v_[j1].Row(m)), 0.0);
1023  model->v_[j1].Row(m).CopyFromVec(tmp);
1024  }
1025  }
1026  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1027  Vector<double> tmp(accs.phn_space_dim_);
1028  tmp.AddMatVec(1.0, TransInv, kTrans, Vector<double>(model->w_.Row(i)), 0.0);
1029  model->w_.Row(i).CopyFromVec(tmp);
1030 
1031  Matrix<double> tmpM(accs.feature_dim_, accs.phn_space_dim_);
1032  // Multiplying on right not left so must not transpose TransInv.
1033  tmpM.AddMatMat(1.0, Matrix<double>(model->M_[i]), kNoTrans,
1034  TransInv, kNoTrans, 0.0);
1035  model->M_[i].CopyFromMat(tmpM);
1036  }
1037  KALDI_LOG << "Renormalized subspace.";
1038 }
kaldi::int32 int32
const size_t count
Real Sum() const
Returns sum of the elements.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ Update()

void Update ( const MleAmSgmm2Accs accs,
AmSgmm2 model,
SgmmUpdateFlagsType  flags 
)

Definition at line 612 of file estimate-am-sgmm2.cc.

References MleAmSgmm2Accs::a_, VectorBase< Real >::AddRowSumMat(), AmSgmm2::ComputeH(), MleAmSgmm2Accs::gamma_, KALDI_LOG, kaldi::kSgmmCovarianceMatrix, kaldi::kSgmmPhoneProjections, kaldi::kSgmmPhoneVectors, kaldi::kSgmmPhoneWeightProjections, kaldi::kSgmmSpeakerProjections, kaldi::kSgmmSpeakerWeightProjections, kaldi::kSgmmSubstateWeights, AmSgmm2::n_, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::num_groups_, MleAmSgmm2Accs::total_frames_, MleAmSgmm2Accs::total_like_, and AmSgmm2::w_jmi_.

Referenced by main(), and TestSgmm2AccsIO().

614  {
615  // Q_{i}, quadratic term for phonetic subspace estimation. Dim is [I][S][S]
616  std::vector< SpMatrix<double> > Q;
617 
618  // Eq (74): S_{i}^{(means)}, scatter of substate mean vectors for estimating
619  // the shared covariance matrices. [Actually this variable contains also the
620  // term -(Y_i M_i^T + M_i Y_I^T).] Dimension is [I][D][D].
621  std::vector< SpMatrix<double> > S_means;
622  std::vector<Matrix<double> > log_a;
623 
624  Vector<double> gamma_i(accs.num_gaussians_);
625  for (int32 j1 = 0; j1 < accs.num_groups_; j1++)
626  gamma_i.AddRowSumMat(1.0, accs.gamma_[j1]); // add sum of rows of
627  // accs.gamma_[j1], to gamma_i.
628 
629  if (flags & kSgmmPhoneProjections)
630  ComputeQ(accs, *model, &Q);
631  if (flags & kSgmmCovarianceMatrix)
632  ComputeSMeans(accs, *model, &S_means);
633  if (!accs.a_.empty())
634  ComputeLogA(accs, &log_a);
635 
636  // quantities used in both vector and weights updates...
637  vector< SpMatrix<double> > H;
638  // "smoothing" matrices, weighted sums of above.
639  SpMatrix<double> H_sm; // weighted sum of H. Used e.g. in renormalizing phonetic space.
642  model->ComputeH(&H);
643 
644  BaseFloat tot_impr = 0.0;
645 
646  if (flags & kSgmmPhoneVectors)
647  tot_impr += UpdatePhoneVectors(accs, H, log_a, model);
648  if (flags & kSgmmPhoneProjections) {
649  if (options_.tau_map_M > 0.0)
650  tot_impr += MapUpdateM(accs, Q, gamma_i, model); // MAP adaptation of M
651  else
652  tot_impr += UpdateM(accs, Q, gamma_i, model);
653  }
654  if (flags & kSgmmPhoneWeightProjections)
655  tot_impr += UpdateW(accs, log_a, gamma_i, model);
656  if (flags & kSgmmCovarianceMatrix)
657  tot_impr += UpdateVars(accs, S_means, gamma_i, model);
658  if (flags & kSgmmSubstateWeights)
659  tot_impr += UpdateSubstateWeights(accs, model);
660  if (flags & kSgmmSpeakerProjections)
661  tot_impr += UpdateN(accs, gamma_i, model);
662  if (flags & kSgmmSpeakerWeightProjections)
663  tot_impr += UpdateU(accs, gamma_i, model);
664 
665  if ((flags & kSgmmSpeakerProjections) && (options_.renormalize_N))
666  RenormalizeN(accs, gamma_i, model); // if you renormalize N you have to
667  // alter any speaker vectors you're keeping around, as well.
668  // So be careful with this option.
669 
671  RenormalizeV(accs, model, gamma_i, H);
672 
673  KALDI_LOG << "*Overall auxf improvement, combining all parameters, is "
674  << tot_impr;
675 
676  KALDI_LOG << "***Overall data likelihood is "
677  << (accs.total_like_/accs.total_frames_)
678  << " over " << accs.total_frames_ << " frames.";
679 
680  model->n_.clear(); // has become invalid.
681  model->w_jmi_.clear(); // has become invalid.
682  // we updated the v or w quantities.
683 }
void RenormalizeV(const MleAmSgmm2Accs &accs, AmSgmm2 *model, const Vector< double > &gamma_i, const std::vector< SpMatrix< double > > &H)
static void ComputeQ(const MleAmSgmm2Accs &accs, const AmSgmm2 &model, std::vector< SpMatrix< double > > *Q)
Compute the Q_i quantities (Eq. 64).
double UpdateM(const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &Q, const Vector< double > &gamma_i, AmSgmm2 *model)
double MapUpdateM(const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &Q, const Vector< double > &gamma_i, AmSgmm2 *model)
kaldi::int32 int32
double UpdateW(const MleAmSgmm2Accs &accs, const std::vector< Matrix< double > > &log_a, const Vector< double > &gamma_i, AmSgmm2 *model)
static void ComputeSMeans(const MleAmSgmm2Accs &accs, const AmSgmm2 &model, std::vector< SpMatrix< double > > *S_means)
Compute the S_means quantities, minus sum: (Y_i M_i^T + M_i Y_I^T).
double UpdatePhoneVectors(const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &H, const std::vector< Matrix< double > > &log_a, AmSgmm2 *model) const
In this update, smoothing terms are not supported.
void RenormalizeN(const MleAmSgmm2Accs &accs, const Vector< double > &gamma_i, AmSgmm2 *model)
double UpdateVars(const MleAmSgmm2Accs &accs, const std::vector< SpMatrix< double > > &S_means, const Vector< double > &gamma_i, AmSgmm2 *model)
MleAmSgmm2Options options_
t .. not really part of SGMM.
Definition: model-common.h:55
float BaseFloat
Definition: kaldi-types.h:29
The letters correspond to the variable names.
Definition: model-common.h:48
double UpdateSubstateWeights(const MleAmSgmm2Accs &accs, AmSgmm2 *model)
BaseFloat tau_map_M
For MAP update of the phonetic subspace M.
double UpdateU(const MleAmSgmm2Accs &accs, const Vector< double > &gamma_i, AmSgmm2 *model)
#define KALDI_LOG
Definition: kaldi-error.h:153
double UpdateN(const MleAmSgmm2Accs &accs, const Vector< double > &gamma_i, AmSgmm2 *model)
static void ComputeLogA(const MleAmSgmm2Accs &accs, std::vector< Matrix< double > > *log_a)

◆ UpdateM()

double UpdateM ( const MleAmSgmm2Accs accs,
const std::vector< SpMatrix< double > > &  Q,
const Vector< double > &  gamma_i,
AmSgmm2 model 
)
private

Definition at line 1040 of file estimate-am-sgmm2.cc.

References SolverOptions::eps, MleAmSgmm2Accs::feature_dim_, rnnlm::i, SolverOptions::K, KALDI_LOG, KALDI_VLOG, KALDI_WARN, AmSgmm2::M_, SolverOptions::name, MleAmSgmm2Accs::num_gaussians_, AmSgmm2::SigmaInv_, kaldi::SolveQuadraticMatrixProblem(), and MleAmSgmm2Accs::Y_.

1043  {
1044  double tot_count = 0.0, tot_like_impr = 0.0;
1045  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1046  if (gamma_i(i) < accs.feature_dim_) {
1047  KALDI_WARN << "For component " << i << ": not updating M due to very "
1048  << "small count (=" << gamma_i(i) << ").";
1049  continue;
1050  }
1051 
1052  SolverOptions opts;
1053  opts.name = "M";
1054  opts.K = options_.max_cond;
1055  opts.eps = options_.epsilon;
1056 
1057  Matrix<double> Mi(model->M_[i]);
1058  double impr =
1059  SolveQuadraticMatrixProblem(Q[i], accs.Y_[i],
1060  SpMatrix<double>(model->SigmaInv_[i]),
1061  opts, &Mi);
1062 
1063  model->M_[i].CopyFromMat(Mi);
1064 
1065  if (i < 10) {
1066  KALDI_VLOG(2) << "Objf impr for projection M for i = " << i << ", is "
1067  << (impr/(gamma_i(i) + 1.0e-20)) << " over " << gamma_i(i)
1068  << " frames";
1069  }
1070  tot_count += gamma_i(i);
1071  tot_like_impr += impr;
1072  }
1073  tot_like_impr /= (tot_count + 1.0e-20);
1074  KALDI_LOG << "Overall objective function improvement for model projections "
1075  << "M is " << tot_like_impr << " over " << tot_count << " frames";
1076  return tot_like_impr;
1077 }
Real SolveQuadraticMatrixProblem(const SpMatrix< Real > &Q, const MatrixBase< Real > &Y, const SpMatrix< Real > &SigmaInv, const SolverOptions &opts, MatrixBase< Real > *M)
Maximizes the auxiliary function : Like a numerically stable version of .
Definition: sp-matrix.cc:729
kaldi::int32 int32
BaseFloat epsilon
very small value used to prevent SVD crashing.
MleAmSgmm2Options options_
#define KALDI_WARN
Definition: kaldi-error.h:150
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
#define KALDI_VLOG(v)
Definition: kaldi-error.h:156
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ UpdateN()

double UpdateN ( const MleAmSgmm2Accs accs,
const Vector< double > &  gamma_i,
AmSgmm2 model 
)
private

Definition at line 1486 of file estimate-am-sgmm2.cc.

References SolverOptions::eps, rnnlm::i, SolverOptions::K, KALDI_ERR, KALDI_LOG, KALDI_WARN, AmSgmm2::N_, SolverOptions::name, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::R_, AmSgmm2::SigmaInv_, kaldi::SolveQuadraticMatrixProblem(), MleAmSgmm2Accs::spk_space_dim_, and MleAmSgmm2Accs::Z_.

1488  {
1489  double tot_count = 0.0, tot_like_impr = 0.0;
1490  if (accs.spk_space_dim_ == 0 || accs.R_.size() == 0 || accs.Z_.size() == 0) {
1491  KALDI_ERR << "Speaker subspace dim is zero or no stats accumulated";
1492  }
1493  SolverOptions opts;
1494  opts.name = "N";
1495  opts.K = options_.max_cond;
1496  opts.eps = options_.epsilon;
1497 
1498 
1499  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1500  if (gamma_i(i) < 2 * accs.spk_space_dim_) {
1501  KALDI_WARN << "Not updating speaker basis for i = " << (i)
1502  << " because count is too small " << (gamma_i(i));
1503  continue;
1504  }
1505  Matrix<double> Ni(model->N_[i]);
1506  double impr =
1507  SolveQuadraticMatrixProblem(accs.R_[i], accs.Z_[i],
1508  SpMatrix<double>(model->SigmaInv_[i]),
1509  opts, &Ni);
1510  model->N_[i].CopyFromMat(Ni);
1511  if (i < 10) {
1512  KALDI_LOG << "Objf impr for spk projection N for i = " << (i)
1513  << ", is " << (impr / (gamma_i(i) + 1.0e-20)) << " over "
1514  << gamma_i(i) << " frames";
1515  }
1516  tot_count += gamma_i(i);
1517  tot_like_impr += impr;
1518  }
1519 
1520  KALDI_LOG << "**Overall objf impr for N is " << (tot_like_impr/tot_count)
1521  << " over " << tot_count << " frames";
1522  return (tot_like_impr/tot_count);
1523 }
Real SolveQuadraticMatrixProblem(const SpMatrix< Real > &Q, const MatrixBase< Real > &Y, const SpMatrix< Real > &SigmaInv, const SolverOptions &opts, MatrixBase< Real > *M)
Maximizes the auxiliary function : Like a numerically stable version of .
Definition: sp-matrix.cc:729
kaldi::int32 int32
BaseFloat epsilon
very small value used to prevent SVD crashing.
MleAmSgmm2Options options_
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_WARN
Definition: kaldi-error.h:150
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ UpdatePhoneVectors()

double UpdatePhoneVectors ( const MleAmSgmm2Accs accs,
const std::vector< SpMatrix< double > > &  H,
const std::vector< Matrix< double > > &  log_a,
AmSgmm2 model 
) const
private

In this update, smoothing terms are not supported.

However, it does compute the auxiliary function after doing the update, and backtracks if it did not increase (due to the weight terms, increase is not mathematically guaranteed).

Definition at line 782 of file estimate-am-sgmm2.cc.

References count, MleAmSgmm2Accs::gamma_, KALDI_LOG, MleAmSgmm2Accs::num_groups_, and kaldi::RunMultiThreaded().

786  {
787 
788  KALDI_LOG << "Updating phone vectors";
789 
790  double count = 0.0, auxf_impr = 0.0; // sum over all states
791 
792  for (int32 j1 = 0; j1 < accs.num_groups_; j1++)
793  count += accs.gamma_[j1].Sum();
794 
795  UpdatePhoneVectorsClass c(*this, accs, H, log_a, model, &auxf_impr);
796  RunMultiThreaded(c);
797 
798  double auxf_per_frame = auxf_impr / (count + 1.0e-20);
799 
800  KALDI_LOG << "**Overall auxf impr for v is " << auxf_per_frame << " over "
801  << count << " frames";
802  return auxf_per_frame;
803 }
kaldi::int32 int32
const size_t count
void RunMultiThreaded(const C &c_in)
Here, class C should inherit from MultiThreadable.
Definition: kaldi-thread.h:151
friend class UpdatePhoneVectorsClass
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ UpdatePhoneVectorsInternal()

void UpdatePhoneVectorsInternal ( const MleAmSgmm2Accs accs,
const std::vector< SpMatrix< double > > &  H,
const std::vector< Matrix< double > > &  log_a,
AmSgmm2 model,
double *  auxf_impr,
int32  num_threads,
int32  thread_id 
) const
private

Definition at line 838 of file estimate-am-sgmm2.cc.

References VectorBase< Real >::Add(), VectorBase< Real >::AddMatVec(), SpMatrix< Real >::AddSp(), VectorBase< Real >::AddVec(), SpMatrix< Real >::AddVec2(), VectorBase< Real >::ApplyExp(), SolverOptions::eps, MleAmSgmm2Accs::gamma_, rnnlm::i, SolverOptions::K, KALDI_LOG, KALDI_WARN, kaldi::kNoTrans, VectorBase< Real >::LogSumExp(), SolverOptions::name, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::num_groups_, AmSgmm2::NumSubstatesForGroup(), MleAmSgmm2Accs::phn_space_dim_, MatrixBase< Real >::Row(), kaldi::SolveQuadraticProblem(), AmSgmm2::v_, kaldi::VecSpVec(), kaldi::VecVec(), AmSgmm2::w_, and MleAmSgmm2Accs::y_.

845  {
846 
847  int32 J1 = accs.num_groups_, block_size = (J1 + (num_threads-1)) / num_threads,
848  j1_start = block_size * thread_id,
849  j1_end = std::min(accs.num_groups_, j1_start + block_size);
850 
851  double tot_auxf_impr = 0.0;
852 
853  for (int32 j1 = j1_start; j1 < j1_end; j1++) {
854  for (int32 m = 0; m < model->NumSubstatesForGroup(j1); m++) {
855  double gamma_jm = accs.gamma_[j1].Row(m).Sum();
856  SpMatrix<double> X_jm(accs.phn_space_dim_); // = \sum_i \gamma_{jmi} H_i
857 
858  for (int32 i = 0; i < accs.num_gaussians_; i++) {
859  double gamma_jmi = accs.gamma_[j1](m, i);
860  if (gamma_jmi != 0.0)
861  X_jm.AddSp(gamma_jmi, H[i]);
862  }
863 
864  Vector<double> v_jm_orig(model->v_[j1].Row(m)),
865  v_jm(v_jm_orig);
866 
867  double exact_auxf_start = 0.0, exact_auxf = 0.0, approx_auxf_impr = 0.0;
868  int32 backtrack_iter, max_backtrack = 10;
869  for (backtrack_iter = 0; backtrack_iter < max_backtrack; backtrack_iter++) {
870  // Note: the 1st time we go through this loop we have not yet updated
871  // v_jm and it has the old value; the 2nd time, it has the updated value
872  // and we will typically break at this point, after verifying that
873  // the auxf has improved.
874 
875  // w_jm = softmax([w_{k1}^T ... w_{kD}^T] * v_{jkm}) eq.(7)
876  Vector<double> w_jm(accs.num_gaussians_);
877  w_jm.AddMatVec(1.0, Matrix<double>(model->w_), kNoTrans,
878  v_jm, 0.0);
879  if (!log_a.empty()) w_jm.AddVec(1.0, log_a[j1].Row(m)); // SSGMM techreport eq. 42
880  w_jm.Add(-w_jm.LogSumExp()); // it is now log w_jm
881 
882 
883  exact_auxf = VecVec(w_jm, accs.gamma_[j1].Row(m))
884  + VecVec(v_jm, accs.y_[j1].Row(m))
885  -0.5 * VecSpVec(v_jm, X_jm, v_jm);
886 
887  if (backtrack_iter == 0) {
888  exact_auxf_start = exact_auxf;
889  } else {
890  if (exact_auxf >= exact_auxf_start) {
891  break; // terminate backtracking.
892  } else {
893  KALDI_LOG << "Backtracking computation of v_jm for j = " << j1
894  << " and m = " << m << " because auxf changed by "
895  << (exact_auxf-exact_auxf_start) << " [vs. predicted:] "
896  << approx_auxf_impr;
897  v_jm.AddVec(1.0, v_jm_orig);
898  v_jm.Scale(0.5);
899  }
900  }
901 
902  if (backtrack_iter == 0) { // computing updated value.
903  w_jm.ApplyExp(); // it is now w_jm
904  SpMatrix<double> H_jm(X_jm);
905  Vector<double> g_jm(accs.y_[j1].Row(m));
906  for (int32 i = 0; i < accs.num_gaussians_; i++) {
907  double gamma_jmi = accs.gamma_[j1](m, i);
908  double quadratic_term = std::max(gamma_jmi, gamma_jm * w_jm(i));
909  double scalar = gamma_jmi - gamma_jm * w_jm(i) + quadratic_term
910  * VecVec(model->w_.Row(i), model->v_[j1].Row(m));
911  g_jm.AddVec(scalar, model->w_.Row(i));
912  if (quadratic_term > 1.0e-10) {
913  H_jm.AddVec2(static_cast<BaseFloat>(quadratic_term), model->w_.Row(i));
914  }
915  }
916 
917  SolverOptions opts;
918  opts.name = "v";
919  opts.K = options_.max_cond;
920  opts.eps = options_.epsilon;
921 
922  approx_auxf_impr = SolveQuadraticProblem(H_jm, g_jm, opts, &v_jm);
923  }
924  }
925  double exact_auxf_impr = exact_auxf - exact_auxf_start;
926  tot_auxf_impr += exact_auxf_impr;
927  if (backtrack_iter == max_backtrack) {
928  KALDI_WARN << "Backtracked " << max_backtrack << " times [not updating]";
929  } else {
930  model->v_[j1].Row(m).CopyFromVec(v_jm);
931  }
932 
933  if (j1 < 3 && m < 3) {
934  KALDI_LOG << "Auxf impr for j = " << j1 << " m = " << m << " is "
935  << (exact_auxf_impr/gamma_jm+1.0e-20) << " per frame over "
936  << gamma_jm << " frames.";
937  }
938  }
939  }
940  *auxf_impr_ptr = tot_auxf_impr;
941 }
double SolveQuadraticProblem(const SpMatrix< double > &H, const VectorBase< double > &g, const SolverOptions &opts, VectorBase< double > *x)
Definition: sp-matrix.cc:635
kaldi::int32 int32
BaseFloat epsilon
very small value used to prevent SVD crashing.
MleAmSgmm2Options options_
Real VecSpVec(const VectorBase< Real > &v1, const SpMatrix< Real > &M, const VectorBase< Real > &v2)
Computes v1^T * M * v2.
Definition: sp-matrix.cc:964
#define KALDI_WARN
Definition: kaldi-error.h:150
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
#define KALDI_LOG
Definition: kaldi-error.h:153
Real VecVec(const VectorBase< Real > &a, const VectorBase< Real > &b)
Returns dot product between v1 and v2.
Definition: kaldi-vector.cc:37

◆ UpdateSubstateWeights()

double UpdateSubstateWeights ( const MleAmSgmm2Accs accs,
AmSgmm2 model 
)
private

Definition at line 1682 of file estimate-am-sgmm2.cc.

References VectorBase< Real >::Add(), AmSgmm2::c_, MleAmSgmm2Accs::gamma_c_, KALDI_LOG, KALDI_WARN, kaldi::Log(), MleAmSgmm2Accs::num_pdfs_, AmSgmm2::NumSubstatesForPdf(), and VectorBase< Real >::Sum().

1683  {
1684  KALDI_LOG << "Updating substate mixture weights";
1685  // Also set the vector gamma_j which is a cache of the state occupancies.
1686 
1687  double tot_gamma = 0.0, objf_impr = 0.0;
1688  for (int32 j2 = 0; j2 < accs.num_pdfs_; j2++) {
1689  double gamma_j_sm = 0.0;
1690  int32 num_substates = model->NumSubstatesForPdf(j2);
1691  const Vector<double> &occs(accs.gamma_c_[j2]);
1692  Vector<double> smoothed_occs(occs);
1693  smoothed_occs.Add(options_.tau_c);
1694  gamma_j_sm += smoothed_occs.Sum();
1695  tot_gamma += occs.Sum();
1696 
1697  for (int32 m = 0; m < num_substates; m++) {
1698  double cur_weight = model->c_[j2](m);
1699  if (cur_weight <= 0) {
1700  KALDI_WARN << "Zero or negative weight, flooring";
1701  cur_weight = 1.0e-10; // future work(arnab): remove magic numbers
1702  }
1703  model->c_[j2](m) = smoothed_occs(m) / gamma_j_sm;
1704  objf_impr += Log(model->c_[j2](m) / cur_weight) * occs(m);
1705  }
1706  }
1707  KALDI_LOG << "**Overall objf impr for c is " << (objf_impr/tot_gamma)
1708  << ", over " << tot_gamma << " frames.";
1709  return (objf_impr/tot_gamma);
1710 }
BaseFloat tau_c
Smoothing constant for sub-state weights [count to add to each one].
kaldi::int32 int32
MleAmSgmm2Options options_
double Log(double x)
Definition: kaldi-math.h:100
#define KALDI_WARN
Definition: kaldi-error.h:150
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ UpdateU()

double UpdateU ( const MleAmSgmm2Accs accs,
const Vector< double > &  gamma_i,
AmSgmm2 model 
)
private

Definition at line 1439 of file estimate-am-sgmm2.cc.

References VectorBase< Real >::AddVec(), SolverOptions::eps, rnnlm::i, SolverOptions::K, KALDI_LOG, KALDI_WARN, SolverOptions::name, MleAmSgmm2Accs::num_gaussians_, MatrixBase< Real >::Row(), VectorBase< Real >::Scale(), kaldi::SolveQuadraticProblem(), MleAmSgmm2Accs::spk_space_dim_, VectorBase< Real >::Sum(), MleAmSgmm2Accs::t_, MleAmSgmm2Accs::U_, and AmSgmm2::u_.

1441  {
1442  double tot_impr = 0.0;
1443  SolverOptions opts;
1444  opts.name = "u";
1445  opts.K = options_.max_cond;
1446  opts.eps = options_.epsilon;
1447 
1448  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1449  if (gamma_i(i) < 200.0) {
1450  KALDI_LOG << "Count is small " << gamma_i(i) << " for gaussian "
1451  << i << ", not updating u_i.";
1452  continue;
1453  }
1454  Vector<double> u_i(model->u_.Row(i));
1455  Vector<double> delta_u(accs.spk_space_dim_);
1456  double impr =
1457  SolveQuadraticProblem(accs.U_[i], accs.t_.Row(i), opts, &delta_u);
1458  double impr_per_frame = impr / gamma_i(i);
1459  if (impr_per_frame > options_.max_impr_u) {
1460  KALDI_WARN << "Updating speaker weight projections u, for Gaussian index "
1461  << i << ", impr/frame is " << impr_per_frame << " over "
1462  << gamma_i(i) << " frames, scaling back to not exceed "
1463  << options_.max_impr_u;
1464  double scale = options_.max_impr_u / impr_per_frame;
1465  impr *= scale;
1466  delta_u.Scale(scale);
1467  // Note: a linear scaling of "impr" with "scale" is not quite accurate
1468  // in depicting how the quadratic auxiliary function varies as we change
1469  // the scale on "delta", but this does not really matter-- the goal is
1470  // to limit the auxiliary-function change to not be too large.
1471  }
1472  if (i < 10) {
1473  KALDI_LOG << "Objf impr for spk weight-projection u for i = " << (i)
1474  << ", is " << (impr / (gamma_i(i) + 1.0e-20)) << " over "
1475  << gamma_i(i) << " frames";
1476  }
1477  u_i.AddVec(1.0, delta_u);
1478  model->u_.Row(i).CopyFromVec(u_i);
1479  tot_impr += impr;
1480  }
1481  KALDI_LOG << "**Overall objf impr for u is " << (tot_impr/gamma_i.Sum())
1482  << ", over " << gamma_i.Sum() << " frames";
1483  return tot_impr / gamma_i.Sum();
1484 }
double SolveQuadraticProblem(const SpMatrix< double > &H, const VectorBase< double > &g, const SolverOptions &opts, VectorBase< double > *x)
Definition: sp-matrix.cc:635
kaldi::int32 int32
BaseFloat epsilon
very small value used to prevent SVD crashing.
MleAmSgmm2Options options_
BaseFloat max_impr_u
max improvement per frame allowed in update of u.
#define KALDI_WARN
Definition: kaldi-error.h:150
Real Sum() const
Returns sum of the elements.
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
#define KALDI_LOG
Definition: kaldi-error.h:153
void AddVec(const Real alpha, const VectorBase< OtherReal > &v)
Add vector : *this = *this + alpha * rv (with casting between floats and doubles) ...

◆ UpdateVars()

double UpdateVars ( const MleAmSgmm2Accs accs,
const std::vector< SpMatrix< double > > &  S_means,
const Vector< double > &  gamma_i,
AmSgmm2 model 
)
private

Definition at line 1566 of file estimate-am-sgmm2.cc.

References SpMatrix< Real >::AddSp(), VectorBase< Real >::ApplyFloor(), SpMatrix< Real >::CopyFromSp(), rnnlm::d, MleAmSgmm2Accs::feature_dim_, rnnlm::i, rnnlm::j, KALDI_ASSERT, KALDI_LOG, KALDI_VLOG, KALDI_WARN, SpMatrix< Real >::LimitCondDouble(), MleAmSgmm2Accs::num_gaussians_, PackedMatrix< Real >::NumRows(), MleAmSgmm2Accs::S_, PackedMatrix< Real >::Scale(), PackedMatrix< Real >::SetUnit(), AmSgmm2::SigmaInv_, VectorBase< Real >::Sum(), and kaldi::TraceSpSp().

1569  {
1570  KALDI_ASSERT(S_means.size() == static_cast<size_t>(accs.num_gaussians_));
1571 
1572  SpMatrix<double> Sigma_i(accs.feature_dim_), Sigma_i_ml(accs.feature_dim_);
1573  double tot_objf_impr = 0.0, tot_t = 0.0;
1574  SpMatrix<double> covfloor(accs.feature_dim_);
1575  Vector<double> objf_improv(accs.num_gaussians_);
1576 
1577  // First pass over all (shared) Gaussian components to calculate the
1578  // ML estimate of the covariances, and the total covariance for flooring.
1579  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1580  // Eq. (75): Sigma_{i}^{ml} = 1/gamma_{i} [S_{i} + S_{i}^{(means)} - ...
1581  // Y_{i} M_{i}^T - M_{i} Y_{i}^T]
1582  // Note the S_means already contains the Y_{i} M_{i}^T terms.
1583  Sigma_i_ml.CopyFromSp(S_means[i]);
1584  Sigma_i_ml.AddSp(1.0, accs.S_[i]);
1585 
1586  covfloor.AddSp(1.0, Sigma_i_ml);
1587  // inverting small values e.g. 4.41745328e-40 seems to generate inf,
1588  // although would be fixed up later.
1589  if (gamma_i(i) > 1.0e-20) {
1590  Sigma_i_ml.Scale(1 / (gamma_i(i) + 1.0e-20));
1591  } else {
1592  Sigma_i_ml.SetUnit();
1593  }
1594  KALDI_ASSERT(1.0 / Sigma_i_ml(0, 0) != 0.0);
1595  // Eq. (76): Compute the objective function with the old parameter values
1596  objf_improv(i) = model->SigmaInv_[i].LogPosDefDet() -
1597  TraceSpSp(SpMatrix<double>(model->SigmaInv_[i]), Sigma_i_ml);
1598 
1599  model->SigmaInv_[i].CopyFromSp(Sigma_i_ml); // inverted in the next loop.
1600  }
1601 
1602  // Compute the covariance floor.
1603  if (gamma_i.Sum() == 0) { // If no count, use identity.
1604  KALDI_WARN << "Updating variances: zero counts. Setting floor to unit.";
1605  covfloor.SetUnit();
1606  } else { // else, use the global average covariance.
1607  covfloor.Scale(options_.cov_floor / gamma_i.Sum());
1608  int32 tmp;
1609  if ((tmp = covfloor.LimitCondDouble(options_.max_cond)) != 0) {
1610  KALDI_WARN << "Covariance flooring matrix is poorly conditioned. Fixed "
1611  << "up " << tmp << " eigenvalues.";
1612  }
1613  }
1614 
1615  if (options_.cov_diag_ratio > 1000) {
1616  KALDI_LOG << "Assuming you want to build a diagonal system since "
1617  << "cov_diag_ratio is large: making diagonal covFloor.";
1618  for (int32 i = 0; i < covfloor.NumRows(); i++)
1619  for (int32 j = 0; j < i; j++)
1620  covfloor(i, j) = 0.0;
1621  }
1622 
1623  // Second pass over all (shared) Gaussian components to calculate the
1624  // floored estimate of the covariances, and update the model.
1625  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1626  Sigma_i.CopyFromSp(model->SigmaInv_[i]);
1627  Sigma_i_ml.CopyFromSp(Sigma_i);
1628  // In case of insufficient counts, make the covariance matrix diagonal.
1629  // cov_diag_ratio is 2 by default, set to very large to always get diag-cov
1630  if (gamma_i(i) < options_.cov_diag_ratio * accs.feature_dim_) {
1631  KALDI_WARN << "For Gaussian component " << i << ": Too low count "
1632  << gamma_i(i) << " for covariance matrix estimation. Setting to "
1633  << "diagonal";
1634  for (int32 d = 0; d < accs.feature_dim_; d++)
1635  for (int32 e = 0; e < d; e++)
1636  Sigma_i(d, e) = 0.0; // SpMatrix, can only set lower triangular part
1637 
1638  int floored = Sigma_i.ApplyFloor(covfloor);
1639  if (floored > 0) {
1640  KALDI_WARN << "For Gaussian component " << i << ": Floored " << floored
1641  << " covariance eigenvalues.";
1642  }
1643  model->SigmaInv_[i].CopyFromSp(Sigma_i);
1644  model->SigmaInv_[i].InvertDouble();
1645  } else { // Updating the full covariance matrix.
1646  try {
1647  int floored = Sigma_i.ApplyFloor(covfloor);
1648  if (floored > 0) {
1649  KALDI_WARN << "For Gaussian component " << i << ": Floored "
1650  << floored << " covariance eigenvalues.";
1651  }
1652  model->SigmaInv_[i].CopyFromSp(Sigma_i);
1653  model->SigmaInv_[i].InvertDouble();
1654 
1655  objf_improv(i) += Sigma_i.LogPosDefDet() +
1656  TraceSpSp(SpMatrix<double>(model->SigmaInv_[i]), Sigma_i_ml);
1657  objf_improv(i) *= (-0.5 * gamma_i(i)); // Eq. (76)
1658 
1659  tot_objf_impr += objf_improv(i);
1660  tot_t += gamma_i(i);
1661  if (i < 5) {
1662  KALDI_VLOG(2) << "objf impr from variance update =" << objf_improv(i)
1663  / (gamma_i(i) + 1.0e-20) << " over " << (gamma_i(i))
1664  << " frames for i = " << (i);
1665  }
1666  } catch(...) {
1667  KALDI_WARN << "Updating within-class covariance matrix i = " << (i)
1668  << ", numerical problem";
1669  // This is a catch-all thing in case of unanticipated errors, but
1670  // flooring should prevent this occurring for the most part.
1671  model->SigmaInv_[i].SetUnit(); // Set to unit.
1672  }
1673  }
1674  }
1675  KALDI_LOG << "**Overall objf impr for variance update = "
1676  << (tot_objf_impr / (tot_t+ 1.0e-20))
1677  << " over " << tot_t << " frames";
1678  return tot_objf_impr / (tot_t + 1.0e-20);
1679 }
BaseFloat cov_floor
Floor covariance matrices Sigma_i to this times average cov.
kaldi::int32 int32
MleAmSgmm2Options options_
BaseFloat cov_diag_ratio
ratio to dim below which we use diagonal. default 2, set to inf for diag.
void ApplyFloor(Real floor_val, MatrixIndexT *floored_count=nullptr)
Applies floor to all elements.
Definition: kaldi-vector.h:149
double TraceSpSp(const SpMatrix< double > &A, const SpMatrix< double > &B)
Definition: sp-matrix.cc:326
#define KALDI_WARN
Definition: kaldi-error.h:150
Real Sum() const
Returns sum of the elements.
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_VLOG(v)
Definition: kaldi-error.h:156
#define KALDI_LOG
Definition: kaldi-error.h:153

◆ UpdateW()

double UpdateW ( const MleAmSgmm2Accs accs,
const std::vector< Matrix< double > > &  log_a,
const Vector< double > &  gamma_i,
AmSgmm2 model 
)
private

Definition at line 1321 of file estimate-am-sgmm2.cc.

References VectorBase< Real >::Add(), MatrixBase< Real >::AddMat(), MatrixBase< Real >::AddMatMat(), MatrixBase< Real >::CopyFromMat(), PackedMatrix< Real >::CopyFromVec(), SolverOptions::eps, MleAmSgmm2Accs::gamma_, rnnlm::i, SolverOptions::K, KALDI_ASSERT, KALDI_LOG, KALDI_VLOG, KALDI_WARN, kaldi::kNoTrans, kaldi::kTrans, VectorBase< Real >::LogSumExp(), SolverOptions::name, MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::num_groups_, AmSgmm2::NumSubstatesForGroup(), MleAmSgmm2Accs::phn_space_dim_, MatrixBase< Real >::Row(), kaldi::RunMultiThreaded(), VectorBase< Real >::Scale(), MatrixBase< Real >::SetZero(), kaldi::SolveQuadraticProblem(), VectorBase< Real >::Sum(), kaldi::TraceMatMat(), AmSgmm2::v_, kaldi::VecSpVec(), kaldi::VecVec(), AmSgmm2::w_, and AmSgmm2::w_jmi_.

1324  {
1325  KALDI_LOG << "Updating weight projections";
1326 
1327  // tot_like_{after, before} are totals over multiple iterations,
1328  // not valid likelihoods. but difference is valid (when divided by tot_count).
1329  double tot_predicted_like_impr = 0.0, tot_like_before = 0.0,
1330  tot_like_after = 0.0;
1331 
1332  Matrix<double> g_i(accs.num_gaussians_, accs.phn_space_dim_);
1333  // View F_i as a vector of SpMatrix.
1334  Matrix<double> F_i(accs.num_gaussians_,
1335  (accs.phn_space_dim_*(accs.phn_space_dim_+1))/2);
1336 
1337  Matrix<double> w(model->w_);
1338  double tot_count = gamma_i.Sum();
1339 
1340  for (int iter = 0; iter < options_.weight_projections_iters; iter++) {
1341  F_i.SetZero();
1342  g_i.SetZero();
1343  double k_like_before = 0.0;
1344 
1345  UpdateWClass c(accs, *model, w, log_a, &F_i, &g_i, &k_like_before);
1346  RunMultiThreaded(c);
1347 
1348  Matrix<double> w_orig(w);
1349  double k_predicted_like_impr = 0.0, k_like_after = 0.0;
1350  double min_step = 0.001, step_size;
1351 
1352  SolverOptions opts;
1353  opts.name = "w";
1354  opts.K = options_.max_cond;
1355  opts.eps = options_.epsilon;
1356 
1357  for (step_size = 1.0; step_size >= min_step; step_size /= 2) {
1358  k_predicted_like_impr = 0.0;
1359  k_like_after = 0.0;
1360 
1361  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1362  // auxf is formulated in terms of change in w.
1363  Vector<double> delta_w(accs.phn_space_dim_);
1364  // returns objf impr with step_size = 1,
1365  // but it may not be 1 so we recalculate it.
1366  SpMatrix<double> this_F_i(accs.phn_space_dim_);
1367  this_F_i.CopyFromVec(F_i.Row(i));
1368  SolveQuadraticProblem(this_F_i, g_i.Row(i), opts, &delta_w);
1369 
1370  delta_w.Scale(step_size);
1371  double predicted_impr = VecVec(delta_w, g_i.Row(i)) -
1372  0.5 * VecSpVec(delta_w, this_F_i, delta_w);
1373 
1374  // should never be negative because
1375  // we checked inside SolveQuadraticProblem.
1376  KALDI_ASSERT(predicted_impr >= -1.0e-05);
1377 
1378  if (i < 10)
1379  KALDI_LOG << "Predicted objf impr for w, iter = " << iter
1380  << ", i = " << i << " is "
1381  << (predicted_impr/gamma_i(i)+1.0e-20)
1382  << " per frame over " << gamma_i(i) << " frames.";
1383  k_predicted_like_impr += predicted_impr;
1384  w.Row(i).AddVec(1.0, delta_w);
1385  }
1386  for (int32 j1 = 0; j1 < accs.num_groups_; j1++) {
1387  int32 M = model->NumSubstatesForGroup(j1);
1388  Matrix<double> w_j(M, accs.num_gaussians_);
1389  w_j.AddMatMat(1.0, Matrix<double>(model->v_[j1]), kNoTrans,
1390  w, kTrans, 0.0);
1391  if (!log_a.empty()) w_j.AddMat(1.0, log_a[j1]); // SSGMM techreport eq. 42
1392  for (int32 m = 0; m < M; m++) {
1393  SubVector<double> w_jm(w_j, m);
1394  w_jm.Add(-1.0 * w_jm.LogSumExp());
1395  }
1396  k_like_after += TraceMatMat(w_j, accs.gamma_[j1], kTrans);
1397  }
1398  KALDI_VLOG(2) << "For iteration " << iter << ", updating w gives "
1399  << "predicted per-frame like impr "
1400  << (k_predicted_like_impr / tot_count) << ", actual "
1401  << ((k_like_after - k_like_before) / tot_count) << ", over "
1402  << tot_count << " frames";
1403  if (k_like_after < k_like_before) {
1404  w.CopyFromMat(w_orig); // Undo what we computed.
1405  if (fabs(k_like_after - k_like_before) / tot_count < 1.0e-05) {
1406  k_like_after = k_like_before;
1407  KALDI_WARN << "Not updating weights as not increasing auxf and "
1408  << "probably due to numerical issues (since small change).";
1409  break;
1410  } else {
1411  KALDI_WARN << "Halving step size for weights as likelihood did "
1412  << "not increase";
1413  }
1414  } else {
1415  break;
1416  }
1417  }
1418  if (step_size < min_step) {
1419  // Undo any step as we have no confidence that this is right.
1420  w.CopyFromMat(w_orig);
1421  } else {
1422  tot_predicted_like_impr += k_predicted_like_impr;
1423  tot_like_after += k_like_after;
1424  tot_like_before += k_like_before;
1425  }
1426  }
1427 
1428  model->w_.CopyFromMat(w);
1429  model->w_jmi_.clear(); // invalidated.
1430 
1431  tot_predicted_like_impr /= tot_count;
1432  tot_like_after = (tot_like_after - tot_like_before) / tot_count;
1433  KALDI_LOG << "**Overall objf impr for w is " << tot_predicted_like_impr
1434  << ", actual " << tot_like_after << ", over "
1435  << tot_count << " frames";
1436  return tot_like_after;
1437 }
double SolveQuadraticProblem(const SpMatrix< double > &H, const VectorBase< double > &g, const SolverOptions &opts, VectorBase< double > *x)
Definition: sp-matrix.cc:635
kaldi::int32 int32
BaseFloat epsilon
very small value used to prevent SVD crashing.
MleAmSgmm2Options options_
int weight_projections_iters
Number of iters when re-estimating weight projections "w".
void RunMultiThreaded(const C &c_in)
Here, class C should inherit from MultiThreadable.
Definition: kaldi-thread.h:151
Real VecSpVec(const VectorBase< Real > &v1, const SpMatrix< Real > &M, const VectorBase< Real > &v2)
Computes v1^T * M * v2.
Definition: sp-matrix.cc:964
#define KALDI_WARN
Definition: kaldi-error.h:150
Real TraceMatMat(const MatrixBase< Real > &A, const MatrixBase< Real > &B, MatrixTransposeType trans)
We need to declare this here as it will be a friend function.
Real Sum() const
Returns sum of the elements.
BaseFloat max_cond
Max on condition of matrices in update beyond which we do not update.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_VLOG(v)
Definition: kaldi-error.h:156
#define KALDI_LOG
Definition: kaldi-error.h:153
Real VecVec(const VectorBase< Real > &a, const VectorBase< Real > &b)
Returns dot product between v1 and v2.
Definition: kaldi-vector.cc:37
void AddVec(const Real alpha, const VectorBase< OtherReal > &v)
Add vector : *this = *this + alpha * rv (with casting between floats and doubles) ...

◆ UpdateWGetStats()

void UpdateWGetStats ( const MleAmSgmm2Accs accs,
const AmSgmm2 model,
const Matrix< double > &  w,
const std::vector< Matrix< double > > &  log_a,
Matrix< double > *  F_i,
Matrix< double > *  g_i,
double *  tot_like,
int32  num_threads,
int32  thread_id 
)
staticprivate

Called, multithreaded, inside UpdateW.

This function gets stats used inside UpdateW, where it accumulates the F_i and g_i quantities.

Note: F_i is viewed as a vector of SpMatrix (one for each i); each row of F_i is viewed as an SpMatrix even though it's stored as a vector.... Note: on the first iteration w is just a double-precision copy of the matrix model->w_; thereafter it may differ. log_a relates to the SSGMM.

Definition at line 1258 of file estimate-am-sgmm2.cc.

References VectorBase< Real >::Add(), MatrixBase< Real >::AddMat(), MatrixBase< Real >::AddMatMat(), SpMatrix< Real >::AddVec2(), VectorBase< Real >::ApplyExp(), MleAmSgmm2Accs::gamma_, rnnlm::i, kaldi::kNoTrans, kaldi::kTrans, VectorBase< Real >::LogSumExp(), MleAmSgmm2Accs::num_gaussians_, MleAmSgmm2Accs::num_groups_, AmSgmm2::NumSubstatesForGroup(), MleAmSgmm2Accs::phn_space_dim_, MatrixBase< Real >::Row(), PackedMatrix< Real >::SetZero(), AmSgmm2::v_, and kaldi::VecVec().

Referenced by UpdateWClass::operator()().

1266  {
1267 
1268  // Accumulate stats from a block of states (this gets called in parallel).
1269  int32 block_size = (accs.num_groups_ + (num_threads-1)) / num_threads,
1270  j1_start = block_size * thread_id,
1271  j1_end = std::min(accs.num_groups_, j1_start + block_size);
1272 
1273  // Unlike in the report the inner most loop is over Gaussians, where
1274  // per-gaussian statistics are accumulated. This is more memory demanding
1275  // but more computationally efficient, as outer product v_{jvm} v_{jvm}^T
1276  // is computed only once for all gaussians.
1277 
1278  SpMatrix<double> v_vT(accs.phn_space_dim_);
1279 
1280  for (int32 j1 = j1_start; j1 < j1_end; j1++) {
1281  int32 num_substates = model.NumSubstatesForGroup(j1);
1282  Matrix<double> w_j(num_substates, accs.num_gaussians_);
1283  // The linear term and quadratic term for each Gaussian-- two scalars
1284  // for each Gaussian, they appear in the accumulation formulas.
1285  Matrix<double> linear_term(num_substates, accs.num_gaussians_);
1286  Matrix<double> quadratic_term(num_substates, accs.num_gaussians_);
1287  Matrix<double> v_vT_m(num_substates,
1288  (accs.phn_space_dim_*(accs.phn_space_dim_+1))/2);
1289 
1290  // w_jm = softmax([w_{k1}^T ... w_{kD}^T] * v_{jkm}) eq.(7)
1291  Matrix<double> v_j_double(model.v_[j1]);
1292  w_j.AddMatMat(1.0, v_j_double, kNoTrans, w, kTrans, 0.0);
1293  if (!log_a.empty()) w_j.AddMat(1.0, log_a[j1]); // SSGMM techreport eq. 42
1294 
1295  for (int32 m = 0; m < model.NumSubstatesForGroup(j1); m++) {
1296  SubVector<double> w_jm(w_j, m);
1297  double gamma_jm = accs.gamma_[j1].Row(m).Sum();
1298  w_jm.Add(-1.0 * w_jm.LogSumExp());
1299  *tot_like += VecVec(w_jm, accs.gamma_[j1].Row(m));
1300  w_jm.ApplyExp();
1301  v_vT.SetZero();
1302  // v_vT := v_{jkm} v_{jkm}^T
1303  v_vT.AddVec2(static_cast<BaseFloat>(1.0), v_j_double.Row(m));
1304  v_vT_m.Row(m).CopyFromPacked(v_vT); // a bit wasteful, but does not dominate.
1305 
1306  for (int32 i = 0; i < accs.num_gaussians_; i++) {
1307  // Suggestion: g_jkm can be computed more efficiently
1308  // using the Vector/Matrix routines for all i at once
1309  // linear term around cur value.
1310  linear_term(m, i) = accs.gamma_[j1](m, i) - gamma_jm * w_jm(i);
1311  quadratic_term(m, i) = std::max(accs.gamma_[j1](m, i),
1312  gamma_jm * w_jm(i));
1313  }
1314  } // loop over substates
1315  g_i->AddMatMat(1.0, linear_term, kTrans, v_j_double, kNoTrans, 1.0);
1316  F_i->AddMatMat(1.0, quadratic_term, kTrans, v_vT_m, kNoTrans, 1.0);
1317  } // loop over states
1318 }
kaldi::int32 int32
Real VecVec(const VectorBase< Real > &a, const VectorBase< Real > &b)
Returns dot product between v1 and v2.
Definition: kaldi-vector.cc:37

Friends And Related Function Documentation

◆ EbwAmSgmm2Updater

friend class EbwAmSgmm2Updater
friend

Definition at line 272 of file estimate-am-sgmm2.h.

◆ EbwEstimateAmSgmm2

friend class EbwEstimateAmSgmm2
friend

Definition at line 261 of file estimate-am-sgmm2.h.

◆ UpdatePhoneVectorsClass

friend class UpdatePhoneVectorsClass
friend

Definition at line 260 of file estimate-am-sgmm2.h.

◆ UpdateWClass

friend class UpdateWClass
friend

Definition at line 259 of file estimate-am-sgmm2.h.

Member Data Documentation

◆ options_

MleAmSgmm2Options options_
private

Definition at line 274 of file estimate-am-sgmm2.h.


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