lda-estimate-test.cc
Go to the documentation of this file.
1 // transform/lda-estimate-test.cc
2 
3 // Copyright 2009-2011 Jan Silovsky; Saarland University
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 "transform/lda-estimate.h"
21 #include "util/common-utils.h"
22 
23 using namespace kaldi;
24 
25 void rand_posdef_spmatrix(size_t dim, SpMatrix<BaseFloat> *matrix,
26  TpMatrix<BaseFloat> *matrix_sqrt = NULL,
27  BaseFloat *logdet = NULL) {
28  // generate random (non-singular) matrix
29  Matrix<BaseFloat> tmp(dim, dim);
30  while (1) {
31  tmp.SetRandn();
32  if (tmp.Cond() < 100) break;
33  std::cout << "Condition number of random matrix large "
34  << static_cast<float>(tmp.Cond()) << ", trying again (this is normal)"
35  << '\n';
36  }
37  // tmp * tmp^T will give positive definite matrix
38  matrix->AddMat2(1.0, tmp, kNoTrans, 0.0);
39 
40  if (matrix_sqrt != NULL) matrix_sqrt->Cholesky(*matrix);
41  if (logdet != NULL) *logdet = matrix->LogPosDefDet();
42  if ((matrix_sqrt == NULL) && (logdet == NULL)) {
43  TpMatrix<BaseFloat> sqrt(dim);
44  sqrt.Cholesky(*matrix);
45  }
46 }
47 
48 void
49 test_io(const LdaEstimate &lda_est, bool binary) {
50  std::cout << "Testing I/O, binary = " << binary << '\n';
51 
52  size_t dim = lda_est.Dim();
53 
54  lda_est.Write(Output("tmp_stats", binary).Stream(), binary);
55 
56  bool binary_in;
57  LdaEstimate lda_est2;
58  lda_est2.Init(lda_est.NumClasses(), lda_est.Dim());
59  Input ki("tmp_stats", &binary_in);
60  lda_est2.Read(ki.Stream(),
61  binary_in, false); // not adding
62 
63  Input ki2("tmp_stats", &binary_in);
64  lda_est2.Read(ki2.Stream(),
65  binary_in, true); // adding
66 
67  lda_est2.Scale(0.5);
68  // 0.5 -> make it same as what it would have been if we read just once.
69 
72 
73  LdaEstimateOptions opts;
74  opts.dim = dim;
75  lda_est.Estimate(opts, &m1);
76  lda_est2.Estimate(opts, &m2);
77 
78  m1.AddMat(-1.0, m2, kNoTrans);
79  KALDI_ASSERT(m1.IsZero(1.0e-02));
80 
81  unlink("tmp_stats");
82 }
83 
84 void
86  // using namespace kaldi;
87 
88  // dimension of the gmm
89  size_t dim = kaldi::RandInt(10, 20);
90 
91  // number of mixtures in the data
92  size_t num_class = dim + kaldi::RandInt(1, 10); // must be at least dim + 1
93 
94  std::cout << "Running test with " << num_class << " classes and "
95  << dim << " dimensional vectors" << '\n';
96 
97  // generate random feature vectors
98  // first, generate parameters of vectors distribution
99  // (mean and covariance matrices)
100  Matrix<BaseFloat> means_f(num_class, dim);
101  std::vector<SpMatrix<BaseFloat> > vars_f(num_class);
102  std::vector<TpMatrix<BaseFloat> > vars_f_sqrt(num_class);
103  for (size_t mix = 0; mix < num_class; mix++) {
104  vars_f[mix].Resize(dim);
105  vars_f_sqrt[mix].Resize(dim);
106  }
107 
108  for (size_t m = 0; m < num_class; m++) {
109  for (size_t d = 0; d < dim; d++) {
110  means_f(m, d) = kaldi::RandGauss();
111  }
112  rand_posdef_spmatrix(dim, &vars_f[m], &vars_f_sqrt[m], NULL);
113  }
114 
115  // second, generate X feature vectors for each of the mixture components
116  size_t counter = 0;
117  size_t vec_count = 1000;
118  Matrix<BaseFloat> feats(num_class * vec_count, dim);
119  std::vector<int32> feats_class(num_class * vec_count);
120  Vector<BaseFloat> rnd_vec(dim);
121  for (size_t m = 0; m < num_class; m++) {
122  for (size_t i = 0; i < vec_count; i++) {
123  for (size_t d = 0; d < dim; d++) {
124  rnd_vec(d) = RandGauss();
125  }
126  feats.Row(counter).CopyFromVec(means_f.Row(m));
127  feats.Row(counter).AddTpVec(1.0, vars_f_sqrt[m], kNoTrans, rnd_vec, 1.0);
128  feats_class[counter] = m;
129  ++counter;
130  }
131  }
132 
133  // Compute total covar and means for classes.
134  Vector<double> total_mean(dim);
135  Matrix<double> class_mean(num_class, dim);
136  SpMatrix<double> total_covar(dim);
137  Vector<double> tmp_vec_d(dim);
138  for (size_t i = 0; i < counter; i++) {
139  tmp_vec_d.CopyFromVec(feats.Row(i));
140  class_mean.Row(feats_class[i]).AddVec(1.0, tmp_vec_d);
141  total_mean.AddVec(1.0, tmp_vec_d);
142  total_covar.AddVec2(1.0, tmp_vec_d);
143  }
144  total_mean.Scale(1/static_cast<double>(counter));
145  total_covar.Scale(1/static_cast<double>(counter));
146  total_covar.AddVec2(-1.0, total_mean);
147  // Compute between-class covar.
148  SpMatrix<double> bc_covar(dim);
149  for (size_t c = 0; c < num_class; c++) {
150  class_mean.Row(c).Scale(1/static_cast<double>(vec_count));
151  bc_covar.AddVec2(static_cast<double>(vec_count)/counter, class_mean.Row(c));
152  }
153  bc_covar.AddVec2(-1.0, total_mean);
154  // Compute within-class covar.
155  SpMatrix<double> wc_covar(total_covar);
156  wc_covar.AddSp(-1.0, bc_covar);
157 
158  // Estimate LDA transform matrix
159  LdaEstimate lda_est;
160  lda_est.Init(num_class, dim);
161  lda_est.ZeroAccumulators();
162  for (size_t i = 0; i < counter; i++) {
163  lda_est.Accumulate(feats.Row(i), feats_class[i]);
164  }
165  LdaEstimateOptions opts;
166  opts.dim = dim;
167 
168  Matrix<BaseFloat> lda_mat_bf,
169  lda_mat_bf_mean_remove;
170  lda_est.Estimate(opts, &lda_mat_bf);
171  opts.remove_offset = true;
172  lda_est.Estimate(opts, &lda_mat_bf_mean_remove);
173 
174  {
175  Vector<BaseFloat> mean_ext(total_mean);
176  mean_ext.Resize(mean_ext.Dim() + 1, kCopyData);
177  mean_ext(mean_ext.Dim() - 1) = 1.0;
178  Vector<BaseFloat> zero(mean_ext.Dim() - 1);
179  zero.AddMatVec(1.0, lda_mat_bf_mean_remove, kNoTrans, mean_ext, 0.0);
180  KALDI_ASSERT(zero.IsZero(0.001));
181  }
182 
183  // Check lda_mat
184  Matrix<double> lda_mat(lda_mat_bf);
185  Matrix<double> tmp_mat(dim, dim);
186  Matrix<double> wc_covar_mat(wc_covar);
187  Matrix<double> bc_covar_mat(bc_covar);
188  // following product should give unit matrix
189  tmp_mat.AddMatMatMat(1.0, lda_mat, kNoTrans, wc_covar_mat, kNoTrans,
190  lda_mat, kTrans, 0.0);
191  KALDI_ASSERT(tmp_mat.IsUnit());
192  // following product should give diagonal matrix with ordered diagonal (desc)
193  tmp_mat.AddMatMatMat(1.0, lda_mat, kNoTrans, bc_covar_mat, kNoTrans,
194  lda_mat, kTrans, 0.0);
195  KALDI_ASSERT(tmp_mat.IsDiagonal());
196  for (int32 i = 1; i < static_cast<int32>(dim); i++) {
197  if (tmp_mat(i, i) < 1.0e-10) { tmp_mat(i, i) = 0.0; }
198  KALDI_ASSERT(tmp_mat(i - 1, i - 1) >= tmp_mat(i, i));
199  }
200 
201  // test I/O
202  test_io(lda_est, false);
203  test_io(lda_est, true);
204 }
205 
206 int
207 main() {
208  // repeat the test X times
209  for (int i = 0; i < 2; i++)
211  std::cout << "Test OK.\n";
212 }
void Accumulate(const VectorBase< BaseFloat > &data, int32 class_id, BaseFloat weight=1.0)
Accumulates data.
Definition: lda-estimate.cc:45
void AddMat2(const Real alpha, const MatrixBase< Real > &M, MatrixTransposeType transM, const Real beta)
rank-N update: if (transM == kNoTrans) (*this) = beta*(*this) + alpha * M * M^T, or (if transM == kTr...
Definition: sp-matrix.cc:1110
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
Packed symetric matrix class.
Definition: matrix-common.h:62
bool IsDiagonal(Real cutoff=1.0e-05) const
Returns true if matrix is Diagonal.
void Scale(Real c)
Class for computing linear discriminant analysis (LDA) transform.
Definition: lda-estimate.h:57
void rand_posdef_spmatrix(size_t dim, SpMatrix< BaseFloat > *matrix, TpMatrix< BaseFloat > *matrix_sqrt=NULL, BaseFloat *logdet=NULL)
Real Cond() const
Returns condition number by computing Svd.
int32 Dim() const
Returns the dimensionality of the feature vectors.
Definition: lda-estimate.h:66
void Scale(BaseFloat f)
Scales all accumulators.
Definition: lda-estimate.cc:38
void Write(std::ostream &out_stream, bool binary) const
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 Resize(MatrixIndexT length, MatrixResizeType resize_type=kSetZero)
Set vector to a specified size (can be zero).
void Init(int32 num_classes, int32 dimension)
Allocates memory for accumulators.
Definition: lda-estimate.cc:26
bool IsZero(Real cutoff=1.0e-05) const
Returns true if matrix is all zeros.
void CopyFromVec(const VectorBase< Real > &v)
Copy data from another vector (must match own size).
void AddVec2(const Real alpha, const VectorBase< OtherReal > &v)
rank-one update, this <– this + alpha v v&#39;
Definition: sp-matrix.cc:946
std::istream & Stream()
Definition: kaldi-io.cc:826
void Cholesky(const SpMatrix< Real > &orig)
Definition: tp-matrix.cc:88
float BaseFloat
Definition: kaldi-types.h:29
void Estimate(const LdaEstimateOptions &opts, Matrix< BaseFloat > *M, Matrix< BaseFloat > *Mfull=NULL) const
Estimates the LDA transform matrix m.
Definition: lda-estimate.cc:85
int main()
Real LogPosDefDet() const
Computes log determinant but only for +ve-def matrices (it uses Cholesky).
Definition: sp-matrix.cc:36
const SubVector< Real > Row(MatrixIndexT i) const
Return specific row of matrix [const].
Definition: kaldi-matrix.h:188
void Read(std::istream &in_stream, bool binary, bool add)
void AddSp(const Real alpha, const SpMatrix< Real > &Ma)
Definition: sp-matrix.h:211
void SetRandn()
Sets to random values of a normal distribution.
void AddMatMatMat(const Real alpha, const MatrixBase< Real > &A, MatrixTransposeType transA, const MatrixBase< Real > &B, MatrixTransposeType transB, const MatrixBase< Real > &C, MatrixTransposeType transC, const Real beta)
this <– beta*this + alpha*A*B*C.
Packed symetric matrix class.
Definition: matrix-common.h:63
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
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
int32 NumClasses() const
Returns the number of classes.
Definition: lda-estimate.h:64
A class representing a vector.
Definition: kaldi-vector.h:406
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void UnitTestEstimateLda()
void ZeroAccumulators()
Sets all accumulators to zero.
Definition: lda-estimate.cc:32
void test_io(const LdaEstimate &lda_est, bool binary)
bool IsUnit(Real cutoff=1.0e-05) const
Returns true if the matrix is all zeros, except for ones on diagonal.
void AddVec(const Real alpha, const VectorBase< OtherReal > &v)
Add vector : *this = *this + alpha * rv (with casting between floats and doubles) ...
int32 RandInt(int32 min_val, int32 max_val, struct RandomState *state)
Definition: kaldi-math.cc:95