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 1013 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().

1015  {
1016  int32 num_added = 0;
1017  for (int32 i = 0; i < request.inputs.size(); i++) {
1018  int32 n = nnet.GetNodeIndex(request.inputs[i].name);
1019  if (n == -1)
1020  KALDI_ERR << "Network has no input with name "
1021  << request.inputs[i].name;
1022  NodeType t = nnet.GetNode(n).node_type;
1023  KALDI_ASSERT((t == kInput || t == kComponent) &&
1024  "Inputs to graph only allowed for Input and Component nodes.");
1025 
1026  for (int32 j = 0; j < request.inputs[i].indexes.size(); j++) {
1027  Cindex cindex(n, request.inputs[i].indexes[j]);
1028  bool is_input = true, is_new;
1029  graph->GetCindexId(cindex, is_input, &is_new); // ignore the return value.
1030  KALDI_ASSERT(is_new && "Input index seems to be listed more than once");
1031  num_added++;
1032  }
1033  }
1034  KALDI_ASSERT(num_added > 0 && "AddInputToGraph: nothing to add.");
1035 }
std::pair< int32, Index > Cindex
Definition: nnet-common.h:115
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 990 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().

992  {
993  int32 num_added = 0;
994  for (int32 i = 0; i < request.outputs.size(); i++) {
995  int32 n = nnet.GetNodeIndex(request.outputs[i].name);
996  if (n == -1)
997  KALDI_ERR << "Network has no output with name "
998  << request.outputs[i].name;
999  for (int32 j = 0; j < request.outputs[i].indexes.size(); j++) {
1000  Cindex cindex(n, request.outputs[i].indexes[j]);
1001  bool is_input = false, is_new;
1002  graph->GetCindexId(cindex, is_input, &is_new); // ignore the return value.
1003  KALDI_ASSERT(is_new && "Output index seems to be listed more than once");
1004  num_added++;
1005  }
1006  }
1007  KALDI_ASSERT(num_added > 0 && "AddOutputToGraph: nothing to add.");
1008 }
std::pair< int32, Index > Cindex
Definition: nnet-common.h:115
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 1047 of file nnet-computation-graph.cc.

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

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

1050  {
1051  int32 num_cindex_ids = graph.cindexes.size();
1052  KALDI_ASSERT(cindex_id_to_segment_and_epoch.size() == num_cindex_ids);
1053  dependencies_subset->resize(num_cindex_ids);
1054  for (int32 cindex_id = 0; cindex_id < num_cindex_ids; cindex_id++) {
1055  int32 phase_index = cindex_id_to_segment_and_epoch[cindex_id];
1056  const std::vector<int32> &dependencies = graph.dependencies[cindex_id];
1057  std::vector<int32> &dep_subset = (*dependencies_subset)[cindex_id];
1058  int32 num_dep = dependencies.size();
1059  for (int32 i = 0; i < num_dep; i++) {
1060  int32 d = dependencies[i];
1061  if (cindex_id_to_segment_and_epoch[d] == phase_index)
1062  dep_subset.push_back(d);
1063  }
1064  }
1065 }
#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 1101 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().

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