get-feature-transform.cc
Go to the documentation of this file.
1 // nnet2/get-feature-transform.cc
2 
3 // Copyright 2009-2011 Jan Silovsky
4 // 2013 Johns Hopkins University (author: Daniel Povey)
5 
6 // See ../../COPYING for clarification regarding multiple authors
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 // http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 // MERCHANTABLITY OR NON-INFRINGEMENT.
18 // See the Apache 2 License for the specific language governing permissions and
19 // limitations under the License.
20 
21 
23 
24 namespace kaldi {
25 
26 
27 
30  TpMatrix<BaseFloat> *C) const {
31  double count;
32  Vector<double> total_mean;
33  SpMatrix<double> total_covar, between_covar;
34  GetStats(&total_covar, &between_covar, &total_mean, &count);
35  KALDI_LOG << "Data count is " << count;
36  EstimateInternal(opts, total_covar, between_covar, total_mean, M, C);
37 }
38 
39 // static
42  const SpMatrix<double> &total_covar,
43  const SpMatrix<double> &between_covar,
44  const Vector<double> &total_mean,
47 
48  int32 target_dim = opts.dim, dim = total_covar.NumRows();
49  // Interpret zero or negative target_dim as the full dim
50  if (target_dim <= 0)
51  target_dim = dim;
52  // between-class covar is of most rank C-1
53  KALDI_ASSERT(target_dim <= dim);
54 
55  // within-class covariance
56  SpMatrix<double> wc_covar(total_covar);
57  wc_covar.AddSp(-1.0, between_covar);
58  TpMatrix<double> wc_covar_sqrt(dim);
59  try {
60  wc_covar_sqrt.Cholesky(wc_covar);
61  if (C != NULL) {
62  C->Resize(dim);
63  C->CopyFromTp(wc_covar_sqrt);
64  }
65  } catch (...) {
66  BaseFloat smooth = 1.0e-03 * wc_covar.Trace() / wc_covar.NumRows();
67  KALDI_LOG << "Cholesky failed (possibly not +ve definite), so adding " << smooth
68  << " to diagonal and trying again.\n";
69  for (int32 i = 0; i < wc_covar.NumRows(); i++)
70  wc_covar(i, i) += smooth;
71  wc_covar_sqrt.Cholesky(wc_covar);
72  }
73  Matrix<double> wc_covar_sqrt_mat(wc_covar_sqrt);
74  wc_covar_sqrt_mat.Invert();
75 
76  SpMatrix<double> tmp_sp(dim);
77  tmp_sp.AddMat2Sp(1.0, wc_covar_sqrt_mat, kNoTrans, between_covar, 0.0);
78  Matrix<double> tmp_mat(tmp_sp);
79  Matrix<double> svd_u(dim, dim), svd_vt(dim, dim);
80  Vector<double> svd_d(dim);
81  tmp_mat.Svd(&svd_d, &svd_u, &svd_vt);
82  SortSvd(&svd_d, &svd_u);
83 
84  KALDI_LOG << "LDA singular values are " << svd_d;
85 
86  KALDI_LOG << "Sum of all singular values is " << svd_d.Sum();
87  KALDI_LOG << "Sum of selected singular values is " <<
88  SubVector<double>(svd_d, 0, target_dim).Sum();
89 
90  Matrix<double> lda_mat(dim, dim);
91  lda_mat.AddMatMat(1.0, svd_u, kTrans, wc_covar_sqrt_mat, kNoTrans, 0.0);
92 
93  // finally, copy first target_dim rows to m
94  M->Resize(target_dim, dim);
95  M->CopyFromMat(lda_mat.Range(0, target_dim, 0, dim));
96 
97  if (opts.within_class_factor != 1.0) {
98  for (int32 i = 0; i < svd_d.Dim(); i++) {
99  BaseFloat old_var = 1.0 + svd_d(i), // the total variance of that dim..
100  new_var = opts.within_class_factor + svd_d(i), // the variance we want..
101  scale = sqrt(new_var / old_var);
102  if (i < M->NumRows())
103  M->Row(i).Scale(scale);
104  }
105  }
106 
107  if (opts.max_singular_value > 0.0) {
108  int32 rows = M->NumRows(), cols = M->NumCols(),
109  min_dim = std::min(rows, cols);
110  Matrix<BaseFloat> U(rows, min_dim), Vt(min_dim, cols);
111  Vector<BaseFloat> s(min_dim);
112  M->Svd(&s, &U, &Vt); // decompose m = U diag(s) Vt.
113  BaseFloat max_s = s.Max();
114  int32 n;
115  s.ApplyCeiling(opts.max_singular_value, &n);
116  if (n > 0) {
117  KALDI_LOG << "Applied ceiling to " << n << " out of " << s.Dim()
118  << " singular values of transform using ceiling "
119  << opts.max_singular_value << ", max is " << max_s;
120  Vt.MulRowsVec(s);
121  // reconstruct m with the modified singular values:
122  M->AddMatMat(1.0, U, kNoTrans, Vt, kNoTrans, 0.0);
123  }
124  }
125 
126  if (opts.remove_offset)
127  AddMeanOffset(total_mean, M);
128 }
129 
132  const std::vector<int32> &indexes,
133  const SpMatrix<double> &total_covar,
134  const SpMatrix<double> &between_covar,
135  const Vector<double> &mean,
136  Matrix<BaseFloat> *M) const {
137 
138  int32 full_dim = Dim(), proj_dim = indexes.size();
139  Matrix<double> transform(proj_dim, full_dim); // projects from full to projected dim.
140  for (int32 i = 0; i < proj_dim; i++)
141  transform(i, indexes[i]) = 1.0;
142 
143  SpMatrix<double> total_covar_proj(proj_dim), between_covar_proj(proj_dim);
144  Vector<double> mean_proj(proj_dim);
145  total_covar_proj.AddMat2Sp(1.0, transform, kNoTrans, total_covar, 0.0);
146  between_covar_proj.AddMat2Sp(1.0, transform, kNoTrans, between_covar, 0.0);
147  mean_proj.AddMatVec(1.0, transform, kNoTrans, mean, 0.0);
148 
149  Matrix<BaseFloat> M_proj;
150  FeatureTransformEstimateOptions opts_tmp(opts);
151  opts_tmp.dim = proj_dim;
152  EstimateInternal(opts_tmp, total_covar_proj, between_covar_proj, mean_proj,
153  &M_proj, NULL);
154  if (M_proj.NumCols() == proj_dim + 1) { // Extend transform to add the extra "1" that we
155  // use to handle mean shifts..
156  transform.Resize(proj_dim + 1, full_dim + 1, kCopyData);
157  transform(proj_dim, full_dim) = 1.0;
158  }
159  M->Resize(proj_dim, transform.NumCols());
160  // Produce output..
161  M->AddMatMat(1.0, M_proj, kNoTrans, Matrix<BaseFloat>(transform),
162  kNoTrans, 0.0);
163 }
164 
167  const std::vector<std::vector<int32> > &indexes,
168  Matrix<BaseFloat> *M) const {
169 
170  int32 input_dim = Dim(), output_dim = 0, num_transforms = indexes.size();
171  for (int32 i = 0; i < num_transforms; i++) { // some input-checking.
172  KALDI_ASSERT(indexes[i].size() > 0);
173  std::vector<int32> this_indexes(indexes[i]);
174  std::sort(this_indexes.begin(), this_indexes.end());
175  KALDI_ASSERT(IsSortedAndUniq(this_indexes)); // check for duplicates.
176  KALDI_ASSERT(this_indexes.front() >= 0);
177  KALDI_ASSERT(this_indexes.back() < input_dim);
178  output_dim += this_indexes.size();
179  }
180 
181  int32 input_dim_ext = (opts.remove_offset ? input_dim + 1 : input_dim);
182  M->Resize(output_dim, input_dim_ext);
183 
184  double count;
185  Vector<double> total_mean;
186  SpMatrix<double> total_covar, between_covar;
187  GetStats(&total_covar, &between_covar, &total_mean, &count);
188 
189  int32 cur_output_index = 0;
190  for (int32 i = 0; i < num_transforms; i++) {
191  Matrix<BaseFloat> M_tmp;
192  EstimateTransformPart(opts, indexes[i], total_covar, between_covar,
193  total_mean, &M_tmp);
194  int32 this_output_dim = indexes[i].size();
195  M->Range(cur_output_index, this_output_dim, 0, M->NumCols()).
196  CopyFromMat(M_tmp);
197  cur_output_index += this_output_dim;
198  }
199 
200 }
201 
202 
203 } // End of namespace kaldi
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
MatrixIndexT NumCols() const
Returns number of columns (or zero for empty matrix).
Definition: kaldi-matrix.h:67
int32 Dim() const
Returns the dimensionality of the feature vectors.
Definition: lda-estimate.h:66
Real Trace() const
Definition: sp-matrix.cc:171
void ApplyCeiling(Real ceil_val, MatrixIndexT *ceiled_count=nullptr)
Applies ceiling to all elements.
Definition: kaldi-vector.h:155
void Resize(MatrixIndexT nRows, MatrixResizeType resize_type=kSetZero)
Definition: tp-matrix.h:124
void Estimate(const FeatureTransformEstimateOptions &opts, Matrix< BaseFloat > *M, TpMatrix< BaseFloat > *within_cholesky) const
Estimates the LDA transform matrix m.
kaldi::int32 int32
void CopyFromMat(const MatrixBase< OtherReal > &M, MatrixTransposeType trans=kNoTrans)
Copy given matrix. (no resize is done).
MatrixIndexT NumRows() const
This file is modified from transform/lda-estimate.h It contains a class intended to be used in precon...
const size_t count
void Cholesky(const SpMatrix< Real > &orig)
Definition: tp-matrix.cc:88
void Estimate(const FeatureTransformEstimateOptions &opts, const std::vector< std::vector< int32 > > &indexes, Matrix< BaseFloat > *M) const
This is as FeatureTransformEstimate, but for use in nnet-get-feature-transform-multi.cc, see the usage message of that program for a description of what it does.
const SubVector< Real > Row(MatrixIndexT i) const
Return specific row of matrix [const].
Definition: kaldi-matrix.h:188
void AddSp(const Real alpha, const SpMatrix< Real > &Ma)
Definition: sp-matrix.h:211
static void AddMeanOffset(const VectorBase< double > &total_mean, Matrix< BaseFloat > *projection)
This function modifies the LDA matrix so that it also subtracts the mean feature value.
struct rnnlm::@11::@12 n
void AddMatMat(const Real alpha, const MatrixBase< Real > &A, MatrixTransposeType transA, const MatrixBase< Real > &B, MatrixTransposeType transB, const Real beta)
Real Max() const
Returns the maximum value of any element, or -infinity for the empty vector.
Packed symetric matrix class.
Definition: matrix-common.h:63
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
void EstimateTransformPart(const FeatureTransformEstimateOptions &opts, const std::vector< int32 > &indexes, const SpMatrix< double > &total_covar, const SpMatrix< double > &between_covar, const Vector< double > &mean, Matrix< BaseFloat > *M) const
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
void GetStats(SpMatrix< double > *total_covar, SpMatrix< double > *between_covar, Vector< double > *total_mean, double *sum) const
Extract a more processed form of the stats.
Definition: lda-estimate.cc:57
static void EstimateInternal(const FeatureTransformEstimateOptions &opts, const SpMatrix< double > &total_covar, const SpMatrix< double > &between_covar, const Vector< double > &mean, Matrix< BaseFloat > *M, TpMatrix< BaseFloat > *C)
void MulRowsVec(const VectorBase< Real > &scale)
Equivalent to (*this) = diag(scale) * (*this).
void CopyFromTp(const TpMatrix< Real > &other)
CopyFromTp copies another triangular matrix into this one.
Definition: tp-matrix.h:104
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
MatrixIndexT NumRows() const
Returns number of rows (or zero for empty matrix).
Definition: kaldi-matrix.h:64
void AddMat2Sp(const Real alpha, const MatrixBase< Real > &M, MatrixTransposeType transM, const SpMatrix< Real > &A, const Real beta=0.0)
Extension of rank-N update: this <– beta*this + alpha * M * A * M^T.
Definition: sp-matrix.cc:982
SubMatrix< Real > Range(const MatrixIndexT row_offset, const MatrixIndexT num_rows, const MatrixIndexT col_offset, const MatrixIndexT num_cols) const
Return a sub-part of matrix.
Definition: kaldi-matrix.h:202
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).
void Svd(VectorBase< Real > *s, MatrixBase< Real > *U, MatrixBase< Real > *Vt) const
Compute SVD (*this) = U diag(s) Vt.
void Invert(Real *log_det=NULL, Real *det_sign=NULL, bool inverse_needed=true)
matrix inverse.
Definition: kaldi-matrix.cc:38
bool IsSortedAndUniq(const std::vector< T > &vec)
Returns true if the vector is sorted and contains each element only once.
Definition: stl-utils.h:63
#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 SortSvd(VectorBase< Real > *s, MatrixBase< Real > *U, MatrixBase< Real > *Vt, bool sort_on_absolute_value)
Function to ensure that SVD is sorted.