ComputationChecker Class Reference

#include <nnet-analyze.h>

Collaboration diagram for ComputationChecker:

Public Member Functions

 ComputationChecker (const CheckComputationOptions &config, const Nnet &nnet, const NnetComputation &computation)
 
void Check ()
 

Private Member Functions

void CheckComputationIndexes () const
 This very basic check just makes sure that all indexes in the commands are within range, that dimensions agree with the request, that row/column dimensions agree with component dimensions. More...
 
void CheckComputationUndefined () const
 Checks for the situation where a variable is read before being written. More...
 
void CheckComputationRewrite () const
 Checks for the situation where a read-only operation on a variable is followed by an operation that writes to the variable. More...
 
void CheckComputationMatrixAccesses () const
 
void CheckComputationCompression () const
 
void CheckComputationDebugInfo () const
 

Private Attributes

const CheckComputationOptionsconfig_
 
const Nnetnnet_
 
const NnetComputationcomputation_
 
Analyzer a_
 

Detailed Description

Definition at line 411 of file nnet-analyze.h.

Constructor & Destructor Documentation

◆ ComputationChecker()

ComputationChecker ( const CheckComputationOptions config,
const Nnet nnet,
const NnetComputation computation 
)

Definition at line 571 of file nnet-analyze.cc.

574  :
575  config_(config), nnet_(nnet), computation_(computation) { }
const NnetComputation & computation_
Definition: nnet-analyze.h:433
const CheckComputationOptions & config_
Definition: nnet-analyze.h:431

Member Function Documentation

◆ Check()

void Check ( )

Definition at line 579 of file nnet-analyze.cc.

References ComputationChecker::a_, CheckComputationOptions::check_rewrite, ComputationChecker::CheckComputationCompression(), ComputationChecker::CheckComputationDebugInfo(), ComputationChecker::CheckComputationIndexes(), ComputationChecker::CheckComputationMatrixAccesses(), ComputationChecker::CheckComputationRewrite(), ComputationChecker::CheckComputationUndefined(), ComputationChecker::computation_, ComputationChecker::config_, Analyzer::Init(), and ComputationChecker::nnet_.

Referenced by ComputationCache::Check(), kaldi::nnet3::CheckComputation(), kaldi::nnet3::CheckComputationOnline(), CachingOptimizingCompiler::CompileNoShortcut(), kaldi::nnet3::UnitTestNnetAnalyze(), kaldi::nnet3::UnitTestNnetCompute(), kaldi::nnet3::UnitTestNnetInputDerivatives(), and kaldi::nnet3::UnitTestNnetOptimizeWithOptions().

579  {
588 }
const NnetComputation & computation_
Definition: nnet-analyze.h:433
void Init(const Nnet &nnet, const NnetComputation &computation)
void CheckComputationIndexes() const
This very basic check just makes sure that all indexes in the commands are within range...
void CheckComputationRewrite() const
Checks for the situation where a read-only operation on a variable is followed by an operation that w...
const CheckComputationOptions & config_
Definition: nnet-analyze.h:431
void CheckComputationUndefined() const
Checks for the situation where a variable is read before being written.

◆ CheckComputationCompression()

void CheckComputationCompression ( ) const
private

Definition at line 728 of file nnet-analyze.cc.

References ComputationChecker::a_, MatrixAccesses::accesses, NnetComputation::Command::alpha, NnetComputation::Command::arg1, NnetComputation::Command::arg2, Access::command_index, NnetComputation::Command::command_type, NnetComputation::commands, ComputationChecker::computation_, Nnet::GetComponent(), rnnlm::i, KALDI_ASSERT, kaldi::nnet3::kBackprop, kaldi::kCompressedMatrixUint8, kaldi::nnet3::kCompressMatrix, kaldi::nnet3::kDecompressMatrix, kaldi::nnet3::kNoOperationMarker, Analyzer::matrix_accesses, ComputationChecker::nnet_, and Component::Type().

Referenced by ComputationChecker::Check().

728  {
729  int32 num_matrices = a_.matrix_accesses.size();
730 
731  // 'middle_command' will be the index of the command that separates
732  // the forward and backward passes.
733  int32 middle_command = -1;
734  for (size_t i = 0; i < computation_.commands.size(); i++) {
735  if (computation_.commands[i].command_type == kNoOperationMarker) {
736  middle_command = static_cast<int32>(i);
737  break;
738  }
739  }
740  for (int32 matrix_index = 1; matrix_index < num_matrices; matrix_index++) {
741  const MatrixAccesses &accesses = a_.matrix_accesses[matrix_index];
742  int32 num_accesses = accesses.accesses.size();
743  for (int32 a = 0; a < num_accesses; a++) {
744  const Access &access = accesses.accesses[a];
745  int32 command_index = access.command_index;
746  const NnetComputation::Command &command =
747  computation_.commands[command_index];
748  if (command.command_type == kDecompressMatrix) {
749  // check that the previous access to this matrix was a compression
750  // command.
751  KALDI_ASSERT(
752  a > 0 && computation_.commands[
753  accesses.accesses[a-1].command_index].command_type ==
755  }
756  if (command.command_type == kCompressMatrix) {
757  // check that the next access to this matrix is an uncompression
758  // command.
759  int32 next_command_index = accesses.accesses[a+1].command_index;
760  KALDI_ASSERT(computation_.commands[next_command_index].command_type ==
762  command_index < middle_command &&
763  next_command_index > middle_command);
764  if (command.alpha == 0.0) {
765  // alpha == 0.0 means we're only retaining the sign; we should
766  // only do this if this is the output of a ReLU.
767  // make sure there are only 2 commands after this: the uncompress
768  // command, and a relu backprop command. (Any deallocation
769  // command doesn't show up in the list of 'accesses').
770  KALDI_ASSERT(a > 0 && command.arg2 == kCompressedMatrixUint8 &&
771  num_accesses == a + 3);
772  // make sure the next access to that matrix, apart from the
773  // uncompression command, is a ReLU propagation.
774  int32 next_command_index = accesses.accesses[a+2].command_index;
775  const NnetComputation::Command &next_command =
776  computation_.commands[next_command_index];
777  KALDI_ASSERT(next_command.command_type == kBackprop &&
778  nnet_.GetComponent(next_command.arg1)->Type() ==
779  "RectifiedLinearComponent");
780  }
781  }
782  }
783  }
784 }
kaldi::int32 int32
std::vector< Command > commands
const NnetComputation & computation_
Definition: nnet-analyze.h:433
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
virtual std::string Type() const =0
Returns a string such as "SigmoidComponent", describing the type of the object.
std::vector< MatrixAccesses > matrix_accesses
Definition: nnet-analyze.h:298
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ CheckComputationDebugInfo()

void CheckComputationDebugInfo ( ) const
private

Definition at line 1094 of file nnet-analyze.cc.

References ComputationChecker::computation_, rnnlm::i, KALDI_ERR, NnetComputation::matrices, and NnetComputation::matrix_debug_info.

Referenced by ComputationChecker::Check().

1094  {
1095  if (computation_.matrix_debug_info.empty()) return;
1096  if (computation_.matrix_debug_info.size() !=
1097  computation_.matrices.size())
1098  KALDI_ERR << "Debug info has wrong size";
1099  for (size_t i = 1; i < computation_.matrix_debug_info.size(); i++) {
1100  if (computation_.matrix_debug_info[i].cindexes.size() !=
1101  static_cast<size_t>(computation_.matrices[i].num_rows))
1102  KALDI_ERR << "Debug info for matrix m" << i
1103  << " has wrong num-rows.";
1104  std::vector<Cindex>::const_iterator
1105  iter = computation_.matrix_debug_info[i].cindexes.begin(),
1106  end = computation_.matrix_debug_info[i].cindexes.end();
1107  for (; iter != end; ++iter) {
1108  if (iter->second.n < 0) {
1109  KALDI_ERR << "Negative n index in debug info";
1110  }
1111  }
1112  }
1113 }
std::vector< MatrixDebugInfo > matrix_debug_info
std::vector< MatrixInfo > matrices
const NnetComputation & computation_
Definition: nnet-analyze.h:433
#define KALDI_ERR
Definition: kaldi-error.h:147

◆ CheckComputationIndexes()

void CheckComputationIndexes ( ) const
private

This very basic check just makes sure that all indexes in the commands are within range, that dimensions agree with the request, that row/column dimensions agree with component dimensions.

Definition at line 791 of file nnet-analyze.cc.

References NnetComputation::Command::alpha, NnetComputation::Command::arg1, NnetComputation::Command::arg2, NnetComputation::Command::arg3, NnetComputation::Command::arg4, NnetComputation::Command::arg5, NnetComputation::Command::arg6, NnetComputation::Command::arg7, NnetComputation::Command::command_type, NnetComputation::commands, NnetComputation::component_precomputed_indexes, ComputationChecker::computation_, Nnet::GetComponent(), NnetComputation::indexes, NnetComputation::indexes_multi, NnetComputation::indexes_ranges, Component::InputDim(), Nnet::IsInputNode(), Nnet::IsOutputNode(), NnetComputation::IsWholeMatrix(), kaldi::nnet3::kAcceptInput, kaldi::nnet3::kAddRowRanges, kaldi::nnet3::kAddRows, kaldi::nnet3::kAddRowsMulti, kaldi::nnet3::kAddToRowsMulti, KALDI_ASSERT, KALDI_ERR, kaldi::nnet3::kAllocMatrix, kaldi::nnet3::kBackprop, kaldi::nnet3::kBackpropInPlace, kaldi::nnet3::kBackpropNeedsInput, kaldi::nnet3::kBackpropNeedsOutput, kaldi::nnet3::kBackpropNoModelUpdate, kaldi::kCompressedMatrixInt8, kaldi::kCompressedMatrixUint16, kaldi::kCompressedMatrixUint8, kaldi::nnet3::kCompressMatrix, kaldi::nnet3::kCopyRows, kaldi::nnet3::kCopyRowsMulti, kaldi::nnet3::kCopyToRowsMulti, kaldi::nnet3::kDeallocMatrix, kaldi::nnet3::kDecompressMatrix, kaldi::nnet3::kGotoLabel, kaldi::nnet3::kMatrixAdd, kaldi::nnet3::kMatrixCopy, kaldi::nnet3::kNoOperation, kaldi::nnet3::kNoOperationLabel, kaldi::nnet3::kNoOperationMarker, kaldi::nnet3::kNoOperationPermanent, kaldi::nnet3::kPropagate, kaldi::nnet3::kPropagateInPlace, kaldi::nnet3::kProvideOutput, kaldi::nnet3::kSetConst, kaldi::nnet3::kSimpleComponent, kaldi::nnet3::kSwapMatrix, kaldi::nnet3::kUpdatableComponent, kaldi::nnet3::kUsesMemo, ComputationChecker::nnet_, Nnet::NumComponents(), Component::OutputDim(), Component::Properties(), and NnetComputation::submatrices.

Referenced by ComputationChecker::Check().

791  {
792  int32 num_commands = computation_.commands.size(),
793  num_submatrices = computation_.submatrices.size();
794  const std::vector<NnetComputation::SubMatrixInfo> &submatrices =
796 
797  // This maps from the memo-index > 0 to the Propagate command
798  // which created it. When the corresponding Backprop command
799  // is encountered, we delete the map element.
800  std::unordered_map<int32, int32> memo_to_command;
801 
802  for (int32 command_index = 0; command_index < num_commands; command_index++) {
803  const NnetComputation::Command &c = computation_.commands[command_index];
804  switch (c.command_type) {
805  case kAllocMatrix:
806  case kDeallocMatrix:
807  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
808  !computation_.IsWholeMatrix(c.arg1))
809  KALDI_ERR << "submatrix index out of range or invalid";
810  break;
811  case kSetConst:
812  if (c.arg1 < 1 || c.arg1 >= num_submatrices)
813  KALDI_ERR << "submatrix index out of range or invalid";
814  break;
815  case kSwapMatrix:
816  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
817  !computation_.IsWholeMatrix(c.arg1) ||
818  c.arg2 < 1 || c.arg2 >= num_submatrices ||
819  !computation_.IsWholeMatrix(c.arg2))
820  KALDI_ERR << "submatrix index out of range or invalid";
821  if (computation_.submatrices[c.arg1].num_rows !=
822  computation_.submatrices[c.arg2].num_rows ||
823  computation_.submatrices[c.arg1].num_cols !=
824  computation_.submatrices[c.arg2].num_cols)
825  KALDI_ERR << "Dimension mismatch in kSwapMatrix command";
826  break;
827  case kPropagate: {
828  if (c.arg1 < 0 || c.arg1 >= nnet_.NumComponents())
829  KALDI_ERR << "Component index out of range";
830  const Component *component = nnet_.GetComponent(c.arg1);
831  int32 properties = component->Properties();
832  if (c.arg2 < 0 ||
834  KALDI_ERR << "Precomputed-indexes index out of range";
835  if (c.arg2 != 0 && (properties & kSimpleComponent))
836  KALDI_ERR << "Precomputed-indexes index nonzero for simple component";
837  // note: input may be the empty matrix (in unusual circumstances, for non-simple
838  // components).
839  if (c.arg3 < 0 || c.arg3 >= num_submatrices ||
840  (c.arg3 == 0 && (properties & kSimpleComponent)) ||
841  c.arg4 < 1 || c.arg4 >= num_submatrices)
842  KALDI_ERR << "Sub-matrix indexes out of range.";
843  if (c.arg3 > 0 && submatrices[c.arg3].num_cols != component->InputDim())
844  KALDI_ERR << "Input-dim mismatch.";
845  if (submatrices[c.arg4].num_cols != component->OutputDim())
846  KALDI_ERR << "Input-dim mismatch.";
847  if ((properties & kSimpleComponent) &&
848  submatrices[c.arg3].num_rows !=
849  submatrices[c.arg4].num_rows)
850  KALDI_ERR << "Num-rows mismatch for simple component.";
851  if (!(properties & kPropagateInPlace) &&
852  c.arg3 == c.arg4)
853  KALDI_ERR << "In-place propagation not supported for this component";
854  if (c.arg5 > 0) {
855  KALDI_ASSERT(memo_to_command.count(c.arg5) == 0 &&
856  "Memo index re-used.");
857  memo_to_command[c.arg5] = command_index;
858  }
859  KALDI_ASSERT(c.arg6 == 0 || c.arg6 == 1);
860  break;
861  }
862  case kBackprop:
863  case kBackpropNoModelUpdate: {
864  if (c.arg1 < 0 || c.arg1 >= nnet_.NumComponents())
865  KALDI_ERR << "Component index in backprop invalid or out of range";
866  const Component *component = nnet_.GetComponent(c.arg1);
867  int32 properties = component->Properties();
868  if (c.arg2 < 0 ||
870  KALDI_ERR << "Precomputed-indexes index out of range";
871  if (c.arg2 != 0 && (properties & kSimpleComponent))
872  KALDI_ERR << "Precomputed-indexes index nonzero for simple component";
873  // output-deriv (arg5) must be supplied; others could plausibly be zero.
874  if (c.arg3 < 0 || c.arg3 >= num_submatrices ||
875  c.arg4 < 0 || c.arg4 >= num_submatrices ||
876  c.arg5 < 1 || c.arg5 >= num_submatrices ||
877  c.arg6 < 0 || c.arg6 >= num_submatrices)
878  KALDI_ERR << "Submatrix index out of range for backprop.";
879  if ((properties & kBackpropNeedsInput) && c.arg3 == 0)
880  KALDI_ERR << "Backprop input needed but not supplied.";
881  if ((properties & kBackpropNeedsOutput) && c.arg4 == 0)
882  KALDI_ERR << "Backprop output needed but not supplied.";
883  if (c.arg6 == 0 && !(properties & kUpdatableComponent)) {
884  // note: we could perhaps make this just a warning,
885  // or optimize it away somehow.
886  KALDI_ERR << "Backprop is done but has no effect.";
887  }
888  if (c.arg5 == c.arg6 && !(properties & kBackpropInPlace))
889  KALDI_ERR << "In-place backprop used where not supported.";
890  if (c.arg3 != 0 &&
891  submatrices[c.arg3].num_cols != component->InputDim())
892  KALDI_ERR << "Input-dim mismatch in backprop.";
893  if (c.arg4 != 0 &&
894  submatrices[c.arg4].num_cols != component->OutputDim())
895  KALDI_ERR << "Output-dim mismatch in backprop.";
896  if (c.arg5 != 0 &&
897  submatrices[c.arg5].num_cols != component->OutputDim())
898  KALDI_ERR << "Output-dim mismatch in backprop.";
899  if (c.arg6 != 0 &&
900  submatrices[c.arg6].num_cols != component->InputDim())
901  KALDI_ERR << "Input-dim mismatch in backprop.";
902  // check num-rows consistency for input.
903  if (c.arg3 != 0 && c.arg6 != 0 &&
904  submatrices[c.arg3].num_rows != submatrices[c.arg6].num_rows)
905  KALDI_ERR << "Num-rows mismatch in backprop input";
906  // check num-rows consistency for output
907  if (c.arg4 != 0 &&
908  submatrices[c.arg4].num_rows != submatrices[c.arg5].num_rows)
909  KALDI_ERR << "Num-rows mismatch in backprop output";
910  if ((properties & kSimpleComponent) && c.arg6 != 0 &&
911  submatrices[c.arg5].num_rows != submatrices[c.arg6].num_rows)
912  KALDI_ERR << "Num-rows mismatch in backprop input vs output.";
913  if (c.arg7 != 0) {
914  KALDI_ASSERT(c.arg7 > 0);
915  if (memo_to_command.count(c.arg7) == 0)
916  KALDI_ERR << "Memo-index " << c.arg7 << " not used for propagate.";
917  int32 propagate_command = memo_to_command[c.arg7];
918  memo_to_command.erase(c.arg7);
919  if (c.arg1 != computation_.commands[propagate_command].arg1)
920  KALDI_ERR << "Mismatch in component-node for memo index";
921  if (!(properties & kUsesMemo))
922  KALDI_ERR << "Component not expected to use a memo.";
923  }
924  break;
925  }
926  case kMatrixCopy:
927  case kMatrixAdd:
928  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
929  c.arg2 < 1 || c.arg2 >= num_submatrices)
930  KALDI_ERR << "Submatrix indexes out of range in matrix copy/add";
931  if (submatrices[c.arg1].num_rows != submatrices[c.arg2].num_rows ||
932  submatrices[c.arg1].num_cols != submatrices[c.arg2].num_cols)
933  KALDI_ERR << "Submatrix indexes out of range in matrix copy/add";
934  if (c.arg1 == c.arg2) {
935  // we allow copying to itself if alpha != 1.0; this is how we
936  // implement scaling.
937  if (!(c.command_type == kMatrixCopy && c.alpha != 1.0)) {
938  KALDI_ERR << "Adding/copying to self";
939  }
940  }
941  break;
942  case kAddRows:
943  case kCopyRows: {
944  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
945  c.arg2 < 1 || c.arg2 >= num_submatrices ||
946  static_cast<size_t>(c.arg3) >= computation_.indexes.size())
947  KALDI_ERR << "Index out of range in add-rows/copy-rows command.";
948  const std::vector<int32> &indexes = computation_.indexes[c.arg3];
949  if (indexes.size() != static_cast<size_t>(submatrices[c.arg1].num_rows))
950  KALDI_ERR << "Indexes size mismatch in add-rows/copy-rows";
951  if (submatrices[c.arg1].num_cols != submatrices[c.arg2].num_cols)
952  KALDI_ERR << "Dimension mismatch in add-rows/copy-rows";
953  if (*std::max_element(indexes.begin(), indexes.end()) >=
954  submatrices[c.arg2].num_rows)
955  KALDI_ERR << "Row-index out of range in add-rows/copy-rows";
956  if (c.arg1 == c.arg2)
957  KALDI_ERR << "Copying to self in add-rows/copy-rows command.";
958  break;
959  }
960  case kAddRowsMulti:
961  case kCopyRowsMulti:
962  case kAddToRowsMulti:
963  case kCopyToRowsMulti: {
964  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
965  static_cast<size_t>(c.arg2) >= computation_.indexes_multi.size())
966  KALDI_ERR << "Index out of range in *-multi command";
967  const std::vector<std::pair<int32, int32> > pairs =
968  computation_.indexes_multi[c.arg2];
969  int32 num_rows = submatrices[c.arg1].num_rows,
970  num_cols = submatrices[c.arg1].num_cols;
971  if (pairs.size() != static_cast<size_t>(num_rows))
972  KALDI_ERR << "Indexes dimension mismatch in *-multi command";
973  std::vector<std::pair<int32, int32> >::const_iterator
974  iter = pairs.begin(), end = pairs.end();
975  for (; iter != end; ++iter) {
976  int32 submatrix_index = iter->first, row_index = iter->second;
977  if (submatrix_index == -1) {
978  if (row_index != -1)
979  KALDI_ERR << "Expected -1 row index if submatrix index is -1";
980  } else {
981  if (submatrix_index < 1 || submatrix_index >= num_submatrices)
982  KALDI_ERR << "Submatrix index out of range in indexes_multi";
983  if (row_index < 0 ||
984  row_index >= submatrices[submatrix_index].num_rows)
985  KALDI_ERR << "Row index out of range in indexes_multi";
986  if (submatrix_index == c.arg1)
987  KALDI_ERR << "Copying from self in *-multi command.";
988  if (submatrices[submatrix_index].num_cols != num_cols)
989  KALDI_ERR << "Mismatching dimension in *-multi command";
990  }
991  }
992  if (c.command_type == kAddToRowsMulti ||
993  c.command_type == kCopyToRowsMulti) {
994  // check for duplicates; these are not allowed in kAddToRowsMulti
995  // or kCopyToRowsMulti because they would necessitate extra work
996  // in CUDA kernels.
997  std::vector<std::pair<int32, int32> > pairs_copy(pairs);
998  std::sort(pairs_copy.begin(), pairs_copy.end());
999  std::vector<std::pair<int32, int32> >::const_iterator
1000  iter = pairs_copy.begin(), end = pairs_copy.end(),
1001  next_iter;
1002  for (; iter != end; ++iter) {
1003  next_iter = iter;
1004  ++next_iter;
1005  if (next_iter != end && *iter == *next_iter &&
1006  iter->first != -1) {
1007  KALDI_ERR << "Duplicate element "
1008  << iter->first << ',' << iter->second << " found in "
1009  << "indexes for {add,copy}-to-rows-multi command.";
1010  }
1011  }
1012  }
1013  break;
1014  }
1015  case kAddRowRanges: {
1016  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
1017  c.arg2 < 1 || c.arg2 >= num_submatrices ||
1018  static_cast<size_t>(c.arg3) >= computation_.indexes_ranges.size())
1019  KALDI_ERR << "Index out of range in add-row-ranges command";
1020  const std::vector<std::pair<int32, int32> > pairs =
1021  computation_.indexes_ranges[c.arg3];
1022  if (static_cast<size_t>(submatrices[c.arg1].num_rows) != pairs.size())
1023  KALDI_ERR << "Num-rows mismatch in add-row-ranges command";
1024  if (submatrices[c.arg1].num_cols != submatrices[c.arg2].num_cols)
1025  KALDI_ERR << "Dimension mismatch in add-row-ranges command";
1026  int32 src_num_rows = submatrices[c.arg2].num_rows;
1027  std::vector<std::pair<int32, int32> >::const_iterator
1028  iter = pairs.begin(), end = pairs.end();
1029  for (; iter != end; ++iter) {
1030  if (!((iter->first == -1 && iter->second == -1) ||
1031  (iter->second > iter->first &&
1032  iter->first >= 0 && iter->second <= src_num_rows)))
1033  KALDI_ERR << "Row range " << iter->first << ',' << iter->second
1034  << " is invalid in add-row-ranges command.";
1035  }
1036  break;
1037  }
1038  case kCompressMatrix: {
1039  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
1040  !computation_.IsWholeMatrix(c.arg1))
1041  KALDI_ERR << "submatrix index out of range or invalid";
1042  if (c.arg2 < static_cast<int32>(kCompressedMatrixInt8) ||
1043  c.arg2 > static_cast<int32>(kCompressedMatrixUint16))
1044  KALDI_ERR << "Invalid compressed-matrix type.";
1045  if (c.arg3 != 0 && c.arg3 != 1)
1046  KALDI_ERR << "Invalid 'truncate' option for compressing matrix.";
1047  if (c.alpha < 0.0 || c.alpha > 1000.0 ||
1048  (c.alpha == 0.0 && c.arg2 != kCompressedMatrixUint8))
1049  KALDI_ERR << "Invalid alpha in kCompressMatrix command.";
1050  break;
1051  }
1052  case kDecompressMatrix: {
1053  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
1054  !computation_.IsWholeMatrix(c.arg1))
1055  KALDI_ERR << "submatrix index out of range or invalid";
1056  break;
1057  }
1058  case kAcceptInput: case kProvideOutput: {
1059  if (c.arg1 < 1 || c.arg1 >= num_submatrices ||
1060  !computation_.IsWholeMatrix(c.arg1))
1061  KALDI_ERR << "submatrix index out of range or invalid";
1062  // note: we may later change the following condition to allow component
1063  // nodes. we allow it on output node because of derivatives.
1064  if (!nnet_.IsInputNode(c.arg2) && !nnet_.IsOutputNode(c.arg2))
1065  KALDI_ERR << "Invalid network node";
1066  break;
1067  }
1068  case kNoOperation:
1069  case kNoOperationPermanent:
1070  case kNoOperationMarker:
1071  case kNoOperationLabel:
1072  break;
1073  case kGotoLabel: {
1074  int32 label_index = c.arg1;
1075  if (label_index < 0 || label_index >= command_index ||
1076  computation_.commands[label_index].command_type != kNoOperationLabel)
1077  KALDI_ERR << "kGotoLabel command has invalid destination index.";
1078  if (command_index + 1 != num_commands) {
1079  KALDI_ERR << "kGotoLabel is not the last command in the computation";
1080  }
1081  break;
1082  }
1083  default:
1084  KALDI_ERR << "Unknown command type.";
1085  }
1086  }
1087  if (!memo_to_command.empty()) {
1088  KALDI_ERR << "Memo was used in command "
1089  << memo_to_command.begin()->second
1090  << " but never consumed.";
1091  }
1092 }
bool IsInputNode(int32 node) const
Returns true if this is an output node, meaning that it is of type kInput.
Definition: nnet-nnet.cc:120
kaldi::int32 int32
std::vector< Command > commands
const NnetComputation & computation_
Definition: nnet-analyze.h:433
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
std::vector< std::vector< std::pair< int32, int32 > > > indexes_multi
std::vector< SubMatrixInfo > submatrices
#define KALDI_ERR
Definition: kaldi-error.h:147
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
std::vector< PrecomputedIndexesInfo > component_precomputed_indexes
int32 NumComponents() const
Definition: nnet-nnet.h:124
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
std::vector< std::vector< int32 > > indexes
bool IsWholeMatrix(int32 submatrix_index) const
std::vector< std::vector< std::pair< int32, int32 > > > indexes_ranges

◆ CheckComputationMatrixAccesses()

void CheckComputationMatrixAccesses ( ) const
private

Definition at line 682 of file nnet-analyze.cc.

References ComputationChecker::a_, MatrixAccesses::accesses, MatrixAccesses::allocate_command, CheckComputationOptions::check_unused_variables, NnetComputation::commands, ComputationChecker::computation_, ComputationChecker::config_, MatrixAccesses::deallocate_command, MatrixAccesses::is_input, KALDI_ERR, KALDI_WARN, kaldi::nnet3::kSetConst, and Analyzer::matrix_accesses.

Referenced by ComputationChecker::Check().

682  {
683  int32 num_matrices = a_.matrix_accesses.size();
684 
685  for (int32 matrix_index = 1; matrix_index < num_matrices; matrix_index++) {
686  const MatrixAccesses &accesses = a_.matrix_accesses[matrix_index];
687  if (accesses.allocate_command == -1)
688  KALDI_ERR << "Matrix m" << matrix_index << " is not initialized.";
689  if (accesses.accesses.empty()) {
690  KALDI_ERR << "Matrix m" << matrix_index << " is never accessed.";
691  } else if (accesses.accesses.front().command_index <
692  accesses.allocate_command) {
693  KALDI_ERR << "Matrix m" << matrix_index << " is accessed before "
694  "it is initialized";
695  }
696  if (accesses.accesses.size() == 1 && config_.check_unused_variables) {
697  int32 first_access_command = accesses.accesses[0].command_index;
698  if (computation_.commands[first_access_command].command_type == kSetConst) {
700  KALDI_ERR << "Matrix m" << matrix_index << " is only set to a constant "
701  << "value, but then never accessed.";
702  }
703  }
704 
705  if (accesses.accesses.empty()) {
706  if (accesses.is_input) {
707  // we allow there to be no accesses if it is an input, e.g. if an
708  // output derivative is supplied for some reason but never used.
709  // We'll warn, though (once).
711  KALDI_WARN << "Matrix m" << matrix_index << " is never accessed. "
712  "Allowing because it is an input (un-needed input or "
713  "derivative?) Will warn only once.";
715  }
716  } else {
717  KALDI_ERR << "Matrix m" << matrix_index << " is never accessed.";
718  }
719  } else if (accesses.deallocate_command != -1 &&
720  accesses.accesses.back().command_index >=
721  accesses.deallocate_command) {
722  KALDI_ERR << "Matrix m" << matrix_index << " is accessed after "
723  "it is destroyed";
724  }
725  }
726 }
kaldi::int32 int32
std::vector< Command > commands
const NnetComputation & computation_
Definition: nnet-analyze.h:433
const CheckComputationOptions & config_
Definition: nnet-analyze.h:431
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_WARN
Definition: kaldi-error.h:150
std::vector< MatrixAccesses > matrix_accesses
Definition: nnet-analyze.h:298
static bool computation_checker_warned_unused_input
Checks that we never use variables before they are allocated or after they are deallocated, and some other checks that can be done from the MatrixAccesses.

◆ CheckComputationRewrite()

void CheckComputationRewrite ( ) const
private

Checks for the situation where a read-only operation on a variable is followed by an operation that writes to the variable.

This should never occur prior to optimization, but after certain optimization we in effect "re-use" variables by doing things like propagate and backprop in-place, so this check shouldn't be performed after optimization.

Definition at line 598 of file nnet-analyze.cc.

References ComputationChecker::a_, CheckComputationOptions::check_unused_variables, ComputationChecker::config_, ComputationVariables::DescribeVariable(), KALDI_ERR, kaldi::nnet3::kReadAccess, Analyzer::variable_accesses, and Analyzer::variables.

Referenced by ComputationChecker::Check().

598  {
599  int32 num_variables = a_.variable_accesses.size();
600  for (int32 v = 0; v < num_variables; v++) {
601  const std::vector<Access> &accesses = a_.variable_accesses[v];
602  if (accesses.empty()) {
604  KALDI_ERR << "Variable " << v << " = " << a_.variables.DescribeVariable(v)
605  << " is never used.";
606  } else {
607  continue;
608  }
609  }
610  int32 num_accesses = accesses.size();
611  int32 first_pure_read = -1;
612  for (int32 access = 0; access < num_accesses; access++) {
613  if (accesses[access].access_type == kReadAccess) {
614  first_pure_read = access;
615  break;
616  }
617  }
618  if (first_pure_read != -1) {
619  for (int32 access = first_pure_read + 1;
620  access < num_accesses; access++) {
621  if (accesses[access].access_type != kReadAccess) {
622  KALDI_ERR << "Variable " << v << " = "
624  << " is modified after being read"
625  << " (this is not expected before optimization)";
626  }
627  }
628  }
629  }
630 }
kaldi::int32 int32
const CheckComputationOptions & config_
Definition: nnet-analyze.h:431
#define KALDI_ERR
Definition: kaldi-error.h:147
std::vector< std::vector< Access > > variable_accesses
Definition: nnet-analyze.h:297
ComputationVariables variables
Definition: nnet-analyze.h:295
std::string DescribeVariable(int32 variable) const

◆ CheckComputationUndefined()

void CheckComputationUndefined ( ) const
private

Checks for the situation where a variable is read before being written.

Definition at line 636 of file nnet-analyze.cc.

References ComputationChecker::a_, CheckComputationOptions::check_unused_variables, NnetComputation::SubMatrixInfo::col_offset, NnetComputation::commands, ComputationChecker::computation_, ComputationChecker::config_, ComputationVariables::DescribeVariable(), KALDI_ERR, kaldi::nnet3::kCompressMatrix, kaldi::nnet3::kWriteAccess, NnetComputation::matrices, NnetComputation::SubMatrixInfo::matrix_index, NnetComputation::MatrixInfo::num_cols, NnetComputation::SubMatrixInfo::num_cols, NnetComputation::MatrixInfo::num_rows, NnetComputation::SubMatrixInfo::row_offset, Analyzer::variable_accesses, ComputationVariables::VariableInfo(), and Analyzer::variables.

Referenced by ComputationChecker::Check().

636  {
637  // the variable 'min_proportion' needs to be <= the min_proportion_ value in
638  // class MatrixExtender, otherwise this code could spuriously reject a
639  // computation.
640  BaseFloat min_proportion = 0.8;
641 
642  int32 num_variables = a_.variable_accesses.size();
643  for (int32 v = 0; v < num_variables; v++) {
644  const std::vector<Access> &accesses = a_.variable_accesses[v];
645  if (accesses.empty()) {
647  NnetComputation::SubMatrixInfo info = a_.variables.VariableInfo(v);
648  const NnetComputation::MatrixInfo &matrix_info =
649  computation_.matrices[info.matrix_index];
650  // Before we throw an error, we want to check that it isn't a case that
651  // can be produced by the ExtendMatrices() optimization, that is
652  // actually allowed. This is a case when a variable is inside the last
653  // few rows of a matrix, but not all columns of those last rows.
654  if (info.row_offset >= min_proportion * matrix_info.num_rows &&
655  !(info.col_offset == 0 && info.num_cols == matrix_info.num_cols)) {
656  continue;
657  }
658  KALDI_ERR << "Variable " << v << " == "
659  << a_.variables.DescribeVariable(v) << " is never used.";
660  }
661  } else {
662  // It's OK if part of a matrix is compressed, that is undefined;
663  // likely that part won't be referred to when we uncompress.
664  if (accesses[0].access_type != kWriteAccess &&
665  !(computation_.commands[accesses[0].command_index].command_type ==
667  KALDI_ERR << "Variable " << v << " == "
669  << " is read before it is written to";
670  }
671  }
672 }
kaldi::int32 int32
std::vector< MatrixInfo > matrices
std::vector< Command > commands
const NnetComputation & computation_
Definition: nnet-analyze.h:433
float BaseFloat
Definition: kaldi-types.h:29
const CheckComputationOptions & config_
Definition: nnet-analyze.h:431
#define KALDI_ERR
Definition: kaldi-error.h:147
std::vector< std::vector< Access > > variable_accesses
Definition: nnet-analyze.h:297
NnetComputation::SubMatrixInfo VariableInfo(int32 variable) const
ComputationVariables variables
Definition: nnet-analyze.h:295
std::string DescribeVariable(int32 variable) const

Member Data Documentation

◆ a_

◆ computation_

◆ config_

◆ nnet_


The documentation for this class was generated from the following files: