nnet-compute-test.cc
Go to the documentation of this file.
1 // nnet3/nnet-compute-test.cc
2 
3 // Copyright 2015 Johns Hopkins University (author: Daniel Povey)
4 // 2015 Xiaohui Zhang
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 "nnet3/nnet-nnet.h"
22 #include "nnet3/nnet-compile.h"
23 #include "nnet3/nnet-analyze.h"
24 #include "nnet3/nnet-test-utils.h"
25 #include "nnet3/nnet-utils.h"
26 #include "nnet3/nnet-optimize.h"
27 #include "nnet3/nnet-compute.h"
30 
31 namespace kaldi {
32 namespace nnet3 {
33 
35  bool binary = (Rand() % 2 == 0);
36  std::ostringstream os;
37  computation->Write(os, binary);
38  const std::string &original_output = os.str();
39  std::istringstream computation_is(original_output);
40  computation->Read(computation_is, binary);
41  std::istringstream computation_is2(original_output);
42  NnetComputation computation2;
43  computation2.Read(computation_is2, binary);
44 
45  std::ostringstream os2, os3;
46  computation->Write(os2, binary);
47  computation2.Write(os3, binary);
48 
49  if (binary) {
50  if (!(os2.str() == original_output)) {
51  KALDI_ERR << "Outputs differ for computation";
52  }
53  }
54 }
55 
57  bool binary = (Rand() % 2 == 0);
58  std::ostringstream os;
59  request->Write(os, binary);
60  const std::string &original_output = os.str();
61  std::istringstream request_is(original_output);
62  request->Read(request_is, binary);
63  std::istringstream request_is2(original_output);
64  ComputationRequest request2;
65  request2.Read(request_is2, binary);
66 
67  std::ostringstream os2, os3;
68  request->Write(os2, binary);
69  request2.Write(os3, binary);
70  KALDI_ASSERT(*request == request2);
71 
72  if (binary) {
73  KALDI_ASSERT(os2.str() == original_output);
74  KALDI_ASSERT(os3.str() == original_output);
75  }
76 }
77 
78 // this checks that a couple of different decodable objects give the same
79 // answer.
80 void TestNnetDecodable(Nnet *nnet) {
81  int32 num_frames = 5 + RandInt(1, 100),
82  input_dim = nnet->InputDim("input"),
83  output_dim = nnet->OutputDim("output"),
84  ivector_dim = std::max<int32>(0, nnet->InputDim("ivector"));
85  Matrix<BaseFloat> input(num_frames, input_dim);
86 
87  SetBatchnormTestMode(true, nnet);
88  SetDropoutTestMode(true, nnet);
89 
90  input.SetRandn();
91  Vector<BaseFloat> ivector(ivector_dim);
92  ivector.SetRandn();
93 
94  Vector<BaseFloat> priors(RandInt(0, 1) == 0 ? output_dim : 0);
95  if (priors.Dim() != 0) {
96  priors.SetRandn();
97  priors.ApplyExp();
98  }
99 
100  Matrix<BaseFloat> output1(num_frames, output_dim),
101  output2(num_frames, output_dim);
102 
103  {
105  opts.frames_per_chunk = RandInt(5, 25);
106  CachingOptimizingCompiler compiler(*nnet);
107  DecodableNnetSimple decodable(opts, *nnet, priors, input, &compiler,
108  (ivector_dim != 0 ? &ivector : NULL));
109  for (int32 t = 0; t < num_frames; t++) {
110  SubVector<BaseFloat> row(output1, t);
111  decodable.GetOutputForFrame(t, &row);
112  }
113  }
114 
115  {
117  // caution: this may modify nnet, by changing how it consumes iVectors.
118  DecodableNnetSimpleLoopedInfo info(opts, priors, nnet);
119  DecodableNnetSimpleLooped decodable(info, input,
120  (ivector_dim != 0 ? &ivector : NULL));
121  for (int32 t = 0; t < num_frames; t++) {
122  SubVector<BaseFloat> row(output2, t);
123  decodable.GetOutputForFrame(t, &row);
124  }
125  }
126 
127 
128  // the components that we exclude from this test, are excluded because they
129  // all take "optional" right context, and this destroys the equivalence that
130  // we are testing.
131  if (!NnetIsRecurrent(*nnet) &&
132  nnet->Info().find("statistics-extraction") == std::string::npos &&
133  nnet->Info().find("TimeHeightConvolutionComponent") == std::string::npos &&
134  nnet->Info().find("RestrictedAttentionComponent") == std::string::npos) {
135  // this equivalence will not hold for recurrent nnets, or those that
136  // have the statistics-extraction/statistics-pooling layers,
137  // or in general for nnets with convolution components (because these
138  // might have 'optional' context if required-time-offsets != time-offsets.
139  for (int32 t = 0; t < num_frames; t++) {
140  SubVector<BaseFloat> row1(output1, t),
141  row2(output2, t);
142  KALDI_ASSERT(row1.ApproxEqual(row2));
143  }
144  }
145 }
146 
148  for (int32 n = 0; n < 20; n++) {
149  struct NnetGenerationOptions gen_config;
150  bool test_collapse_model = (RandInt(0, 1) == 0);
151 
152  std::vector<std::string> configs;
153  GenerateConfigSequence(gen_config, &configs);
154  Nnet nnet;
155  for (size_t j = 0; j < configs.size(); j++) {
156  KALDI_LOG << "Input config[" << j << "] is: " << configs[j];
157  std::istringstream is(configs[j]);
158  nnet.ReadConfig(is);
159  }
160 
161  ComputationRequest request;
162  std::vector<Matrix<BaseFloat> > inputs;
163  ComputeExampleComputationRequestSimple(nnet, &request, &inputs);
164 
165  // Test CollapseModel(). Note: lines with 'collapse' in some part of them
166  // are not necessary for the rest of the test to run; they only test
167  // CollapseModel().
168  if (test_collapse_model) {
169  // this model collapsing code requires that test mode is set for batchnorm
170  // and dropout components.
171  SetBatchnormTestMode(true, &nnet);
172  SetDropoutTestMode(true, &nnet);
173  }
174 
175  NnetComputation computation;
176  Compiler compiler(request, nnet);
177  CompilerOptions opts;
178  compiler.CreateComputation(opts, &computation);
179 
180  Nnet nnet_collapsed(nnet);
181  CollapseModelConfig collapse_config;
182  NnetComputation computation_collapsed;
183 
184  if (test_collapse_model) {
185  CollapseModel(collapse_config, &nnet_collapsed);
186  Compiler compiler_collapsed(request, nnet_collapsed);
187  compiler_collapsed.CreateComputation(opts, &computation_collapsed);
188  computation_collapsed.ComputeCudaIndexes();
189  }
190 
191 
192  {
193  std::ostringstream os;
194  computation.Print(os, nnet);
195  KALDI_LOG << "Generated computation is: " << os.str();
196  UnitTestNnetComputationIo(&computation);
198  }
199  CheckComputationOptions check_config;
200  // we can do the rewrite check since it's before optimization.
201  check_config.check_rewrite = true;
202  ComputationChecker checker(check_config, nnet, computation);
203  checker.Check();
204 
205  if (RandInt(0, 1) == 0) {
206  NnetOptimizeOptions opt_config;
207 
208  Optimize(opt_config, nnet,
209  MaxOutputTimeInRequest(request),
210  &computation);
211  {
212  std::ostringstream os;
213  computation.Print(os, nnet);
214  KALDI_LOG << "Optimized computation is: " << os.str();
215  }
216  }
217 
218  NnetComputeOptions compute_opts;
219  if (RandInt(0, 1) == 0)
220  compute_opts.debug = true;
221 
222  computation.ComputeCudaIndexes();
223  NnetComputer computer(compute_opts,
224  computation,
225  nnet,
226  &nnet);
227  // provide the input to the computation.
228  for (size_t i = 0; i < request.inputs.size(); i++) {
229  CuMatrix<BaseFloat> temp(inputs[i]);
230  KALDI_LOG << "Input sum is " << temp.Sum();
231  computer.AcceptInput(request.inputs[i].name, &temp);
232 
233  }
234  computer.Run();
235 
236 
237  const CuMatrixBase<BaseFloat> &output(computer.GetOutput("output"));
238 
239  KALDI_LOG << "Output sum is " << output.Sum();
240 
241  if (test_collapse_model) {
242  NnetComputer computer_collapsed(compute_opts,
243  computation_collapsed,
244  nnet_collapsed,
245  &nnet_collapsed);
246  for (size_t i = 0; i < request.inputs.size(); i++) {
247  CuMatrix<BaseFloat> temp(inputs[i]);
248  KALDI_LOG << "Input sum is " << temp.Sum();
249  computer_collapsed.AcceptInput(request.inputs[i].name, &temp);
250  }
251  computer_collapsed.Run();
252  const CuMatrixBase<BaseFloat> &output_collapsed(
253  computer_collapsed.GetOutput("output"));
254  KALDI_LOG << "Output sum [collapsed] is " << output_collapsed.Sum();
255  if (!ApproxEqual(output, output_collapsed)) {
256  KALDI_ERR << "Regular and collapsed computations' outputs differ";
257  }
258  }
259 
260  CuMatrix<BaseFloat> output_deriv(output.NumRows(), output.NumCols());
261  output_deriv.SetRandn();
262  // output_deriv sum won't be informative so don't print it.
263  if (request.outputs[0].has_deriv) {
264  computer.AcceptInput("output", &output_deriv);
265  computer.Run();
266  for (size_t i = 0; i < request.inputs.size(); i++) {
267  if (request.inputs[i].has_deriv) {
268  const CuMatrixBase<BaseFloat> &in_deriv =
269  computer.GetOutput(request.inputs[i].name);
270  KALDI_LOG << "Input-deriv sum for input '"
271  << request.inputs[i].name << "' is " << in_deriv.Sum();
272  }
273  }
274  }
275  TestNnetDecodable(&nnet);
276  }
277 }
278 
279 } // namespace nnet3
280 } // namespace kaldi
281 
282 int main() {
283  using namespace kaldi;
284  using namespace kaldi::nnet3;
285  // uncommenting the following activates extra checks during optimization, that
286  // can help narrow down the source of problems.
287  //SetVerboseLevel(4);
288 
289 
290  for (kaldi::int32 loop = 0; loop < 2; loop++) {
291 #if HAVE_CUDA == 1
292  CuDevice::Instantiate().SetDebugStrideMode(true);
293  if (loop == 0)
294  CuDevice::Instantiate().SelectGpuId("no");
295  else
296  CuDevice::Instantiate().SelectGpuId("yes");
297 #endif
299  }
300 
301  KALDI_LOG << "Nnet tests succeeded.";
302 
303  return 0;
304 }
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
int32 InputDim(const std::string &input_name) const
Definition: nnet-nnet.cc:669
void CollapseModel(const CollapseModelConfig &config, Nnet *nnet)
This function modifies the neural net for efficiency, in a way that suitable to be done in test time...
Definition: nnet-utils.cc:2100
void TestNnetDecodable(Nnet *nnet)
void ApplyExp()
Apply exponential to each value in vector.
void ReadConfig(std::istream &config_file)
Definition: nnet-nnet.cc:189
int main()
This class enables you to do the compilation and optimization in one call, and also ensures that if t...
Real Sum() const
Definition: cu-matrix.cc:3012
This file contains various routines that are useful in test code.
void Print(std::ostream &os, const Nnet &nnet) const
This file contains utilities for analyzing and checking computations, which are used in the optimizat...
void SetBatchnormTestMode(bool test_mode, Nnet *nnet)
This function affects only components of type BatchNormComponent.
Definition: nnet-utils.cc:564
kaldi::int32 int32
std::vector< IoSpecification > inputs
This class represents a matrix that&#39;s stored on the GPU if we have one, and in memory if not...
Definition: matrix-common.h:71
void GetOutputForFrame(int32 frame, VectorBase< BaseFloat > *output)
int32 OutputDim(const std::string &output_name) const
Definition: nnet-nnet.cc:677
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
void SetDropoutTestMode(bool test_mode, Nnet *nnet)
This function affects components of child-classes of RandomComponent.
Definition: nnet-utils.cc:573
void AcceptInput(const std::string &node_name, CuMatrix< BaseFloat > *input)
e.g.
void ComputeExampleComputationRequestSimple(const Nnet &nnet, ComputationRequest *request, std::vector< Matrix< BaseFloat > > *inputs)
This function computes an example computation request, for testing purposes.
const CuMatrixBase< BaseFloat > & GetOutput(const std::string &node_name)
void Read(std::istream &istream, bool binary)
int32 MaxOutputTimeInRequest(const ComputationRequest &request)
struct rnnlm::@11::@12 n
void Read(std::istream &istream, bool binary)
#define KALDI_ERR
Definition: kaldi-error.h:147
void GetOutputForFrame(int32 subsampled_frame, VectorBase< BaseFloat > *output)
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
void Optimize(const NnetOptimizeOptions &config, const Nnet &nnet, int32 max_output_time_in_request, NnetComputation *computation)
This is the top-level function for optimizing a computation.
int Rand(struct RandomState *state)
Definition: kaldi-math.cc:45
void SetRandn()
Set vector to random normally-distributed noise.
void UnitTestComputationRequestIo(ComputationRequest *request)
Matrix for CUDA computing.
Definition: matrix-common.h:69
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
void CreateComputation(const CompilerOptions &opts, NnetComputation *computation)
Definition: nnet-compile.cc:50
void UnitTestNnetCompute()
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
std::vector< IoSpecification > outputs
This class creates an initial version of the NnetComputation, without any optimization or sharing of ...
Definition: nnet-compile.h:44
void UnitTestNnetComputationIo(NnetComputation *computation)
void Write(std::ostream &ostream, bool binary) const
bool NnetIsRecurrent(const Nnet &nnet)
Returns true if &#39;nnet&#39; has some kind of recurrency.
Definition: nnet-utils.cc:1441
void GenerateConfigSequence(const NnetGenerationOptions &opts, std::vector< std::string > *configs)
Generates a sequence of at least one config files, output as strings, where the first in the sequence...
#define KALDI_LOG
Definition: kaldi-error.h:153
When you instantiate class DecodableNnetSimpleLooped, you should give it a const reference to this cl...
Represents a non-allocating general vector which can be defined as a sub-vector of higher-level vecto...
Definition: kaldi-vector.h:501
static bool ApproxEqual(float a, float b, float relative_tolerance=0.001)
return abs(a - b) <= relative_tolerance * (abs(a)+abs(b)).
Definition: kaldi-math.h:265
int32 RandInt(int32 min_val, int32 max_val, struct RandomState *state)
Definition: kaldi-math.cc:95
void Write(std::ostream &ostream, bool binary) const
Config class for the CollapseModel function.
Definition: nnet-utils.h:240
void Run()
This does either the forward or backward computation, depending when it is called (in a typical compu...