fmpe-test.cc
Go to the documentation of this file.
1 // transform/fmpe-test.cc
2 
3 // Copyright 2012 Johns Hopkins University (Author: Daniel Povey)
4 
5 // See ../../COPYING for clarification regarding multiple authors
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
15 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
16 // MERCHANTABLITY OR NON-INFRINGEMENT.
17 // See the Apache 2 License for the specific language governing permissions and
18 // limitations under the License.
19 
20 #include "util/common-utils.h"
21 #include "gmm/diag-gmm.h"
22 #include "gmm/diag-gmm-normal.h"
23 #include "gmm/model-test-common.h"
24 #include "transform/fmpe.h"
25 
26 namespace kaldi {
27 
28 
29 // Compute derivative of GMM log-likelihood w.r.t. features.
30 // Note: this code copied from gmm-get-feat-deriv.cc; had
31 // to simplify a bit.
32 void GetFeatDeriv(const DiagGmm &gmm,
33  const Matrix<BaseFloat> &feats,
34  Matrix<BaseFloat> *deriv) {
35 
36  deriv->Resize(feats.NumRows(), feats.NumCols());
37 
38  Vector<BaseFloat> gauss_posteriors;
39  Vector<BaseFloat> temp_vec(feats.NumCols());
40  for (int32 i = 0; i < feats.NumRows(); i++) {
41  SubVector<BaseFloat> this_feat(feats, i);
42  SubVector<BaseFloat> this_deriv(*deriv, i);
43  gmm.ComponentPosteriors(this_feat, &gauss_posteriors);
44  BaseFloat weight = 1.0;
45  gauss_posteriors.Scale(weight);
46  // The next line does: to i'th row of deriv, add
47  // means_invvars^T * gauss_posteriors,
48  // where each row of means_invvars is the mean times
49  // diagonal inverse covariance... after transposing,
50  // this becomes a weighted of these rows, weighted by
51  // the posteriors. This comes from the term
52  // feat^T * inv_var * mean
53  // in the objective function.
54  this_deriv.AddMatVec(1.0, gmm.means_invvars(), kTrans,
55  gauss_posteriors, 1.0);
56 
57  // next line does temp_vec == inv_vars^T * gauss_posteriors,
58  // which sets temp_vec to a weighted sum of the inv_vars,
59  // weighed by Gaussian posterior.
60  temp_vec.AddMatVec(1.0, gmm.inv_vars(), kTrans,
61  gauss_posteriors, 0.0);
62  // Add to the derivative, -(this_feat .* temp_vec),
63  // which is the term that comes from the -0.5 * inv_var^T feat_sq,
64  // in the objective function (where inv_var is a vector, and feat_sq
65  // is a vector of squares of the feature values).
66  this_deriv.AddVecVec(-1.0, this_feat, temp_vec, 1.0);
67  }
68 }
69 
70 // Gets total log-likelihood, summed over all frames.
72  const Matrix<BaseFloat> &feats) {
73  BaseFloat ans = 0.0;
74  for (int32 i = 0; i < feats.NumRows(); i++)
75  ans += gmm.LogLikelihood(feats.Row(i));
76  return ans;
77 }
78 
79 void TestFmpe() {
80  int32 dim = 10 + (Rand() % 10);
81  int32 num_comp = 10 + (Rand() % 10);
82  DiagGmm gmm;
83  unittest::InitRandDiagGmm(dim, num_comp, &gmm);
84 
85  int32 num_frames = 20;
86  Matrix<BaseFloat> feats(num_frames, dim);
87 
88  for (int32 i = 0; i < num_frames; i++)
89  for (int32 j = 0; j < dim; j++)
90  feats(i, j) = RandGauss();
91 
92  FmpeOptions opts; // Default.
93  {
94  Fmpe fmpe(gmm, opts);
95  {
96  bool binary = (Rand() % 2 == 1);
97  Output ko("tmpf", binary);
98  fmpe.Write(ko.Stream(), binary);
99  }
100  }
101  Fmpe fmpe(gmm, opts);
102  {
103  bool binary_in;
104  Input ki("tmpf", &binary_in);
105  fmpe.Read(ki.Stream(), binary_in);
106  }
107 
108  // We'll first be testing that the feature derivative is
109  // accurate, by measuring a small random offset in feature space.
110  {
111  Matrix<BaseFloat> deriv;
112  Matrix<BaseFloat> random_offset(feats.NumRows(), feats.NumCols());
113  for (int32 i = 0; i < feats.NumRows(); i++)
114  for (int32 j = 0; j < feats.NumCols(); j++)
115  random_offset(i, j) = 1.0e-03 * RandGauss();
116  BaseFloat like_before = GetGmmLike(gmm, feats);
117  feats.AddMat(1.0, random_offset);
118  BaseFloat like_after = GetGmmLike(gmm, feats);
119  feats.AddMat(-1.0, random_offset); // undo the change.
120  GetFeatDeriv(gmm, feats, &deriv);
121  BaseFloat change1 = like_after - like_before,
122  change2 = TraceMatMat(random_offset, deriv, kTrans);
123  KALDI_LOG << "Random offset led to like change "
124  << change1 << " (manually), and " << change2
125  << " (derivative)";
126  // note: not making this threshold smaller, as don't want
127  // spurious failures. Seems to be OK though.
128  KALDI_ASSERT( fabs(change1-change2) < 0.15*fabs(change1+change2));
129  }
130 
131  std::vector<std::vector<int32> > gselect(feats.NumRows()); // make it have all Gaussians...
132  for (int32 i = 0; i < feats.NumRows(); i++)
133  for (int32 j = 0; j < gmm.NumGauss(); j++)
134  gselect[i].push_back(j);
135 
136  Matrix<BaseFloat> fmpe_offset;
137  // Check that the fMPE feature offset is zero.
138  fmpe.ComputeFeatures(feats, gselect, &fmpe_offset);
139  KALDI_ASSERT(fmpe_offset.IsZero());
140 
141  // Note: we're just using the ML objective function here.
142  // This is just to make sure the derivatives are all computed
143  // correctly.
144  BaseFloat like_before_update = GetGmmLike(gmm, feats);
145  // Now get stats for update.
146  FmpeStats stats(fmpe);
147  Matrix<BaseFloat> deriv;
148  GetFeatDeriv(gmm, feats, &deriv);
149  fmpe.AccStats(feats, gselect, deriv, NULL, &stats);
150  FmpeUpdateOptions update_opts;
151  update_opts.learning_rate = 0.001; // so linear assumption is more valid.
152  BaseFloat delta = fmpe.Update(update_opts, stats);
153 
154  fmpe.ComputeFeatures(feats, gselect, &fmpe_offset);
155  feats.AddMat(1.0, fmpe_offset);
156 
157  BaseFloat like_after_update = GetGmmLike(gmm, feats);
158 
159  BaseFloat delta2 = like_after_update - like_before_update;
160  KALDI_LOG << "Change predicted by fMPE Update function is "
161  << delta << ", change computed directly is "
162  << delta2;
163  KALDI_ASSERT(fabs(delta-delta2) < 0.15 * fabs(delta+delta2));
164 
165  unlink("tmpf");
166 }
167 
168 }
169 
170 
171 int main() {
173  for (int i = 0; i <= 10; i++)
174  kaldi::TestFmpe();
175  std::cout << "Test OK.\n";
176 }
177 
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
void ComputeFeatures(const MatrixBase< BaseFloat > &feat_in, const std::vector< std::vector< int32 > > &gselect, Matrix< BaseFloat > *feat_out) const
Definition: fmpe.cc:370
BaseFloat learning_rate
Definition: fmpe.h:89
MatrixIndexT NumCols() const
Returns number of columns (or zero for empty matrix).
Definition: kaldi-matrix.h:67
const Matrix< BaseFloat > & means_invvars() const
Definition: diag-gmm.h:179
BaseFloat Update(const FmpeUpdateOptions &config, const FmpeStats &stats)
Definition: fmpe.cc:443
void AddMat(const Real alpha, const MatrixBase< Real > &M, MatrixTransposeType transA=kNoTrans)
*this += alpha * M [or M^T]
float RandGauss(struct RandomState *state=NULL)
Definition: kaldi-math.h:155
kaldi::int32 int32
void AddVecVec(Real alpha, const VectorBase< Real > &v, const VectorBase< Real > &r, Real beta)
Add element-by-element product of vectors:
bool IsZero(Real cutoff=1.0e-05) const
Returns true if matrix is all zeros.
std::istream & Stream()
Definition: kaldi-io.cc:826
BaseFloat ComponentPosteriors(const VectorBase< BaseFloat > &data, Vector< BaseFloat > *posteriors) const
Computes the posterior probabilities of all Gaussian components given a data point.
Definition: diag-gmm.cc:601
std::ostream & Stream()
Definition: kaldi-io.cc:701
const SubVector< Real > Row(MatrixIndexT i) const
Return specific row of matrix [const].
Definition: kaldi-matrix.h:188
void InitRandDiagGmm(int32 dim, int32 num_comp, DiagGmm *gmm)
BaseFloat LogLikelihood(const VectorBase< BaseFloat > &data) const
Returns the log-likelihood of a data point (vector) given the GMM.
Definition: diag-gmm.cc:517
BaseFloat GetGmmLike(const DiagGmm &gmm, const Matrix< BaseFloat > &feats)
Definition: fmpe-test.cc:71
void Read(std::istream &is, bool binary)
Definition: fmpe.cc:512
void TestFmpe()
Definition: fmpe-test.cc:79
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.
void GetFeatDeriv(const DiagGmm &gmm, const Matrix< BaseFloat > &feats, Matrix< BaseFloat > *deriv)
Definition: fmpe-test.cc:32
int32 NumGauss() const
Returns the number of mixture components in the GMM.
Definition: diag-gmm.h:72
void Scale(Real alpha)
Multiplies all elements by this constant.
void AddMatVec(const Real alpha, const MatrixBase< Real > &M, const MatrixTransposeType trans, const VectorBase< Real > &v, const Real beta)
Add matrix times vector : this <– beta*this + alpha*M*v.
Definition: kaldi-vector.cc:92
int Rand(struct RandomState *state)
Definition: kaldi-math.cc:45
A class representing a vector.
Definition: kaldi-vector.h:406
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
int32 g_kaldi_verbose_level
This is set by util/parse-options.
Definition: kaldi-error.cc:46
MatrixIndexT NumRows() const
Returns number of rows (or zero for empty matrix).
Definition: kaldi-matrix.h:64
Definition for Gaussian Mixture Model with diagonal covariances.
Definition: diag-gmm.h:42
void Resize(const MatrixIndexT r, const MatrixIndexT c, MatrixResizeType resize_type=kSetZero, MatrixStrideType stride_type=kDefaultStride)
Sets matrix to a specified size (zero is OK as long as both r and c are zero).
int main()
Definition: fmpe-test.cc:171
#define KALDI_LOG
Definition: kaldi-error.h:153
Represents a non-allocating general vector which can be defined as a sub-vector of higher-level vecto...
Definition: kaldi-vector.h:501
void AccStats(const MatrixBase< BaseFloat > &feat_in, const std::vector< std::vector< int32 > > &gselect, const MatrixBase< BaseFloat > &direct_feat_deriv, const MatrixBase< BaseFloat > *indirect_feat_deriv, FmpeStats *stats) const
Definition: fmpe.cc:395
const Matrix< BaseFloat > & inv_vars() const
Definition: diag-gmm.h:180
void Write(std::ostream &os, bool binary) const
Definition: fmpe.cc:500