All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
kaldi::nnet3::computation_graph Namespace Reference

Functions

void AddOutputToGraph (const ComputationRequest &request, const Nnet &nnet, ComputationGraph *graph)
 
void AddInputToGraph (const ComputationRequest &request, const Nnet &nnet, ComputationGraph *graph)
 
static void ComputeDependenciesSubset (const ComputationGraph &graph, const std::vector< int32 > &cindex_id_to_segment_and_epoch, std::vector< std::vector< int32 > > *dependencies_subset)
 This function outputs to dependencies_subset[c], for each cindex_id c, the subset of elements d of graph.dependencies[c] such that cindex_id_to_segment_and_epoch[d] == cindex_id_to_segment_and_epoch[c]. More...
 
static void ComputeEpochInfo (const Nnet &nnet, const ComputationGraph &graph, std::vector< int32 > *cindex_id_to_segment_and_epoch, std::vector< std::vector< std::vector< int32 > > > *epochs_per_segment, std::vector< bool > *epoch_is_trivial)
 This function computes certain information about "epochs" of cindex_ids. More...
 

Function Documentation

void kaldi::nnet3::computation_graph::AddInputToGraph ( const ComputationRequest &  request,
const Nnet &  nnet,
ComputationGraph *  graph 
)

Definition at line 1003 of file nnet-computation-graph.cc.

References ComputationGraph::GetCindexId(), Nnet::GetNode(), Nnet::GetNodeIndex(), rnnlm::i, ComputationRequest::inputs, rnnlm::j, KALDI_ASSERT, KALDI_ERR, kaldi::nnet3::kComponent, kaldi::nnet3::kInput, rnnlm::n, and NetworkNode::node_type.

Referenced by kaldi::nnet3::ComputeComputationGraph().

1005  {
1006  int32 num_added = 0;
1007  for (int32 i = 0; i < request.inputs.size(); i++) {
1008  int32 n = nnet.GetNodeIndex(request.inputs[i].name);
1009  if (n == -1)
1010  KALDI_ERR << "Network has no input with name "
1011  << request.inputs[i].name;
1012  NodeType t = nnet.GetNode(n).node_type;
1013  KALDI_ASSERT((t == kInput || t == kComponent) &&
1014  "Inputs to graph only allowed for Input and Component nodes.");
1015 
1016  for (int32 j = 0; j < request.inputs[i].indexes.size(); j++) {
1017  Cindex cindex(n, request.inputs[i].indexes[j]);
1018  bool is_input = true, is_new;
1019  graph->GetCindexId(cindex, is_input, &is_new); // ignore the return value.
1020  KALDI_ASSERT(is_new && "Input index seems to be listed more than once");
1021  num_added++;
1022  }
1023  }
1024  KALDI_ASSERT(num_added > 0 && "AddInputToGraph: nothing to add.");
1025 }
std::pair< int32, Index > Cindex
Definition: nnet-common.h:106
struct rnnlm::@11::@12 n
#define KALDI_ERR
Definition: kaldi-error.h:127
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
void kaldi::nnet3::computation_graph::AddOutputToGraph ( const ComputationRequest &  request,
const Nnet &  nnet,
ComputationGraph *  graph 
)

Definition at line 980 of file nnet-computation-graph.cc.

References ComputationGraph::GetCindexId(), Nnet::GetNodeIndex(), rnnlm::i, rnnlm::j, KALDI_ASSERT, KALDI_ERR, rnnlm::n, and ComputationRequest::outputs.

Referenced by kaldi::nnet3::ComputeComputationGraph().

982  {
983  int32 num_added = 0;
984  for (int32 i = 0; i < request.outputs.size(); i++) {
985  int32 n = nnet.GetNodeIndex(request.outputs[i].name);
986  if (n == -1)
987  KALDI_ERR << "Network has no output with name "
988  << request.outputs[i].name;
989  for (int32 j = 0; j < request.outputs[i].indexes.size(); j++) {
990  Cindex cindex(n, request.outputs[i].indexes[j]);
991  bool is_input = false, is_new;
992  graph->GetCindexId(cindex, is_input, &is_new); // ignore the return value.
993  KALDI_ASSERT(is_new && "Output index seems to be listed more than once");
994  num_added++;
995  }
996  }
997  KALDI_ASSERT(num_added > 0 && "AddOutputToGraph: nothing to add.");
998 }
std::pair< int32, Index > Cindex
Definition: nnet-common.h:106
struct rnnlm::@11::@12 n
#define KALDI_ERR
Definition: kaldi-error.h:127
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
static void kaldi::nnet3::computation_graph::ComputeDependenciesSubset ( const ComputationGraph &  graph,
const std::vector< int32 > &  cindex_id_to_segment_and_epoch,
std::vector< std::vector< int32 > > *  dependencies_subset 
)
static

This function outputs to dependencies_subset[c], for each cindex_id c, the subset of elements d of graph.dependencies[c] such that cindex_id_to_segment_and_epoch[d] == cindex_id_to_segment_and_epoch[c].

That is, it's the dependency graph of the entire computation, but removing links that go from one segment/epoch to another segment/epoch. Topologically, 'dependencies_subset' would therefore consist of a bunch of disconnected graphs.

Definition at line 1037 of file nnet-computation-graph.cc.

References ComputationGraph::cindexes, rnnlm::d, ComputationGraph::dependencies, rnnlm::i, and KALDI_ASSERT.

Referenced by kaldi::nnet3::ComputeComputationPhases().

1040  {
1041  int32 num_cindex_ids = graph.cindexes.size();
1042  KALDI_ASSERT(cindex_id_to_segment_and_epoch.size() == num_cindex_ids);
1043  dependencies_subset->resize(num_cindex_ids);
1044  for (int32 cindex_id = 0; cindex_id < num_cindex_ids; cindex_id++) {
1045  int32 phase_index = cindex_id_to_segment_and_epoch[cindex_id];
1046  const std::vector<int32> &dependencies = graph.dependencies[cindex_id];
1047  std::vector<int32> &dep_subset = (*dependencies_subset)[cindex_id];
1048  int32 num_dep = dependencies.size();
1049  for (int32 i = 0; i < num_dep; i++) {
1050  int32 d = dependencies[i];
1051  if (cindex_id_to_segment_and_epoch[d] == phase_index)
1052  dep_subset.push_back(d);
1053  }
1054  }
1055 }
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
static void kaldi::nnet3::computation_graph::ComputeEpochInfo ( const Nnet &  nnet,
const ComputationGraph &  graph,
std::vector< int32 > *  cindex_id_to_segment_and_epoch,
std::vector< std::vector< std::vector< int32 > > > *  epochs_per_segment,
std::vector< bool > *  epoch_is_trivial 
)
static

This function computes certain information about "epochs" of cindex_ids.

The function ComputeNnetComputationEpochs() from nnet-graph.h gives us a map from the NetworkNode index to an index we call the "epoch" index: basically, nodes that are computed first have a lower epoch index, and all nodes that are part of strongly connected components have the same epoch index. In an acyclic nnet graph each component will usually have its own epoch index, but in things like LSTMs, each LSTM layer (with multiple components) will have its own epoch index.

The overall computation order that we compute, will respect this ordering into epochs (except that outputs of nodes of type kComponent that are actually provided as inputs to the network, won't be subject to these limitations but will come first in the order)... we will just ignore the output of this function as it concerns cindex-ids that are provided as input to the network.

Parameters
nnet[in] The neural net
graph[in] The computation graph
cindex_id_to_segment_and_epoch[out] A vector that maps cindex_id to a number that is the same if two cindex_ids are in the same segment and same epoch, and different otherwise. This number combines the segment index and the epoch index; the details are not important to the calling code.
epochs_per_segment[out] This is a listing of all the cindex_ids in the computation graph, divided up first by segment and then by epoch.
epoch_is_trivial[out] A vector of bool, indexed by the epoch index which is the same as the second index of 'epochs_per_segment', that's true if this epoch index corresponds to just a single NetworkNode (and also true for epoch indexes corresponding to inputs to the network, which will be the first epoch of each segment). This depends on the neural network structure only.

Definition at line 1091 of file nnet-computation-graph.cc.

References ComputationGraph::cindexes, kaldi::nnet3::ComputeNnetComputationEpochs(), rnnlm::i, ComputationGraph::is_input, KALDI_ASSERT, KALDI_VLOG, rnnlm::n, Nnet::NumNodes(), kaldi::nnet3::PrintIntegerVector(), and ComputationGraph::segment_ends.

Referenced by kaldi::nnet3::ComputeComputationPhases().

1096  {
1097 
1098  // node_to_epoch maps each nnet node to an index >= 0 that tells us coarsely
1099  // what order to compute them in... but we may need to compute a finer
1100  // ordering at the cindex_id level in cases like RNNs.
1101  std::vector<int32> node_to_epoch;
1102  ComputeNnetComputationEpochs(nnet, &node_to_epoch);
1103  {
1104  std::ostringstream os;
1105  PrintIntegerVector(os, node_to_epoch);
1106  KALDI_VLOG(6) << "node_to_epoch: " << os.str();
1107  }
1108 
1109  // Add one to the epoch numbering because we will be reserving
1110  // zero for inputs to the network, and we don't want to have to
1111  // prove that epoch number 0 would correspond only to inputs.
1112  for (int32 i = 0; i < node_to_epoch.size(); i++)
1113  node_to_epoch[i]++;
1114  int32 num_nodes = nnet.NumNodes(),
1115  num_cindex_ids = graph.cindexes.size(),
1116  num_segments = graph.segment_ends.size(),
1117  num_epoch_indexes = 1 + *std::max_element(node_to_epoch.begin(),
1118  node_to_epoch.end());
1119  KALDI_ASSERT(node_to_epoch.size() == num_nodes);
1120 
1121  epochs_per_segment->clear();
1122  epochs_per_segment->resize(num_segments);
1123 
1124  // epoch_to_num_nodes is only used so we know whether each epoch
1125  // index corresponds to multiple nodes; if it's just one node then we know
1126  // the computation is very simple and we can do an optimization.
1127  std::vector<int32> epoch_to_num_nodes(num_epoch_indexes, 0);
1128  for (int32 n = 0; n < num_nodes; n++)
1129  epoch_to_num_nodes[node_to_epoch[n]]++;
1130 
1131  epoch_is_trivial->resize(num_epoch_indexes);
1132  for (int32 o = 0; o < num_epoch_indexes; o++) {
1133  KALDI_ASSERT(o == 0 || epoch_to_num_nodes[o] > 0);
1134  (*epoch_is_trivial)[o] = (epoch_to_num_nodes[o] <= 1);
1135  }
1136  cindex_id_to_segment_and_epoch->resize(num_cindex_ids);
1137  KALDI_ASSERT(graph.segment_ends.back() == num_cindex_ids);
1138  int32 cur_segment_start = 0, cur_segment_end;
1139  for (int32 segment = 0; segment < num_segments; segment++) {
1140  cur_segment_end = graph.segment_ends[segment];
1141  std::vector<std::vector<int32> > &epochs = (*epochs_per_segment)[segment];
1142  epochs.resize(num_epoch_indexes);
1143 
1144  for (int32 cindex_id = cur_segment_start;
1145  cindex_id < cur_segment_end; cindex_id++) {
1146  int32 node_index = graph.cindexes[cindex_id].first,
1147  epoch_index = (graph.is_input[cindex_id] ? 0 :
1148  node_to_epoch[node_index]);
1149  (*cindex_id_to_segment_and_epoch)[cindex_id] =
1150  epoch_index + segment * num_epoch_indexes;
1151  epochs[epoch_index].push_back(cindex_id);
1152  }
1153  cur_segment_start = cur_segment_end;
1154  }
1155 }
struct rnnlm::@11::@12 n
void ComputeNnetComputationEpochs(const Nnet &nnet, std::vector< int32 > *node_to_epoch)
This function computes the order in which we need to compute each node in the graph, where each node-index n maps to an epoch-index t = 0, 1, ...
Definition: nnet-graph.cc:265
void PrintIntegerVector(std::ostream &os, const std::vector< int32 > &ints)
Definition: nnet-common.cc:491
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
#define KALDI_VLOG(v)
Definition: kaldi-error.h:136