ComputationStepsComputer Class Reference

This class arranges the cindex_ids of the computation into a sequence of lists called "steps", which will correspond roughly to the commands in the compiled computation. More...

#include <nnet-computation-graph.h>

Collaboration diagram for ComputationStepsComputer:

Public Member Functions

 ComputationStepsComputer (const Nnet &nnet, ComputationGraph *graph, std::vector< std::vector< int32 > > *steps, std::vector< std::pair< int32, int32 > > *locations)
 Constructor. More...
 
void ComputeForSegment (const ComputationRequest &request, const std::vector< std::vector< int32 > > &phases)
 You call this once for each segment, in order (note: for normal, non-online computations, there is only one segment). More...
 
void Check () const
 This is only to be called after you have called ComputeForSegment for all the segments. More...
 

Private Member Functions

void ProcessSubPhase (const ComputationRequest &request, const std::vector< Cindex > &sub_phase)
 
void ProcessDimRangeSubPhase (const std::vector< Cindex > &sub_phase)
 
void ProcessInputOrOutputStep (const ComputationRequest &request, bool is_output, const std::vector< Cindex > &sub_phase)
 
void ProcessComponentStep (const std::vector< Cindex > &step)
 
void SplitIntoSubPhases (const std::vector< int32 > &phase, std::vector< std::vector< Cindex > > *sub_phase) const
 
int32 AddStep (const std::vector< Cindex > &cindexes, bool add_if_absent=false)
 
int32 AddStep (std::vector< int32 > *cindex_ids)
 
void ConvertToCindexes (const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
 
void ConvertToCindexIds (const std::vector< Cindex > &cindexes, std::vector< int32 > *cindex_ids) const
 
void ConvertToLocations (const std::vector< int32 > &cindex_ids, std::vector< std::pair< int32, int32 > > *locations) const
 

Static Private Member Functions

static void ConvertToIndexes (const std::vector< Cindex > &cindexes, std::vector< Index > *indexes)
 
static void ConvertToCindexes (const std::vector< Index > &indexes, int32 node_index, std::vector< Cindex > *cindexes)
 

Private Attributes

const Nnetnnet_
 
ComputationGraphgraph_
 
std::vector< std::vector< int32 > > * steps_
 steps_ is a pointer to an output that's passed in in the constructor. More...
 
std::vector< std::pair< int32, int32 > > * locations_
 locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides, so if (*locations_)[c] = (i,j), then (*steps_)[i][j] == c. More...
 
std::unordered_set< std::pair< int32, int32 >, PairHasher< int32 > > dim_range_nodes_
 dim_range_nodes_ is used when allocating steps for nodes of type kDimRangeNode. More...
 

Detailed Description

This class arranges the cindex_ids of the computation into a sequence of lists called "steps", which will correspond roughly to the commands in the compiled computation.

The steps are finer than phases. (See Organizing the computation into steps for more info). To summarize the properties that these steps will satisfy:

  • All cindex_ids within a given step correspond to the same node in the graph
  • All dependencies of cindex_ids within a given step have been computed in earlier steps.
  • All cindex_ids within a given step share the same location when computed (i.e. a matrix or submatix)

There are also some extra, more obscure properties that the sequence of steps must satisfy:

  • Any input or output specified in a ComputationRequest must be in one step, with the Indexes in the same order as specified in the ComputationRequest. (Note: inputs can be for nodes of type kComponent as well as kInput).
  • If a step corresponds to a node of type kComponent (and does not correspond to an input in the ComputationRequest), then the immediately preceding step must correspond to a node of type kDescriptor, and the sequence of Indexes in the two steps must be identical.
  • If a step corresponds to a node of type kDimRange, then there must be a preceding step corresponding to the source node, with exactly the same Indexes appearing in the same order. (This lets us use a sub-matrix for the kDimRange node). We guarantee this by adding extra cindexes to the kDimRange steps as needed.

The reason why computation_graph is not provided as a const argument is that in order to ensure the final property we may have to add a few new cindex_ids.

Definition at line 415 of file nnet-computation-graph.h.

Constructor & Destructor Documentation

◆ ComputationStepsComputer()

ComputationStepsComputer ( const Nnet nnet,
ComputationGraph graph,
std::vector< std::vector< int32 > > *  steps,
std::vector< std::pair< int32, int32 > > *  locations 
)

Constructor.

Parameters
[in]nnetThe neural network that this computation is for.
[in,out]graphThe computation graph that we're computing the steps for. It's only non-const because there are couple of unusual situations in which we may need to add new cindexes: (1) For nodes of type kDimRange, we may add cindexes to enable the node to span a contiguous range of the input indexes. (2) For certain non-simple Components (principally CNN-related components), we may need to add 'blank' cindexes (defined as cindexes where the 't' indexes are replaced by kNoTime), for zero-padding and to turn irregularly structured computations into regularly structured ones as needed by the component's implementation.
[out]stepsThe main output of this class, which is a sequence of steps, each step being an ordered list of cindex_ids. It just gets cleared in the constructor; it's set up when you call ComputeForSegment().
[out]locationsThe additional output of this class, which is a function of the information in 'steps'. The array 'locations' is indexed by cindex_id, and each one is a pair (step-index, index-into-step), so that for any cindex_id c, (*steps)[locations[c].first][locations[c].second] == c. It's possible in principle if there are non-simple Components, that for nodes corresponding to component-input descriptors, a cindex might be present in more than one step, so it doesn't follow that if (*steps)[i][j] == c, then locations[c] == (i,j).

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

References ComputationGraph::cindexes, ComputationStepsComputer::graph_, ComputationStepsComputer::locations_, and ComputationStepsComputer::steps_.

1519  :
1520  nnet_(nnet), graph_(graph), steps_(steps), locations_(locations) {
1521  steps_->clear();
1522  locations_->clear();
1523  int32 num_cindexes = graph_->cindexes.size();
1524  // leave a little space in case a few cindexes are added (unlikely
1525  // but could happen with dim-range nodes).
1526  locations_->reserve(num_cindexes + num_cindexes / 10);
1527  locations_->resize(num_cindexes, std::pair<int32,int32>(-1, -1));
1528 }
std::vector< std::pair< int32, int32 > > * locations_
locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides...
kaldi::int32 int32
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
std::vector< std::vector< int32 > > * steps_
steps_ is a pointer to an output that&#39;s passed in in the constructor.

Member Function Documentation

◆ AddStep() [1/2]

int32 AddStep ( const std::vector< Cindex > &  cindexes,
bool  add_if_absent = false 
)
private

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

References ComputationGraph::GetCindexId(), ComputationStepsComputer::graph_, KALDI_ASSERT, ComputationStepsComputer::locations_, and ComputationStepsComputer::steps_.

Referenced by ComputationStepsComputer::ProcessComponentStep(), ComputationStepsComputer::ProcessDimRangeSubPhase(), and ComputationStepsComputer::ProcessInputOrOutputStep().

1584  {
1585  // note: we can't assert that cindexes is nonempty, because it's possible for
1586  // input steps for GeneralComponents to be empty if they require no input
1587  // indexes; and because the compiler code expects component steps to be
1588  // preceded by component-input steps, we can't just omit these empty steps.
1589  // [note: a component-input step is about preparing the input for a component's
1590  // propagation.]
1591  int32 step_index = steps_->size();
1592  steps_->push_back(std::vector<int32>());
1593  std::vector<int32> &step = steps_->back(); // vector of cindex_id.
1594  step.resize(cindexes.size());
1595  size_t row_index = 0;
1596  std::vector<Cindex>::const_iterator iter = cindexes.begin(),
1597  end = cindexes.end();
1598  std::vector<int32>::iterator out_iter = step.begin();
1599  std::pair<int32, int32> *locations = &((*locations_)[0]);
1600  if (!add_if_absent) {
1601  // this version of GetCindexId will not add CindexIds, and
1602  // will crash if CindexIds not present in the graph are
1603  // encountered.
1604  for (; iter != end; ++iter, ++out_iter, ++row_index) {
1605  int32 cindex_id = graph_->GetCindexId(*iter);
1606  *out_iter = cindex_id;
1607  locations[cindex_id].first = step_index;
1608  locations[cindex_id].second = row_index;
1609  }
1610  } else {
1611  for (; iter != end; ++iter, ++out_iter, ++row_index) {
1612  bool is_input = false; // only relevant if we have to add the cindex to
1613  // the computation graph, which we won't for
1614  // inputs (we only might for dim-range nodes
1615  // and for the component-input and component
1616  // steps of non-simple Components.
1617  bool added;
1618  int32 cindex_id = graph_->GetCindexId(*iter, is_input, &added);
1619  *out_iter = cindex_id;
1620  if (added) {
1621  KALDI_ASSERT(cindex_id == static_cast<int32>(locations_->size()));
1622  locations_->resize(cindex_id + 1, std::pair<int32, int32>(-1, -1));
1623  locations_->back().first = step_index;
1624  locations_->back().second = row_index;
1625  locations = &((*locations_)[0]); // in case it was reallocated
1626  } else {
1627  locations[cindex_id].first = step_index;
1628  locations[cindex_id].second = row_index;
1629  }
1630  }
1631  }
1632  return step_index;
1633 }
std::vector< std::pair< int32, int32 > > * locations_
locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides...
kaldi::int32 int32
int32 GetCindexId(const Cindex &cindex, bool is_input, bool *is_new)
Maps a Cindex to an integer cindex_id.
std::vector< std::vector< int32 > > * steps_
steps_ is a pointer to an output that&#39;s passed in in the constructor.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ AddStep() [2/2]

int32 AddStep ( std::vector< int32 > *  cindex_ids)
private

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

References ComputationGraph::cindexes, ComputationStepsComputer::graph_, KALDI_ASSERT, and ComputationStepsComputer::steps_.

1636  {
1637  int32 step_index = steps_->size();
1638  steps_->push_back(std::vector<int32>());
1639  steps_->back().swap(*cindex_ids);
1640  std::vector<int32>::const_iterator iter = steps_->back().begin(),
1641  end = steps_->back().end();
1642  int32 row_index = 0;
1643  std::pair<int32,int32> *locations = &((*locations_)[0]);
1644  size_t num_cindexes = graph_->cindexes.size();
1645  for (; iter != end; ++iter, ++row_index) {
1646  int32 cindex_id = *iter;
1647  KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
1648  locations[cindex_id].first = step_index;
1649  locations[cindex_id].second = row_index;
1650  }
1651  return step_index;
1652 }
kaldi::int32 int32
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
std::vector< std::vector< int32 > > * steps_
steps_ is a pointer to an output that&#39;s passed in in the constructor.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ Check()

void Check ( ) const

This is only to be called after you have called ComputeForSegment for all the segments.

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

References ComputationGraph::cindexes, ComputationStepsComputer::graph_, KALDI_ASSERT, KALDI_ERR, kaldi::nnet3::kNoTime, ComputationStepsComputer::locations_, and ComputationStepsComputer::steps_.

Referenced by Compiler::CreateComputation().

1922  {
1923  int32 num_cindexes = graph_->cindexes.size();
1924  KALDI_ASSERT(locations_->size() == num_cindexes);
1925  for (int32 c = 0; c < num_cindexes; c++) {
1926  int32 step = (*locations_)[c].first,
1927  row = (*locations_)[c].second;
1928  if (!(step >= 0 && row >= 0 && (*steps_)[step][row] == c)) {
1929  // normally the 'locations' of cindexes should be unique, so we should
1930  // never normally reach this point; but it's not an error to have
1931  // duplicates of the cindexes used for 'padding' by the ReorderIndexes()
1932  // function of non-simple Components. So we check whether that's the case
1933  // before we die.
1934  if (graph_->cindexes[c].second.t != kNoTime) {
1935  // if this happens it will likely require some debugging by Dan.
1936  KALDI_ERR << "Error in computing computation steps (likely code error)";
1937  }
1938  }
1939 
1940  }
1941 }
std::vector< std::pair< int32, int32 > > * locations_
locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides...
kaldi::int32 int32
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
std::vector< std::vector< int32 > > * steps_
steps_ is a pointer to an output that&#39;s passed in in the constructor.
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
const int kNoTime
Definition: nnet-common.cc:573

◆ ComputeForSegment()

void ComputeForSegment ( const ComputationRequest request,
const std::vector< std::vector< int32 > > &  phases 
)

You call this once for each segment, in order (note: for normal, non-online computations, there is only one segment).

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

References rnnlm::i, rnnlm::j, ComputationStepsComputer::ProcessSubPhase(), and ComputationStepsComputer::SplitIntoSubPhases().

Referenced by Compiler::CreateComputation().

1532  {
1533  int32 this_num_phases = phases.size();
1534  for (int32 i = 0; i < this_num_phases; i++) {
1535  std::vector<std::vector<Cindex> > sub_phases;
1536  SplitIntoSubPhases(phases[i], &sub_phases);
1537  for (size_t j = 0; j < sub_phases.size(); j++) {
1538  ProcessSubPhase(request, sub_phases[j]);
1539  }
1540  }
1541 }
kaldi::int32 int32
void SplitIntoSubPhases(const std::vector< int32 > &phase, std::vector< std::vector< Cindex > > *sub_phase) const
void ProcessSubPhase(const ComputationRequest &request, const std::vector< Cindex > &sub_phase)

◆ ConvertToCindexes() [1/2]

void ConvertToCindexes ( const std::vector< int32 > &  cindex_ids,
std::vector< Cindex > *  cindexes 
) const
private

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

References ComputationGraph::cindexes, ComputationStepsComputer::graph_, and KALDI_ASSERT.

Referenced by ComputationStepsComputer::ProcessComponentStep(), ComputationStepsComputer::ProcessDimRangeSubPhase(), and ComputationStepsComputer::SplitIntoSubPhases().

1657  {
1658  cindexes->resize(cindex_ids.size());
1659  size_t num_cindexes = graph_->cindexes.size();
1660  std::vector<int32>::const_iterator iter = cindex_ids.begin(),
1661  end = cindex_ids.end();
1662  std::vector<Cindex>::iterator out_iter = cindexes->begin();
1663  for (; iter != end; ++iter, ++out_iter) {
1664  int32 cindex_id = *iter;
1665  KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
1666  *out_iter = graph_->cindexes[cindex_id];
1667  }
1668 }
kaldi::int32 int32
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ ConvertToCindexes() [2/2]

void ConvertToCindexes ( const std::vector< Index > &  indexes,
int32  node_index,
std::vector< Cindex > *  cindexes 
)
staticprivate

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

References KALDI_ASSERT.

1702  {
1703  KALDI_ASSERT(node_index >= 0);
1704  cindexes->resize(indexes.size());
1705  std::vector<Index>::const_iterator iter = indexes.begin(),
1706  end = indexes.end();
1707  std::vector<Cindex>::iterator out_iter = cindexes->begin();
1708  for (; iter != end; ++iter, ++out_iter) {
1709  out_iter->first = node_index;
1710  out_iter->second = *iter;
1711  }
1712 }
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ ConvertToCindexIds()

void ConvertToCindexIds ( const std::vector< Cindex > &  cindexes,
std::vector< int32 > *  cindex_ids 
) const
private

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

References ComputationGraph::GetCindexId(), ComputationStepsComputer::graph_, and KALDI_ASSERT.

Referenced by ComputationStepsComputer::ProcessComponentStep(), and ComputationStepsComputer::ProcessDimRangeSubPhase().

1673  {
1674  cindex_ids->resize(cindexes.size());
1675  std::vector<Cindex>::const_iterator iter = cindexes.begin(),
1676  end = cindexes.end();
1677  std::vector<int32>::iterator out_iter = cindex_ids->begin();
1678  for (; iter != end; ++iter, ++out_iter) {
1679  int32 cindex_id = graph_->GetCindexId(*iter);
1680  KALDI_ASSERT(cindex_id >= 0);
1681  *out_iter = cindex_id;
1682  }
1683 }
kaldi::int32 int32
int32 GetCindexId(const Cindex &cindex, bool is_input, bool *is_new)
Maps a Cindex to an integer cindex_id.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ ConvertToIndexes()

void ConvertToIndexes ( const std::vector< Cindex > &  cindexes,
std::vector< Index > *  indexes 
)
staticprivate

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

Referenced by ComputationStepsComputer::ProcessComponentStep().

1689  {
1690  indexes->resize(cindexes.size());
1691  std::vector<Cindex>::const_iterator iter = cindexes.begin(),
1692  end = cindexes.end();
1693  std::vector<Index>::iterator out_iter = indexes->begin();
1694  for (; iter != end; ++iter, ++out_iter)
1695  *out_iter = iter->second;
1696 }

◆ ConvertToLocations()

void ConvertToLocations ( const std::vector< int32 > &  cindex_ids,
std::vector< std::pair< int32, int32 > > *  locations 
) const
private

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

References KALDI_ASSERT, and ComputationStepsComputer::locations_.

Referenced by ComputationStepsComputer::ProcessDimRangeSubPhase().

1808  {
1809  locations->resize(cindex_ids.size());
1810  std::vector<int32>::const_iterator iter = cindex_ids.begin(),
1811  end = cindex_ids.end();
1812  std::vector<std::pair<int32, int32> >::iterator out_iter =
1813  locations->begin();
1814  // note, locations_ and locations are different variables.
1815  std::pair<int32, int32> *locations_ptr = &((*locations_)[0]);
1816  size_t num_cindexes = locations_->size();
1817  for (; iter != end; ++iter, ++out_iter) {
1818  int32 cindex_id = *iter;
1819  KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
1820  int32 step = locations_ptr[cindex_id].first,
1821  row = locations_ptr[cindex_id].second;
1822  KALDI_ASSERT(step >= 0);
1823  out_iter->first = step;
1824  out_iter->second = row;
1825  }
1826 }
std::vector< std::pair< int32, int32 > > * locations_
locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides...
kaldi::int32 int32
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ ProcessComponentStep()

void ProcessComponentStep ( const std::vector< Cindex > &  step)
private

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

References ComputationStepsComputer::AddStep(), ComputationGraph::cindexes, NetworkNode::component_index, ComputationStepsComputer::ConvertToCindexes(), ComputationStepsComputer::ConvertToCindexIds(), ComputationStepsComputer::ConvertToIndexes(), rnnlm::d, ComputationGraph::dependencies, Nnet::GetComponent(), Nnet::GetNode(), ComputationStepsComputer::graph_, Nnet::IsComponentNode(), KALDI_ASSERT, kaldi::nnet3::kReordersIndexes, kaldi::nnet3::kSimpleComponent, ComputationStepsComputer::nnet_, Component::Properties(), Component::ReorderIndexes(), and NetworkNode::u.

Referenced by ComputationStepsComputer::ProcessSubPhase().

1718  {
1719  KALDI_ASSERT(!step.empty());
1720  int32 component_node_index = step.front().first;
1721  int32 component_input_index = component_node_index - 1;
1722  KALDI_ASSERT(nnet_.IsComponentNode(component_node_index));
1723  const NetworkNode &node = nnet_.GetNode(component_node_index);
1724  int32 c = node.u.component_index;
1725  const Component *component = nnet_.GetComponent(c);
1726  if (component->Properties() & kSimpleComponent) {
1727  // for simple components, the input cindexes will be the same as the
1728  // output ones except for the node index, so we do a shortcut that's
1729  // faster (no following dependencies).
1730  std::vector<Cindex> input_step(step.size());
1731  input_step.resize(step.size());
1732  std::vector<Cindex>::iterator iter = input_step.begin(),
1733  end = input_step.end();
1734  std::vector<Cindex>::const_iterator src = step.begin();
1735  for (; iter != end; ++iter,++src) {
1736  iter->first = component_input_index;
1737  iter->second = src->second;
1738  }
1739  AddStep(input_step);
1740  AddStep(step);
1741  } else {
1742  std::vector<int32> step_cindex_ids;
1743  ConvertToCindexIds(step, &step_cindex_ids);
1744  // to get the input cindexes we need to follow dependencies back.
1745  unordered_set<int32> input_cindex_ids;
1746  std::vector<int32>::iterator iter = step_cindex_ids.begin(),
1747  end = step_cindex_ids.end();
1748  for (; iter != end; ++iter) {
1749  int32 c = *iter;
1750  const std::vector<int32> &dependencies = graph_->dependencies[c];
1751  std::vector<int32>::const_iterator dep_iter = dependencies.begin(),
1752  dep_end = dependencies.end();
1753  for (; dep_iter != dep_end; ++dep_iter) {
1754  int32 d = *dep_iter;
1755  input_cindex_ids.insert(d);
1756  }
1757  }
1758  // Convert to Cindexes so we can sort them as Cindexes.
1759  std::vector<Cindex> input_step;
1760  input_step.reserve(input_cindex_ids.size());
1761  unordered_set<int32>::iterator set_iter = input_cindex_ids.begin(),
1762  set_end = input_cindex_ids.end();
1763  for (; set_iter != set_end; ++set_iter) {
1764  int32 c = *set_iter;
1765  input_step.push_back(graph_->cindexes[c]);
1766  }
1767 
1768  // sort the input cindexes.
1769  std::sort(input_step.begin(), input_step.end());
1770 
1771  if (component->Properties() & kReordersIndexes) {
1772  std::vector<Index> indexes, input_indexes;
1773  ConvertToIndexes(input_step, &input_indexes);
1774  ConvertToIndexes(step, &indexes);
1775 
1776 
1777  size_t orig_size = indexes.size() + input_indexes.size();
1778 
1779  // the component wants to have the opportunity to change the
1780  // order of these indexes from their default.
1781  component->ReorderIndexes(&input_indexes, &indexes);
1782 
1783  bool added_padding = (orig_size != indexes.size() + input_indexes.size());
1784 
1785  // Now convert back from indexes to cindexes (we know the
1786  // node-index in each case)
1787  std::vector<Cindex> reordered_step;
1788  ConvertToCindexes(indexes, component_node_index, &reordered_step);
1789  ConvertToCindexes(input_indexes, component_input_index, &input_step);
1790  // the 'added_padding' argument becomes the 'add_if_absent' arg of
1791  // AddStep, so it knows to expect that it might have to add new CindexIds.
1792  AddStep(input_step, added_padding);
1793  AddStep(reordered_step, added_padding);
1794  } else {
1795  AddStep(input_step);
1796  // it's more efficient to add the step with cindex_ids; and we have these
1797  // available, so we do it that way. (in the other branch where
1798  // the flag kReordersIndexes was present, we couldn't do this because
1799  // of the reordering).
1800  AddStep(&step_cindex_ids);
1801  }
1802  }
1803 }
void ConvertToCindexIds(const std::vector< Cindex > &cindexes, std::vector< int32 > *cindex_ids) const
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
static void ConvertToIndexes(const std::vector< Cindex > &cindexes, std::vector< Index > *indexes)
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
void ConvertToCindexes(const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
std::vector< std::vector< int32 > > dependencies
dependencies[cindex_id] gives you the list of other cindex_ids that this particular cindex_id directl...
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)

◆ ProcessDimRangeSubPhase()

void ProcessDimRangeSubPhase ( const std::vector< Cindex > &  sub_phase)
private

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

References ComputationStepsComputer::AddStep(), ComputationStepsComputer::ConvertToCindexes(), ComputationStepsComputer::ConvertToCindexIds(), ComputationStepsComputer::ConvertToLocations(), ComputationStepsComputer::dim_range_nodes_, Nnet::GetNode(), Nnet::IsDimRangeNode(), KALDI_ASSERT, ComputationStepsComputer::nnet_, NetworkNode::node_index, and NetworkNode::u.

Referenced by ComputationStepsComputer::ProcessSubPhase().

1829  {
1830  int32 dim_range_node = sub_phase[0].first;
1831  KALDI_ASSERT(nnet_.IsDimRangeNode(dim_range_node));
1832  const NetworkNode &node = nnet_.GetNode(dim_range_node);
1833  // 'input_node_index' is the node index of the component or input node
1834  // that this dim-range node gets its input from.
1835  int32 input_node_index = node.u.node_index;
1836  // input_cindexes will give us the cindexes of the component or input node
1837  // that is the input to this dim-range node
1838  std::vector<Cindex> input_cindexes(sub_phase);
1839  for (std::vector<Cindex>::iterator iter = input_cindexes.begin(),
1840  end = input_cindexes.end(); iter != end; ++iter)
1841  iter->first = input_node_index;
1842  std::vector<int32> input_cindex_ids;
1843  ConvertToCindexIds(input_cindexes, &input_cindex_ids);
1844  std::vector<std::pair<int32, int32> > locations;
1845  ConvertToLocations(input_cindex_ids, &locations);
1846 
1847  // get a list of the source step indexes (corresponding to computations for the
1848  // source component-node)
1849  std::unordered_set<int32> source_step_indexes;
1850  KALDI_ASSERT(!locations.empty());
1851  std::vector<std::pair<int32, int32> >::const_iterator
1852  locations_iter = locations.begin(),
1853  locations_end = locations.end();
1854 
1855  // 'cur_source_step_index' is just an optimization to prevent unnecessary
1856  // unordered_set inserts.
1857  int32 cur_source_step_index = -1;
1858  for (; locations_iter != locations_end; ++locations_iter) {
1859  int32 source_step_index = locations_iter->first;
1860  if (source_step_index != cur_source_step_index) {
1861  cur_source_step_index = source_step_index;
1862  source_step_indexes.insert(cur_source_step_index);
1863  }
1864  }
1865 
1866  std::unordered_set<int32>::const_iterator
1867  source_step_iter = source_step_indexes.begin(),
1868  source_step_end = source_step_indexes.end();
1869  // iterating over the indexes of the source steps.
1870  for (; source_step_iter != source_step_end; ++source_step_iter) {
1871  int32 source_step_index = *source_step_iter;
1872  std::pair<int32, int32> p(source_step_index, dim_range_node);
1873  if (dim_range_nodes_.count(p) > 0) {
1874  // We don't need to do anything; a dim-range node already exists for this
1875  // step and this node index.
1876  continue;
1877  }
1878  dim_range_nodes_.insert(p);
1879  const std::vector<int32> &source_step = (*steps_)[source_step_index];
1880  // 'cindexes' will be the cindexes of the new step that we're going to add.
1881  std::vector<Cindex> cindexes;
1882  ConvertToCindexes(source_step, &cindexes);
1883  std::vector<Cindex>::iterator iter = cindexes.begin(),
1884  end = cindexes.end();
1885  for (; iter != end; ++iter)
1886  iter->first = dim_range_node;
1887  bool add_if_absent = true;
1888  // this add_if_absent says, even if cindexes were not in the graph,
1889  // add them. This is possible; the step will contain all cindexes for the
1890  // input step, even if they won't be needed. (This is costless; it's just
1891  // setting up a sub-matrix).
1892  AddStep(cindexes, add_if_absent);
1893  }
1894 }
void ConvertToLocations(const std::vector< int32 > &cindex_ids, std::vector< std::pair< int32, int32 > > *locations) const
void ConvertToCindexIds(const std::vector< Cindex > &cindexes, std::vector< int32 > *cindex_ids) const
kaldi::int32 int32
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
void ConvertToCindexes(const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
std::unordered_set< std::pair< int32, int32 >, PairHasher< int32 > > dim_range_nodes_
dim_range_nodes_ is used when allocating steps for nodes of type kDimRangeNode.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)
bool IsDimRangeNode(int32 node) const
Returns true if this is a dim-range node, meaning that it is of type kDimRange.
Definition: nnet-nnet.cc:138

◆ ProcessInputOrOutputStep()

void ProcessInputOrOutputStep ( const ComputationRequest request,
bool  is_output,
const std::vector< Cindex > &  sub_phase 
)
private

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

References ComputationStepsComputer::AddStep(), ComputationGraph::GetCindexId(), Nnet::GetNodeName(), ComputationStepsComputer::graph_, rnnlm::i, ComputationRequest::inputs, Nnet::IsInputNode(), Nnet::IsOutputNode(), KALDI_ASSERT, ComputationStepsComputer::locations_, ComputationStepsComputer::nnet_, and ComputationRequest::outputs.

Referenced by ComputationStepsComputer::ProcessSubPhase().

1546  {
1547  int32 io_node = sub_phase[0].first;
1548  if (is_output){
1549  KALDI_ASSERT(nnet_.IsOutputNode(io_node));
1550  } else {
1551  KALDI_ASSERT(nnet_.IsInputNode(io_node));
1552  }
1553  std::string node_name = nnet_.GetNodeName(io_node);
1554  const std::vector<IoSpecification> &inputs_or_outputs =
1555  (is_output ? request.outputs : request.inputs);
1556  int32 io_index = -1;
1557  for (size_t i = 0; i < inputs_or_outputs.size(); i++)
1558  if (inputs_or_outputs[i].name == node_name)
1559  io_index = i;
1560  KALDI_ASSERT(io_index >= 0);
1561  const std::vector<Index> &io_indexes = inputs_or_outputs[io_index].indexes;
1562  std::vector<Cindex> io_cindexes(io_indexes.size());
1563  for (size_t i = 0, size = io_cindexes.size(); i < size; i++) {
1564  io_cindexes[i].first = io_node;
1565  io_cindexes[i].second = io_indexes[i];
1566  }
1567  KALDI_ASSERT(io_cindexes.size() == sub_phase.size());
1568  // we expect the list of cindexes in 'io_cindexes' to be identical to
1569  // that in 'sub_phase' (but they don't have to be in the same order)... for now we check the size, we'll spot-check
1570  // that they are the same later.
1571  // The actual output in 'steps' must be in the same order as
1572  int32 step_index = AddStep(io_cindexes);
1573  // Now spot-check that the cindexes in 'sub_phase' are the same as those
1574  // we just added. [note: they don't have to be in the same order, but
1575  // they should be the same set.]
1576  for (size_t i = 0; i < sub_phase.size(); i += 10) {
1577  const Cindex &cindex = sub_phase[i];
1578  int32 cindex_id = graph_->GetCindexId(cindex);
1579  KALDI_ASSERT(cindex_id >= 0 && (*locations_)[cindex_id].first == step_index);
1580  }
1581 }
const std::string & GetNodeName(int32 node_index) const
returns individual node name.
Definition: nnet-nnet.cc:684
std::vector< std::pair< int32, int32 > > * locations_
locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides...
bool IsInputNode(int32 node) const
Returns true if this is an output node, meaning that it is of type kInput.
Definition: nnet-nnet.cc:120
kaldi::int32 int32
std::pair< int32, Index > Cindex
Definition: nnet-common.h:115
int32 GetCindexId(const Cindex &cindex, bool is_input, bool *is_new)
Maps a Cindex to an integer cindex_id.
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
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)

◆ ProcessSubPhase()

void ProcessSubPhase ( const ComputationRequest request,
const std::vector< Cindex > &  sub_phase 
)
private

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

References Nnet::IsComponentInputNode(), Nnet::IsComponentNode(), Nnet::IsDimRangeNode(), Nnet::IsInputNode(), Nnet::IsOutputNode(), KALDI_ASSERT, KALDI_ERR, ComputationStepsComputer::nnet_, ComputationStepsComputer::ProcessComponentStep(), ComputationStepsComputer::ProcessDimRangeSubPhase(), and ComputationStepsComputer::ProcessInputOrOutputStep().

Referenced by ComputationStepsComputer::ComputeForSegment().

1898  {
1899  KALDI_ASSERT(!sub_phase.empty());
1900  int32 node_index = sub_phase[0].first;
1901  KALDI_ASSERT(sub_phase.back().first == node_index);
1902  if (nnet_.IsComponentNode(node_index)) {
1903  ProcessComponentStep(sub_phase);
1904  } else if (nnet_.IsInputNode(node_index)) {
1905  ProcessInputOrOutputStep(request, false, sub_phase);
1906  } else if (nnet_.IsOutputNode(node_index)) {
1907  ProcessInputOrOutputStep(request, true, sub_phase);
1908  } else if (nnet_.IsDimRangeNode(node_index)) {
1909  // this might turn out to be multiple steps, see the code.
1910  ProcessDimRangeSubPhase(sub_phase);
1911  } else if (nnet_.IsComponentInputNode(node_index)) {
1912  // We actually do nothing with these sub-phases, because they are processed
1913  // when we process the associated component's sub-phase/step. Doing it this
1914  // way resolves certain problems.
1915  return;
1916  } else {
1917  KALDI_ERR << "Unknown node type.";
1918  }
1919 }
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
void ProcessDimRangeSubPhase(const std::vector< Cindex > &sub_phase)
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
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
#define KALDI_ERR
Definition: kaldi-error.h:147
void ProcessComponentStep(const std::vector< Cindex > &step)
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void ProcessInputOrOutputStep(const ComputationRequest &request, bool is_output, const std::vector< Cindex > &sub_phase)
bool IsDimRangeNode(int32 node) const
Returns true if this is a dim-range node, meaning that it is of type kDimRange.
Definition: nnet-nnet.cc:138
bool IsComponentInputNode(int32 node) const
Returns true if this is component-input node, i.e.
Definition: nnet-nnet.cc:172

◆ SplitIntoSubPhases()

void SplitIntoSubPhases ( const std::vector< int32 > &  phase,
std::vector< std::vector< Cindex > > *  sub_phase 
) const
private

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

References ComputationStepsComputer::ConvertToCindexes(), rnnlm::i, and KALDI_ASSERT.

Referenced by ComputationStepsComputer::ComputeForSegment().

1945  {
1946  std::vector<Cindex> phase_cindexes;
1947  ConvertToCindexes(phase, &phase_cindexes);
1948  KALDI_ASSERT(!phase_cindexes.empty());
1949  std::sort(phase_cindexes.begin(), phase_cindexes.end());
1950  // 'sub_phase_begins' is the indexes onto 'phase_cindees' that
1951  // start a run of the same node-index
1952  std::vector<size_t> segment_begins;
1953  int32 cur_node_index = -1;
1954  size_t size = phase_cindexes.size();
1955  for (size_t i = 0; i < size; i++) {
1956  if (phase_cindexes[i].first != cur_node_index) {
1957  cur_node_index = phase_cindexes[i].first;
1958  segment_begins.push_back(i);
1959  }
1960  }
1961  size_t num_sub_phases = segment_begins.size();
1962  segment_begins.push_back(size);
1963  sub_phases->clear();
1964  sub_phases->resize(num_sub_phases);
1965  for (size_t i = 0; i < num_sub_phases; i++) {
1966  size_t this_begin = segment_begins[i],
1967  this_end = segment_begins[i+1];
1968  (*sub_phases)[i].insert((*sub_phases)[i].end(),
1969  phase_cindexes.begin() + this_begin,
1970  phase_cindexes.begin() + this_end);
1971  }
1972 }
kaldi::int32 int32
void ConvertToCindexes(const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

Member Data Documentation

◆ dim_range_nodes_

std::unordered_set<std::pair<int32, int32>, PairHasher<int32> > dim_range_nodes_
private

dim_range_nodes_ is used when allocating steps for nodes of type kDimRangeNode.

This is a set of (source_step, dim_range_node_index), where source_step is the step in which we computed of the input of the dim-range node (this step will be for a node of type kComponentNode). This just tells us whether we've already added a particular dim-range node for this step, so we know whether we need to add it again.

Definition at line 559 of file nnet-computation-graph.h.

Referenced by ComputationStepsComputer::ProcessDimRangeSubPhase().

◆ graph_

◆ locations_

std::vector<std::pair<int32, int32> >* locations_
private

locations_ is a map from cindex_id to the pair of indexes into steps_ where that cindex_id resides, so if (*locations_)[c] = (i,j), then (*steps_)[i][j] == c.

This is also an output (we get the pointer in the constructor).

Definition at line 550 of file nnet-computation-graph.h.

Referenced by ComputationStepsComputer::AddStep(), ComputationStepsComputer::Check(), ComputationStepsComputer::ComputationStepsComputer(), ComputationStepsComputer::ConvertToLocations(), and ComputationStepsComputer::ProcessInputOrOutputStep().

◆ nnet_

◆ steps_

std::vector<std::vector<int32> >* steps_
private

steps_ is a pointer to an output that's passed in in the constructor.

Definition at line 545 of file nnet-computation-graph.h.

Referenced by ComputationStepsComputer::AddStep(), ComputationStepsComputer::Check(), and ComputationStepsComputer::ComputationStepsComputer().


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