nnet-diagnostics.cc
Go to the documentation of this file.
1 // nnet3/nnet-diagnostics.cc
2 
3 // Copyright 2015 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 "nnet3/nnet-diagnostics.h"
21 #include "nnet3/nnet-utils.h"
22 
23 namespace kaldi {
24 namespace nnet3 {
25 
27  const Nnet &nnet):
28  config_(config),
29  nnet_(nnet),
30  deriv_nnet_owned_(true),
31  deriv_nnet_(NULL),
32  compiler_(nnet, config_.optimize_config, config_.compiler_config),
33  num_minibatches_processed_(0) {
34  if (config_.compute_deriv) {
35  deriv_nnet_ = new Nnet(nnet_);
36  ScaleNnet(0.0, deriv_nnet_);
37  SetNnetAsGradient(deriv_nnet_); // force simple update
38  } else if (config_.store_component_stats) {
39  KALDI_ERR << "If you set store_component_stats == true and "
40  << "compute_deriv == false, use the other constructor.";
41  }
42 }
43 
44 
46  Nnet *nnet):
47  config_(config),
48  nnet_(*nnet),
49  deriv_nnet_owned_(false),
50  deriv_nnet_(nnet),
51  compiler_(*nnet, config_.optimize_config, config_.compiler_config),
54 }
55 
56 
57 
60  KALDI_ERR << "GetDeriv() called when no derivatives were requested.";
61  return *deriv_nnet_;
62 }
63 
66  delete deriv_nnet_; // delete does nothing if pointer is NULL.
67 }
68 
71  objf_info_.clear();
72  accuracy_info_.clear();
73  if (deriv_nnet_) {
74  ScaleNnet(0.0, deriv_nnet_);
76  }
77 }
78 
80  bool need_model_derivative = config_.compute_deriv,
81  store_component_stats = config_.store_component_stats;
82  ComputationRequest request;
83  GetComputationRequest(nnet_, eg, need_model_derivative,
84  store_component_stats,
85  &request);
86  std::shared_ptr<const NnetComputation> computation = compiler_.Compile(request);
87  NnetComputer computer(config_.compute_config, *computation,
89  // give the inputs to the computer object.
90  computer.AcceptInputs(nnet_, eg.io);
91  computer.Run();
92  this->ProcessOutputs(eg, &computer);
94  computer.Run();
95 }
96 
98  NnetComputer *computer) {
99  std::vector<NnetIo>::const_iterator iter = eg.io.begin(),
100  end = eg.io.end();
101  for (; iter != end; ++iter) {
102  const NnetIo &io = *iter;
103  int32 node_index = nnet_.GetNodeIndex(io.name);
104  if (node_index < 0)
105  KALDI_ERR << "Network has no output named " << io.name;
106  ObjectiveType obj_type = nnet_.GetNode(node_index).u.objective_type;
107  if (nnet_.IsOutputNode(node_index)) {
108  const CuMatrixBase<BaseFloat> &output = computer->GetOutput(io.name);
109  if (output.NumCols() != io.features.NumCols()) {
110  KALDI_ERR << "Nnet versus example output dimension (num-classes) "
111  << "mismatch for '" << io.name << "': " << output.NumCols()
112  << " (nnet) vs. " << io.features.NumCols() << " (egs)\n";
113  }
114  {
115  BaseFloat tot_weight, tot_objf;
116  bool supply_deriv = config_.compute_deriv;
117  ComputeObjectiveFunction(io.features, obj_type, io.name,
118  supply_deriv, computer,
119  &tot_weight, &tot_objf);
120  SimpleObjectiveInfo &totals = objf_info_[io.name];
121  totals.tot_weight += tot_weight;
122  totals.tot_objective += tot_objf;
123  }
124  // May not be meaningful in non-classification tasks
126  BaseFloat tot_weight, tot_accuracy;
127  PerDimObjectiveInfo &acc_totals = accuracy_info_[io.name];
128 
130  acc_totals.tot_objective_vec.Dim() == 0) {
131  acc_totals.tot_objective_vec.Resize(output.NumCols());
132  acc_totals.tot_weight_vec.Resize(output.NumCols());
133  }
134 
135  ComputeAccuracy(io.features, output,
136  &tot_weight, &tot_accuracy,
138  &acc_totals.tot_weight_vec : NULL,
140  &acc_totals.tot_objective_vec : NULL);
141  acc_totals.tot_weight += tot_weight;
142  acc_totals.tot_objective += tot_accuracy;
143  }
144  }
145  }
147 }
148 
150  bool ans = false;
151  { // First print regular objectives
152  unordered_map<std::string, SimpleObjectiveInfo,
153  StringHasher>::const_iterator iter, end;
154  iter = objf_info_.begin();
155  end = objf_info_.end();
156  for (; iter != end; ++iter) {
157  const std::string &name = iter->first;
158  int32 node_index = nnet_.GetNodeIndex(name);
159  KALDI_ASSERT(node_index >= 0);
160  ObjectiveType obj_type = nnet_.GetNode(node_index).u.objective_type;
161  const SimpleObjectiveInfo &info = iter->second;
162  KALDI_LOG << "Overall "
163  << (obj_type == kLinear ? "log-likelihood" : "objective")
164  << " for '" << name << "' is "
165  << (info.tot_objective / info.tot_weight) << " per frame"
166  << ", over " << info.tot_weight << " frames.";
167  if (info.tot_weight > 0)
168  ans = true;
169  }
170  }
171  {
172  unordered_map<std::string, PerDimObjectiveInfo,
173  StringHasher>::const_iterator iter, end;
174  // now print accuracies.
175  iter = accuracy_info_.begin();
176  end = accuracy_info_.end();
177  for (; iter != end; ++iter) {
178  const std::string &name = iter->first;
179  const PerDimObjectiveInfo &info = iter->second;
180  KALDI_LOG << "Overall accuracy for '" << name << "' is "
181  << (info.tot_objective / info.tot_weight) << " per frame"
182  << ", over " << info.tot_weight << " frames.";
183 
184  if (info.tot_weight_vec.Dim() > 0) {
185  Vector<BaseFloat> accuracy_vec(info.tot_weight_vec.Dim());
186  for (size_t j = 0; j < info.tot_weight_vec.Dim(); j++) {
187  if (info.tot_weight_vec(j) != 0) {
188  accuracy_vec(j) = info.tot_objective_vec(j)
189  / info.tot_weight_vec(j);
190  } else {
191  accuracy_vec(j) = -1.0;
192  }
193  }
194 
195  KALDI_LOG << "Overall per-dim accuracy vector for '" << name
196  << "' is " << accuracy_vec << " per frame"
197  << ", over " << info.tot_weight << " frames.";
198  }
199  // don't bother changing ans; the loop over the regular objective should
200  // already have set it to true if we got any data.
201  }
202  }
203  return ans;
204 }
205 
206 void ComputeAccuracy(const GeneralMatrix &supervision,
207  const CuMatrixBase<BaseFloat> &nnet_output,
208  BaseFloat *tot_weight_out,
209  BaseFloat *tot_accuracy_out,
210  VectorBase<BaseFloat> *tot_weight_vec,
211  VectorBase<BaseFloat> *tot_accuracy_vec) {
212  int32 num_rows = nnet_output.NumRows(),
213  num_cols = nnet_output.NumCols();
214  KALDI_ASSERT(supervision.NumRows() == num_rows &&
215  supervision.NumCols() == num_cols);
216 
217  if (tot_accuracy_vec || tot_weight_vec)
218  KALDI_ASSERT(tot_accuracy_vec && tot_weight_vec &&
219  tot_accuracy_vec->Dim() == num_cols &&
220  tot_weight_vec->Dim() == num_cols);
221  if (tot_accuracy_vec) tot_accuracy_vec->Set(0.0);
222  if (tot_weight_vec) tot_weight_vec->Set(0.0);
223 
224  CuArray<int32> best_index(num_rows);
225  nnet_output.FindRowMaxId(&best_index);
226  std::vector<int32> best_index_cpu;
227  // wasteful copy, but doesn't dominate.
228  best_index.CopyToVec(&best_index_cpu);
229 
230 
231  double tot_weight = 0.0,
232  tot_accuracy = 0.0;
233 
234  // note: we expect that in most cases where this code is called,
235  // supervision.Type() will be kSparseMatrix.
236  switch (supervision.Type()) {
237  case kCompressedMatrix: {
238  Matrix<BaseFloat> mat;
239  supervision.GetMatrix(&mat);
240  for (int32 r = 0; r < num_rows; r++) {
241  SubVector<BaseFloat> vec(mat, r);
242  BaseFloat row_sum = vec.Sum();
243  int32 best_index;
244  vec.Max(&best_index); // discard max value.
245  tot_weight += row_sum;
246  if (tot_weight_vec)
247  (*tot_weight_vec)(best_index) += row_sum;
248  if (best_index == best_index_cpu[r]) {
249  tot_accuracy += row_sum;
250  if (tot_accuracy_vec)
251  (*tot_accuracy_vec)(best_index) += row_sum;
252  }
253  }
254  break;
255  }
256  case kFullMatrix: {
257  const Matrix<BaseFloat> &mat = supervision.GetFullMatrix();
258  for (int32 r = 0; r < num_rows; r++) {
259  SubVector<BaseFloat> vec(mat, r);
260  BaseFloat row_sum = vec.Sum();
261  int32 best_index;
262  vec.Max(&best_index); // discard max value.
263  tot_weight += row_sum;
264  if (tot_weight_vec)
265  (*tot_weight_vec)(best_index) += row_sum;
266  if (best_index == best_index_cpu[r]) {
267  tot_accuracy += row_sum;
268  if (tot_accuracy_vec)
269  (*tot_accuracy_vec)(best_index) += row_sum;
270  }
271  }
272  break;
273  }
274  case kSparseMatrix: {
275  const SparseMatrix<BaseFloat> &smat = supervision.GetSparseMatrix();
276  for (int32 r = 0; r < num_rows; r++) {
277  const SparseVector<BaseFloat> &row = smat.Row(r);
278  BaseFloat row_sum = row.Sum();
279  int32 best_index;
280  row.Max(&best_index);
281  KALDI_ASSERT(best_index < num_cols);
282  tot_weight += row_sum;
283  if (tot_weight_vec)
284  (*tot_weight_vec)(best_index) += row_sum;
285  if (best_index == best_index_cpu[r]) {
286  tot_accuracy += row_sum;
287  if (tot_accuracy_vec)
288  (*tot_accuracy_vec)(best_index) += row_sum;
289  }
290  }
291  break;
292  }
293  default: KALDI_ERR << "Bad general-matrix type.";
294  }
295  *tot_weight_out = tot_weight;
296  *tot_accuracy_out = tot_accuracy;
297 }
298 
300  const std::string &output_name) const {
301  unordered_map<std::string, SimpleObjectiveInfo, StringHasher>::const_iterator
302  iter = objf_info_.find(output_name);
303  if (iter != objf_info_.end())
304  return &(iter->second);
305  else
306  return NULL;
307 }
308 
309 double NnetComputeProb::GetTotalObjective(double *total_weight) const {
310  double tot_objectives = 0.0;
311  double tot_weight = 0.0;
312  unordered_map<std::string, SimpleObjectiveInfo, StringHasher>::const_iterator
313  iter = objf_info_.begin(), end = objf_info_.end();
314  for (; iter != end; ++iter) {
315  tot_objectives += iter->second.tot_objective;
316  tot_weight += iter->second.tot_weight;
317  }
318 
319  if (total_weight) *total_weight = tot_weight;
320  return tot_objectives;
321 }
322 
323 } // namespace nnet3
324 } // namespace kaldi
NnetExample is the input data and corresponding label (or labels) for one or more frames of input...
Definition: nnet-example.h:111
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
unordered_map< std::string, PerDimObjectiveInfo, StringHasher > accuracy_info_
void ScaleNnet(BaseFloat scale, Nnet *nnet)
Scales the nnet parameters and stats by this scale.
Definition: nnet-utils.cc:312
This class is a wrapper that enables you to store a matrix in one of three forms: either as a Matrix<...
const Nnet & GetDeriv() const
Real Max(int32 *index) const
void CopyToVec(std::vector< T > *dst) const
This function resizes *dst if needed.
Definition: cu-array-inl.h:177
void GetMatrix(Matrix< BaseFloat > *mat) const
Outputs the contents as a matrix.
void ComputeObjectiveFunction(const GeneralMatrix &supervision, ObjectiveType objective_type, const std::string &output_name, bool supply_deriv, NnetComputer *computer, BaseFloat *tot_weight, BaseFloat *tot_objf)
This function computes the objective function, and if supply_deriv = true, supplies its derivative to...
void Compute(const NnetExample &eg)
NnetComputeProbOptions config_
NnetComputeProb(const NnetComputeProbOptions &config, const Nnet &nnet)
kaldi::int32 int32
GeneralMatrix features
The features or labels.
Definition: nnet-example.h:46
const Matrix< BaseFloat > & GetFullMatrix() const
Returns the contents as a Matrix<BaseFloat>.
void ProcessOutputs(const NnetExample &eg, NnetComputer *computer)
ObjectiveType objective_type
Definition: nnet-nnet.h:97
A hashing function object for strings.
Definition: stl-utils.h:248
unordered_map< std::string, SimpleObjectiveInfo, StringHasher > objf_info_
This file contains some miscellaneous functions dealing with class Nnet.
void SetNnetAsGradient(Nnet *nnet)
Sets nnet as gradient by Setting is_gradient_ to true and learning_rate_ to 1 for each UpdatableCompo...
Definition: nnet-utils.cc:292
MatrixIndexT NumCols() const
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
float BaseFloat
Definition: kaldi-types.h:29
void ComputeAccuracy(const GeneralMatrix &supervision, const CuMatrixBase< BaseFloat > &nnet_output, BaseFloat *tot_weight_out, BaseFloat *tot_accuracy_out, VectorBase< BaseFloat > *tot_weight_vec, VectorBase< BaseFloat > *tot_accuracy_vec)
This function computes the frame accuracy for this minibatch.
Vector< BaseFloat > tot_objective_vec
const CuMatrixBase< BaseFloat > & GetOutput(const std::string &node_name)
bool IsOutputNode(int32 node) const
Returns true if this is an output node, meaning that it is of type kDescriptor and is not directly fo...
Definition: nnet-nnet.cc:112
GeneralMatrixType Type() const
Returns the type of the matrix: kSparseMatrix, kCompressedMatrix or kFullMatrix.
void AcceptInputs(const Nnet &nnet, const std::vector< NnetIo > &io)
This convenience function calls AcceptInput() in turn on all the inputs in the training example...
#define KALDI_ERR
Definition: kaldi-error.h:147
Real Max() const
Returns the maximum value of any element, or -infinity for the empty vector.
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
const SimpleObjectiveInfo * GetObjective(const std::string &output_name) const
Real Sum() const
Returns sum of the elements.
void FindRowMaxId(CuArray< int32 > *id) const
Find the id of the maximal element for each row (resizes the &#39;id&#39; array to the appropriate size)...
Definition: cu-matrix.cc:1829
std::shared_ptr< const NnetComputation > Compile(const ComputationRequest &request)
Does the compilation and returns a const pointer to the result, which is owned by this class...
ObjectiveType
This enum is for a kind of annotation we associate with output nodes of the network; it&#39;s for the con...
Definition: nnet-nnet.h:52
Matrix for CUDA computing.
Definition: matrix-common.h:69
MatrixIndexT NumCols() const
Definition: cu-matrix.h:216
CachingOptimizingCompiler compiler_
A class representing a vector.
Definition: kaldi-vector.h:406
class NnetComputer is responsible for executing the computation described in the "computation" object...
Definition: nnet-compute.h:59
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
MatrixIndexT NumRows() const
void Set(Real f)
Set all members of a vector to a specified value.
double GetTotalObjective(double *tot_weight) const
std::string name
the name of the input in the neural net; in simple setups it will just be "input".
Definition: nnet-example.h:36
union kaldi::nnet3::NetworkNode::@15 u
int32 GetNodeIndex(const std::string &node_name) const
returns index associated with this node name, or -1 if no such index.
Definition: nnet-nnet.cc:466
const SparseMatrix< BaseFloat > & GetSparseMatrix() const
Returns the contents as a SparseMatrix.
MatrixIndexT NumRows() const
Dimensions.
Definition: cu-matrix.h:215
Provides a vector abstraction class.
Definition: kaldi-vector.h:41
std::vector< NnetIo > io
"io" contains the input and output.
Definition: nnet-example.h:116
#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 GetComputationRequest(const Nnet &nnet, const NnetExample &eg, bool need_model_derivative, bool store_component_stats, ComputationRequest *request)
This function takes a NnetExample (which should already have been frame-selected, if desired...
const SparseVector< Real > & Row(MatrixIndexT r) const
void Run()
This does either the forward or backward computation, depending when it is called (in a typical compu...