cmvn.cc
Go to the documentation of this file.
1 // transform/cmvn.cc
2 
3 // Copyright 2009-2013 Microsoft Corporation
4 // 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 #include "transform/cmvn.h"
22 
23 namespace kaldi {
24 
25 void InitCmvnStats(int32 dim, Matrix<double> *stats) {
26  KALDI_ASSERT(dim > 0);
27  stats->Resize(2, dim+1);
28 }
29 
30 void AccCmvnStats(const VectorBase<BaseFloat> &feats, BaseFloat weight, MatrixBase<double> *stats) {
31  int32 dim = feats.Dim();
32  KALDI_ASSERT(stats != NULL);
33  KALDI_ASSERT(stats->NumRows() == 2 && stats->NumCols() == dim + 1);
34  // Remove these __restrict__ modifiers if they cause compilation problems.
35  // It's just an optimization.
36  double *__restrict__ mean_ptr = stats->RowData(0),
37  *__restrict__ var_ptr = stats->RowData(1),
38  *__restrict__ count_ptr = mean_ptr + dim;
39  const BaseFloat * __restrict__ feats_ptr = feats.Data();
40  *count_ptr += weight;
41  // Careful-- if we change the format of the matrix, the "mean_ptr < count_ptr"
42  // statement below might become wrong.
43  for (; mean_ptr < count_ptr; mean_ptr++, var_ptr++, feats_ptr++) {
44  *mean_ptr += *feats_ptr * weight;
45  *var_ptr += *feats_ptr * *feats_ptr * weight;
46  }
47 }
48 
50  const VectorBase<BaseFloat> *weights,
51  MatrixBase<double> *stats) {
52  int32 num_frames = feats.NumRows();
53  if (weights != NULL) {
54  KALDI_ASSERT(weights->Dim() == num_frames);
55  }
56  for (int32 i = 0; i < num_frames; i++) {
57  SubVector<BaseFloat> this_frame = feats.Row(i);
58  BaseFloat weight = (weights == NULL ? 1.0 : (*weights)(i));
59  if (weight != 0.0)
60  AccCmvnStats(this_frame, weight, stats);
61  }
62 }
63 
64 void ApplyCmvn(const MatrixBase<double> &stats,
65  bool var_norm,
66  MatrixBase<BaseFloat> *feats) {
67  KALDI_ASSERT(feats != NULL);
68  int32 dim = stats.NumCols() - 1;
69  if (stats.NumRows() > 2 || stats.NumRows() < 1 || feats->NumCols() != dim) {
70  KALDI_ERR << "Dim mismatch: cmvn "
71  << stats.NumRows() << 'x' << stats.NumCols()
72  << ", feats " << feats->NumRows() << 'x' << feats->NumCols();
73  }
74  if (stats.NumRows() == 1 && var_norm)
75  KALDI_ERR << "You requested variance normalization but no variance stats "
76  << "are supplied.";
77 
78  double count = stats(0, dim);
79  // Do not change the threshold of 1.0 here: in the balanced-cmvn code, when
80  // computing an offset and representing it as stats, we use a count of one.
81  if (count < 1.0)
82  KALDI_ERR << "Insufficient stats for cepstral mean and variance normalization: "
83  << "count = " << count;
84 
85  if (!var_norm) {
86  Vector<BaseFloat> offset(dim);
87  SubVector<double> mean_stats(stats.RowData(0), dim);
88  offset.AddVec(-1.0 / count, mean_stats);
89  feats->AddVecToRows(1.0, offset);
90  return;
91  }
92  // norm(0, d) = mean offset;
93  // norm(1, d) = scale, e.g. x(d) <-- x(d)*norm(1, d) + norm(0, d).
94  Matrix<BaseFloat> norm(2, dim);
95  for (int32 d = 0; d < dim; d++) {
96  double mean, offset, scale;
97  mean = stats(0, d)/count;
98  double var = (stats(1, d)/count) - mean*mean,
99  floor = 1.0e-20;
100  if (var < floor) {
101  KALDI_WARN << "Flooring cepstral variance from " << var << " to "
102  << floor;
103  var = floor;
104  }
105  scale = 1.0 / sqrt(var);
106  if (scale != scale || 1/scale == 0.0)
107  KALDI_ERR << "NaN or infinity in cepstral mean/variance computation";
108  offset = -(mean*scale);
109  norm(0, d) = offset;
110  norm(1, d) = scale;
111  }
112  // Apply the normalization.
113  feats->MulColsVec(norm.Row(1));
114  feats->AddVecToRows(1.0, norm.Row(0));
115 }
116 
118  bool var_norm,
119  MatrixBase<BaseFloat> *feats) {
120  KALDI_ASSERT(feats != NULL);
121  int32 dim = stats.NumCols() - 1;
122  if (stats.NumRows() > 2 || stats.NumRows() < 1 || feats->NumCols() != dim) {
123  KALDI_ERR << "Dim mismatch: cmvn "
124  << stats.NumRows() << 'x' << stats.NumCols()
125  << ", feats " << feats->NumRows() << 'x' << feats->NumCols();
126  }
127  if (stats.NumRows() == 1 && var_norm)
128  KALDI_ERR << "You requested variance normalization but no variance stats "
129  << "are supplied.";
130 
131  double count = stats(0, dim);
132  // Do not change the threshold of 1.0 here: in the balanced-cmvn code, when
133  // computing an offset and representing it as stats, we use a count of one.
134  if (count < 1.0)
135  KALDI_ERR << "Insufficient stats for cepstral mean and variance normalization: "
136  << "count = " << count;
137 
138  Matrix<BaseFloat> norm(2, dim); // norm(0, d) = mean offset
139  // norm(1, d) = scale, e.g. x(d) <-- x(d)*norm(1, d) + norm(0, d).
140  for (int32 d = 0; d < dim; d++) {
141  double mean, offset, scale;
142  mean = stats(0, d) / count;
143  if (!var_norm) {
144  scale = 1.0;
145  offset = mean;
146  } else {
147  double var = (stats(1, d)/count) - mean*mean,
148  floor = 1.0e-20;
149  if (var < floor) {
150  KALDI_WARN << "Flooring cepstral variance from " << var << " to "
151  << floor;
152  var = floor;
153  }
154  // we aim to transform zero-mean, unit-variance input into data
155  // with the given mean and variance.
156  scale = sqrt(var);
157  offset = mean;
158  }
159  norm(0, d) = offset;
160  norm(1, d) = scale;
161  }
162  if (var_norm)
163  feats->MulColsVec(norm.Row(1));
164  feats->AddVecToRows(1.0, norm.Row(0));
165 }
166 
167 
168 void FakeStatsForSomeDims(const std::vector<int32> &dims,
169  MatrixBase<double> *stats) {
170  KALDI_ASSERT(stats->NumRows() == 2 && stats->NumCols() > 1);
171  int32 dim = stats->NumCols() - 1;
172  double count = (*stats)(0, dim);
173  for (size_t i = 0; i < dims.size(); i++) {
174  int32 d = dims[i];
175  KALDI_ASSERT(d >= 0 && d < dim);
176  (*stats)(0, d) = 0.0;
177  (*stats)(1, d) = count;
178  }
179 }
180 
181 
182 
183 } // 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
Base class which provides matrix operations not involving resizing or allocation. ...
Definition: kaldi-matrix.h:49
Real * RowData(MatrixIndexT i)
Returns pointer to data for one row (non-const)
Definition: kaldi-matrix.h:87
kaldi::int32 int32
void ApplyCmvnReverse(const MatrixBase< double > &stats, bool var_norm, MatrixBase< BaseFloat > *feats)
This is as ApplyCmvn, but does so in the reverse sense, i.e.
Definition: cmvn.cc:117
const size_t count
float BaseFloat
Definition: kaldi-types.h:29
const SubVector< Real > Row(MatrixIndexT i) const
Return specific row of matrix [const].
Definition: kaldi-matrix.h:188
void AddVecToRows(const Real alpha, const VectorBase< OtherReal > &v)
[each row of *this] += alpha * v
void InitCmvnStats(int32 dim, Matrix< double > *stats)
This function initializes the matrix to dimension 2 by (dim+1); 1st "dim" elements of 1st row are mea...
Definition: cmvn.cc:25
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_WARN
Definition: kaldi-error.h:150
Real * Data()
Returns a pointer to the start of the vector&#39;s data.
Definition: kaldi-vector.h:70
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
void AccCmvnStats(const VectorBase< BaseFloat > &feats, BaseFloat weight, MatrixBase< double > *stats)
Accumulation from a single frame (weighted).
Definition: cmvn.cc:30
void MulColsVec(const VectorBase< Real > &scale)
Equivalent to (*this) = (*this) * diag(scale).
A class representing a vector.
Definition: kaldi-vector.h:406
#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 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).
Provides a vector abstraction class.
Definition: kaldi-vector.h:41
void AddVec(const Real alpha, const VectorBase< OtherReal > &v)
Add vector : *this = *this + alpha * rv (with casting between floats and doubles) ...
void ApplyCmvn(const MatrixBase< double > &stats, bool var_norm, MatrixBase< BaseFloat > *feats)
Apply cepstral mean and variance normalization to a matrix of features.
Definition: cmvn.cc:64
Represents a non-allocating general vector which can be defined as a sub-vector of higher-level vecto...
Definition: kaldi-vector.h:501
void FakeStatsForSomeDims(const std::vector< int32 > &dims, MatrixBase< double > *stats)
Modify the stats so that for some dimensions (specified in "dims"), we replace them with "fake" stats...
Definition: cmvn.cc:168