Compiler Class Reference

This class creates an initial version of the NnetComputation, without any optimization or sharing of matrices. More...

#include <nnet-compile.h>

Collaboration diagram for Compiler:

Classes

struct  StepInfo
 

Public Member Functions

 Compiler (const ComputationRequest &request, const Nnet &nnet)
 
 Compiler (const std::vector< const ComputationRequest *> &request, const Nnet &nnet)
 
void CreateComputation (const CompilerOptions &opts, NnetComputation *computation)
 

Private Member Functions

void ComputeStepDependencies (const std::vector< int32 > &this_step, int32 step_index, unordered_set< int32 > *dep_steps)
 
void ComputeDerivNeeded (const std::vector< std::vector< int32 > > &steps, const std::vector< int32 > &step_to_segment, std::vector< bool > *deriv_needed)
 
void CreateStepInfo (const std::vector< bool > &deriv_needed, const std::vector< int32 > &step_to_segment, std::vector< std::vector< int32 > > *by_step, NnetComputation *computation)
 
MatrixStrideType GetStrideType (int32 node_index) const
 
void DefineMatrices (NnetComputation *computation) const
 
void DefineSubmatrices (NnetComputation *computation)
 
void AllocateMatrices (const std::vector< int32 > &whole_submatrices, NnetComputation *computation) const
 
void SetUpPrecomputedIndexes (const std::vector< int32 > &step_to_segment, NnetComputation *computation)
 
void CompileForward (int32 step, NnetComputation *computation) const
 
void AddForwardStepComponent (int32 step, NnetComputation *computation) const
 
void AddForwardStepInput (int32 step, NnetComputation *computation) const
 
bool IsInputStep (int32 step) const
 
void CompileForwardDescriptor (int32 step, NnetComputation *computation) const
 
void CompileForwardSumDescriptor (int32 step, int32 part_index, NnetComputation *computation) const
 
void ComputeInputLocationsList (int32 step, int32 part_index, std::vector< std::vector< std::pair< int32, int32 > > > *input_locations) const
 
BaseFloat SplitByScale (const SumDescriptor &descriptor, const std::vector< std::vector< std::pair< int32, int32 > > > &input_locations_list, std::vector< std::pair< BaseFloat, std::vector< std::vector< std::pair< int32, int32 > > > > > *split_locations_lists) const
 This function helps to handle scalar factors in Descriptors (expressions like `Scale(-1.0, <descriptor)`). More...
 
void ComputeValueSubmatLocationsList (const std::vector< std::vector< std::pair< int32, int32 > > > &input_locations_list, std::vector< std::vector< std::pair< int32, int32 > > > *submat_locations_list) const
 
void ComputeDerivSubmatLocationsList (const std::vector< std::vector< std::pair< int32, int32 > > > &input_locations_list, std::vector< std::vector< std::pair< int32, int32 > > > *submat_locations_list) const
 
void CompileForwardFromSubmatLocationsList (int32 value_submatrix_index, BaseFloat alpha, const std::vector< std::vector< std::pair< int32, int32 > > > &submat_locations, NnetComputation *computation) const
 Adds to 'computation' commands for part of the forward computation corresponding to a Descriptor. More...
 
void CompileForwardFromSubmatLocations (int32 value_submatrix_index, BaseFloat alpha, const std::vector< std::pair< int32, int32 > > &submat_locations, NnetComputation *computation) const
 Adds to 'computation' commands for part of the forward computation corresponding to a Descriptor. More...
 
void CompileForwardFromIndexes (int32 value_submatrix_index, int32 input_submatrix_index, BaseFloat alpha, const std::vector< int32 > &indexes, NnetComputation *computation) const
 Adds to `computation` a command that adds to the submatrix in `value_submatrix_index` a quantity consisting of alpha times the submatrix in `input_submatrix_index`, with a row mapping given by `indexes`. More...
 
void CompileBackward (int32 step, NnetComputation *computation)
 
void AddBackwardStepComponent (int32 step, NnetComputation *computation) const
 
void AddBackwardStepInput (int32 step, NnetComputation *computation) const
 
void CompileBackwardDescriptor (int32 step, NnetComputation *computation)
 
void CompileBackwardSumDescriptor (int32 step, int32 part_index, NnetComputation *computation) const
 
void CompileBackwardFromSubmatLocationsList (int32 deriv_submatrix_index, BaseFloat alpha, const std::vector< std::vector< std::pair< int32, int32 > > > &submat_locations, NnetComputation *computation) const
 
void CompileBackwardFromSubmatLocations (int32 deriv_submatrix_index, BaseFloat alpha, const std::vector< std::pair< int32, int32 > > &submat_locations, NnetComputation *computation) const
 
void CompileBackwardFromIndexes (int32 deriv_submatrix_index, int32 input_deriv_submatrix_index, BaseFloat alpha, const std::vector< int32 > &indexes, NnetComputation *computation) const
 
void DeallocateMatrices (const std::vector< int32 > &whole_submatrices, const std::vector< int32 > &step_to_segment, NnetComputation *computation)
 
void OutputDebugInfo (NnetComputation *computation) const
 
void AddCommands (const std::vector< bool > &deriv_needed, const std::vector< int32 > &step_to_segment, NnetComputation *computation)
 

Private Attributes

std::vector< const ComputationRequest * > requests_
 
const Nnetnnet_
 
ComputationGraph graph_
 
std::vector< StepInfosteps_
 
std::vector< std::pair< int32, int32 > > cindex_id_to_location_
 This maps each cindex_id to its location. More...
 

Detailed Description

This class creates an initial version of the NnetComputation, without any optimization or sharing of matrices.

Note: for a user-level interface that includes optimization, see class CachingOptimizingCompiler in nnet-optimize.h.

Definition at line 44 of file nnet-compile.h.

Constructor & Destructor Documentation

◆ Compiler() [1/2]

Compiler ( const ComputationRequest request,
const Nnet nnet 
)

Definition at line 29 of file nnet-compile.cc.

References Compiler::requests_.

31  : nnet_(nnet) {
32  requests_.push_back(&request);
33 }
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62

◆ Compiler() [2/2]

Compiler ( const std::vector< const ComputationRequest *> &  request,
const Nnet nnet 
)

Definition at line 35 of file nnet-compile.cc.

References rnnlm::i, KALDI_ASSERT, and Compiler::requests_.

37  : requests_(requests), nnet_(nnet) {
38  KALDI_ASSERT(requests_.size() >= 1);
39  // We are currently not supporting getting model derivatives for multi-segment
40  // (online) computations.
41  if (requests_.size() != 1) {
42  for (size_t i = 0; i < requests_.size(); i++) {
43  KALDI_ASSERT(!requests_[i]->need_model_derivative);
44  KALDI_ASSERT(requests_[i]->store_component_stats ==
45  requests_[0]->store_component_stats);
46  }
47  }
48 }
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

Member Function Documentation

◆ AddBackwardStepComponent()

void AddBackwardStepComponent ( int32  step,
NnetComputation computation 
) const
private

Definition at line 1149 of file nnet-compile.cc.

References NnetComputation::commands, NetworkNode::component_index, Compiler::StepInfo::deriv, Nnet::GetComponent(), Nnet::GetNode(), KALDI_ASSERT, kaldi::nnet3::kBackprop, kaldi::nnet3::kBackpropNeedsInput, kaldi::nnet3::kBackpropNeedsOutput, kaldi::nnet3::kComponent, kaldi::nnet3::kUpdatableComponent, kaldi::nnet3::kUsesMemo, Compiler::nnet_, NetworkNode::node_type, Component::Properties(), Compiler::steps_, NetworkNode::u, and Compiler::StepInfo::value.

Referenced by Compiler::CompileBackward().

1150  {
1151  KALDI_ASSERT(static_cast<size_t>(step) < steps_.size());
1152  const StepInfo &step_info = steps_[step];
1153  int32 input_step = step - 1;
1154  const StepInfo &input_step_info = steps_[input_step];
1155  int32 node_index = step_info.node_index;
1156  const NetworkNode &node = nnet_.GetNode(node_index);
1157  KALDI_ASSERT(node.node_type == kComponent);
1158  int32 component_index = node.u.component_index;
1159  const Component *component = nnet_.GetComponent(component_index);
1160  int32 properties = component->Properties();
1161 
1162  int32 input_submatrix_index = input_step_info.value,
1163  output_submatrix_index = step_info.value,
1164  input_deriv_submatrix_index = input_step_info.deriv,
1165  output_deriv_submatrix_index = step_info.deriv,
1166  memo_index = (properties & kUsesMemo ? step : 0);
1167  KALDI_ASSERT(output_deriv_submatrix_index > 0 &&
1168  (input_deriv_submatrix_index > 0 ||
1169  properties & kUpdatableComponent));
1170 
1171  if (! (properties & kBackpropNeedsInput))
1172  input_submatrix_index = 0;
1173  if (! (properties & kBackpropNeedsOutput))
1174  output_submatrix_index = 0;
1175 
1176  NnetComputation::Command c(kBackprop,
1177  component_index,
1178  step_info.precomputed_indexes_index,
1179  input_submatrix_index,
1180  output_submatrix_index,
1181  output_deriv_submatrix_index,
1182  input_deriv_submatrix_index,
1183  memo_index);
1184  computation->commands.push_back(c);
1185 }
kaldi::int32 int32
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ AddBackwardStepInput()

void AddBackwardStepInput ( int32  step,
NnetComputation computation 
) const
private

Definition at line 1131 of file nnet-compile.cc.

References NnetComputation::commands, Nnet::GetNode(), NnetComputation::IsWholeMatrix(), KALDI_ASSERT, kaldi::nnet3::kComponent, kaldi::nnet3::kInput, kaldi::nnet3::kProvideOutput, Compiler::nnet_, and Compiler::steps_.

Referenced by Compiler::CompileBackward().

1132  {
1133  KALDI_ASSERT(static_cast<size_t>(step) < steps_.size());
1134  const StepInfo &step_info = steps_[step];
1135  int32 node_index = step_info.node_index,
1136  deriv_submatrix_index = step_info.deriv;
1137  if (deriv_submatrix_index == 0)
1138  return; // Nothing to do.
1139  KALDI_ASSERT(computation->IsWholeMatrix(deriv_submatrix_index));
1140  const NetworkNode &node = nnet_.GetNode(node_index);
1141  // actually, currently the node type would always be kInput.
1142  KALDI_ASSERT(node.node_type == kInput || node.node_type == kComponent);
1143 
1144  NnetComputation::Command c(kProvideOutput, deriv_submatrix_index, node_index);
1145  computation->commands.push_back(c);
1146 }
kaldi::int32 int32
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ AddCommands()

void AddCommands ( const std::vector< bool > &  deriv_needed,
const std::vector< int32 > &  step_to_segment,
NnetComputation computation 
)
private

Definition at line 107 of file nnet-compile.cc.

References Compiler::AllocateMatrices(), NnetComputation::commands, Compiler::CompileBackward(), Compiler::CompileForward(), Compiler::DeallocateMatrices(), NnetComputation::GetWholeSubmatrices(), kaldi::nnet3::kNoOperationMarker, NnetComputation::matrices, NnetComputation::need_model_derivative, Compiler::requests_, Compiler::SetUpPrecomputedIndexes(), and Compiler::steps_.

Referenced by Compiler::CreateComputation().

109  {
110  computation->need_model_derivative = requests_[0]->need_model_derivative;
111  int32 arbitrary_factor = 8;
112  computation->commands.reserve(computation->matrices.size()
113  * arbitrary_factor);
114 
115  std::vector<int32> whole_submatrices;
116  computation->GetWholeSubmatrices(&whole_submatrices);
117  AllocateMatrices(whole_submatrices, computation);
118  SetUpPrecomputedIndexes(step_to_segment, computation);
119  int32 num_steps = steps_.size();
120  for (int32 step = 0; step < num_steps; step++) {
121  CompileForward(step, computation);
122  if (step + 1 < static_cast<int32>(step_to_segment.size()) &&
123  step_to_segment[step + 1] != step_to_segment[step]) {
124  // insert a marker that separates segments of the computation.
125  computation->commands.push_back(
126  NnetComputation::Command(kNoOperationMarker));
127  }
128  }
129 
130  // mark the end of the forward phase.
131  computation->commands.push_back(
132  NnetComputation::Command(kNoOperationMarker));
133 
134  for (int32 step = num_steps - 1; step >= 0; step--)
135  if (deriv_needed[step])
136  CompileBackward(step, computation);
137 
138  DeallocateMatrices(whole_submatrices, step_to_segment, computation);
139 }
void CompileBackward(int32 step, NnetComputation *computation)
void AllocateMatrices(const std::vector< int32 > &whole_submatrices, NnetComputation *computation) const
kaldi::int32 int32
void CompileForward(int32 step, NnetComputation *computation) const
void SetUpPrecomputedIndexes(const std::vector< int32 > &step_to_segment, NnetComputation *computation)
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62
void DeallocateMatrices(const std::vector< int32 > &whole_submatrices, const std::vector< int32 > &step_to_segment, NnetComputation *computation)

◆ AddForwardStepComponent()

void AddForwardStepComponent ( int32  step,
NnetComputation computation 
) const
private

Definition at line 1097 of file nnet-compile.cc.

References NnetComputation::commands, NetworkNode::component_index, Nnet::GetComponent(), Nnet::GetNode(), KALDI_ASSERT, kaldi::nnet3::kComponent, kaldi::nnet3::kPropagate, kaldi::nnet3::kStoresStats, kaldi::nnet3::kUsesMemo, Compiler::nnet_, NetworkNode::node_type, Component::Properties(), Compiler::requests_, Compiler::steps_, NetworkNode::u, and Compiler::StepInfo::value.

Referenced by Compiler::CompileForward().

1098  {
1099  KALDI_ASSERT(static_cast<size_t>(step) < steps_.size());
1100  const StepInfo &step_info = steps_[step];
1101  int32 input_step = step - 1;
1102  const StepInfo &input_step_info = steps_[input_step];
1103  int32 node_index = step_info.node_index;
1104  const NetworkNode &node = nnet_.GetNode(node_index);
1105  KALDI_ASSERT(node.node_type == kComponent);
1106  int32 component_index = node.u.component_index;
1107  const Component *component = nnet_.GetComponent(component_index);
1108 
1109  // note RE memo_index: we'll renumber them in optimization to get rid of gaps.
1110  // The use of 'step' as the memo index is OK because step > 0 if we're doing
1111  // forward propagation, there must be preceding steps for inputs or for
1112  // component-input nodes).
1113  int32 properties = component->Properties(),
1114  input_submatrix_index = input_step_info.value,
1115  output_submatrix_index = step_info.value,
1116  memo_index = (step_info.deriv > 0 && (properties & kUsesMemo) ? step : 0),
1117  store_stats = (requests_[0]->store_component_stats &&
1118  (properties & kStoresStats) ? 1 : 0);
1119 
1120  NnetComputation::Command c(kPropagate,
1121  component_index,
1122  step_info.precomputed_indexes_index,
1123  input_submatrix_index,
1124  output_submatrix_index,
1125  memo_index,
1126  store_stats);
1127  computation->commands.push_back(c);
1128 }
kaldi::int32 int32
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ AddForwardStepInput()

void AddForwardStepInput ( int32  step,
NnetComputation computation 
) const
private

Definition at line 1080 of file nnet-compile.cc.

References NnetComputation::commands, Nnet::GetNode(), NnetComputation::IsWholeMatrix(), kaldi::nnet3::kAcceptInput, KALDI_ASSERT, kaldi::nnet3::kComponent, kaldi::nnet3::kInput, Compiler::nnet_, and Compiler::steps_.

Referenced by Compiler::CompileForward().

1081  {
1082  KALDI_ASSERT(static_cast<size_t>(step) < steps_.size());
1083  const StepInfo &step_info = steps_[step];
1084  int32 node_index = step_info.node_index,
1085  submatrix_index = step_info.value;
1086  KALDI_ASSERT(computation->IsWholeMatrix(submatrix_index));
1087 
1088  const NetworkNode &node = nnet_.GetNode(node_index);
1089  // actually currently the node type would always be kInput.
1090  KALDI_ASSERT(node.node_type == kInput || node.node_type == kComponent);
1091 
1092  NnetComputation::Command c(kAcceptInput, submatrix_index, node_index);
1093  computation->commands.push_back(c);
1094 }
kaldi::int32 int32
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ AllocateMatrices()

void AllocateMatrices ( const std::vector< int32 > &  whole_submatrices,
NnetComputation computation 
) const
private

Definition at line 1189 of file nnet-compile.cc.

References NnetComputation::commands, Compiler::StepInfo::deriv, Compiler::graph_, ComputationGraph::is_input, Nnet::IsOutputNode(), KALDI_ASSERT, kaldi::nnet3::kAllocMatrix, kaldi::nnet3::kSetConst, NnetComputation::matrices, Compiler::nnet_, Compiler::StepInfo::node_index, Compiler::StepInfo::output_cindex_ids, Compiler::steps_, NnetComputation::submatrices, and Compiler::StepInfo::value.

Referenced by Compiler::AddCommands().

1190  {
1191  KALDI_ASSERT(computation->commands.empty());
1192  // Work out which matrices are inputs to the computation (or output-derivs,
1193  // which are also supplied as inputs to the computation); we won't be setting
1194  // these up.
1195  unordered_set<int32> input_and_oderiv_matrices;
1196  int32 num_steps = steps_.size();
1197  for (int32 step = 0; step < num_steps; step++) {
1198  const StepInfo &this_info = steps_[step];
1199  if (this_info.output_cindex_ids.empty())
1200  continue;
1201  int32 first_cindex_id = this_info.output_cindex_ids.front(),
1202  node_index = this_info.node_index;
1203  bool is_input = graph_.is_input[first_cindex_id],
1204  is_output = nnet_.IsOutputNode(node_index);
1205  if (is_input) {
1206  int32 value_submatrix_index = this_info.value,
1207  value_matrix_index =
1208  computation->submatrices[value_submatrix_index].matrix_index;
1209  input_and_oderiv_matrices.insert(value_matrix_index);
1210  }
1211  if (is_output && this_info.deriv != 0) {
1212  int32 deriv_submatrix_index = this_info.deriv,
1213  deriv_matrix_index =
1214  computation->submatrices[deriv_submatrix_index].matrix_index;
1215  input_and_oderiv_matrices.insert(deriv_matrix_index);
1216  }
1217  }
1218 
1219  int32 num_matrices = computation->matrices.size();
1220  for (int32 m = 1; m < num_matrices; m++) {
1221  // We don't set up the matrices that are inputs to the computation;
1222  // this happens when the user provides the input.
1223  if (input_and_oderiv_matrices.count(m) == 0) {
1224  // get a submatrix index that refers to the entire matrix.
1225  int32 submatrix_index = whole_submatrices[m];
1226 
1227  computation->commands.push_back(
1228  NnetComputation::Command(kAllocMatrix, submatrix_index));
1229  // Later in the optimization phase, it turns out that zeroing is not
1230  // necessary for some matrices, we'll remove the redundant kSetConst
1231  // commands.
1232  computation->commands.push_back(
1233  NnetComputation::Command(0.0, kSetConst, submatrix_index));
1234  }
1235  }
1236 }
kaldi::int32 int32
ComputationGraph graph_
Definition: nnet-compile.h:64
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< bool > is_input
For each Cindex this tells us whether it was provided as an input to the network. ...
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ CompileBackward()

void CompileBackward ( int32  step,
NnetComputation computation 
)
private

Definition at line 1050 of file nnet-compile.cc.

References Compiler::AddBackwardStepComponent(), Compiler::AddBackwardStepInput(), NnetComputation::commands, Compiler::CompileBackwardDescriptor(), Nnet::GetNode(), Compiler::IsInputStep(), KALDI_ASSERT, KALDI_ERR, kaldi::nnet3::kComponent, kaldi::nnet3::kDescriptor, kaldi::nnet3::kDimRange, kaldi::nnet3::kInput, kaldi::nnet3::kNoOperationPermanent, Compiler::nnet_, Compiler::StepInfo::node_index, NetworkNode::node_type, and Compiler::steps_.

Referenced by Compiler::AddCommands().

1051  {
1052  KALDI_ASSERT(step < static_cast<int32>(steps_.size()));
1053  const StepInfo &step_info = steps_[step];
1054  int32 node_index = step_info.node_index;
1055  const NetworkNode &node = nnet_.GetNode(node_index);
1056 
1057  switch (node.node_type) {
1058  case kInput:
1059  AddBackwardStepInput(step, computation);
1060  if (!IsInputStep(step + 1)) // Make sure backward computation is nonempty.
1061  computation->commands.push_back(
1062  NnetComputation::Command(kNoOperationPermanent));
1063  break;
1064  case kDimRange:
1065  break; // Nothing to do.
1066  case kComponent:
1067  AddBackwardStepComponent(step, computation);
1068  break;
1069  case kDescriptor:
1070  CompileBackwardDescriptor(step, computation);
1071  break;
1072  default:
1073  KALDI_ERR << "Invalid node type";
1074  }
1075 }
void AddBackwardStepComponent(int32 step, NnetComputation *computation) const
kaldi::int32 int32
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
#define KALDI_ERR
Definition: kaldi-error.h:147
void CompileBackwardDescriptor(int32 step, NnetComputation *computation)
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void AddBackwardStepInput(int32 step, NnetComputation *computation) const
bool IsInputStep(int32 step) const

◆ CompileBackwardDescriptor()

void CompileBackwardDescriptor ( int32  step,
NnetComputation computation 
)
private

Definition at line 1029 of file nnet-compile.cc.

References NnetComputation::commands, Compiler::CompileBackwardSumDescriptor(), Compiler::StepInfo::deriv, Nnet::IsOutputNode(), NnetComputation::IsWholeMatrix(), kaldi::nnet3::kAcceptInput, KALDI_ASSERT, Compiler::nnet_, Compiler::StepInfo::node_index, Compiler::steps_, and Compiler::StepInfo::value_parts.

Referenced by Compiler::CompileBackward().

1030  {
1031  StepInfo &step_info = steps_[step];
1032  if (nnet_.IsOutputNode(step_info.node_index) &&
1033  step_info.deriv > 0) {
1034  int32 deriv_submatrix_index = step_info.deriv;
1035  KALDI_ASSERT(computation->IsWholeMatrix(deriv_submatrix_index));
1036  NnetComputation::Command c(kAcceptInput, deriv_submatrix_index,
1037  step_info.node_index);
1038  computation->commands.push_back(c);
1039  }
1040 
1041  // the top-level descriptor has a bunch of parts that we concatenate features
1042  // over.
1043  int32 num_parts = step_info.value_parts.size();
1044  for (int32 part = 0; part < num_parts; part++)
1045  CompileBackwardSumDescriptor(step, part,
1046  computation);
1047 }
kaldi::int32 int32
void CompileBackwardSumDescriptor(int32 step, int32 part_index, NnetComputation *computation) const
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< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ CompileBackwardFromIndexes()

void CompileBackwardFromIndexes ( int32  deriv_submatrix_index,
int32  input_deriv_submatrix_index,
BaseFloat  alpha,
const std::vector< int32 > &  indexes,
NnetComputation computation 
) const
private

Definition at line 939 of file nnet-compile.cc.

References NnetComputation::commands, kaldi::nnet3::HasContiguousProperty(), rnnlm::i, NnetComputation::indexes, NnetComputation::indexes_ranges, kaldi::nnet3::kAddRowRanges, kaldi::nnet3::kAddRows, KALDI_ASSERT, KALDI_ERR, kaldi::nnet3::kMatrixAdd, and NnetComputation::submatrices.

Referenced by Compiler::CompileBackwardFromSubmatLocations().

944  {
945 
946  int32 num_rows = computation->submatrices[deriv_submatrix_index].num_rows,
947  input_num_rows =
948  computation->submatrices[input_deriv_submatrix_index].num_rows;
949  KALDI_ASSERT(indexes.size() == num_rows);
950  if (input_num_rows == num_rows) {
951  int32 i;
952  for (i = 0; i < num_rows; i++)
953  if (indexes[i] != i)
954  break;
955  if (i == num_rows) { // Simplest case: just matrix addition.
956  computation->commands.push_back(
957  NnetComputation::Command(alpha,
958  kMatrixAdd,
959  input_deriv_submatrix_index,
960  deriv_submatrix_index));
961 
962  return;
963  }
964  }
965  if (input_num_rows >= num_rows) {
966  // If there are no repeated elements in the "indexes" array, we can reverse
967  // the mapping and make it an operation of type kAddRows. TODO: change this
968  // to use kAddToRows, kCopyToRows, when implemented (will be more
969  // efficient).
970  std::vector<int32> reverse_indexes(input_num_rows, -1);
971  int32 i;
972  for (i = 0; i < num_rows; i++) {
973  int32 index_i = indexes[i];
974  KALDI_ASSERT(index_i >= -1 && index_i < input_num_rows);
975  if (index_i >= 0) {
976  if (reverse_indexes[index_i] == -1)
977  reverse_indexes[index_i] = i;
978  else
979  break;
980  } // note: there may be -1's in 'indexes', meaning just use zero.
981  }
982  if (i == num_rows) {
983  // There were no repeated elements, and this strategy will work.
984  int32 indexes_index = computation->indexes.size();
985  computation->indexes.push_back(reverse_indexes);
986  computation->commands.push_back(
987  NnetComputation::Command(alpha,
988  kAddRows,
989  input_deriv_submatrix_index,
990  deriv_submatrix_index,
991  indexes_index));
992  return;
993  }
994  }
995  std::vector<std::pair<int32, int32> > ranges;
996  if (HasContiguousProperty(indexes, &ranges)) {
997  // the operation can be set up as AddRowRanges.
998  if (static_cast<int32>(ranges.size()) != input_num_rows) {
999  KALDI_ASSERT(static_cast<int32>(ranges.size()) < input_num_rows);
1000  // extend with (-1, -1) pairs.
1001  ranges.resize(input_num_rows, std::pair<int32,int32>(-1, -1));
1002  }
1003  int32 indexes_ranges_index = computation->indexes_ranges.size();
1004  computation->indexes_ranges.push_back(ranges);
1005  computation->commands.push_back(
1006  NnetComputation::Command(alpha,
1007  kAddRowRanges,
1008  input_deriv_submatrix_index,
1009  deriv_submatrix_index,
1010  indexes_ranges_index));
1011  // TODO: if any of these ranges are quite long (summing over many rows), the
1012  // resulting code could be inefficient because the AddRowRanges kernels
1013  // takes time linear in the length of the range. Using a temporary matrix
1014  // with an intermediate size would make this more efficient in that case, so
1015  // the one command would be two commands (plus commands to set up and
1016  // destroy the temporary matrix).
1017  return;
1018  }
1019 
1020  // If you ever reach here, it means someone has used a type of network that we
1021  // don't yet support in the backprop. Basically this case can be handled by
1022  // creating a temporary matrix to reorder the matrix at deriv_submatrix_index,
1023  // (using CopyRows), and doing AddRowRanges from that.
1024  // It wouldn't be too much work.
1025  KALDI_ERR << "This case not implemented yet.";
1026 }
bool HasContiguousProperty(const std::vector< int32 > &indexes, std::vector< std::pair< int32, int32 > > *reverse_indexes)
This function returns true if for each integer i != -1, all the indexes j at which indexes[j] == i ar...
kaldi::int32 int32
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ CompileBackwardFromSubmatLocations()

void CompileBackwardFromSubmatLocations ( int32  deriv_submatrix_index,
BaseFloat  alpha,
const std::vector< std::pair< int32, int32 > > &  submat_locations,
NnetComputation computation 
) const
private

Definition at line 887 of file nnet-compile.cc.

References NnetComputation::commands, Compiler::CompileBackwardFromIndexes(), kaldi::nnet3::ConvertToIndexes(), NnetComputation::indexes_multi, kaldi::IsSortedAndUniq(), kaldi::nnet3::kAddToRowsMulti, and KALDI_ERR.

Referenced by Compiler::CompileBackwardFromSubmatLocationsList().

891  {
892  // This function creates a command to handle an individual piece of the
893  // Descriptor, for backprop. Note: because the backprop case is a little
894  // trickier to implement efficiently on the GPU, there may be cases
895  // which we will refuse to implement backprop for if we get here.
896 
897 
898 
899  int32 first_value;
900  std::vector<int32> second_values;
901  if (ConvertToIndexes(submat_locations, &first_value,
902  &second_values)) {
903  int32 input_deriv_submatrix_index = first_value;
904  CompileBackwardFromIndexes(deriv_submatrix_index,
905  input_deriv_submatrix_index,
906  alpha,
907  second_values,
908  computation);
909  return;
910  } else {
911  // There are multiple source matrices.
912  std::vector<std::pair<int32, int32> > submat_locations_sorted;
913  std::sort(submat_locations_sorted.begin(), submat_locations_sorted.end());
914  if (IsSortedAndUniq(submat_locations_sorted)) {
915  // There are no repeats in any of the submat locations. This means that
916  // we can just use kAddToRowsMulti (i.e. AddToRows with pointer
917  // destination). If there were repeats, the CUDA kernel would require
918  // special synchronization so we don't allow it.
919  int32 indexes_multi_index = computation->indexes_multi.size();
920  computation->indexes_multi.push_back(submat_locations);
921  computation->commands.push_back(
922  NnetComputation::Command(alpha,
924  deriv_submatrix_index,
925  indexes_multi_index));
926  return;
927  }
928  // If you reach this point, there is a case that wasn't handled. Our
929  // intended strategy to handle it, if it's ever needed, is to create a
930  // temporary matrix consisting of all the unique submat_locations in the
931  // input. We would first recurse to CompileBackwardFromIndexes, and
932  // let it write to this temporary matrix; and then do the kAddToRowsMulti
933  // command as above to go from the temporary matrix to the multiple
934  // matrices.
935  KALDI_ERR << "This case not handled.";
936  }
937 }
bool ConvertToIndexes(const std::vector< std::pair< int32, int32 > > &location_vector, int32 *first_value, std::vector< int32 > *second_values)
If it is the case for some i >= 0 that all the .first elements of "location_vector" are either i or -...
kaldi::int32 int32
#define KALDI_ERR
Definition: kaldi-error.h:147
bool IsSortedAndUniq(const std::vector< T > &vec)
Returns true if the vector is sorted and contains each element only once.
Definition: stl-utils.h:63
void CompileBackwardFromIndexes(int32 deriv_submatrix_index, int32 input_deriv_submatrix_index, BaseFloat alpha, const std::vector< int32 > &indexes, NnetComputation *computation) const

◆ CompileBackwardFromSubmatLocationsList()

void CompileBackwardFromSubmatLocationsList ( int32  deriv_submatrix_index,
BaseFloat  alpha,
const std::vector< std::vector< std::pair< int32, int32 > > > &  submat_locations,
NnetComputation computation 
) const
private

Definition at line 818 of file nnet-compile.cc.

References Compiler::CompileBackwardFromSubmatLocations(), rnnlm::i, and kaldi::nnet3::SplitLocationsBackward().

Referenced by Compiler::CompileBackwardSumDescriptor().

822  {
823  std::vector<std::vector<std::pair<int32, int32> > > split_lists;
824  SplitLocationsBackward(submat_lists, &split_lists);
825  int32 size = split_lists.size(); // size may be zero e.g. for unused outputs.
826  for (int32 i = 0; i < size; i++)
828  deriv_submatrix_index,
829  alpha,
830  split_lists[i],
831  computation);
832 }
kaldi::int32 int32
void CompileBackwardFromSubmatLocations(int32 deriv_submatrix_index, BaseFloat alpha, const std::vector< std::pair< int32, int32 > > &submat_locations, NnetComputation *computation) const
void SplitLocationsBackward(const std::vector< std::vector< std::pair< int32, int32 > > > &submat_lists, std::vector< std::vector< std::pair< int32, int32 > > > *split_lists)
This function has the same interface as SplitLocations(); however, it ensures certain additional prop...

◆ CompileBackwardSumDescriptor()

void CompileBackwardSumDescriptor ( int32  step,
int32  part_index,
NnetComputation computation 
) const
private

Definition at line 835 of file nnet-compile.cc.

References Compiler::CompileBackwardFromSubmatLocationsList(), Compiler::ComputeDerivSubmatLocationsList(), Compiler::StepInfo::deriv_parts, NetworkNode::descriptor, Nnet::GetNode(), rnnlm::i, Compiler::StepInfo::input_locations_list, KALDI_ASSERT, Compiler::nnet_, Compiler::StepInfo::node_index, Descriptor::Part(), Compiler::SplitByScale(), and Compiler::steps_.

Referenced by Compiler::CompileBackwardDescriptor().

836  {
837  const StepInfo &step_info = steps_[step];
838  int32 deriv_submatrix_index = step_info.deriv_parts[part_index];
839  KALDI_ASSERT(deriv_submatrix_index > 0); // or should not have called this.
840  const SumDescriptor &descriptor =
841  nnet_.GetNode(step_info.node_index).descriptor.Part(part_index);
842  // Note: `offset_term` appeared in the forward computation here but does not
843  // come into the backward computation.
844 
845  // `input_locations_list` is a vector indexed by row-index, with each element
846  // being a list of pairs (step, row_index) representing terms in a weighted
847  // sum.
848  const std::vector<std::vector<std::pair<int32,int32> > >
849  &input_locations_list = step_info.input_locations_list[part_index];
850 
851  // `split_locations_lists` is a vector of pairs `(alpha, locations_list)`
852  // where alpha is the scale in which these items appear in the
853  // summation and `locations_list` is the same format as `input_locations_list`
854  std::vector<std::pair<BaseFloat,
855  std::vector<std::vector<std::pair<int32,int32> > > > > split_locations_lists;
856  BaseFloat shared_alpha = SplitByScale(descriptor, input_locations_list,
857  &split_locations_lists);
858  if (shared_alpha - shared_alpha == 0.0) {
859  // If the returned value 'shared_alpha' is finite, this indicates that there
860  // was no need to split up 'input_locations_list' because all the alpha
861  // values (scales) were the same. We treat this case specially for
862  // efficiency reasons; this branch will be the most common branch.
863  std::vector<std::vector<std::pair<int32, int32> > > submat_locations_list;
864  ComputeDerivSubmatLocationsList(input_locations_list,
865  &submat_locations_list);
866  CompileBackwardFromSubmatLocationsList(deriv_submatrix_index,
867  shared_alpha,
868  submat_locations_list,
869  computation);
870  } else {
871  for (size_t i = 0; i < split_locations_lists.size(); i++) {
872  BaseFloat this_alpha = split_locations_lists[i].first;
873  KALDI_ASSERT(this_alpha - this_alpha == 0.0);
874  std::vector<std::vector<std::pair<int32, int32> > > submat_locations_list;
875  ComputeDerivSubmatLocationsList(split_locations_lists[i].second,
876  &submat_locations_list);
877  CompileBackwardFromSubmatLocationsList(deriv_submatrix_index,
878  this_alpha,
879  submat_locations_list,
880  computation);
881  }
882  }
883 }
BaseFloat SplitByScale(const SumDescriptor &descriptor, const std::vector< std::vector< std::pair< int32, int32 > > > &input_locations_list, std::vector< std::pair< BaseFloat, std::vector< std::vector< std::pair< int32, int32 > > > > > *split_locations_lists) const
This function helps to handle scalar factors in Descriptors (expressions like `Scale(-1.0, <descriptor)`).
void CompileBackwardFromSubmatLocationsList(int32 deriv_submatrix_index, BaseFloat alpha, const std::vector< std::vector< std::pair< int32, int32 > > > &submat_locations, NnetComputation *computation) const
kaldi::int32 int32
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
const SumDescriptor & Part(int32 n) const
returns the n&#39;th part.
void ComputeDerivSubmatLocationsList(const std::vector< std::vector< std::pair< int32, int32 > > > &input_locations_list, std::vector< std::vector< std::pair< int32, int32 > > > *submat_locations_list) const
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ CompileForward()

void CompileForward ( int32  step,
NnetComputation computation 
) const
private

Definition at line 406 of file nnet-compile.cc.

References Compiler::AddForwardStepComponent(), Compiler::AddForwardStepInput(), NnetComputation::commands, Compiler::CompileForwardDescriptor(), Nnet::GetNode(), Compiler::IsInputStep(), KALDI_ASSERT, KALDI_ERR, kaldi::nnet3::kComponent, kaldi::nnet3::kDescriptor, kaldi::nnet3::kDimRange, kaldi::nnet3::kInput, kaldi::nnet3::kNoOperationPermanent, Compiler::nnet_, Compiler::StepInfo::node_index, NetworkNode::node_type, and Compiler::steps_.

Referenced by Compiler::AddCommands().

407  {
408  KALDI_ASSERT(step < static_cast<int32>(steps_.size()));
409  const StepInfo &step_info = steps_[step];
410  const NetworkNode &node = nnet_.GetNode(step_info.node_index);
411  switch (node.node_type) {
412  case kInput: // Note: input nodes appear before other node types.
413  AddForwardStepInput(step, computation);
414  if (!IsInputStep(step + 1)) // Make sure forward computation is nonempty.
415  computation->commands.push_back(
416  NnetComputation::Command(kNoOperationPermanent));
417  break;
418  case kDimRange: break; // Nothing to do.
419  case kComponent:
420  AddForwardStepComponent(step, computation);
421  break;
422  case kDescriptor:
423  CompileForwardDescriptor(step, computation);
424  break;
425  default:
426  KALDI_ERR << "Invalid node type";
427  }
428 
429 }
void AddForwardStepInput(int32 step, NnetComputation *computation) const
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
void CompileForwardDescriptor(int32 step, NnetComputation *computation) const
#define KALDI_ERR
Definition: kaldi-error.h:147
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
bool IsInputStep(int32 step) const
void AddForwardStepComponent(int32 step, NnetComputation *computation) const

◆ CompileForwardDescriptor()

void CompileForwardDescriptor ( int32  step,
NnetComputation computation 
) const
private

Definition at line 432 of file nnet-compile.cc.

References NnetComputation::commands, Compiler::CompileForwardSumDescriptor(), Nnet::IsOutputNode(), NnetComputation::IsWholeMatrix(), KALDI_ASSERT, kaldi::nnet3::kProvideOutput, Compiler::nnet_, Compiler::StepInfo::node_index, Compiler::steps_, and Compiler::StepInfo::value.

Referenced by Compiler::CompileForward().

433  {
434  int32 num_parts = steps_[step].value_parts.size();
435  for (int32 part = 0; part < num_parts; part++)
436  CompileForwardSumDescriptor(step, part, computation);
437  const StepInfo &step_info = steps_[step];
438  if (nnet_.IsOutputNode(step_info.node_index)) {
439  // If the node is an output then we need to add commands to provide the
440  // output to the user, and possibly to get derivatives w.r.t. the output
441  // from the user.
442  int32 node_index = step_info.node_index,
443  submatrix_index = step_info.value;
444  KALDI_ASSERT(computation->IsWholeMatrix(submatrix_index));
445  NnetComputation::Command c(kProvideOutput, submatrix_index, node_index);
446  computation->commands.push_back(c);
447  }
448 }
kaldi::int32 int32
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< StepInfo > steps_
Definition: nnet-compile.h:153
void CompileForwardSumDescriptor(int32 step, int32 part_index, NnetComputation *computation) const
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ CompileForwardFromIndexes()

void CompileForwardFromIndexes ( int32  value_submatrix_index,
int32  input_submatrix_index,
BaseFloat  alpha,
const std::vector< int32 > &  indexes,
NnetComputation computation 
) const
private

Adds to `computation` a command that adds to the submatrix in `value_submatrix_index` a quantity consisting of alpha times the submatrix in `input_submatrix_index`, with a row mapping given by `indexes`.

Definition at line 738 of file nnet-compile.cc.

References NnetComputation::commands, rnnlm::i, NnetComputation::indexes, kaldi::nnet3::kAddRows, kaldi::nnet3::kMatrixAdd, and NnetComputation::submatrices.

Referenced by Compiler::CompileForwardFromSubmatLocations().

743  {
744 
745  int32 input_num_rows =
746  computation->submatrices[input_submatrix_index].num_rows,
747  num_rows = indexes.size();
748  if (input_num_rows == num_rows) {
749  int32 i;
750  for (i = 0; i < num_rows; i++)
751  if (indexes[i] != i)
752  break;
753  if (i == num_rows) { // Simplest case: just matrix addition.
754  computation->commands.push_back(
755  NnetComputation::Command(alpha, kMatrixAdd,
756  value_submatrix_index,
757  input_submatrix_index));
758 
759  return;
760  }
761  }
762  // if we got to here, it's not just a case of matrix-copy or matrix-add,
763  // but it's still from a single source matrix.
764  int32 indexes_index = computation->indexes.size();
765  computation->indexes.push_back(indexes);
766  computation->commands.push_back(
767  NnetComputation::Command(alpha, kAddRows, value_submatrix_index,
768  input_submatrix_index, indexes_index));
769  return;
770 }
kaldi::int32 int32

◆ CompileForwardFromSubmatLocations()

void CompileForwardFromSubmatLocations ( int32  value_submatrix_index,
BaseFloat  alpha,
const std::vector< std::pair< int32, int32 > > &  submat_locations,
NnetComputation computation 
) const
private

Adds to 'computation' commands for part of the forward computation corresponding to a Descriptor.

This is called from CompileForwardFromSubmatLocationsList.

Parameters
[in]value_submatrix_indexThe submatrix index of the quanitity we are computing (part of a Descriptor; it's something like Sum(tdnn1, tdnn2) in general).
[in]alphaThe scale (1.0 unless Scale(...) expressions are involved in descriptors) with which these terms are present in the summation.
[in]submat_locationsIndexed by the row index corresponding to the rows of the submatrix referred to by 'value_submatrix_index', this reprenents the source vector which we are adding to this row, in the format (submatrix-index, row-index), or (-1, -1) if in this case there is nothing to add.
[in,out]computationThe computation which we are adding commands to.

Definition at line 772 of file nnet-compile.cc.

References NnetComputation::commands, Compiler::CompileForwardFromIndexes(), kaldi::nnet3::ConvertToIndexes(), NnetComputation::indexes_multi, and kaldi::nnet3::kAddRowsMulti.

Referenced by Compiler::CompileForwardFromSubmatLocationsList().

776  {
777 
778  int32 input_submatrix_index = -1;
779  std::vector<int32> indexes;
780  if (ConvertToIndexes(submat_locations, &input_submatrix_index, &indexes)) {
781  CompileForwardFromIndexes(value_submatrix_index,
782  input_submatrix_index,
783  alpha,
784  indexes,
785  computation);
786  return;
787  } else {
788  // There are multiple source matrices.
789  int32 indexes_multi_index = computation->indexes_multi.size();
790  computation->indexes_multi.push_back(submat_locations);
791  computation->commands.push_back(
792  NnetComputation::Command(alpha, kAddRowsMulti,
793  value_submatrix_index,
794  indexes_multi_index));
795  return;
796  }
797 }
bool ConvertToIndexes(const std::vector< std::pair< int32, int32 > > &location_vector, int32 *first_value, std::vector< int32 > *second_values)
If it is the case for some i >= 0 that all the .first elements of "location_vector" are either i or -...
kaldi::int32 int32
void CompileForwardFromIndexes(int32 value_submatrix_index, int32 input_submatrix_index, BaseFloat alpha, const std::vector< int32 > &indexes, NnetComputation *computation) const
Adds to `computation` a command that adds to the submatrix in `value_submatrix_index` a quantity cons...

◆ CompileForwardFromSubmatLocationsList()

void CompileForwardFromSubmatLocationsList ( int32  value_submatrix_index,
BaseFloat  alpha,
const std::vector< std::vector< std::pair< int32, int32 > > > &  submat_locations,
NnetComputation computation 
) const
private

Adds to 'computation' commands for part of the forward computation corresponding to a Descriptor.

This is called from CompileForwardSumDescriptor.

Parameters
[in]value_submatrix_indexThe submatrix index of the quanitity we are computing (part of a Descriptor; it's something like Sum(tdnn1, tdnn2) in general).
[in]alphaThe scale (1.0 unless Scale(...) expressions are involved in descriptors) with which these terms are present in the summation.
[in]submat_locationsIndexed by the row index of the submatrix referred to by 'value_submatrix_index', each element is a list of sources over which we must sum to obtain that row. Each source is a pair (submatrix-index, row-index).

Definition at line 799 of file nnet-compile.cc.

References Compiler::CompileForwardFromSubmatLocations(), rnnlm::i, and kaldi::nnet3::SplitLocations().

Referenced by Compiler::CompileForwardSumDescriptor().

803  {
804  std::vector<std::vector<std::pair<int32, int32> > > split_lists;
805  SplitLocations(submat_lists, &split_lists);
806  int32 size = split_lists.size();
807  // note: `size` may be empty in unusual cases so don't assert that it's
808  // nonzero.
809  for (int32 i = 0; i < size; i++)
811  value_submatrix_index,
812  alpha,
813  split_lists[i],
814  computation);
815 }
kaldi::int32 int32
void CompileForwardFromSubmatLocations(int32 value_submatrix_index, BaseFloat alpha, const std::vector< std::pair< int32, int32 > > &submat_locations, NnetComputation *computation) const
Adds to &#39;computation&#39; commands for part of the forward computation corresponding to a Descriptor...
void SplitLocations(const std::vector< std::vector< std::pair< int32, int32 > > > &submat_lists, std::vector< std::vector< std::pair< int32, int32 > > > *split_lists)
The input to this function is a vector (indexed by matrix-row-index) of lists of pairs (submat_index...

◆ CompileForwardSumDescriptor()

void CompileForwardSumDescriptor ( int32  step,
int32  part_index,
NnetComputation computation 
) const
private

Definition at line 676 of file nnet-compile.cc.

References NnetComputation::commands, Compiler::CompileForwardFromSubmatLocationsList(), Compiler::ComputeValueSubmatLocationsList(), NetworkNode::descriptor, Nnet::GetNode(), SumDescriptor::GetScaleForNode(), rnnlm::i, Compiler::StepInfo::input_locations_list, KALDI_ASSERT, kaldi::nnet3::kSetConst, Compiler::nnet_, Compiler::StepInfo::node_index, Descriptor::Part(), Compiler::SplitByScale(), Compiler::steps_, and Compiler::StepInfo::value_parts.

Referenced by Compiler::CompileForwardDescriptor().

677  {
678  const StepInfo &step_info = steps_[step];
679  int32 value_submatrix_index = step_info.value_parts[part_index];
680  const SumDescriptor &descriptor =
681  nnet_.GetNode(step_info.node_index).descriptor.Part(part_index);
682 
683  BaseFloat offset_term = descriptor.GetScaleForNode(-1);
684  if (offset_term != 0.0) {
685  computation->commands.push_back(
686  NnetComputation::Command(offset_term, kSetConst,
687  value_submatrix_index));
688  // if offset_term == 0.0 there's no need to do this, because
689  // we zeroed the matrix when we allocated it; search in this
690  // file for kSetConst to see the code. If we are redundantly
691  // setting the value, this will later be optimized out (in the
692  // common cases).
693  }
694 
695 
696  // `input_locations_list` is a vector indexed by row-index, with each element
697  // being a list of pairs (step, row_index) representing terms in a weighted
698  // sum.
699  const std::vector<std::vector<std::pair<int32,int32> > >
700  &input_locations_list = step_info.input_locations_list[part_index];
701 
702  // `split_locations_lists` is a vector of pairs `(alpha, locations_list)`
703  // where alpha is the scale in which these items appear in the
704  // summation and `locations_list` is the same format as `input_locations_list`
705  std::vector<std::pair<BaseFloat,
706  std::vector<std::vector<std::pair<int32,int32> > > > > split_locations_lists;
707  BaseFloat shared_alpha = SplitByScale(descriptor, input_locations_list,
708  &split_locations_lists);
709  if (shared_alpha - shared_alpha == 0.0) {
710  // If the returned value 'shared_alpha' is finite, this indicates that there was no
711  // need to split up 'input_locations_list' because all the alpha values
712  // (scales) were the same. We treat this case specially for efficiency
713  // reasons; this branch will be the most common branch.
714  std::vector<std::vector<std::pair<int32, int32> > > submat_locations_list;
715  ComputeValueSubmatLocationsList(input_locations_list,
716  &submat_locations_list);
718  value_submatrix_index,
719  shared_alpha,
720  submat_locations_list,
721  computation);
722  } else {
723  for (size_t i = 0; i < split_locations_lists.size(); i++) {
724  BaseFloat this_alpha = split_locations_lists[i].first;
725  KALDI_ASSERT(this_alpha - this_alpha == 0.0);
726  std::vector<std::vector<std::pair<int32, int32> > > submat_locations_list;
727  ComputeValueSubmatLocationsList(split_locations_lists[i].second,
728  &submat_locations_list);
730  value_submatrix_index,
731  this_alpha,
732  submat_locations_list,
733  computation);
734  }
735  }
736 }
BaseFloat SplitByScale(const SumDescriptor &descriptor, const std::vector< std::vector< std::pair< int32, int32 > > > &input_locations_list, std::vector< std::pair< BaseFloat, std::vector< std::vector< std::pair< int32, int32 > > > > > *split_locations_lists) const
This function helps to handle scalar factors in Descriptors (expressions like `Scale(-1.0, <descriptor)`).
void CompileForwardFromSubmatLocationsList(int32 value_submatrix_index, BaseFloat alpha, const std::vector< std::vector< std::pair< int32, int32 > > > &submat_locations, NnetComputation *computation) const
Adds to &#39;computation&#39; commands for part of the forward computation corresponding to a Descriptor...
kaldi::int32 int32
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
const SumDescriptor & Part(int32 n) const
returns the n&#39;th part.
void ComputeValueSubmatLocationsList(const std::vector< std::vector< std::pair< int32, int32 > > > &input_locations_list, std::vector< std::vector< std::pair< int32, int32 > > > *submat_locations_list) const
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ ComputeDerivNeeded()

void ComputeDerivNeeded ( const std::vector< std::vector< int32 > > &  steps,
const std::vector< int32 > &  step_to_segment,
std::vector< bool > *  deriv_needed 
)
private

Definition at line 176 of file nnet-compile.cc.

References ComputationGraph::cindexes, NetworkNode::component_index, Compiler::ComputeStepDependencies(), Nnet::GetComponent(), Nnet::GetNode(), Nnet::GetNodeNames(), kaldi::GetVerboseLevel(), Compiler::graph_, rnnlm::i, ComputationRequest::IndexForInput(), ComputationRequest::IndexForOutput(), ComputationRequest::inputs, ComputationGraph::is_input, Nnet::IsComponentNode(), Nnet::IsOutputNode(), KALDI_ASSERT, KALDI_VLOG, kaldi::nnet3::kUpdatableComponent, UpdatableComponent::LearningRate(), ComputationRequest::need_model_derivative, Compiler::nnet_, ComputationRequest::outputs, Component::Properties(), Compiler::requests_, and NetworkNode::u.

Referenced by Compiler::CreateComputation().

179  {
180  KALDI_ASSERT(steps.size() == step_to_segment.size() &&
181  step_to_segment[0] == 0 &&
182  step_to_segment.back() + 1 == requests_.size());
183  deriv_needed->clear();
184  int32 num_steps = steps.size();
185  deriv_needed->resize(num_steps, false);
186 
187  for (int32 step = 0; step < num_steps; step++) {
188  const std::vector<int32> &this_step = steps[step];
189  if (this_step.empty()) // empty steps are theoretically possible, e.g.
190  continue; // if a non-simple Component requires no input.
191  int32 cindex_id = this_step[0];
192  int32 node_index = graph_.cindexes[cindex_id].first;
193  bool is_input = graph_.is_input[cindex_id];
194 
195  std::string node_name = nnet_.GetNodeNames()[node_index];
196  unordered_set<int32> input_steps;
197  ComputeStepDependencies(this_step, step, &input_steps);
198 
199  unordered_set<int32>::iterator iter = input_steps.begin(),
200  end = input_steps.end();
201  // if some step that we depend on needs a derivative, we need the derivative.
202  for (; iter != end; ++iter) {
203  int32 dep_step = *iter;
204  KALDI_ASSERT(dep_step < step);
205  if ((*deriv_needed)[dep_step])
206  (*deriv_needed)[step] = true;
207  }
208  // if this step is an input and the user requested the derivative w.r.t. that
209  // input, we need the derivative.
210  const ComputationRequest &request = *(requests_[step_to_segment[step]]);
211 
212  if (is_input) {
213  int32 input_index = request.IndexForInput(node_name);
214  KALDI_ASSERT(input_index != -1);
215  if (request.inputs[input_index].has_deriv)
216  (*deriv_needed)[step] = true;
217  }
218  // if this step is an output and the user is providing the derivative w.r.t. that
219  // output, we need a place to store the derivative, so we set (*deriv_needed) to
220  // true.
221  if (nnet_.IsOutputNode(node_index)) {
222  int32 output_index = request.IndexForOutput(node_name);
223  KALDI_ASSERT(output_index != -1);
224  if (request.outputs[output_index].has_deriv)
225  (*deriv_needed)[step] = true;
226  }
227 
228  // If this is an updatable Component node with a nonzero learning rate and
229  // the user requested model derivatives (e.g. during training), we need this
230  // step's derivative.
231  if (nnet_.IsComponentNode(node_index) && request.need_model_derivative) {
232  const NetworkNode &node = nnet_.GetNode(node_index);
233  const Component *c = nnet_.GetComponent(node.u.component_index);
234  if (c->Properties() & kUpdatableComponent) {
235  const UpdatableComponent *u = dynamic_cast<const UpdatableComponent*>(c);
236  KALDI_ASSERT(u != NULL);
237  if (u->LearningRate() != 0)
238  (*deriv_needed)[step] = true;
239  }
240  }
241  }
242  if (GetVerboseLevel() >= 5) {
243  std::ostringstream os;
244  os << "deriv_needed = ";
245  for (int32 i = 0; i < deriv_needed->size(); i++)
246  os << ((*deriv_needed)[i] ? "t" : "f");
247  os << "\n";
248  KALDI_VLOG(5) << os.str();
249  }
250 }
int32 GetVerboseLevel()
Get verbosity level, usually set via command line &#39;–verbose=&#39; switch.
Definition: kaldi-error.h:60
kaldi::int32 int32
bool IsComponentNode(int32 node) const
Returns true if this is a component node, meaning that it is of type kComponent.
Definition: nnet-nnet.cc:132
ComputationGraph graph_
Definition: nnet-compile.h:64
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
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< bool > is_input
For each Cindex this tells us whether it was provided as an input to the network. ...
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
#define KALDI_VLOG(v)
Definition: kaldi-error.h:156
void ComputeStepDependencies(const std::vector< int32 > &this_step, int32 step_index, unordered_set< int32 > *dep_steps)
const std::vector< std::string > & GetNodeNames() const
returns vector of node names (needed by some parsing code, for instance).
Definition: nnet-nnet.cc:63

◆ ComputeDerivSubmatLocationsList()

void ComputeDerivSubmatLocationsList ( const std::vector< std::vector< std::pair< int32, int32 > > > &  input_locations_list,
std::vector< std::vector< std::pair< int32, int32 > > > *  submat_locations_list 
) const
private

Definition at line 531 of file nnet-compile.cc.

References rnnlm::i, and Compiler::steps_.

Referenced by Compiler::CompileBackwardSumDescriptor().

534  {
535  submat_locations_list->clear();
536  submat_locations_list->resize(input_locations_list.size());
537  int32 size = submat_locations_list->size();
538  for (int32 i = 0; i < size; i++) {
539  const std::vector<std::pair<int32, int32> > &this_list = input_locations_list[i];
540  std::vector<std::pair<int32, int32> > &this_submat_list = (*submat_locations_list)[i];
541  this_submat_list.reserve(this_list.size());
542  std::vector<std::pair<int32, int32> >::const_iterator
543  input_iter = this_list.begin(), input_end = this_list.end();
544  for (; input_iter != input_end; ++input_iter) {
545  int32 step = input_iter->first,
546  deriv_submat_index = steps_[step].deriv,
547  row = input_iter->second;
548  if (deriv_submat_index > 0)
549  this_submat_list.push_back(std::pair<int32,int32>(deriv_submat_index,
550  row));
551  }
552  }
553 }
kaldi::int32 int32
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153

◆ ComputeInputLocationsList()

void ComputeInputLocationsList ( int32  step,
int32  part_index,
std::vector< std::vector< std::pair< int32, int32 > > > *  input_locations 
) const
private

Definition at line 457 of file nnet-compile.cc.

References Compiler::cindex_id_to_location_, NetworkNode::descriptor, ComputationGraph::GetCindexId(), Nnet::GetNode(), Compiler::graph_, rnnlm::i, SumDescriptor::IsComputable(), rnnlm::j, KALDI_ASSERT, kaldi::nnet3::kNoTime, Compiler::nnet_, Descriptor::Part(), Compiler::steps_, and Index::t.

Referenced by Compiler::CreateStepInfo().

460  {
461 
462  KALDI_ASSERT(static_cast<size_t>(step) < steps_.size());
463  const StepInfo &step_info = steps_[step];
464  const std::vector<Index> &output_indexes = step_info.output_indexes;
465  const NetworkNode &node = nnet_.GetNode(step_info.node_index);
466  const SumDescriptor &descriptor = node.descriptor.Part(part_index);
467  int32 num_indexes = output_indexes.size();
468  submat_locations_list->clear();
469  submat_locations_list->resize(num_indexes);
470 
471  for (int32 i = 0; i < num_indexes; i++) {
472  const Index &index = output_indexes[i];
473  std::vector<std::pair<int32, int32> > &this_locations_list =
474  (*submat_locations_list)[i];
475  if (index.t != kNoTime) {
476  // a real Index, not a 'blank' one
477  // ('blank' indexes are inserted by some non-simple Components to
478  // satisfy internal constraints.
479  std::vector<int32> input_cindex_ids;
480  std::vector<Cindex> input_cindexes;
481  CindexSet cindex_set(graph_);
482  bool ans = descriptor.IsComputable(index, cindex_set, &input_cindexes);
483  // earlier compilation stages should have checked that it is computable,
484  // and the graph should still contain required inputs.
485  KALDI_ASSERT(ans);
486  std::sort(input_cindexes.begin(), input_cindexes.end());
487  int32 size = input_cindexes.size();
488  input_cindex_ids.resize(size);
489  for (int32 j = 0; j < size; j++) {
490  int32 c = graph_.GetCindexId(input_cindexes[j]);
491  KALDI_ASSERT(c != -1);
492  input_cindex_ids[j] = c;
493  }
494  this_locations_list.resize(size);
495  for (int32 j = 0; j < size; j++)
496  this_locations_list[j] = cindex_id_to_location_[input_cindex_ids[j]];
497  } else {
498  this_locations_list.clear();
499  }
500  }
501 }
kaldi::int32 int32
ComputationGraph graph_
Definition: nnet-compile.h:64
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
int32 GetCindexId(const Cindex &cindex, bool is_input, bool *is_new)
Maps a Cindex to an integer cindex_id.
const SumDescriptor & Part(int32 n) const
returns the n&#39;th part.
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
std::vector< std::pair< int32, int32 > > cindex_id_to_location_
This maps each cindex_id to its location.
Definition: nnet-compile.h:161
const int kNoTime
Definition: nnet-common.cc:573

◆ ComputeStepDependencies()

void ComputeStepDependencies ( const std::vector< int32 > &  this_step,
int32  step_index,
unordered_set< int32 > *  dep_steps 
)
private

Definition at line 142 of file nnet-compile.cc.

References Compiler::cindex_id_to_location_, ComputationGraph::cindexes, ComputationGraph::dependencies, Compiler::graph_, Nnet::IsComponentNode(), KALDI_ASSERT, and Compiler::nnet_.

Referenced by Compiler::ComputeDerivNeeded().

145  {
146  dep_steps->clear();
147  if (this_step.empty())
148  return;
149  // steps always have a single node index, we can pick the first.
150  int32 node_index = graph_.cindexes[this_step[0]].first;
151  if (nnet_.IsComponentNode(node_index)) {
152  // there is only one step that a component step depends on, and it's the
153  // immediately preceding step (the component-input step).
154  KALDI_ASSERT(step_index > 0);
155  dep_steps->insert(step_index - 1);
156  return;
157  }
158  std::vector<int32>::const_iterator step_iter = this_step.begin(),
159  step_end = this_step.end();
160  int32 prev_input_step = -1; // this is an optimization for speed.
161  for (; step_iter != step_end; ++step_iter) {
162  int32 cindex_id = *step_iter;
163  const std::vector<int32> &dep = graph_.dependencies[cindex_id];
164  std::vector<int32>::const_iterator iter = dep.begin(), end = dep.end();
165  for (; iter != end; ++iter) {
166  int32 dep_cindex_id = *iter,
167  input_step = cindex_id_to_location_[dep_cindex_id].first;
168  if (input_step != prev_input_step) { // optimization.
169  prev_input_step = input_step;
170  dep_steps->insert(input_step);
171  }
172  }
173  }
174 }
kaldi::int32 int32
bool IsComponentNode(int32 node) const
Returns true if this is a component node, meaning that it is of type kComponent.
Definition: nnet-nnet.cc:132
ComputationGraph graph_
Definition: nnet-compile.h:64
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
std::vector< std::vector< int32 > > dependencies
dependencies[cindex_id] gives you the list of other cindex_ids that this particular cindex_id directl...
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
std::vector< std::pair< int32, int32 > > cindex_id_to_location_
This maps each cindex_id to its location.
Definition: nnet-compile.h:161

◆ ComputeValueSubmatLocationsList()

void ComputeValueSubmatLocationsList ( const std::vector< std::vector< std::pair< int32, int32 > > > &  input_locations_list,
std::vector< std::vector< std::pair< int32, int32 > > > *  submat_locations_list 
) const
private

Definition at line 503 of file nnet-compile.cc.

References rnnlm::i, and Compiler::steps_.

Referenced by Compiler::CompileForwardSumDescriptor().

506  {
507  submat_locations_list->clear();
508  submat_locations_list->resize(input_locations_list.size());
509  int32 size = submat_locations_list->size();
510  for (int32 i = 0; i < size; i++) {
511  const std::vector<std::pair<int32, int32> > &this_list =
512  input_locations_list[i];
513  std::vector<std::pair<int32, int32> > &this_submat_list =
514  (*submat_locations_list)[i];
515  this_submat_list.resize(this_list.size());
516  std::vector<std::pair<int32, int32> >::const_iterator
517  input_iter = this_list.begin(), input_end = this_list.end();
518  std::vector<std::pair<int32, int32> >::iterator iter =
519  this_submat_list.begin();
520  for (; input_iter != input_end; ++input_iter, ++iter) {
521  int32 step = input_iter->first,
522  value_submat_index = steps_[step].value,
523  row = input_iter->second;
524  iter->first = value_submat_index;
525  iter->second = row;
526  }
527  }
528 }
kaldi::int32 int32
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153

◆ CreateComputation()

void CreateComputation ( const CompilerOptions opts,
NnetComputation computation 
)

Definition at line 50 of file nnet-compile.cc.

References Compiler::AddCommands(), ComputationGraphBuilder::AllOutputsAreComputable(), ComputationStepsComputer::Check(), Compiler::cindex_id_to_location_, NnetComputation::Clear(), ComputationGraphBuilder::Compute(), kaldi::nnet3::ComputeComputationPhases(), Compiler::ComputeDerivNeeded(), ComputationStepsComputer::ComputeForSegment(), kaldi::nnet3::ConsolidateIoOperations(), Compiler::CreateStepInfo(), ComputationGraphBuilder::ExplainWhyAllOutputsNotComputable(), Compiler::graph_, KALDI_ERR, Compiler::nnet_, CompilerOptions::output_debug_info, Compiler::OutputDebugInfo(), ComputationGraphBuilder::Prune(), and Compiler::requests_.

Referenced by kaldi::nnet3::CompileLoopedInternal(), CachingOptimizingCompiler::CompileNoShortcut(), kaldi::nnet3::UnitTestNnetAnalyze(), kaldi::nnet3::UnitTestNnetCompile(), kaldi::nnet3::UnitTestNnetCompute(), and kaldi::nnet3::UnitTestNnetOptimizeWithOptions().

51  {
52  computation->Clear();
53  ComputationGraphBuilder builder(nnet_, &graph_);
54  // note: there are only >1 segments in a 'looped' computation.
55  for (size_t segment = 0; segment < requests_.size(); segment++) {
56  builder.Compute(*(requests_[segment]));
57  if (!builder.AllOutputsAreComputable()) {
58  builder.ExplainWhyAllOutputsNotComputable(); // prints logging info
59  KALDI_ERR << "Not all outputs were computable, cannot create computation.";
60  }
61  builder.Prune();
62  }
63  // see function declaration's comment for more on the meaning of "phases" (a
64  // phase will later be decomposed into one or more steps). for each segment
65  // s, phases_per_segment[s] is a list of phases; each phase is a list of
66  // cindex_ids.
67  std::vector<std::vector<std::vector<int32> > > phases_per_segment;
68  ComputeComputationPhases(nnet_, graph_, &phases_per_segment);
69  std::vector<std::vector<int32> > steps;
70  steps.reserve(1000);
71 
72  // maps each step to the segment in which it appears. in the normal case
73  // (non-looped computation), a vector of all zeros.
74  std::vector<int32> step_to_segment;
75 
76 
77  {
78  // note: this class will output to 'steps' and to 'cindex_id_to_location_'.
79  // it may incidentally change 'graph_' by adding a few cindexes.
80  ComputationStepsComputer steps_computer(nnet_, &graph_, &steps,
82 
83  for (size_t segment = 0; segment < requests_.size(); segment++) {
84  steps_computer.ComputeForSegment(*(requests_[segment]),
85  phases_per_segment[segment]);
86  while (step_to_segment.size() < steps.size())
87  step_to_segment.push_back(segment);
88 
89  // save memory, by deleting the phases we just consumed. the
90  // following two lines just exist to save memory.
91  std::vector<std::vector<int32> > temp;
92  phases_per_segment[segment].swap(temp);
93  }
94  steps_computer.Check();
95  }
96  std::vector<bool> deriv_needed;
97  ComputeDerivNeeded(steps, step_to_segment, &deriv_needed);
98  CreateStepInfo(deriv_needed, step_to_segment, &steps, computation);
99  AddCommands(deriv_needed, step_to_segment, computation);
100  // the following command reorders commands so kAcceptInput and kProvideOutput
101  // appear in the desired places.
102  ConsolidateIoOperations(nnet_, computation);
103  if (opts.output_debug_info)
104  OutputDebugInfo(computation);
105 }
void ConsolidateIoOperations(const Nnet &nnet, NnetComputation *computation)
This optimization puts the input operations (kAcceptInput) and output operations (kProvideOutput) at ...
void CreateStepInfo(const std::vector< bool > &deriv_needed, const std::vector< int32 > &step_to_segment, std::vector< std::vector< int32 > > *by_step, NnetComputation *computation)
ComputationGraph graph_
Definition: nnet-compile.h:64
void ComputeDerivNeeded(const std::vector< std::vector< int32 > > &steps, const std::vector< int32 > &step_to_segment, std::vector< bool > *deriv_needed)
void ComputeComputationPhases(const Nnet &nnet, const ComputationGraph &graph, std::vector< std::vector< std::vector< int32 > > > *phases_per_segment)
This function divides a computation into &#39;phases&#39;, where a &#39;phase&#39; is a collection of cindexes which ...
#define KALDI_ERR
Definition: kaldi-error.h:147
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62
void OutputDebugInfo(NnetComputation *computation) const
std::vector< std::pair< int32, int32 > > cindex_id_to_location_
This maps each cindex_id to its location.
Definition: nnet-compile.h:161
void AddCommands(const std::vector< bool > &deriv_needed, const std::vector< int32 > &step_to_segment, NnetComputation *computation)

◆ CreateStepInfo()

void CreateStepInfo ( const std::vector< bool > &  deriv_needed,
const std::vector< int32 > &  step_to_segment,
std::vector< std::vector< int32 > > *  by_step,
NnetComputation computation 
)
private

Definition at line 279 of file nnet-compile.cc.

References Compiler::cindex_id_to_location_, ComputationGraph::cindexes, Compiler::ComputeInputLocationsList(), ComputationGraph::dependencies, Compiler::StepInfo::deriv, Compiler::StepInfo::deriv_parts, NetworkNode::descriptor, NetworkNode::dim, NetworkNode::Dim(), SumDescriptor::Dim(), Descriptor::Dim(), NetworkNode::dim_offset, Nnet::GetNode(), Compiler::GetStrideType(), Compiler::graph_, Compiler::StepInfo::input_locations_list, KALDI_ASSERT, KALDI_PARANOID_ASSERT, kaldi::nnet3::kDescriptor, kaldi::nnet3::kDimRange, NnetComputation::NewMatrix(), NnetComputation::NewSubMatrix(), Compiler::nnet_, Compiler::StepInfo::node_index, NetworkNode::node_type, Descriptor::NumParts(), Compiler::StepInfo::output_cindex_ids, Compiler::StepInfo::output_indexes, Descriptor::Part(), Compiler::StepInfo::segment, Compiler::steps_, NnetComputation::submatrices, Compiler::StepInfo::value, and Compiler::StepInfo::value_parts.

Referenced by Compiler::CreateComputation().

283  {
284  KALDI_ASSERT(!by_step->empty());
285  int32 num_steps = by_step->size();
286  steps_.resize(num_steps);
287  for (int32 step = 0; step < num_steps; step++) {
288  StepInfo &this_info = steps_[step];
289  this_info.output_cindex_ids.swap((*by_step)[step]);
290  this_info.segment = step_to_segment[step];
291  int32 num_ids = this_info.output_cindex_ids.size();
292  this_info.output_indexes.resize(num_ids);
293  for (int32 row_index = 0; row_index < num_ids; row_index++)
294  this_info.output_indexes[row_index] =
295  graph_.cindexes[this_info.output_cindex_ids[row_index]].second;
296  if (num_ids > 0) {
297  // node id's of all Cindexes are the same, so just use first one.
298  this_info.node_index =
299  graph_.cindexes[this_info.output_cindex_ids.front()].first;
300  } else {
301  // it's possible to have an empty step if it's the component-input step of
302  // a GeneralComponent that does not always have dependencies, such as the
303  // ConstantFunctionComponent. This is just a kind of placeholder; it will
304  // generate no commands. The next command works because the next
305  // step will be the propagate for that Component, whose node-index is one
306  // more than the component-input node.
307  KALDI_ASSERT((step+1) < by_step->size() && !(*by_step)[step+1].empty());
308  this_info.node_index =
309  graph_.cindexes[(*by_step)[step+1][0]].first - 1;
310  KALDI_ASSERT(this_info.node_index >= 0);
311  continue; // we don't need to do anything else for this step.
312  }
313  const NetworkNode &node = nnet_.GetNode(this_info.node_index);
314  int32 num_rows = num_ids, num_cols = node.Dim(nnet_);
315 
316  if (node.node_type != kDimRange) {
317  MatrixStrideType stride_type = GetStrideType(this_info.node_index);
318  this_info.value = computation->NewMatrix(num_rows, num_cols,
319  stride_type);
320  if (deriv_needed[step])
321  this_info.deriv = computation->NewMatrix(num_rows, num_cols,
322  stride_type);
323  } else {
324  // kDimRange. Will just be a sub-matrix of a Component or Input node.
325  std::vector<int32>::const_iterator
326  iter = this_info.output_cindex_ids.begin(),
327  end = this_info.output_cindex_ids.end();
328  int32 source_cindex_id = -1;
329  for (; iter != end; ++iter) {
330  int32 cindex_id = *iter;
331  if (!graph_.dependencies[cindex_id].empty()) {
332  KALDI_ASSERT(graph_.dependencies[cindex_id].size() == 1);
333  source_cindex_id = graph_.dependencies[cindex_id][0];
334  break;
335  }
336  }
337  KALDI_ASSERT(source_cindex_id >= 0);
338  int32 input_step = cindex_id_to_location_[source_cindex_id].first;
339  KALDI_ASSERT(this_info.output_cindex_ids.size() ==
340  steps_[input_step].output_cindex_ids.size());
341  KALDI_ASSERT(input_step >= 0 && input_step < step);
342  KALDI_PARANOID_ASSERT(this_info.output_indexes ==
343  steps_[input_step].output_indexes);
344  this_info.value = computation->NewSubMatrix(steps_[input_step].value,
345  0, -1,
346  node.dim_offset, node.dim);
347  if (deriv_needed[step])
348  this_info.deriv = computation->NewSubMatrix(steps_[input_step].deriv,
349  0, -1,
350  node.dim_offset, node.dim);
351  }
352  if (node.node_type == kDescriptor) {
353  // we have a couple of things to do: set up input_locations_list which
354  // says where we copy the data from, and also set up value_parts and
355  // possibly deriv_parts.
356  const Descriptor &desc = node.descriptor;
357  int32 num_parts = desc.NumParts();
358  KALDI_ASSERT(num_parts > 0);
359  // set up input_locations_list.
360  this_info.input_locations_list.resize(num_parts);
361  for (int32 part = 0; part < num_parts; part++)
362  ComputeInputLocationsList(step, part,
363  &(this_info.input_locations_list[part]));
364  // set up value_parts and deriv_parts.
365  if (num_parts == 1) {
366  this_info.value_parts.push_back(this_info.value);
367  if (deriv_needed[step])
368  this_info.deriv_parts.push_back(this_info.deriv);
369  } else { // num_parts > 1.
370  int32 cur_dim_offset = 0;
371  // Have multiple parts, so need to set up sub-matrices.
372  this_info.value_parts.resize(num_parts);
373  if (deriv_needed[step])
374  this_info.deriv_parts.resize(num_parts);
375  for (int32 p = 0; p < num_parts; p++) {
376  const SumDescriptor &this_part = desc.Part(p);
377  int32 this_dim = this_part.Dim(nnet_);
378  this_info.value_parts[p] =
379  computation->NewSubMatrix(this_info.value,
380  0, -1,
381  cur_dim_offset, this_dim);
382  if (deriv_needed[step])
383  this_info.deriv_parts[p] =
384  computation->NewSubMatrix(this_info.deriv,
385  0, -1,
386  cur_dim_offset, this_dim);
387  cur_dim_offset += this_dim;
388  }
389  KALDI_ASSERT(cur_dim_offset == desc.Dim(nnet_));
390  }
391  }
392  KALDI_ASSERT(static_cast<int32>(this_info.output_cindex_ids.size()) ==
393  computation->submatrices[this_info.value].num_rows);
394  }
395 }
kaldi::int32 int32
ComputationGraph graph_
Definition: nnet-compile.h:64
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
std::vector< std::vector< int32 > > dependencies
dependencies[cindex_id] gives you the list of other cindex_ids that this particular cindex_id directl...
void ComputeInputLocationsList(int32 step, int32 part_index, std::vector< std::vector< std::pair< int32, int32 > > > *input_locations) const
MatrixStrideType
Definition: matrix-common.h:44
#define KALDI_PARANOID_ASSERT(cond)
Definition: kaldi-error.h:206
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
MatrixStrideType GetStrideType(int32 node_index) const
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
std::vector< std::pair< int32, int32 > > cindex_id_to_location_
This maps each cindex_id to its location.
Definition: nnet-compile.h:161

◆ DeallocateMatrices()

void DeallocateMatrices ( const std::vector< int32 > &  whole_submatrices,
const std::vector< int32 > &  step_to_segment,
NnetComputation computation 
)
private

Definition at line 1293 of file nnet-compile.cc.

References NnetComputation::commands, Compiler::StepInfo::deriv, Nnet::GetNodeNames(), rnnlm::i, ComputationRequest::inputs, Nnet::IsInputNode(), Nnet::IsOutputNode(), KALDI_ASSERT, kaldi::nnet3::kDeallocMatrix, NnetComputation::matrices, Compiler::nnet_, Compiler::StepInfo::node_index, Compiler::requests_, Compiler::steps_, NnetComputation::submatrices, and Compiler::StepInfo::value.

Referenced by Compiler::AddCommands().

1295  {
1296  // This adds the commands to destroy all the matrices- but not the
1297  // ones that might be needed as outputs of the computation. The ones that
1298  // are spared from destruction are those corresponding to outputs of the
1299  // computation, and those corresponding to input derivatives that were
1300  // requested by the user.
1301  int32 num_matrices = computation->matrices.size();
1302  std::vector<bool> will_destroy(num_matrices, true);
1303 
1304  int32 num_steps = steps_.size();
1305  for (int32 step = 0; step < num_steps; step++) {
1306  const StepInfo &step_info = steps_[step];
1307  const ComputationRequest &request = *(requests_[step_to_segment[step]]);
1308  if (nnet_.IsOutputNode(step_info.node_index)) {
1309  // steps corresponding to output nodes need to have their "value" kept.
1310  int32 value_matrix_index =
1311  computation->submatrices[step_info.value].matrix_index;
1312  will_destroy[value_matrix_index] = false;
1313  } else if (nnet_.IsInputNode(step_info.node_index)) {
1314  // steps corresponding to input nodes need to have their "deriv" kept, but
1315  // only if the corresponding input derivative was requested. (we don't
1316  // need to worry about whether outputs were requested, because if they
1317  // were not requested we would not be computing them in the first place).
1318  std::string input_name = nnet_.GetNodeNames()[step_info.node_index];
1319  int32 i = 0, num_inputs = request.inputs.size();
1320  bool has_deriv = false;
1321  for (; i < num_inputs; i++) {
1322  if (input_name == request.inputs[i].name) {
1323  has_deriv = request.inputs[i].has_deriv;
1324  break;
1325  }
1326  }
1327  KALDI_ASSERT(i != num_inputs); // assert we found an input-request with
1328  // this name
1329  if (has_deriv) {
1330  int32 deriv_matrix_index =
1331  computation->submatrices[step_info.deriv].matrix_index;
1332  will_destroy[deriv_matrix_index] = false;
1333  }
1334  }
1335  }
1336  // note: matrix-index 0 is the empty matrix.
1337  for (int32 m = 1; m < num_matrices; m++) {
1338  if (will_destroy[m]) {
1339  int32 submatrix_index = whole_submatrices[m];
1340  computation->commands.push_back(
1341  NnetComputation::Command(kDeallocMatrix, submatrix_index));
1342  }
1343  }
1344 }
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
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< StepInfo > steps_
Definition: nnet-compile.h:153
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
const std::vector< std::string > & GetNodeNames() const
returns vector of node names (needed by some parsing code, for instance).
Definition: nnet-nnet.cc:63

◆ DefineMatrices()

void DefineMatrices ( NnetComputation computation) const
private

◆ DefineSubmatrices()

void DefineSubmatrices ( NnetComputation computation)
private

◆ GetStrideType()

MatrixStrideType GetStrideType ( int32  node_index) const
private

Definition at line 252 of file nnet-compile.cc.

References NetworkNode::component_index, Nnet::GetComponent(), Nnet::GetNode(), Nnet::IsComponentInputNode(), Nnet::IsComponentNode(), kaldi::kDefaultStride, kaldi::nnet3::kInputContiguous, kaldi::nnet3::kOutputContiguous, kaldi::kStrideEqualNumCols, Compiler::nnet_, Component::Properties(), and NetworkNode::u.

Referenced by Compiler::CreateStepInfo().

252  {
253  int32 component_node_index;
254  bool is_input;
255  if (nnet_.IsComponentInputNode(node_index)) {
256  // this node is for the input to a component.
257  component_node_index = node_index + 1;
258  is_input = true;
259  } else if (nnet_.IsComponentNode(node_index)) {
260  component_node_index = node_index;
261  is_input = false;
262  } else {
263  return kDefaultStride;
264  }
265  const NetworkNode &node = nnet_.GetNode(component_node_index);
266  const Component *c = nnet_.GetComponent(node.u.component_index);
267  if (is_input) {
268  return (c->Properties() & kInputContiguous) ?
270  } else {
271  return (c->Properties() & kOutputContiguous) ?
273  }
274 }
kaldi::int32 int32
bool IsComponentNode(int32 node) const
Returns true if this is a component node, meaning that it is of type kComponent.
Definition: nnet-nnet.cc:132
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
bool IsComponentInputNode(int32 node) const
Returns true if this is component-input node, i.e.
Definition: nnet-nnet.cc:172

◆ IsInputStep()

bool IsInputStep ( int32  step) const
private

Definition at line 397 of file nnet-compile.cc.

References Nnet::GetNode(), KALDI_ASSERT, kaldi::nnet3::kInput, Compiler::nnet_, Compiler::StepInfo::node_index, NetworkNode::node_type, and Compiler::steps_.

Referenced by Compiler::CompileBackward(), and Compiler::CompileForward().

397  {
398  KALDI_ASSERT(step >= 0);
399  if (step >= steps_.size())
400  return false;
401  const StepInfo &step_info = steps_[step];
402  const NetworkNode &node = nnet_.GetNode(step_info.node_index);
403  return (node.node_type == kInput);
404 }
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ OutputDebugInfo()

void OutputDebugInfo ( NnetComputation computation) const
private

Definition at line 1346 of file nnet-compile.cc.

References kaldi::nnet3::AppendCindexes(), NnetComputation::MatrixDebugInfo::cindexes, Compiler::StepInfo::deriv, NnetComputation::MatrixDebugInfo::is_deriv, NnetComputation::IsWholeMatrix(), NnetComputation::matrices, NnetComputation::matrix_debug_info, Compiler::StepInfo::node_index, Compiler::StepInfo::output_indexes, Compiler::steps_, NnetComputation::submatrices, and Compiler::StepInfo::value.

Referenced by Compiler::CreateComputation().

1346  {
1347  int32 num_matrices = computation->matrices.size(),
1348  num_steps = steps_.size();
1349  computation->matrix_debug_info.resize(num_matrices);
1350  for (int32 step = 0; step < num_steps; step++) {
1351  const StepInfo &step_info = steps_[step];
1352  if (step_info.value == 0)
1353  continue; // e.g. input step for ConstantComponent.
1354  if (!computation->IsWholeMatrix(step_info.value))
1355  continue;
1356  int32 value_matrix = computation->submatrices[step_info.value].matrix_index;
1357  int32 deriv_matrix = 0;
1358  if (step_info.deriv != 0 && computation->IsWholeMatrix(step_info.deriv))
1359  deriv_matrix = computation->submatrices[step_info.deriv].matrix_index;
1360 
1361  NnetComputation::MatrixDebugInfo &debug_info =
1362  computation->matrix_debug_info[value_matrix];
1363  debug_info.is_deriv = false;
1364  if (!debug_info.cindexes.empty()) {
1365  // This can happen if we created an alias for a node using a
1366  // dim-range-node that covers all the dimensions (would satisfy
1367  // IsWholeMatrix() above while not being a unique matrix). We sometimes
1368  // do that to work around compiler constraints when creating expressions
1369  // that have the same quantity with more than one scaling value within the
1370  // same expression (like for computing deltas).
1371  continue;
1372  }
1373  AppendCindexes(step_info.node_index, step_info.output_indexes,
1374  &debug_info.cindexes);
1375  if (deriv_matrix != 0) {
1376  NnetComputation::MatrixDebugInfo &deriv_debug_info =
1377  computation->matrix_debug_info[deriv_matrix];
1378  deriv_debug_info.is_deriv = true;
1379  deriv_debug_info.cindexes = debug_info.cindexes;
1380  }
1381  }
1382 }
kaldi::int32 int32
void AppendCindexes(int32 node, const std::vector< Index > &indexes, std::vector< Cindex > *out)
Appends to &#39;out&#39; the pairs (node, indexes[0]), (node, indexes[1]), ...
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153

◆ SetUpPrecomputedIndexes()

void SetUpPrecomputedIndexes ( const std::vector< int32 > &  step_to_segment,
NnetComputation computation 
)
private

Definition at line 1239 of file nnet-compile.cc.

References NetworkNode::component_index, NnetComputation::component_precomputed_indexes, NnetComputation::PrecomputedIndexesInfo::data, Nnet::GetComponent(), Nnet::GetNode(), NnetComputation::PrecomputedIndexesInfo::input_indexes, KALDI_ASSERT, kaldi::nnet3::kComponent, ComputationRequest::misc_info, ComputationRequest::NeedDerivatives(), Compiler::nnet_, Compiler::StepInfo::node_index, NetworkNode::node_type, Compiler::StepInfo::output_indexes, NnetComputation::PrecomputedIndexesInfo::output_indexes, Compiler::StepInfo::precomputed_indexes_index, Component::PrecomputeIndexes(), Compiler::requests_, Compiler::steps_, and NetworkNode::u.

Referenced by Compiler::AddCommands().

1241  {
1242  int32 num_steps = steps_.size();
1243  KALDI_ASSERT(computation->component_precomputed_indexes.empty());
1244  // the zeroth commponent is special, contains a NULL pointer.
1245  computation->component_precomputed_indexes.resize(1);
1246  for (int32 step = 0; step < num_steps; step++) {
1247  StepInfo &step_info = steps_[step];
1248  int32 node_index = step_info.node_index;
1249  const NetworkNode &node = nnet_.GetNode(node_index);
1250  // There is only something to do for nodes of type Component.
1251  if (node.node_type != kComponent)
1252  continue;
1253  const StepInfo &input_step_info = steps_[step - 1];
1254  int32 component_index = node.u.component_index;
1255  int32 input_node_index = input_step_info.node_index;
1256  KALDI_ASSERT(input_node_index == node_index - 1);
1257  const std::vector<Index> &input_indexes = input_step_info.output_indexes;
1258  const std::vector<Index> &output_indexes = step_info.output_indexes;
1259 
1260  const Component *component = nnet_.GetComponent(component_index);
1261 
1262  const ComputationRequest &request = *(requests_[step_to_segment[step]]);
1263  bool need_derivs = request.NeedDerivatives();
1264  ComponentPrecomputedIndexes *precomputed_indexes =
1265  component->PrecomputeIndexes(request.misc_info,
1266  input_indexes, output_indexes,
1267  need_derivs);
1268  if (precomputed_indexes == NULL) {
1269  // e.g. simple Components, and some other Components, will return NULL for
1270  // precomputed_indexes.
1271  step_info.precomputed_indexes_index = 0;
1272  } else {
1273  step_info.precomputed_indexes_index =
1274  computation->component_precomputed_indexes.size();
1275 
1276  NnetComputation::PrecomputedIndexesInfo info;
1277  info.data = precomputed_indexes;
1278 
1279  if (!input_indexes.empty() && input_indexes.back().n == 1 &&
1280  !output_indexes.empty() && output_indexes.back().n == 1) {
1281  // If these conditions are true, it's *possible* that we are doing
1282  // 'shortcut' compilation. So just in case that's what's going on, we
1283  // store 'input_indexes' and 'output_indexes, which are needed by
1284  // the ExpandComputation() function that is used in that process.
1285  info.input_indexes = input_indexes;
1286  info.output_indexes = output_indexes;
1287  }
1288  computation->component_precomputed_indexes.push_back(info);
1289  }
1290  }
1291 }
kaldi::int32 int32
virtual ComponentPrecomputedIndexes * PrecomputeIndexes(const MiscComputationInfo &misc_info, const std::vector< Index > &input_indexes, const std::vector< Index > &output_indexes, bool need_backprop) const
This function must return NULL for simple Components.
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
std::vector< const ComputationRequest * > requests_
Definition: nnet-compile.h:62
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ SplitByScale()

BaseFloat SplitByScale ( const SumDescriptor descriptor,
const std::vector< std::vector< std::pair< int32, int32 > > > &  input_locations_list,
std::vector< std::pair< BaseFloat, std::vector< std::vector< std::pair< int32, int32 > > > > > *  split_locations_lists 
) const
private

This function helps to handle scalar factors in Descriptors (expressions like `Scale(-1.0, <descriptor)`).

It splits an input_locations_list for one SumDescriptor (consisting of one of the appended-together parts of a Descriptor) by scale, such that each split-up locations_list corresponds to a single scaling factor. The scaling factors are all 1.0 by default, but may be different from 1.0 if the user uses `Scale(...)` expressions in descriptors, e.g. `Scale(-1.0, lstm1.z)`. To help efficiency, this function treats the case where all the scales in the expression are the same (usually 1.0), as a special case. In this case, 'split_locations_lists' will be empty and the shared scale (e.g. 1.0) is returned.

Parameters
[in]descriptorThe SumDescriptor for which we're getting scalar factors.
[in]input_locations_listThis is one element of the input_locations_list from the StepInfo of the step we are computing, corresponding to this SumDescriptor (i.e. one part of the Descriptor). It is indexed by row-index, then it is a list of pairs (step, row-index), representing source Cindexes of a summation. This function will work out what scaling factors the pairs in these lists have.
[out]split_locations_listsWe write to this location. If all the scaling factors are the same this will be set to the empty list and the common scaling factor returned. Otherwise +infinity will be returned and the split-up list will be written to the location. Each element (*split_locations_lists)[i] will be set to a pair (alpha, partial_input_locations_list) where alpha is the scaling factor associated with this split-up piece (e.g. -1.0 if it was part of an expression like `Scale(-1.0, lstm1.z)`), and 'partial_input_locations_list' is a vector with the same dimension as 'input_locations_list' (indexed by row-index), where partial_input_locations_list[r] will contain a subset of the pairs present in input_locations_list[r], and if we were to append together all the (*split_locations_lists)[*].second.partial_input_locations_list[r], we'd get a list with the same members as input_locations_list[r], although not necessarily in the same order.
Returns
In the general case (where multiple scales are used), returns +infinity and sets 'split_locations_lists' to the split-up list. In the special, but more common case where only a single scale is used, return that scale (1.0 will be the most common value) and set 'split_locations_lists' to empty; in this special case, which has been made a special case for efficiency reasons, the user should directly use the un-split locations list in 'input_locations_list'.

Definition at line 557 of file nnet-compile.cc.

References SumDescriptor::GetNodeDependencies(), SumDescriptor::GetScaleForNode(), rnnlm::i, rnnlm::j, KALDI_ASSERT, kaldi::SortAndUniq(), and Compiler::steps_.

Referenced by Compiler::CompileBackwardSumDescriptor(), and Compiler::CompileForwardSumDescriptor().

562  {
563  split_locations_lists->clear();
564  // alpha_to_nodes maps from the scale alpha to the list of nodes which are
565  // given that scale.
566  std::map<BaseFloat, std::vector<int32> > alpha_to_nodes;
567  { // This block compute `alpha_to_nodes`.
568  std::vector<int32> nodes;
569  descriptor.GetNodeDependencies(&nodes);
570  SortAndUniq(&nodes);
571  // Now `nodes` is a list of the graph node indexes that are referred to
572  // in the descriptor. E.g. if the Descriptor represents
573  // 'Sum(tdnn1, Offset(tdnn2, -2))' then `nodes` would contain the
574  // integer node indexes for graph-nodes 'tdnn1' and 'tdnn2'.
575  for (size_t i = 0; i < nodes.size(); i++) {
576  int32 node = nodes[i];
577  BaseFloat alpha = descriptor.GetScaleForNode(node);
578  KALDI_ASSERT(alpha - alpha == 0.0); // check it's not infinity.
579  alpha_to_nodes[alpha].push_back(node);
580  }
581  }
582 
583  if (alpha_to_nodes.size() == 1) {
584  // If all the alpha values are the same we treat it as a special case
585  // for efficiency, to avoid a redundant copy of the contents of
586  // 'input_locations_list'.
587  return alpha_to_nodes.begin()->first;
588  }
589 
590  // `steps_used` will be a list of all step indexes that appear as `.first`
591  // elements in `input_locations_list`.
592  unordered_set<int32> steps_used;
593  { // This block computes `steps_used`.
594  int32 cur_step = -1000;
595  std::vector<std::vector<std::pair<int32,int32> > >::const_iterator
596  iter = input_locations_list.begin(),
597  end = input_locations_list.end();
598  for (; iter != end; ++iter) {
599  std::vector<std::pair<int32,int32> >::const_iterator
600  pair_iter = iter->begin(),
601  pair_end = iter->end();
602  for (; pair_iter != pair_end; ++pair_iter) {
603  if (pair_iter->first != cur_step) {
604  cur_step = pair_iter->first;
605  steps_used.insert(cur_step);
606  }
607  }
608  }
609  }
610 
611  // `node_to_steps` will be a map from graph node index to the list of steps
612  // which are present in `steps_used` and which are associated with that graph
613  // node.
614  std::map<int32, std::vector<int32> > node_to_steps;
615  { // This block computes `node_to_steps`.
616  unordered_set<int32>::const_iterator
617  step_iter = steps_used.begin(), step_end = steps_used.end();
618  for (; step_iter != step_end; ++step_iter) {
619  int32 step_index = *step_iter;
620  KALDI_ASSERT(static_cast<size_t>(step_index) < steps_.size());
621  int32 node_index = steps_[step_index].node_index;
622  node_to_steps[node_index].push_back(step_index);
623  }
624  }
625 
626  int32 num_rows = input_locations_list.size();
627  split_locations_lists->resize(alpha_to_nodes.size());
628  // `step_to_index` will map from the step-index to the index into
629  // `split_locations_lists`; each index is associated with a different value of
630  // the scale `alpha`.
631  std::vector<int32> step_to_locations_index(steps_.size(), -1);
632  { // This block computes `step_to_index` and also sets the `alpha` values
633  // which are present as (*split_locations_lists)[*].first.
634  std::map<BaseFloat, std::vector<int32> >::const_iterator
635  iter = alpha_to_nodes.begin(), end = alpha_to_nodes.end();
636  int32 split_locations_index = 0;
637  for (; iter != end; ++iter, ++split_locations_index) {
638  BaseFloat alpha = iter->first;
639  const std::vector<int32> &nodes = iter->second;
640  (*split_locations_lists)[split_locations_index].first = alpha;
641  (*split_locations_lists)[split_locations_index].second.resize(num_rows);
642  for (size_t i = 0; i < nodes.size(); i++) {
643  int32 node_index = nodes[i];
644  KALDI_ASSERT(node_to_steps.count(node_index) != 0);
645  const std::vector<int32> &steps = node_to_steps[node_index];
646  for (size_t j = 0; j < steps.size(); j++) {
647  int32 step_index = steps[j];
648  KALDI_ASSERT(step_index >= 0 &&
649  step_to_locations_index[step_index] == -1);
650  step_to_locations_index[step_index] = split_locations_index;
651  }
652  }
653  }
654  }
655 
656  { // This block populates 'split_locations_lists[*].second' with the
657  // split-by-alpha version of 'input_locations_list'
658  for (int32 r = 0; r < num_rows; r++) {
659  const std::vector<std::pair<int32,int32> > &this_list =
660  input_locations_list[r];
661  std::vector<std::pair<int32,int32> >::const_iterator
662  pair_iter = this_list.begin(),
663  pair_end = this_list.end();
664  for (; pair_iter != pair_end; ++pair_iter) {
665  int32 step = pair_iter->first,
666  split_locations_index = step_to_locations_index[step];
667  (*split_locations_lists)[split_locations_index].second[r].push_back(
668  *pair_iter);
669  }
670  }
671  }
672  return std::numeric_limits<BaseFloat>::infinity();
673 }
kaldi::int32 int32
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq&#39;s (removes duplicates) from a vector.
Definition: stl-utils.h:39
float BaseFloat
Definition: kaldi-types.h:29
std::vector< StepInfo > steps_
Definition: nnet-compile.h:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

Member Data Documentation

◆ cindex_id_to_location_

std::vector<std::pair<int32, int32> > cindex_id_to_location_
private

This maps each cindex_id to its location.

However, you should not rely on its accuracy for cindex_ids that correspond to the Descriptors at Component inputs, since it's possible in principle for such cindex_ids to exist at >1 location. (This is not a problem in practice, because we only need this for the outputs of component-nodes, and for computation inputs). A location is a pair (step-index, matrix-row-index).

Definition at line 161 of file nnet-compile.h.

Referenced by Compiler::ComputeInputLocationsList(), Compiler::ComputeStepDependencies(), Compiler::CreateComputation(), and Compiler::CreateStepInfo().

◆ graph_

◆ nnet_

◆ requests_

◆ steps_


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