nnet3-show-progress.cc
Go to the documentation of this file.
1 // nnet3bin/nnet3-show-progress.cc
2 
3 // Copyright 2015 Johns Hopkins University (author: Daniel Povey)
4 // 2015 Xingyu Na
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 "base/kaldi-common.h"
22 #include "util/common-utils.h"
23 #include "hmm/transition-model.h"
24 #include "nnet3/nnet-utils.h"
25 #include "nnet3/nnet-diagnostics.h"
26 
27 int main(int argc, char *argv[]) {
28  try {
29  using namespace kaldi;
30  using namespace kaldi::nnet3;
31  typedef kaldi::int32 int32;
32  typedef kaldi::int64 int64;
33 
34  const char *usage =
35  "Given an old and a new 'raw' nnet3 network and some training examples\n"
36  "(possibly held-out), show the average objective function given the\n"
37  "mean of the two networks, and the breakdown by component of why this\n"
38  "happened (computed from derivative information). Also shows parameter\n"
39  "differences per layer. If training examples not provided, only shows\n"
40  "parameter differences per layer.\n"
41  "\n"
42  "Usage: nnet3-show-progress [options] <old-net-in> <new-net-in>"
43  " [<training-examples-in>]\n"
44  "e.g.: nnet3-show-progress 1.nnet 2.nnet ark:valid.egs\n";
45 
46  ParseOptions po(usage);
47 
48  int32 num_segments = 1;
49  std::string use_gpu = "no";
50  NnetComputeProbOptions compute_prob_opts;
51  compute_prob_opts.compute_deriv = true;
52 
53  po.Register("num-segments", &num_segments,
54  "Number of line segments used for computing derivatives");
55  po.Register("use-gpu", &use_gpu,
56  "yes|no|optional|wait, only has effect if compiled with CUDA");
57  compute_prob_opts.Register(&po);
58 
59  po.Read(argc, argv);
60 
61  if (po.NumArgs() < 2 || po.NumArgs() > 3) {
62  po.PrintUsage();
63  exit(1);
64  }
65 
66 #if HAVE_CUDA==1
67  CuDevice::Instantiate().SelectGpuId(use_gpu);
68 #endif
69 
70  std::string nnet1_rxfilename = po.GetArg(1),
71  nnet2_rxfilename = po.GetArg(2),
72  examples_rspecifier = po.GetOptArg(3);
73 
74  Nnet nnet1, nnet2;
75  ReadKaldiObject(nnet1_rxfilename, &nnet1);
76  ReadKaldiObject(nnet2_rxfilename, &nnet2);
77 
78  if (NumParameters(nnet1) != NumParameters(nnet2)) {
79  KALDI_WARN << "Parameter-dim mismatch, cannot show progress.";
80  exit(0);
81  }
82 
83  if (!examples_rspecifier.empty() && IsSimpleNnet(nnet1)) {
84  std::vector<NnetExample> examples;
85  SequentialNnetExampleReader example_reader(examples_rspecifier);
86  for (; !example_reader.Done(); example_reader.Next())
87  examples.push_back(example_reader.Value());
88 
89  int32 num_examples = examples.size();
90 
91  if (num_examples == 0)
92  KALDI_ERR << "No examples read.";
93 
94  int32 num_updatable = NumUpdatableComponents(nnet1);
95  Vector<BaseFloat> diff(num_updatable);
96 
97  for (int32 s = 0; s < num_segments; s++) {
98  // start and end segments of the line between 0 and 1
99  BaseFloat start = (s + 0.0) / num_segments,
100  end = (s + 1.0) / num_segments, middle = 0.5 * (start + end);
101  Nnet interp_nnet(nnet2);
102  ScaleNnet(middle, &interp_nnet);
103  AddNnet(nnet1, 1.0 - middle, &interp_nnet);
104 
105  NnetComputeProb prob_computer(compute_prob_opts, interp_nnet);
106  std::vector<NnetExample>::const_iterator eg_iter = examples.begin(),
107  eg_end = examples.end();
108  for (; eg_iter != eg_end; ++eg_iter)
109  prob_computer.Compute(*eg_iter);
110  const SimpleObjectiveInfo *objf_info = prob_computer.GetObjective("output");
111  double objf_per_frame = objf_info->tot_objective / objf_info->tot_weight;
112 
113  prob_computer.PrintTotalStats();
114  const Nnet &nnet_gradient = prob_computer.GetDeriv();
115  KALDI_LOG << "At position " << middle
116  << ", objf per frame is " << objf_per_frame;
117 
118  Vector<BaseFloat> old_dotprod(num_updatable), new_dotprod(num_updatable);
119  ComponentDotProducts(nnet_gradient, nnet1, &old_dotprod);
120  ComponentDotProducts(nnet_gradient, nnet2, &new_dotprod);
121  old_dotprod.Scale(1.0 / objf_info->tot_weight);
122  new_dotprod.Scale(1.0 / objf_info->tot_weight);
123  diff.AddVec(1.0/ num_segments, new_dotprod);
124  diff.AddVec(-1.0 / num_segments, old_dotprod);
125  KALDI_VLOG(1) << "By segment " << s << ", objf change is "
126  << PrintVectorPerUpdatableComponent(nnet1, diff);
127  }
128  KALDI_LOG << "Total objf change per component is "
129  << PrintVectorPerUpdatableComponent(nnet1, diff);
130  }
131 
132  { // Get info about magnitude of parameter change.
133  Nnet diff_nnet(nnet1);
134  AddNnet(nnet2, -1.0, &diff_nnet);
135  if (GetVerboseLevel() >= 1) {
136  KALDI_VLOG(1) << "Printing info for the difference between the neural nets: "
137  << diff_nnet.Info();
138  }
139  int32 num_updatable = NumUpdatableComponents(diff_nnet);
140  Vector<BaseFloat> dot_prod(num_updatable);
141  ComponentDotProducts(diff_nnet, diff_nnet, &dot_prod);
142  dot_prod.ApplyPow(0.5); // take sqrt to get l2 norm of diff
143  KALDI_LOG << "Parameter differences per layer are "
144  << PrintVectorPerUpdatableComponent(nnet1, dot_prod);
145 
146  Vector<BaseFloat> baseline_prod(num_updatable),
147  new_prod(num_updatable);
148  ComponentDotProducts(nnet1, nnet1, &baseline_prod);
149  ComponentDotProducts(nnet2, nnet2, &new_prod);
150  baseline_prod.ApplyPow(0.5);
151  new_prod.ApplyPow(0.5);
152 
153  KALDI_LOG << "Norms of parameter matrices from <new-nnet-in> are "
154  << PrintVectorPerUpdatableComponent(nnet2, new_prod);
155 
156  dot_prod.DivElements(baseline_prod);
157  KALDI_LOG << "Relative parameter differences per layer are "
158  << PrintVectorPerUpdatableComponent(nnet1, dot_prod);
159  }
160 #if HAVE_CUDA==1
161  CuDevice::Instantiate().PrintProfile();
162 #endif
163  return 0;
164  } catch(const std::exception &e) {
165  std::cerr << e.what() << '\n';
166  return -1;
167  }
168 }
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
void ScaleNnet(BaseFloat scale, Nnet *nnet)
Scales the nnet parameters and stats by this scale.
Definition: nnet-utils.cc:312
const Nnet & GetDeriv() const
std::string PrintVectorPerUpdatableComponent(const Nnet &nnet, const VectorBase< BaseFloat > &vec)
This function is for printing, to a string, a vector with one element per updatable component of the ...
Definition: nnet-utils.cc:231
void ComponentDotProducts(const Nnet &nnet1, const Nnet &nnet2, VectorBase< BaseFloat > *dot_prod)
Returns dot products between two networks of the same structure (calls the DotProduct functions of th...
Definition: nnet-utils.cc:211
void PrintUsage(bool print_command_line=false)
Prints the usage documentation [provided in the constructor].
int32 GetVerboseLevel()
Get verbosity level, usually set via command line &#39;–verbose=&#39; switch.
Definition: kaldi-error.h:60
void Compute(const NnetExample &eg)
kaldi::int32 int32
This class is for computing cross-entropy and accuracy values in a neural network, for diagnostics.
void Register(const std::string &name, bool *ptr, const std::string &doc)
void ReadKaldiObject(const std::string &filename, Matrix< float > *m)
Definition: kaldi-io.cc:832
This file contains some miscellaneous functions dealing with class Nnet.
std::string Info() const
returns some human-readable information about the network, mostly for debugging purposes.
Definition: nnet-nnet.cc:821
float BaseFloat
Definition: kaldi-types.h:29
int32 NumParameters(const Nnet &src)
Returns the total of the number of parameters in the updatable components of the nnet.
Definition: nnet-utils.cc:359
The class ParseOptions is for parsing command-line options; see Parsing command-line options for more...
Definition: parse-options.h:36
A templated class for reading objects sequentially from an archive or script file; see The Table conc...
Definition: kaldi-table.h:287
int Read(int argc, const char *const *argv)
Parses the command line options and fills the ParseOptions-registered variables.
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_WARN
Definition: kaldi-error.h:150
std::string GetArg(int param) const
Returns one of the positional parameters; 1-based indexing for argc/argv compatibility.
void Scale(Real alpha)
Multiplies all elements by this constant.
const SimpleObjectiveInfo * GetObjective(const std::string &output_name) const
int NumArgs() const
Number of positional parameters (c.f. argc-1).
bool IsSimpleNnet(const Nnet &nnet)
This function returns true if the nnet has the following properties: It has an output called "output"...
Definition: nnet-utils.cc:52
A class representing a vector.
Definition: kaldi-vector.h:406
void ApplyPow(Real power)
Take all elements of vector to a power.
Definition: kaldi-vector.h:179
#define KALDI_VLOG(v)
Definition: kaldi-error.h:156
void DivElements(const VectorBase< Real > &v)
Divide element-by-element by a vector.
#define KALDI_LOG
Definition: kaldi-error.h:153
void AddVec(const Real alpha, const VectorBase< OtherReal > &v)
Add vector : *this = *this + alpha * rv (with casting between floats and doubles) ...
int32 NumUpdatableComponents(const Nnet &dest)
Returns the number of updatable components in the nnet.
Definition: nnet-utils.cc:422
std::string GetOptArg(int param) const
void AddNnet(const Nnet &src, BaseFloat alpha, Nnet *dest)
Does *dest += alpha * src (affects nnet parameters and stored stats).
Definition: nnet-utils.cc:349
int main(int argc, char *argv[])