All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 414 of file nnet-computation-graph.h.

Constructor & Destructor Documentation

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 1539 of file nnet-computation-graph.cc.

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

1543  :
1544  nnet_(nnet), graph_(graph), steps_(steps), locations_(locations) {
1545  steps_->clear();
1546  locations_->clear();
1547  int32 num_cindexes = graph_->cindexes.size();
1548  // leave a little space in case a few cindexes are added (unlikely
1549  // but could happen with dim-range nodes).
1550  locations_->reserve(num_cindexes + num_cindexes / 10);
1551  locations_->resize(num_cindexes, std::pair<int32,int32>(-1, -1));
1552 }
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...
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's passed in in the constructor.

Member Function Documentation

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

Definition at line 1607 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().

1608  {
1609  // note: we can't assert that cindexes is nonempty, because it's possible for
1610  // input steps for GeneralComponents to be empty if they require no input
1611  // indexes; and because the compiler code expects component steps to be
1612  // preceded by component-input steps, we can't just omit these empty steps.
1613  // [note: a component-input step is about preparing the input for a component's
1614  // propagation.]
1615  int32 step_index = steps_->size();
1616  steps_->push_back(std::vector<int32>());
1617  std::vector<int32> &step = steps_->back(); // vector of cindex_id.
1618  step.resize(cindexes.size());
1619  size_t row_index = 0;
1620  std::vector<Cindex>::const_iterator iter = cindexes.begin(),
1621  end = cindexes.end();
1622  std::vector<int32>::iterator out_iter = step.begin();
1623  std::pair<int32, int32> *locations = &((*locations_)[0]);
1624  if (!add_if_absent) {
1625  // this version of GetCindexId will not add CindexIds, and
1626  // will crash if CindexIds not present in the graph are
1627  // encountered.
1628  for (; iter != end; ++iter, ++out_iter, ++row_index) {
1629  int32 cindex_id = graph_->GetCindexId(*iter);
1630  *out_iter = cindex_id;
1631  locations[cindex_id].first = step_index;
1632  locations[cindex_id].second = row_index;
1633  }
1634  } else {
1635  for (; iter != end; ++iter, ++out_iter, ++row_index) {
1636  bool is_input = false; // only relevant if we have to add the cindex to
1637  // the computation graph, which we won't for
1638  // inputs (we only might for dim-range nodes
1639  // and for the component-input and component
1640  // steps of non-simple Components.
1641  bool added;
1642  int32 cindex_id = graph_->GetCindexId(*iter, is_input, &added);
1643  *out_iter = cindex_id;
1644  if (added) {
1645  KALDI_ASSERT(cindex_id == static_cast<int32>(locations_->size()));
1646  locations_->resize(cindex_id + 1, std::pair<int32, int32>(-1, -1));
1647  locations_->back().first = step_index;
1648  locations_->back().second = row_index;
1649  locations = &((*locations_)[0]); // in case it was reallocated
1650  } else {
1651  locations[cindex_id].first = step_index;
1652  locations[cindex_id].second = row_index;
1653  }
1654  }
1655  }
1656  return step_index;
1657 }
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...
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's passed in in the constructor.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
int32 AddStep ( std::vector< int32 > *  cindex_ids)
private

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

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

1660  {
1661  int32 step_index = steps_->size();
1662  steps_->push_back(std::vector<int32>());
1663  steps_->back().swap(*cindex_ids);
1664  std::vector<int32>::const_iterator iter = steps_->back().begin(),
1665  end = steps_->back().end();
1666  int32 row_index = 0;
1667  std::pair<int32,int32> *locations = &((*locations_)[0]);
1668  size_t num_cindexes = graph_->cindexes.size();
1669  for (; iter != end; ++iter, ++row_index) {
1670  int32 cindex_id = *iter;
1671  KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
1672  locations[cindex_id].first = step_index;
1673  locations[cindex_id].second = row_index;
1674  }
1675  return step_index;
1676 }
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's passed in in the constructor.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
void Check ( ) const

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

Definition at line 1946 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().

1946  {
1947  int32 num_cindexes = graph_->cindexes.size();
1948  KALDI_ASSERT(locations_->size() == num_cindexes);
1949  for (int32 c = 0; c < num_cindexes; c++) {
1950  int32 step = (*locations_)[c].first,
1951  row = (*locations_)[c].second;
1952  if (!(step >= 0 && row >= 0 && (*steps_)[step][row] == c)) {
1953  // normally the 'locations' of cindexes should be unique, so we should
1954  // never normally reach this point; but it's not an error to have
1955  // duplicates of the cindexes used for 'padding' by the ReorderIndexes()
1956  // function of non-simple Components. So we check whether that's the case
1957  // before we die.
1958  if (graph_->cindexes[c].second.t != kNoTime) {
1959  // if this happens it will likely require some debugging by Dan.
1960  KALDI_ERR << "Error in computing computation steps (likely code error)";
1961  }
1962  }
1963 
1964  }
1965 }
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...
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's passed in in the constructor.
#define KALDI_ERR
Definition: kaldi-error.h:127
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
const int kNoTime
Definition: nnet-common.cc:568
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 1554 of file nnet-computation-graph.cc.

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

Referenced by Compiler::CreateComputation().

1556  {
1557  int32 this_num_phases = phases.size();
1558  for (int32 i = 0; i < this_num_phases; i++) {
1559  std::vector<std::vector<Cindex> > sub_phases;
1560  SplitIntoSubPhases(phases[i], &sub_phases);
1561  for (size_t j = 0; j < sub_phases.size(); j++) {
1562  ProcessSubPhase(request, sub_phases[j]);
1563  }
1564  }
1565 }
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)
void ConvertToCindexes ( const std::vector< int32 > &  cindex_ids,
std::vector< Cindex > *  cindexes 
) const
private

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

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

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

1681  {
1682  cindexes->resize(cindex_ids.size());
1683  size_t num_cindexes = graph_->cindexes.size();
1684  std::vector<int32>::const_iterator iter = cindex_ids.begin(),
1685  end = cindex_ids.end();
1686  std::vector<Cindex>::iterator out_iter = cindexes->begin();
1687  for (; iter != end; ++iter, ++out_iter) {
1688  int32 cindex_id = *iter;
1689  KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
1690  *out_iter = graph_->cindexes[cindex_id];
1691  }
1692 }
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
void ConvertToCindexes ( const std::vector< Index > &  indexes,
int32  node_index,
std::vector< Cindex > *  cindexes 
)
staticprivate

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

References KALDI_ASSERT.

1726  {
1727  KALDI_ASSERT(node_index >= 0);
1728  cindexes->resize(indexes.size());
1729  std::vector<Index>::const_iterator iter = indexes.begin(),
1730  end = indexes.end();
1731  std::vector<Cindex>::iterator out_iter = cindexes->begin();
1732  for (; iter != end; ++iter, ++out_iter) {
1733  out_iter->first = node_index;
1734  out_iter->second = *iter;
1735  }
1736 }
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
void ConvertToCindexIds ( const std::vector< Cindex > &  cindexes,
std::vector< int32 > *  cindex_ids 
) const
private

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

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

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

1697  {
1698  cindex_ids->resize(cindexes.size());
1699  std::vector<Cindex>::const_iterator iter = cindexes.begin(),
1700  end = cindexes.end();
1701  std::vector<int32>::iterator out_iter = cindex_ids->begin();
1702  for (; iter != end; ++iter, ++out_iter) {
1703  int32 cindex_id = graph_->GetCindexId(*iter);
1704  KALDI_ASSERT(cindex_id >= 0);
1705  *out_iter = cindex_id;
1706  }
1707 }
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:169
void ConvertToIndexes ( const std::vector< Cindex > &  cindexes,
std::vector< Index > *  indexes 
)
staticprivate

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

Referenced by ComputationStepsComputer::ProcessComponentStep().

1713  {
1714  indexes->resize(cindexes.size());
1715  std::vector<Cindex>::const_iterator iter = cindexes.begin(),
1716  end = cindexes.end();
1717  std::vector<Index>::iterator out_iter = indexes->begin();
1718  for (; iter != end; ++iter, ++out_iter)
1719  *out_iter = iter->second;
1720 }
void ConvertToLocations ( const std::vector< int32 > &  cindex_ids,
std::vector< std::pair< int32, int32 > > *  locations 
) const
private

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

References KALDI_ASSERT, and ComputationStepsComputer::locations_.

Referenced by ComputationStepsComputer::ProcessDimRangeSubPhase().

1832  {
1833  locations->resize(cindex_ids.size());
1834  std::vector<int32>::const_iterator iter = cindex_ids.begin(),
1835  end = cindex_ids.end();
1836  std::vector<std::pair<int32, int32> >::iterator out_iter =
1837  locations->begin();
1838  // note, locations_ and locations are different variables.
1839  std::pair<int32, int32> *locations_ptr = &((*locations_)[0]);
1840  size_t num_cindexes = locations_->size();
1841  for (; iter != end; ++iter, ++out_iter) {
1842  int32 cindex_id = *iter;
1843  KALDI_ASSERT(static_cast<size_t>(cindex_id) < num_cindexes);
1844  int32 step = locations_ptr[cindex_id].first,
1845  row = locations_ptr[cindex_id].second;
1846  KALDI_ASSERT(step >= 0);
1847  out_iter->first = step;
1848  out_iter->second = row;
1849  }
1850 }
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...
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
void ProcessComponentStep ( const std::vector< Cindex > &  step)
private

Definition at line 1741 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().

1742  {
1743  KALDI_ASSERT(!step.empty());
1744  int32 component_node_index = step.front().first;
1745  int32 component_input_index = component_node_index - 1;
1746  KALDI_ASSERT(nnet_.IsComponentNode(component_node_index));
1747  const NetworkNode &node = nnet_.GetNode(component_node_index);
1748  int32 c = node.u.component_index;
1749  const Component *component = nnet_.GetComponent(c);
1750  if (component->Properties() & kSimpleComponent) {
1751  // for simple components, the input cindexes will be the same as the
1752  // output ones except for the node index, so we do a shortcut that's
1753  // faster (no following dependencies).
1754  std::vector<Cindex> input_step(step.size());
1755  input_step.resize(step.size());
1756  std::vector<Cindex>::iterator iter = input_step.begin(),
1757  end = input_step.end();
1758  std::vector<Cindex>::const_iterator src = step.begin();
1759  for (; iter != end; ++iter,++src) {
1760  iter->first = component_input_index;
1761  iter->second = src->second;
1762  }
1763  AddStep(input_step);
1764  AddStep(step);
1765  } else {
1766  std::vector<int32> step_cindex_ids;
1767  ConvertToCindexIds(step, &step_cindex_ids);
1768  // to get the input cindexes we need to follow dependencies back.
1769  unordered_set<int32> input_cindex_ids;
1770  std::vector<int32>::iterator iter = step_cindex_ids.begin(),
1771  end = step_cindex_ids.end();
1772  for (; iter != end; ++iter) {
1773  int32 c = *iter;
1774  const std::vector<int32> &dependencies = graph_->dependencies[c];
1775  std::vector<int32>::const_iterator dep_iter = dependencies.begin(),
1776  dep_end = dependencies.end();
1777  for (; dep_iter != dep_end; ++dep_iter) {
1778  int32 d = *dep_iter;
1779  input_cindex_ids.insert(d);
1780  }
1781  }
1782  // Convert to Cindexes so we can sort them as Cindexes.
1783  std::vector<Cindex> input_step;
1784  input_step.reserve(input_cindex_ids.size());
1785  unordered_set<int32>::iterator set_iter = input_cindex_ids.begin(),
1786  set_end = input_cindex_ids.end();
1787  for (; set_iter != set_end; ++set_iter) {
1788  int32 c = *set_iter;
1789  input_step.push_back(graph_->cindexes[c]);
1790  }
1791 
1792  // sort the input cindexes.
1793  std::sort(input_step.begin(), input_step.end());
1794 
1795  if (component->Properties() & kReordersIndexes) {
1796  std::vector<Index> indexes, input_indexes;
1797  ConvertToIndexes(input_step, &input_indexes);
1798  ConvertToIndexes(step, &indexes);
1799 
1800 
1801  size_t orig_size = indexes.size() + input_indexes.size();
1802 
1803  // the component wants to have the opportunity to change the
1804  // order of these indexes from their default.
1805  component->ReorderIndexes(&input_indexes, &indexes);
1806 
1807  bool added_padding = (orig_size != indexes.size() + input_indexes.size());
1808 
1809  // Now convert back from indexes to cindexes (we know the
1810  // node-index in each case)
1811  std::vector<Cindex> reordered_step;
1812  ConvertToCindexes(indexes, component_node_index, &reordered_step);
1813  ConvertToCindexes(input_indexes, component_input_index, &input_step);
1814  // the 'added_padding' argument becomes the 'add_if_absent' arg of
1815  // AddStep, so it knows to expect that it might have to add new CindexIds.
1816  AddStep(input_step, added_padding);
1817  AddStep(reordered_step, added_padding);
1818  } else {
1819  AddStep(input_step);
1820  // it's more efficient to add the step with cindex_ids; and we have these
1821  // available, so we do it that way. (in the other branch where
1822  // the flag kReordersIndexes was present, we couldn't do this because
1823  // of the reordering).
1824  AddStep(&step_cindex_ids);
1825  }
1826  }
1827 }
void ConvertToCindexIds(const std::vector< Cindex > &cindexes, std::vector< int32 > *cindex_ids) const
static void ConvertToIndexes(const std::vector< Cindex > &cindexes, std::vector< Index > *indexes)
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
std::vector< Cindex > cindexes
The mapping of cindex_id to Cindex.
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
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
void ConvertToCindexes(const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)
union kaldi::nnet3::NetworkNode::@14 u
void ProcessDimRangeSubPhase ( const std::vector< Cindex > &  sub_phase)
private

Definition at line 1852 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().

1853  {
1854  int32 dim_range_node = sub_phase[0].first;
1855  KALDI_ASSERT(nnet_.IsDimRangeNode(dim_range_node));
1856  const NetworkNode &node = nnet_.GetNode(dim_range_node);
1857  // 'input_node_index' is the node index of the component or input node
1858  // that this dim-range node gets its input from.
1859  int32 input_node_index = node.u.node_index;
1860  // input_cindexes will give us the cindexes of the component or input node
1861  // that is the input to this dim-range node
1862  std::vector<Cindex> input_cindexes(sub_phase);
1863  for (std::vector<Cindex>::iterator iter = input_cindexes.begin(),
1864  end = input_cindexes.end(); iter != end; ++iter)
1865  iter->first = input_node_index;
1866  std::vector<int32> input_cindex_ids;
1867  ConvertToCindexIds(input_cindexes, &input_cindex_ids);
1868  std::vector<std::pair<int32, int32> > locations;
1869  ConvertToLocations(input_cindex_ids, &locations);
1870 
1871  // get a list of the source step indexes (corresponding to computations for the
1872  // source component-node)
1873  std::unordered_set<int32> source_step_indexes;
1874  KALDI_ASSERT(!locations.empty());
1875  std::vector<std::pair<int32, int32> >::const_iterator
1876  locations_iter = locations.begin(),
1877  locations_end = locations.end();
1878 
1879  // 'cur_source_step_index' is just an optimization to prevent unnecessary
1880  // unordered_set inserts.
1881  int32 cur_source_step_index = -1;
1882  for (; locations_iter != locations_end; ++locations_iter) {
1883  int32 source_step_index = locations_iter->first;
1884  if (source_step_index != cur_source_step_index) {
1885  cur_source_step_index = source_step_index;
1886  source_step_indexes.insert(cur_source_step_index);
1887  }
1888  }
1889 
1890  std::unordered_set<int32>::const_iterator
1891  source_step_iter = source_step_indexes.begin(),
1892  source_step_end = source_step_indexes.end();
1893  // iterating over the indexes of the source steps.
1894  for (; source_step_iter != source_step_end; ++source_step_iter) {
1895  int32 source_step_index = *source_step_iter;
1896  std::pair<int32, int32> p(source_step_index, dim_range_node);
1897  if (dim_range_nodes_.count(p) > 0) {
1898  // We don't need to do anything; a dim-range node already exists for this
1899  // step and this node index.
1900  continue;
1901  }
1902  dim_range_nodes_.insert(p);
1903  const std::vector<int32> &source_step = (*steps_)[source_step_index];
1904  // 'cindexes' will be the cindexes of the new step that we're going to add.
1905  std::vector<Cindex> cindexes;
1906  ConvertToCindexes(source_step, &cindexes);
1907  std::vector<Cindex>::iterator iter = cindexes.begin(),
1908  end = cindexes.end();
1909  for (; iter != end; ++iter)
1910  iter->first = dim_range_node;
1911  bool add_if_absent = true;
1912  // this add_if_absent says, even if cindexes were not in the graph,
1913  // add them. This is possible; the step will contain all cindexes for the
1914  // input step, even if they won't be needed. (This is costless; it's just
1915  // setting up a sub-matrix).
1916  AddStep(cindexes, add_if_absent);
1917  }
1918 }
void ConvertToCindexIds(const std::vector< Cindex > &cindexes, std::vector< int32 > *cindex_ids) const
const NetworkNode & GetNode(int32 node) const
returns const reference to a particular numbered network node.
Definition: nnet-nnet.h:146
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
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:169
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)
void ConvertToLocations(const std::vector< int32 > &cindex_ids, std::vector< std::pair< int32, int32 > > *locations) const
union kaldi::nnet3::NetworkNode::@14 u
void ProcessInputOrOutputStep ( const ComputationRequest request,
bool  is_output,
const std::vector< Cindex > &  sub_phase 
)
private

Definition at line 1567 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().

1570  {
1571  int32 io_node = sub_phase[0].first;
1572  if (is_output){
1573  KALDI_ASSERT(nnet_.IsOutputNode(io_node));
1574  } else {
1575  KALDI_ASSERT(nnet_.IsInputNode(io_node));
1576  }
1577  std::string node_name = nnet_.GetNodeName(io_node);
1578  const std::vector<IoSpecification> &inputs_or_outputs =
1579  (is_output ? request.outputs : request.inputs);
1580  int32 io_index = -1;
1581  for (size_t i = 0; i < inputs_or_outputs.size(); i++)
1582  if (inputs_or_outputs[i].name == node_name)
1583  io_index = i;
1584  KALDI_ASSERT(io_index >= 0);
1585  const std::vector<Index> &io_indexes = inputs_or_outputs[io_index].indexes;
1586  std::vector<Cindex> io_cindexes(io_indexes.size());
1587  for (size_t i = 0, size = io_cindexes.size(); i < size; i++) {
1588  io_cindexes[i].first = io_node;
1589  io_cindexes[i].second = io_indexes[i];
1590  }
1591  KALDI_ASSERT(io_cindexes.size() == sub_phase.size());
1592  // we expect the list of cindexes in 'io_cindexes' to be identical to
1593  // 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
1594  // that they are the same later.
1595  // The actual output in 'steps' must be in the same order as
1596  int32 step_index = AddStep(io_cindexes);
1597  // Now spot-check that the cindexes in 'sub_phase' are the same as those
1598  // we just added. [note: they don't have to be in the same order, but
1599  // they should be the same set.]
1600  for (size_t i = 0; i < sub_phase.size(); i += 10) {
1601  const Cindex &cindex = sub_phase[i];
1602  int32 cindex_id = graph_->GetCindexId(cindex);
1603  KALDI_ASSERT(cindex_id >= 0 && (*locations_)[cindex_id].first == step_index);
1604  }
1605 }
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
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
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...
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.
const std::string & GetNodeName(int32 node_index) const
returns individual node name.
Definition: nnet-nnet.cc:684
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)
void ProcessSubPhase ( const ComputationRequest request,
const std::vector< Cindex > &  sub_phase 
)
private

Definition at line 1920 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().

1922  {
1923  KALDI_ASSERT(!sub_phase.empty());
1924  int32 node_index = sub_phase[0].first;
1925  KALDI_ASSERT(sub_phase.back().first == node_index);
1926  if (nnet_.IsComponentNode(node_index)) {
1927  ProcessComponentStep(sub_phase);
1928  } else if (nnet_.IsInputNode(node_index)) {
1929  ProcessInputOrOutputStep(request, false, sub_phase);
1930  } else if (nnet_.IsOutputNode(node_index)) {
1931  ProcessInputOrOutputStep(request, true, sub_phase);
1932  } else if (nnet_.IsDimRangeNode(node_index)) {
1933  // this might turn out to be multiple steps, see the code.
1934  ProcessDimRangeSubPhase(sub_phase);
1935  } else if (nnet_.IsComponentInputNode(node_index)) {
1936  // We actually do nothing with these sub-phases, because they are processed
1937  // when we process the associated component's sub-phase/step. Doing it this
1938  // way resolves certain problems.
1939  return;
1940  } else {
1941  KALDI_ERR << "Unknown node type.";
1942  }
1943 }
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
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
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 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
#define KALDI_ERR
Definition: kaldi-error.h:127
void ProcessComponentStep(const std::vector< Cindex > &step)
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
void ProcessInputOrOutputStep(const ComputationRequest &request, bool is_output, const std::vector< Cindex > &sub_phase)
bool IsComponentInputNode(int32 node) const
Returns true if this is component-input node, i.e.
Definition: nnet-nnet.cc:172
void SplitIntoSubPhases ( const std::vector< int32 > &  phase,
std::vector< std::vector< Cindex > > *  sub_phase 
) const
private

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

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

Referenced by ComputationStepsComputer::ComputeForSegment().

1969  {
1970  std::vector<Cindex> phase_cindexes;
1971  ConvertToCindexes(phase, &phase_cindexes);
1972  KALDI_ASSERT(!phase_cindexes.empty());
1973  std::sort(phase_cindexes.begin(), phase_cindexes.end());
1974  // 'sub_phase_begins' is the indexes onto 'phase_cindees' that
1975  // start a run of the same node-index
1976  std::vector<size_t> segment_begins;
1977  int32 cur_node_index = -1;
1978  size_t size = phase_cindexes.size();
1979  for (size_t i = 0; i < size; i++) {
1980  if (phase_cindexes[i].first != cur_node_index) {
1981  cur_node_index = phase_cindexes[i].first;
1982  segment_begins.push_back(i);
1983  }
1984  }
1985  size_t num_sub_phases = segment_begins.size();
1986  segment_begins.push_back(size);
1987  sub_phases->clear();
1988  sub_phases->resize(num_sub_phases);
1989  for (size_t i = 0; i < num_sub_phases; i++) {
1990  size_t this_begin = segment_begins[i],
1991  this_end = segment_begins[i+1];
1992  (*sub_phases)[i].insert((*sub_phases)[i].end(),
1993  phase_cindexes.begin() + this_begin,
1994  phase_cindexes.begin() + this_end);
1995  }
1996 }
void ConvertToCindexes(const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169

Member Data Documentation

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 558 of file nnet-computation-graph.h.

Referenced by ComputationStepsComputer::ProcessDimRangeSubPhase().

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 549 of file nnet-computation-graph.h.

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

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

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

Definition at line 544 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: