29 bool input,
bool *is_new) {
30 typedef unordered_map<Cindex, int32, CindexHasher> map_type;
33 std::pair<Cindex, int32>(cindex, new_index));
34 if (p.second ==
true) {
44 return p.first->second;
48 typedef unordered_map<Cindex, int32, CindexHasher> map_type;
58 const std::vector<bool> &keep) {
60 KALDI_ASSERT(keep.size() == old_num_cindex_ids - start_cindex_id);
63 int32 count_before_renumbering = old_num_cindex_ids - start_cindex_id;
64 std::vector<int32> old2new(count_before_renumbering, -1), new2old;
65 new2old.reserve(old_num_cindex_ids);
66 for (
int32 j = 0;
j < count_before_renumbering;
j++) {
68 old2new[
j] = new2old.size() + start_cindex_id;
69 new2old.push_back(j + start_cindex_id);
74 int32 count_after_renumbering = new2old.size(),
75 new_num_cindex_ids = start_cindex_id + count_after_renumbering;
76 if (count_after_renumbering == count_before_renumbering) {
82 for (
int32 old_cindex_id = start_cindex_id;
83 old_cindex_id < old_num_cindex_ids; old_cindex_id++) {
84 int32 new_cindex_id = old2new[old_cindex_id - start_cindex_id];
86 if (new_cindex_id == -1) {
88 }
else if (new_cindex_id != old_cindex_id) {
93 std::vector<int32> temp;
94 for (
int32 c = start_cindex_id; c < new_num_cindex_ids; c++) {
95 int32 d = new2old[c - start_cindex_id];
101 const std::vector<int32> &src_dependencies =
103 std::vector<int32>::const_iterator
104 iter = src_dependencies.begin(), end = src_dependencies.end();
106 for (; iter != end; ++iter) {
107 int32 old_dep = *iter;
108 if (old_dep < start_cindex_id) {
111 int32 new_dep = old2new[old_dep - start_cindex_id];
115 KALDI_ERR <<
"Dependency on nonexistent cindex-id";
120 cindexes.resize(new_num_cindex_ids);
121 is_input.resize(new_num_cindex_ids);
126 int32 cindex_id)
const {
127 KALDI_ASSERT(static_cast<size_t>(cindex_id) < graph_->cindexes.size());
128 const Cindex &cindex = graph_->cindexes[cindex_id];
129 const std::string &node_name = nnet_.GetNodeName(cindex.first);
130 os << node_name <<
'(' << cindex.second.n <<
", " << cindex.second.t
131 <<
", " << cindex.second.x <<
')';
135 int32 first_cindex_id)
const {
136 int32 max_lines_print = 100;
137 std::deque<int32> cindexes_to_explain;
138 std::vector<bool> added_to_queue(graph_->cindexes.size(),
false);
139 cindexes_to_explain.push_back(first_cindex_id);
140 added_to_queue[first_cindex_id] =
true;
141 KALDI_ASSERT(graph_->cindexes.size() == graph_->dependencies.size());
142 std::ostringstream os;
144 PrintCindexId(os, first_cindex_id);
145 os <<
" is not computable for the following reason: ***\n";
146 for (
int32 num_lines_printed = 0;
147 num_lines_printed < max_lines_print && !cindexes_to_explain.empty();
148 num_lines_printed++) {
149 int32 cindex_id = cindexes_to_explain.front();
150 cindexes_to_explain.pop_front();
151 KALDI_ASSERT(static_cast<size_t>(cindex_id) < graph_->cindexes.size());
152 PrintCindexId(os, cindex_id);
153 os <<
" is " << cindex_info_[cindex_id].computable <<
", dependencies: ";
154 const std::vector<int32>
dependencies = graph_->dependencies[cindex_id];
155 std::vector<int32>::const_iterator iter = dependencies.begin(),
156 end = dependencies.end();
157 for (; iter != end; iter++) {
158 int32 dep_cindex_id = *iter;
159 PrintCindexId(os, dep_cindex_id);
160 const CindexInfo &dep_info = cindex_info_[dep_cindex_id];
162 if (dep_info.
computable != kComputable && !added_to_queue[dep_cindex_id]) {
163 added_to_queue[dep_cindex_id] =
true;
164 cindexes_to_explain.push_back(dep_cindex_id);
177 const std::vector<std::string> &node_names) {
178 int32 max_cindexes_per_line = 50, max_dependencies = 5,
181 std::vector<std::pair<Cindex, std::vector<Cindex> > > pairs;
182 pairs.reserve(num_cindexes);
183 for (
int32 cindex_id = 0; cindex_id < num_cindexes; cindex_id++) {
185 std::vector<Cindex> deps(size);
186 for (
size_t i = 0;
i < size;
i++)
188 std::sort(deps.begin(), deps.end());
189 pairs.push_back(std::pair<
Cindex, std::vector<Cindex> >(
cindexes[cindex_id],
192 std::sort(pairs.begin(), pairs.end());
194 for (
int32 i = 0;
i < num_cindexes;
i++) {
195 if (pairs[
i].first.first != pairs[cur_start].first.first) {
199 if (
i - cur_start < max_cindexes_per_line) {
206 for (
int32 j = 0;
j < pairs[
i].second.size();
j++) {
207 if (
j < max_dependencies) {
209 if (j + 1 < pairs[
i].second.size())
211 }
else if (
j == max_dependencies) {
217 }
else if (
i - cur_start == max_cindexes_per_line) {
231 cindex_id == cindex_info_.size());
232 depend_on_this_.push_back(std::vector<int32>());
256 for (
int32 i = 0;
i < request_->inputs.size();
i++) {
257 int32 n = nnet_.GetNodeIndex(request_->inputs[
i].name);
259 KALDI_ERR <<
"Network has no input with name " 260 << request_->inputs[
i].name;
261 NodeType t = nnet_.GetNode(n).node_type;
263 "Inputs to graph only allowed for Input and Component nodes.");
265 for (
int32 j = 0;
j < request_->inputs[
i].indexes.size();
j++) {
266 Cindex cindex(n, request_->inputs[
i].indexes[
j]);
268 int32 cindex_id = graph_->GetCindexId(cindex, is_input, &is_new);
269 KALDI_ASSERT(is_new &&
"Input index seems to be listed more than once");
270 AddCindexId(cindex_id);
271 cindex_info_.back().computable = kComputable;
275 KALDI_ASSERT(num_added > 0 &&
"AddInputToGraph: nothing to add.");
280 for (
int32 i = 0;
i < request_->outputs.size();
i++) {
281 int32 n = nnet_.GetNodeIndex(request_->outputs[
i].name);
283 KALDI_ERR <<
"Network has no output with name " 284 << request_->outputs[
i].name;
285 for (
int32 j = 0;
j < request_->outputs[
i].indexes.size();
j++) {
286 Cindex cindex(n, request_->outputs[
i].indexes[
j]);
288 int32 cindex_id = graph_->GetCindexId(cindex, is_input, &is_new);
289 KALDI_ASSERT(is_new &&
"Output index seems to be listed more than once");
290 AddCindexId(cindex_id);
291 cindex_info_.back().usable_count = 1;
292 cindex_info_.back().queued =
true;
293 next_queue_.push_back(cindex_id);
297 if (num_added == 0) {
298 KALDI_ERR <<
"Cannot process computation request with no outputs";
300 current_distance_ = 0;
302 current_queue_.swap(next_queue_);
306 auto iter = cindex_info_.begin(),
307 end = cindex_info_.end();
308 for (
int32 cindex_id = 0; iter != end; ++iter, ++cindex_id) {
309 if (iter->computable != kComputable) {
310 int32 network_node = graph_->cindexes[cindex_id].first;
311 if (nnet_.IsOutputNode(network_node))
327 default: os <<
"[invalid enum value]";
break;
335 std::vector<int32> outputs_not_computable;
336 int32 num_outputs_total = 0;
338 std::vector<Cindex>::const_iterator iter = graph_->cindexes.begin(),
339 end = graph_->cindexes.end();
340 for (
int32 cindex_id = 0; iter != end; ++iter,++cindex_id) {
341 int32 network_node = iter->first;
342 if (nnet_.IsOutputNode(network_node)) {
344 if (cindex_info_[cindex_id].computable != kComputable)
345 outputs_not_computable.push_back(cindex_id);
349 "You called this function when everything was computable.");
350 int32 num_print = 10, num_not_computable = outputs_not_computable.size();
351 KALDI_LOG << num_not_computable <<
" output cindexes out of " 352 << num_outputs_total <<
" were not computable.";
353 std::ostringstream os;
355 KALDI_LOG <<
"Computation request was: " << os.str();
356 if (num_not_computable > num_print)
357 KALDI_LOG <<
"Printing the reasons for " << num_print <<
" of these.";
358 for (
int32 i = 0;
i < num_not_computable &&
i < num_print;
i++)
359 ExplainWhyNotComputable(outputs_not_computable[
i]);
368 const CindexInfo &info = cindex_info_[cindex_id];
375 graph_->dependencies[cindex_id].clear();
379 const Cindex &cindex = graph_->cindexes[cindex_id];
380 int32 node_id = cindex.first;
381 const Index &index = cindex.second;
384 std::vector<int32> &
dependencies = graph_->dependencies[cindex_id];
385 std::sort(dependencies.begin(), dependencies.end());
386 std::vector<int32> used_cindex_ids;
391 bool dont_care =
false;
392 CindexSet cindex_set(*graph_, cindex_info_, dont_care);
393 std::vector<Cindex> used_cindexes;
394 bool ans = desc.
IsComputable(index, cindex_set, &used_cindexes);
399 size_t size = used_cindexes.size();
400 used_cindex_ids.resize(size);
401 for (
size_t i = 0;
i < size;
i++) {
402 int32 dep_cindex_id = graph_->GetCindexId(used_cindexes[
i]);
404 used_cindex_ids[
i] = dep_cindex_id;
413 bool dont_care =
false;
417 IndexSet index_set(*graph_, cindex_info_, node_id - 1, dont_care);
418 std::vector<Index> used_indexes;
419 bool ans = c->
IsComputable(request_->misc_info, index, index_set,
425 size_t size = used_indexes.size();
426 used_cindex_ids.resize(size);
427 for (
size_t i = 0;
i < size;
i++) {
428 Cindex dep_cindex(node_id - 1, used_indexes[
i]);
429 int32 dep_cindex_id = graph_->GetCindexId(dep_cindex);
431 used_cindex_ids[
i] = dep_cindex_id;
453 dependencies.swap(used_cindex_ids);
459 nnet_(nnet), request_(NULL), graph_(graph),
460 current_distance_(-1) {
462 "ComputationGraphBuilder initialized with nonempty graph.");
469 KALDI_ERR <<
"You are calling things in the wrong order: should be " 470 <<
"Compute(), Prune(), Compute, Prune(), ...";
477 int32 max_distance = 10000;
482 Check(cur_segment_start);
488 KALDI_ERR <<
"Loop detected while building computation graph (bad " 489 <<
"network topology?)";
492 Check(cur_segment_start);
498 for (
int32 cindex_id = start_cindex_id; cindex_id < num_cindex_ids;
499 cindex_id += 1 +
RandInt(0, num_cindex_ids / 100)) {
502 int32 size = depend_on_this.size();
503 std::sort(depend_on_this.begin(), depend_on_this.end());
505 for (
size_t j = 0;
j < size;
j++) {
506 int32 other_cindex_id = depend_on_this[
j];
515 int32 size = dependencies.size();
516 std::sort(dependencies.begin(), dependencies.end());
518 for (
size_t j = 0;
j < size;
j++) {
519 int32 dep_cindex_id = dependencies[
j];
520 if (dep_cindex_id >= start_cindex_id) {
534 int32 size = depend_on_this.size();
535 for (
size_t j = 0;
j < size;
j++) {
536 int32 other_cindex_id = depend_on_this[
j];
539 usable_count_recomputed++;
550 KALDI_ERR <<
"Mismatch in computable status";
555 if (
RandInt(0, cindex_id) == 0) {
579 for (
int32 cindex_id = start_cindex_id;
580 cindex_id < num_cindex_ids; cindex_id++)
586 std::vector<bool> required;
589 std::vector<bool> keep(num_cindex_ids - start_cindex_id,
false);
590 for (
int32 c = start_cindex_id; c < num_cindex_ids; c++) {
593 "You are calling Prune when not everything is computable.");
594 keep[c - start_cindex_id] =
true;
612 for (
int32 i = start_cindex_id;
i < new_num_cindex_ids;
i++) {
633 int32 node_index = cindex.first;
634 const Index &index = cindex.second;
637 std::vector<Cindex> input_cindexes;
650 std::vector<Index> input_indexes;
653 input_cindexes.resize(input_indexes.size());
654 for (
size_t i = 0;
i < input_indexes.size();
i++) {
655 input_cindexes[
i].first = node_index - 1;
656 input_cindexes[
i].second = input_indexes[
i];
661 input_cindexes.resize(1);
671 int32 num_dependencies = input_cindexes.size();
683 this_dep.resize(num_dependencies);
684 for (
size_t i = 0;
i < num_dependencies;
i++) {
685 bool is_input =
false, is_new;
688 this_dep[
i] = dep_cindex_id;
699 std::vector<int32>::const_iterator iter = this_dep.begin(),
700 end = this_dep.end();
711 for (; iter != end; ++iter) {
712 int32 dep_cindex_id = *iter;
723 int32 node_id = cindex.first;
724 const Index &index = cindex.second;
749 const int32 input_node_id = node_id - 1;
770 if (input_cindex_id != -1)
788 std::vector<std::vector<bool> > *computable)
const {
790 "You need to call this after Compute()!");
792 "You need to call this before Prune()!");
800 std::vector<bool> &this_vec = (*computable)[
i];
801 this_vec.resize(size);
802 for (
size_t j = 0;
j < size;
j++) {
832 std::vector<int32>::const_iterator iter =
depend_on_this_[cindex_id].begin(),
834 for (; iter != end; ++iter) {
835 int32 other_cindex_id = *iter;
847 std::vector<int32>::const_iterator
850 for (; iter != end; ++iter) {
851 int32 dep_cindex_id = *iter;
863 std::vector<int32>::const_iterator
866 for (; iter != end; ++iter) {
867 int32 dep_cindex_id = *iter;
885 std::vector<int32>::const_iterator
888 for (; iter != end; ++iter) {
889 int32 dep_cindex_id = *iter;
919 int32 start_cindex_id,
920 std::vector<bool> *required)
const {
926 required->resize(num_cindex_ids - start_cindex_id,
false);
933 std::vector<int32> queue;
934 for (
int32 c = start_cindex_id; c < num_cindex_ids; c++) {
937 if (is_output_node[node_id]) {
938 (*required)[c - start_cindex_id] =
true;
942 while (!queue.empty()) {
943 int32 c = queue.back();
946 std::vector<int32>::const_iterator iter = dependencies.begin(),
947 end = dependencies.end();
948 for (; iter != end; ++iter) {
950 if (d >= start_cindex_id && !(*required)[d - start_cindex_id]){
951 (*required)[d - start_cindex_id] =
true;
958 for (
int32 c = start_cindex_id; c < num_cindex_ids; c++)
966 namespace computation_graph {
978 KALDI_ERR <<
"Network has no output with name " 982 bool is_input =
false, is_new;
984 KALDI_ASSERT(is_new &&
"Output index seems to be listed more than once");
988 KALDI_ASSERT(num_added > 0 &&
"AddOutputToGraph: nothing to add.");
1001 KALDI_ERR <<
"Network has no input with name " 1005 "Inputs to graph only allowed for Input and Component nodes.");
1009 bool is_input =
true, is_new;
1011 KALDI_ASSERT(is_new &&
"Input index seems to be listed more than once");
1015 KALDI_ASSERT(num_added > 0 &&
"AddInputToGraph: nothing to add.");
1030 const std::vector<int32> &cindex_id_to_segment_and_epoch,
1031 std::vector<std::vector<int32> > *dependencies_subset) {
1033 KALDI_ASSERT(cindex_id_to_segment_and_epoch.size() == num_cindex_ids);
1034 dependencies_subset->resize(num_cindex_ids);
1035 for (
int32 cindex_id = 0; cindex_id < num_cindex_ids; cindex_id++) {
1036 int32 phase_index = cindex_id_to_segment_and_epoch[cindex_id];
1037 const std::vector<int32> &dependencies = graph.
dependencies[cindex_id];
1038 std::vector<int32> &dep_subset = (*dependencies_subset)[cindex_id];
1039 int32 num_dep = dependencies.size();
1040 for (
int32 i = 0;
i < num_dep;
i++) {
1042 if (cindex_id_to_segment_and_epoch[d] == phase_index)
1043 dep_subset.push_back(d);
1085 std::vector<int32> *cindex_id_to_segment_and_epoch,
1086 std::vector<std::vector<std::vector<int32 > > > *epochs_per_segment,
1087 std::vector<bool> *epoch_is_trivial) {
1092 std::vector<int32> node_to_epoch;
1095 std::ostringstream os;
1097 KALDI_VLOG(6) <<
"node_to_epoch: " << os.str();
1103 for (
int32 i = 0;
i < node_to_epoch.size();
i++)
1106 num_cindex_ids = graph.
cindexes.size(),
1108 num_epoch_indexes = 1 + *std::max_element(node_to_epoch.begin(),
1109 node_to_epoch.end());
1112 epochs_per_segment->clear();
1113 epochs_per_segment->resize(num_segments);
1118 std::vector<int32> epoch_to_num_nodes(num_epoch_indexes, 0);
1119 for (
int32 n = 0;
n < num_nodes;
n++)
1120 epoch_to_num_nodes[node_to_epoch[
n]]++;
1122 epoch_is_trivial->resize(num_epoch_indexes);
1123 for (
int32 o = 0; o < num_epoch_indexes; o++) {
1125 (*epoch_is_trivial)[o] = (epoch_to_num_nodes[o] <= 1);
1127 cindex_id_to_segment_and_epoch->resize(num_cindex_ids);
1129 int32 cur_segment_start = 0, cur_segment_end;
1130 for (
int32 segment = 0; segment < num_segments; segment++) {
1132 std::vector<std::vector<int32> > &epochs = (*epochs_per_segment)[segment];
1133 epochs.resize(num_epoch_indexes);
1135 for (
int32 cindex_id = cur_segment_start;
1136 cindex_id < cur_segment_end; cindex_id++) {
1138 epoch_index = (graph.
is_input[cindex_id] ? 0 :
1139 node_to_epoch[node_index]);
1140 (*cindex_id_to_segment_and_epoch)[cindex_id] =
1141 epoch_index + segment * num_epoch_indexes;
1142 epochs[epoch_index].push_back(cindex_id);
1144 cur_segment_start = cur_segment_end;
1155 using namespace computation_graph;
1163 std::vector<int32> queue(graph->
cindexes.size());
1167 while (!queue.empty()) {
1168 int32 cindex_id = queue.back();
1170 if (static_cast<int32>(graph->
dependencies.size()) <= cindex_id)
1179 const Index &index = cindex.second;
1182 std::vector<Cindex> input_cindexes;
1195 std::vector<Index> input_indexes;
1203 input_cindexes.resize(input_indexes.size());
1204 for (
size_t i = 0;
i < input_indexes.size();
i++) {
1205 input_cindexes[
i].first = n - 1;
1206 input_cindexes[
i].second = input_indexes[
i];
1211 input_cindexes.resize(1);
1219 std::vector<int32> &this_dep = graph->
dependencies[cindex_id];
1221 int32 num_dependencies = input_cindexes.size();
1222 this_dep.resize(num_dependencies);
1223 for (
size_t i = 0;
i < num_dependencies;
i++) {
1224 bool is_input =
false, is_new;
1227 this_dep[
i] = dep_cindex_id;
1229 queue.push_back(dep_cindex_id);
1240 std::vector<std::vector<int32> >::const_iterator iter = vec.begin(),
1242 for (; iter != end; ++iter)
1243 ans += iter->size();
1249 for (
size_t i = 0;
i < vec.size();
i++)
1310 const std::vector<int32> &this_epoch,
1311 const std::vector<std::vector<int32> > &dependencies_subset,
1312 const std::vector<std::vector<int32> > &depend_on_subset,
1313 bool epoch_is_trivial,
1314 std::vector<int32> *phase_indexes,
1315 std::vector<std::vector<int32> > *phases) {
1316 std::vector<int32> this_phase, next_phase_candidates;
1318 if (this_epoch.empty())
1321 if (epoch_is_trivial) {
1322 this_phase = this_epoch;
1327 std::vector<int32>::const_iterator iter = this_epoch.begin(),
1328 end = this_epoch.end();
1329 for (; iter != end; ++iter) {
1330 int32 cindex_id = *iter;
1331 if (dependencies_subset[cindex_id].empty())
1332 this_phase.push_back(cindex_id);
1338 "Trying to process computation with cycles");
1340 while (!this_phase.empty()) {
1343 phases->resize(phases->size() + 1);
1344 phases->back().swap(this_phase);
1351 if (epoch_is_trivial)
1354 int32 cur_phase_index = phases->size() - 1;
1359 next_phase_candidates.clear();
1360 std::vector<int32>::const_iterator this_phase_iter = phases->back().begin(),
1361 this_phase_end = phases->back().end();
1363 for (; this_phase_iter != this_phase_end; ++this_phase_iter) {
1364 int32 c = *this_phase_iter;
1365 (*phase_indexes)[c] = cur_phase_index;
1366 std::vector<int32>::const_iterator iter = depend_on_subset[c].begin(),
1367 end = depend_on_subset[c].end();
1368 for (; iter != end; ++iter) {
1370 next_phase_candidates.push_back(d);
1376 this_phase.reserve(next_phase_candidates.size());
1379 std::vector<int32>::const_iterator iter = next_phase_candidates.begin(),
1380 end = next_phase_candidates.end();
1381 for (; iter != end; ++iter) {
1383 std::vector<int32>::const_iterator
1384 dep_iter = dependencies_subset[c].begin(),
1385 dep_end = dependencies_subset[c].end();
1386 for (; dep_iter != dep_end; ++dep_iter) {
1388 if ((*phase_indexes)[d] < 0)
1391 if (dep_iter == dep_end) {
1393 this_phase.push_back(c);
1396 if (!next_phase_candidates.empty() && this_phase.empty()) {
1399 KALDI_ERR <<
"Your model has a type of recurrence that cannot be computed. " 1400 <<
"E.g. if x[t] depends on both x[t+1] and x[t-1]... no order " 1401 <<
"of computation will work.";
1409 std::vector<std::vector<std::vector<int32> > > *phases_per_segment) {
1410 using namespace computation_graph;
1413 std::vector<int32> cindex_id_to_segment_and_epoch;
1414 std::vector<std::vector<std::vector<int32 > > > epochs_per_segment;
1415 std::vector<bool> epoch_is_trivial;
1417 &epochs_per_segment, &epoch_is_trivial);
1426 std::vector<std::vector<int32> > dependencies_subset;
1428 &dependencies_subset);
1430 { std::vector<int32> temp; temp.swap(cindex_id_to_segment_and_epoch); }
1435 std::vector<std::vector<int32> > depend_on_subset;
1438 int32 num_epoch_indexes = epoch_is_trivial.size(),
1442 std::vector<int32> phase_indexes(num_cindex_ids, -1);
1444 phases_per_segment->clear();
1445 phases_per_segment->resize(num_segments);
1447 for (
int32 segment = 0; segment < num_segments; segment++) {
1448 phases_per_segment->reserve(50);
1450 for (
int32 epoch = 0; epoch < num_epoch_indexes; epoch++)
1452 epochs_per_segment[segment][epoch],
1453 dependencies_subset,
1455 epoch_is_trivial[epoch],
1457 &((*phases_per_segment)[segment]));
1467 graph_(graph), info_(NULL) { }
1470 const std::vector<ComputationGraphBuilder::CindexInfo> &info,
1471 bool treat_unknown_as_computable):
1478 if (cindex_id == -1) {
1481 if (
info_ == NULL) {
1485 c = (*info_)[cindex_id].computable;
1494 const std::vector<ComputationGraphBuilder::CindexInfo> &info,
1496 bool treat_unknown_as_computable):
1502 if (cindex_id == -1) {
1518 std::vector<std::vector<int32> > *steps,
1519 std::vector<std::pair<int32, int32> > *locations):
1520 nnet_(nnet),
graph_(graph), steps_(steps), locations_(locations) {
1526 locations_->reserve(num_cindexes + num_cindexes / 10);
1527 locations_->resize(num_cindexes, std::pair<int32,int32>(-1, -1));
1532 const std::vector<std::vector<int32> > &phases) {
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;
1537 for (
size_t j = 0;
j < sub_phases.size();
j++) {
1546 const std::vector<Cindex> &sub_phase) {
1547 int32 io_node = sub_phase[0].first;
1554 const std::vector<IoSpecification> &inputs_or_outputs =
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)
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];
1576 for (
size_t i = 0;
i < sub_phase.size();
i += 10) {
1577 const Cindex &cindex = sub_phase[
i];
1584 bool add_if_absent) {
1592 steps_->push_back(std::vector<int32>());
1593 std::vector<int32> &step =
steps_->back();
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) {
1604 for (; iter != end; ++iter, ++out_iter, ++row_index) {
1606 *out_iter = cindex_id;
1607 locations[cindex_id].first = step_index;
1608 locations[cindex_id].second = row_index;
1611 for (; iter != end; ++iter, ++out_iter, ++row_index) {
1612 bool is_input =
false;
1619 *out_iter = cindex_id;
1622 locations_->resize(cindex_id + 1, std::pair<int32, int32>(-1, -1));
1625 locations = &((*locations_)[0]);
1627 locations[cindex_id].first = step_index;
1628 locations[cindex_id].second = row_index;
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]);
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;
1656 const std::vector<int32> &cindex_ids,
1657 std::vector<Cindex> *cindexes)
const {
1658 cindexes->resize(cindex_ids.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);
1672 const std::vector<Cindex> &cindexes,
1673 std::vector<int32> *cindex_ids)
const {
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) {
1681 *out_iter = cindex_id;
1688 const std::vector<Cindex> &cindexes,
1689 std::vector<Index> *indexes) {
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;
1700 const std::vector<Index> &indexes,
1702 std::vector<Cindex> *cindexes) {
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;
1718 const std::vector<Cindex> &step) {
1720 int32 component_node_index = step.front().first;
1721 int32 component_input_index = component_node_index - 1;
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;
1742 std::vector<int32> step_cindex_ids;
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) {
1751 std::vector<int32>::const_iterator dep_iter = dependencies.begin(),
1752 dep_end = dependencies.end();
1753 for (; dep_iter != dep_end; ++dep_iter) {
1755 input_cindex_ids.insert(d);
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;
1769 std::sort(input_step.begin(), input_step.end());
1772 std::vector<Index> indexes, input_indexes;
1777 size_t orig_size = indexes.size() + input_indexes.size();
1783 bool added_padding = (orig_size != indexes.size() + input_indexes.size());
1787 std::vector<Cindex> reordered_step;
1792 AddStep(input_step, added_padding);
1793 AddStep(reordered_step, added_padding);
1807 const std::vector<int32> &cindex_ids,
1808 std::vector<std::pair<int32, int32> > *locations)
const {
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 =
1815 std::pair<int32, int32> *locations_ptr = &((*locations_)[0]);
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;
1823 out_iter->first = step;
1824 out_iter->second = row;
1829 const std::vector<Cindex> &sub_phase) {
1830 int32 dim_range_node = sub_phase[0].first;
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;
1844 std::vector<std::pair<int32, int32> > locations;
1849 std::unordered_set<int32> source_step_indexes;
1851 std::vector<std::pair<int32, int32> >::const_iterator
1852 locations_iter = locations.begin(),
1853 locations_end = locations.end();
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);
1866 std::unordered_set<int32>::const_iterator
1867 source_step_iter = source_step_indexes.begin(),
1868 source_step_end = source_step_indexes.end();
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);
1879 const std::vector<int32> &source_step = (*steps_)[source_step_index];
1881 std::vector<Cindex> 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;
1892 AddStep(cindexes, add_if_absent);
1898 const std::vector<Cindex> &sub_phase) {
1900 int32 node_index = sub_phase[0].first;
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)) {
1936 KALDI_ERR <<
"Error in computing computation steps (likely code error)";
1944 const std::vector<int32> &phase,
1945 std::vector<std::vector<Cindex> > *sub_phases)
const {
1946 std::vector<Cindex> phase_cindexes;
1949 std::sort(phase_cindexes.begin(), phase_cindexes.end());
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);
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);
virtual bool IsComputable(const MiscComputationInfo &misc_info, const Index &output_index, const IndexSet &input_index_set, std::vector< Index > *used_inputs) const
This function only does something interesting for non-simple Components, and it exists to make it pos...
void ConvertToLocations(const std::vector< int32 > &cindex_ids, std::vector< std::pair< int32, int32 > > *locations) const
void GetDependencies(const Index &index, std::vector< Cindex > *used_inputs) const
This function exists to enable us to manage optional dependencies, i.e.
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
ComputationGraph * graph_
ComputationStepsComputer(const Nnet &nnet, ComputationGraph *graph, std::vector< std::vector< int32 > > *steps, std::vector< std::pair< int32, int32 > > *locations)
Constructor.
void UpdateComputableInfo(int32 cindex_id)
void ExplainWhyNotComputable(int32 cindex_id) const
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.
const std::string & GetNodeName(int32 node_index) const
returns individual node name.
MiscComputationInfo misc_info
misc_info is for extensibility to things that don't easily fit into the framework.
ComputationGraph * graph_
Abstract base-class for neural-net components.
void PrintCindex(std::ostream &os, const Cindex &cindex, const std::vector< std::string > &node_names)
int32 GetVerboseLevel()
Get verbosity level, usually set via command line '–verbose=' switch.
bool treat_unknown_as_computable_
void GetComputableInfo(std::vector< std::vector< bool > > *computable) const
An abstract representation of a set of Indexes.
void ConvertToCindexIds(const std::vector< Cindex > &cindexes, std::vector< int32 > *cindex_ids) const
void PrintCindexId(std::ostream &os, int32 cindex_id) const
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...
virtual void GetInputIndexes(const MiscComputationInfo &misc_info, const Index &output_index, std::vector< Index > *desired_indexes) const
This function only does something interesting for non-simple Components.
bool IsInputNode(int32 node) const
Returns true if this is an output node, meaning that it is of type kInput.
void Check(int32 start_cindex_id) const
const std::vector< ComputationGraphBuilder::CindexInfo > * info_
std::ostream & operator<<(std::ostream &ostream, const Index &index)
void ProcessDimRangeSubPhase(const std::vector< Cindex > &sub_phase)
bool treat_unknown_as_computable_
std::vector< IoSpecification > inputs
void SplitIntoSubPhases(const std::vector< int32 > &phase, std::vector< std::vector< Cindex > > *sub_phase) const
bool operator()(const Cindex &cindex) const
Parenthesis operator; returns true if this cindex exists in the set.
int32 RoundUpToNearestPowerOfTwo(int32 n)
bool IsComponentNode(int32 node) const
Returns true if this is a component node, meaning that it is of type kComponent.
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq's (removes duplicates) from a vector.
void AddCindexId(int32 cindex_id)
void IncrementUsableCount(int32 cindex_id)
static void ConvertToIndexes(const std::vector< Cindex > &cindexes, std::vector< Index > *indexes)
void AddInputToGraph(const ComputationRequest &request, const Nnet &nnet, ComputationGraph *graph)
void ComputeComputationGraph(const Nnet &nnet, const ComputationRequest &request, ComputationGraph *graph)
struct Index is intended to represent the various indexes by which we number the rows of the matrices...
void ComputeGraphTranspose(const std::vector< std::vector< int32 > > &graph, std::vector< std::vector< int32 > > *graph_transpose)
Outputs a graph in which the order of arcs is reversed.
void ComputeRequiredArray(int32 start_cindex_id, std::vector< bool > *required) const
bool operator()(const Index &index) const
Returns true if this Index exists in the set.
const ComputationGraph & graph_
std::pair< int32, Index > Cindex
void AddOutputToGraph(const ComputationRequest &request, const Nnet &nnet, ComputationGraph *graph)
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.
void ConvertToCindexes(const std::vector< int32 > &cindex_ids, std::vector< Cindex > *cindexes) const
static int32 SumVectorSizes(const std::vector< std::vector< int32 > > &vec)
std::vector< std::vector< int32 > > dependencies
dependencies[cindex_id] gives you the list of other cindex_ids that this particular cindex_id directl...
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...
void Check() const
This is only to be called after you have called ComputeForSegment for all the segments.
unordered_map< Cindex, int32, CindexHasher > cindex_to_cindex_id_
Maps each Cindex to an integer cindex_id: reverse mapping of "cindexes".
void ComputeComputationPhases(const Nnet &nnet, const ComputationGraph &graph, std::vector< std::vector< std::vector< int32 > > > *phases_per_segment)
This function divides a computation into 'phases', where a 'phase' is a collection of cindexes which ...
virtual int32 Properties() const =0
Return bitmask of the component's properties.
void PruneDependencies(int32 cindex_id)
virtual void ReorderIndexes(std::vector< Index > *input_indexes, std::vector< Index > *output_indexes) const
This function only does something interesting for non-simple Components.
IndexSet(const ComputationGraph &graph, const std::vector< ComputationGraphBuilder::CindexInfo > &info, int32 node_id, bool treat_unknown_as_computable)
This constructor creates the set of all Indexes x such that a Cindex (node_id, x) which is computable...
std::vector< CindexInfo > cindex_info_
std::vector< bool > is_input
For each Cindex this tells us whether it was provided as an input to the network. ...
std::vector< std::vector< int32 > > depend_on_this_
std::vector< int32 > segment_ends
This variable is only of particular interest in a 'multi-segment' computation, which is used while cr...
bool AllOutputsAreComputable() const
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, ...
std::vector< std::vector< int32 > > * steps_
steps_ is a pointer to an output that's passed in in the constructor.
#define KALDI_PARANOID_ASSERT(cond)
void Compute(const ComputationRequest &request)
void PrintIntegerVector(std::ostream &os, const std::vector< int32 > &ints)
void Renumber(int32 start_cindex_id, const std::vector< bool > &keep)
This function renumbers the cindex-ids (but only those with index c >= start_cindex_id,.
std::vector< int32 > current_queue_
bool IsComputable(const Index &ind, const CindexSet &cindex_set, std::vector< Cindex > *used_inputs) const
Has the same purpose and interface as the IsComputable function of the SumDescriptor function...
NetworkNode is used to represent, three types of thing: either an input of the network (which pretty ...
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
This file contains a few functions that treat the neural net as a graph on nodes: e...
ComputableInfo computable
void ProcessComponentStep(const std::vector< Cindex > &step)
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).
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.
std::vector< Index > indexes
ComputableInfo ComputeComputableInfo(int32 cindex_id) const
static void ComputeComputationPhasesForEpoch(const Nnet &nnet, const ComputationGraph &graph, const std::vector< int32 > &this_epoch, const std::vector< std::vector< int32 > > &dependencies_subset, const std::vector< std::vector< int32 > > &depend_on_subset, bool epoch_is_trivial, std::vector< int32 > *phase_indexes, std::vector< std::vector< int32 > > *phases)
const std::vector< ComputationGraphBuilder::CindexInfo > & info_
#define KALDI_ASSERT(cond)
std::vector< IoSpecification > outputs
void ProcessInputOrOutputStep(const ComputationRequest &request, bool is_output, const std::vector< Cindex > &sub_phase)
const ComputationGraph & graph_
ComputationGraphBuilder(const Nnet &nnet, ComputationGraph *graph)
void AddDependencies(int32 cindex_id)
union kaldi::nnet3::NetworkNode::@15 u
void Print(std::ostream &os, const std::vector< std::string > &node_names)
This function, useful for debugging/visualization purposes, prints out a summary of the computation g...
int32 GetNodeIndex(const std::string &node_name) const
returns index associated with this node name, or -1 if no such index.
void ExplainWhyAllOutputsNotComputable() const
bool IsSortedAndUniq(const std::vector< T > &vec)
Returns true if the vector is sorted and contains each element only once.
void DecrementUsableCount(int32 cindex_id)
int32 AddStep(const std::vector< Cindex > &cindexes, bool add_if_absent=false)
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 gr...
const ComputationRequest * request_
bool IsDimRangeNode(int32 node) const
Returns true if this is a dim-range node, meaning that it is of type kDimRange.
The first step in compilation is to turn the ComputationSpecification into a ComputationGraph, where for each Cindex we have a list of other Cindexes that it depends on.
CindexSet(const ComputationGraph &graph)
with this constructor, represents the set of all Cindexes that exist in the graph.
int32 RandInt(int32 min_val, int32 max_val, struct RandomState *state)
bool IsComponentInputNode(int32 node) const
Returns true if this is component-input node, i.e.
void ProcessSubPhase(const ComputationRequest &request, const std::vector< Cindex > &sub_phase)
std::vector< int32 > next_queue_