43 std::vector<std::vector<std::pair<int32, int32> > > pdf_info;
44 std::vector<int32> num_pdf_classes( 1 + *std::max_element(phones.begin(), phones.end()), -1);
45 for (
size_t i = 0;
i < phones.size();
i++)
47 ctx_dep.
GetPdfInfo(phones, num_pdf_classes, &pdf_info);
51 std::map<std::pair<int32, int32>, std::vector<int32> > to_hmm_state_list;
55 for (
size_t i = 0; i < phones.size(); i++) {
58 for (
int32 j = 0; j < static_cast<int32>(entry.size());
j++) {
59 int32 pdf_class = entry[
j].forward_pdf_class;
61 to_hmm_state_list[std::make_pair(phone, pdf_class)].push_back(
j);
66 for (
int32 pdf = 0; pdf < static_cast<int32>(pdf_info.size()); pdf++) {
67 for (
size_t j = 0;
j < pdf_info[pdf].size();
j++) {
68 int32 phone = pdf_info[pdf][
j].first,
69 pdf_class = pdf_info[pdf][
j].second;
70 const std::vector<int32> &state_vec = to_hmm_state_list[std::make_pair(phone, pdf_class)];
74 for (
size_t k = 0; k < state_vec.size(); k++) {
75 int32 hmm_state = state_vec[k];
90 std::vector<std::vector<std::vector<std::pair<int32, int32> > > > pdf_info;
93 std::vector<std::vector<std::pair<int32, int32> > > pdf_class_pairs;
94 pdf_class_pairs.resize(1 + *std::max_element(phones.begin(), phones.end()));
95 for (
size_t i = 0;
i < phones.size();
i++) {
98 for (
int32 j = 0; j < static_cast<int32>(entry.size());
j++) {
99 int32 forward_pdf_class = entry[
j].forward_pdf_class, self_loop_pdf_class = entry[
j].self_loop_pdf_class;
100 if (forward_pdf_class !=
kNoPdf)
101 pdf_class_pairs[phone].push_back(std::make_pair(forward_pdf_class, self_loop_pdf_class));
104 ctx_dep.
GetPdfInfo(phones, pdf_class_pairs, &pdf_info);
106 std::vector<std::map<std::pair<int32, int32>, std::vector<int32> > > to_hmm_state_list;
107 to_hmm_state_list.resize(1 + *std::max_element(phones.begin(), phones.end()));
111 for (
size_t i = 0;
i < phones.size();
i++) {
114 std::map<std::pair<int32, int32>, std::vector<int32> > phone_to_hmm_state_list;
115 for (
int32 j = 0; j < static_cast<int32>(entry.size());
j++) {
116 int32 forward_pdf_class = entry[
j].forward_pdf_class, self_loop_pdf_class = entry[
j].self_loop_pdf_class;
117 if (forward_pdf_class !=
kNoPdf) {
118 phone_to_hmm_state_list[std::make_pair(forward_pdf_class, self_loop_pdf_class)].push_back(
j);
121 to_hmm_state_list[phone] = phone_to_hmm_state_list;
124 for (
int32 i = 0;
i < phones.size();
i++) {
126 for (
int32 j = 0; j < static_cast<int32>(pdf_info[phone].size());
j++) {
127 int32 pdf_class = pdf_class_pairs[phone][
j].first,
128 self_loop_pdf_class = pdf_class_pairs[phone][
j].second;
129 const std::vector<int32> &state_vec =
130 to_hmm_state_list[phone][std::make_pair(pdf_class, self_loop_pdf_class)];
132 for (
size_t k = 0; k < state_vec.size(); k++) {
133 int32 hmm_state = state_vec[k];
134 for (
size_t m = 0; m < pdf_info[phone][
j].size(); m++) {
135 int32 pdf = pdf_info[phone][
j][m].first,
136 self_loop_pdf = pdf_info[phone][
j][m].second;
137 tuples_.push_back(
Tuple(phone, hmm_state, pdf, self_loop_pdf));
148 int32 cur_transition_id = 1;
150 for (
int32 tstate = 1;
151 tstate <= static_cast<int32>(
tuples_.size()+1);
154 if (static_cast<size_t>(tstate) <=
tuples_.size()) {
156 hmm_state =
tuples_[tstate-1].hmm_state,
157 forward_pdf =
tuples_[tstate-1].forward_pdf,
158 self_loop_pdf =
tuples_[tstate-1].self_loop_pdf;
163 cur_transition_id += my_num_ids;
169 for (
int32 tstate = 1; tstate <= static_cast<int32>(
tuples_.size()); tstate++) {
184 int32 num_big_numbers = std::min<int32>(2000, cur_transition_id);
185 id2pdf_id_.resize(cur_transition_id + num_big_numbers,
186 std::numeric_limits<int32>::max());
200 KALDI_ERR <<
"TransitionModel::InitializeProbs, zero " 201 "probability [should remove that entry in the topology]";
203 KALDI_WARN <<
"TransitionModel::InitializeProbs, prob greater than one.";
234 for (
size_t i = 0;
i < phones.size();
i++) {
237 for (
int32 j = 0; j < static_cast<int32>(entry.size());
j++) {
238 if (entry[
j].forward_pdf_class != entry[
j].self_loop_pdf_class)
255 Tuple tuple(phone, hmm_state, pdf, self_loop_pdf);
259 std::vector<Tuple>::const_iterator iter =
261 if (iter ==
tuples_.end() || !(*iter == tuple)) {
262 KALDI_ERR <<
"TransitionModel::TupleToTransitionState, tuple not found." 263 <<
" (incompatible tree and model?)";
266 return static_cast<int32>((iter -
tuples_.begin())) + 1;
287 return tuples_[trans_state-1].phone;
292 return tuples_[trans_state-1].forward_pdf;
296 int32 trans_state)
const {
300 KALDI_ASSERT(static_cast<size_t>(t.hmm_state) < entry.size());
301 return entry[t.hmm_state].forward_pdf_class;
306 int32 trans_state)
const {
310 KALDI_ASSERT(static_cast<size_t>(t.hmm_state) < entry.size());
311 return entry[t.hmm_state].self_loop_pdf_class;
317 return tuples_[trans_state-1].self_loop_pdf;
322 return tuples_[trans_state-1].hmm_state;
328 return state2id_[trans_state] + trans_index;
333 int32 max_phone_id = 0;
334 for (
int32 i = 0;
i < num_trans_state; ++
i) {
335 if (
tuples_[
i].phone > max_phone_id)
351 entry[tuple.
hmm_state].transitions.size());
354 return (entry[tuple.
hmm_state].transitions[trans_index].first + 1 ==
355 static_cast<int32>(entry.size()));
364 int32 phone = tuple.phone, hmm_state = tuple.hmm_state;
366 KALDI_ASSERT(static_cast<size_t>(hmm_state) < entry.size());
367 for (
int32 trans_index = 0;
368 trans_index < static_cast<int32>(entry[hmm_state].transitions.size());
370 if (entry[hmm_state].transitions[trans_index].first == hmm_state)
384 non_self_loop_prob = 1.0 - self_loop_prob;
385 if (non_self_loop_prob <= 0.0) {
386 KALDI_WARN <<
"ComputeDerivedOfProbs(): non-self-loop prob is " << non_self_loop_prob;
387 non_self_loop_prob = 1.0e-10;
406 if (token ==
"<Tuples>")
408 else if (token ==
"<Triples>")
412 KALDI_ASSERT(token ==
"</Triples>" || token ==
"</Tuples>");
423 bool is_hmm =
IsHmm();
425 if (!binary) os <<
"\n";
432 if (!binary) os <<
"\n";
439 if (!binary) os <<
"\n";
445 if (!binary) os <<
"\n";
447 if (!binary) os <<
"\n";
450 if (!binary) os <<
"\n";
452 if (!binary) os <<
"\n";
483 BaseFloat count_sum = 0.0, objf_impr_sum = 0.0;
484 int32 num_skipped = 0, num_floored = 0;
491 for (
int32 tidx = 0; tidx <
n; tidx++) {
493 counts(tidx) = stats(tid);
495 double tstate_tot = counts.
Sum();
496 count_sum += tstate_tot;
497 if (tstate_tot < cfg.
mincount) { num_skipped++; }
500 for (
int32 tidx = 0; tidx <
n; tidx++) {
504 for (
int32 tidx = 0; tidx <
n; tidx++)
505 new_probs(tidx) = counts(tidx) / tstate_tot;
507 new_probs.
Scale(1.0 / new_probs.
Sum());
508 for (
int32 tidx = 0; tidx <
n; tidx++)
509 new_probs(tidx) = std::max(new_probs(tidx), cfg.
floor);
512 for (
int32 tidx = 0; tidx <
n; tidx++) {
513 if (new_probs(tidx) == cfg.
floor) num_floored++;
514 double objf_change = counts(tidx) * (
Log(new_probs(tidx))
515 -
Log(old_probs(tidx)));
516 objf_impr_sum += objf_change;
519 for (
int32 tidx = 0; tidx <
n; tidx++) {
523 KALDI_ERR <<
"Log probs is inf or NaN: error in update or bad stats?";
528 KALDI_LOG <<
"TransitionModel::Update, objf change is " 529 << (objf_impr_sum / count_sum) <<
" per frame over " << count_sum
531 KALDI_LOG << num_floored <<
" probabilities floored, " << num_skipped
533 "skipped due to insuffient data (it is normal to have some skipped.)";
534 if (objf_impr_out) *objf_impr_out = objf_impr_sum;
535 if (count_out) *count_out = count_sum;
550 BaseFloat count_sum = 0.0, objf_impr_sum = 0.0;
557 for (
int32 tidx = 0; tidx <
n; tidx++) {
559 counts(tidx) = stats(tid);
561 double tstate_tot = counts.
Sum();
562 count_sum += tstate_tot;
564 for (
int32 tidx = 0; tidx <
n; tidx++) {
568 for (
int32 tidx = 0; tidx <
n; tidx++)
569 new_probs(tidx) = (counts(tidx) + cfg.
tau * old_probs(tidx)) /
570 (cfg.
tau + tstate_tot);
572 for (
int32 tidx = 0; tidx <
n; tidx++) {
573 double objf_change = counts(tidx) * (
Log(new_probs(tidx))
574 -
Log(old_probs(tidx)));
575 objf_impr_sum += objf_change;
578 for (
int32 tidx = 0; tidx <
n; tidx++) {
582 KALDI_ERR <<
"Log probs is inf or NaN: error in update or bad stats?";
586 KALDI_LOG <<
"Objf change is " << (objf_impr_sum / count_sum)
587 <<
" per frame over " << count_sum
589 if (objf_impr_out) *objf_impr_out = objf_impr_sum;
590 if (count_out) *count_out = count_sum;
605 BaseFloat count_sum = 0.0, objf_impr_sum = 0.0;
606 int32 num_skipped = 0, num_floored = 0;
608 std::map<int32, std::set<int32> > pdf_to_tstate;
612 pdf_to_tstate[pdf].insert(tstate);
615 pdf_to_tstate[pdf].insert(tstate);
618 std::map<int32, std::set<int32> >::iterator map_iter;
619 for (map_iter = pdf_to_tstate.begin();
620 map_iter != pdf_to_tstate.end();
623 const std::set<int32> &tstates = map_iter->second;
625 int32 one_tstate = *(tstates.begin());
630 for (std::set<int32>::const_iterator iter = tstates.begin();
631 iter != tstates.end();
633 int32 tstate = *iter;
635 KALDI_ERR <<
"Mismatch in #transition indices: you cannot " 636 "use the --share-for-pdfs option with this topology " 637 "and sharing scheme.";
638 for (
int32 tidx = 0; tidx <
n; tidx++) {
640 counts(tidx) += stats(tid);
643 double pdf_tot = counts.
Sum();
644 count_sum += pdf_tot;
645 if (pdf_tot < cfg.
mincount) { num_skipped++; }
652 for (
int32 tidx = 0; tidx <
n; tidx++) {
656 for (
int32 tidx = 0; tidx <
n; tidx++)
657 new_probs(tidx) = counts(tidx) / pdf_tot;
659 new_probs.
Scale(1.0 / new_probs.
Sum());
660 for (
int32 tidx = 0; tidx <
n; tidx++)
661 new_probs(tidx) = std::max(new_probs(tidx), cfg.
floor);
664 for (
int32 tidx = 0; tidx <
n; tidx++) {
665 if (new_probs(tidx) == cfg.
floor) num_floored++;
666 double objf_change = counts(tidx) * (
Log(new_probs(tidx))
667 -
Log(old_probs(tidx)));
668 objf_impr_sum += objf_change;
671 for (std::set<int32>::const_iterator iter = tstates.begin();
672 iter != tstates.end();
674 int32 tstate = *iter;
675 for (
int32 tidx = 0; tidx <
n; tidx++) {
679 KALDI_ERR <<
"Log probs is inf or NaN: error in update or bad stats?";
685 KALDI_LOG <<
"Objf change is " << (objf_impr_sum / count_sum)
686 <<
" per frame over " << count_sum <<
" frames; " 687 << num_floored <<
" probabilities floored, " 688 << num_skipped <<
" pdf-ids skipped due to insuffient data.";
689 if (objf_impr_out) *objf_impr_out = objf_impr_sum;
690 if (count_out) *count_out = count_sum;
704 BaseFloat count_sum = 0.0, objf_impr_sum = 0.0;
706 std::map<int32, std::set<int32> > pdf_to_tstate;
710 pdf_to_tstate[pdf].insert(tstate);
713 pdf_to_tstate[pdf].insert(tstate);
716 std::map<int32, std::set<int32> >::iterator map_iter;
717 for (map_iter = pdf_to_tstate.begin();
718 map_iter != pdf_to_tstate.end();
721 const std::set<int32> &tstates = map_iter->second;
723 int32 one_tstate = *(tstates.begin());
728 for (std::set<int32>::const_iterator iter = tstates.begin();
729 iter != tstates.end();
731 int32 tstate = *iter;
733 KALDI_ERR <<
"Mismatch in #transition indices: you cannot " 734 "use the --share-for-pdfs option with this topology " 735 "and sharing scheme.";
736 for (
int32 tidx = 0; tidx <
n; tidx++) {
738 counts(tidx) += stats(tid);
741 double pdf_tot = counts.
Sum();
742 count_sum += pdf_tot;
749 for (
int32 tidx = 0; tidx <
n; tidx++) {
753 for (
int32 tidx = 0; tidx <
n; tidx++)
754 new_probs(tidx) = (counts(tidx) + old_probs(tidx) * cfg.
tau) /
757 for (
int32 tidx = 0; tidx <
n; tidx++) {
758 double objf_change = counts(tidx) * (
Log(new_probs(tidx))
759 -
Log(old_probs(tidx)));
760 objf_impr_sum += objf_change;
763 for (std::set<int32>::const_iterator iter = tstates.begin();
764 iter != tstates.end();
766 int32 tstate = *iter;
767 for (
int32 tidx = 0; tidx <
n; tidx++) {
771 KALDI_ERR <<
"Log probs is inf or NaN: error in update or bad stats?";
776 KALDI_LOG <<
"Objf change is " << (objf_impr_sum / count_sum)
777 <<
" per frame over " << count_sum
779 if (objf_impr_out) *objf_impr_out = objf_impr_sum;
780 if (count_out) *count_out = count_sum;
788 return tuples_[trans_state-1].phone;
799 return entry[t.
hmm_state].self_loop_pdf_class;
801 return entry[t.
hmm_state].forward_pdf_class;
813 const std::vector<std::string> &phone_names,
817 bool is_hmm =
IsHmm();
821 std::string phone_name = phone_names[tuple.
phone];
823 os <<
"Transition-state " << tstate <<
": phone = " << phone_name
828 os <<
" forward-pdf = " << tuple.
forward_pdf <<
" self-loop-pdf = " 833 os <<
" Transition-id = " << tid <<
" p = " << p;
838 os <<
" count of pdf = " << (*occs)(tuple.
forward_pdf);
845 KALDI_ASSERT(static_cast<size_t>(hmm_state) < entry.size());
846 int32 next_hmm_state = entry[hmm_state].transitions[tidx].first;
848 os <<
" [" << hmm_state <<
" -> " << next_hmm_state <<
"]\n";
855 const std::vector<int32> &phones,
856 std::vector<int32> *pdfs) {
861 if (std::binary_search(phones.begin(), phones.end(),
870 if ((std::binary_search(pdfs->begin(), pdfs->end(),
872 std::binary_search(pdfs->begin(), pdfs->end(),
874 && !std::binary_search(phones.begin(), phones.end(),
881 const std::vector<int32> &pdfs,
882 std::vector<int32> *phones) {
887 if (std::binary_search(pdfs.begin(), pdfs.end(),
889 std::binary_search(pdfs.begin(), pdfs.end(),
896 if (std::binary_search(phones->begin(), phones->end(),
898 && !(std::binary_search(pdfs.begin(), pdfs.end(),
900 std::binary_search(pdfs.begin(), pdfs.end(),
919 KALDI_ASSERT(static_cast<size_t>(hmm_state) < entry.size());
920 return (static_cast<size_t>(trans_index) < entry[hmm_state].transitions.size()
921 && entry[hmm_state].transitions[trans_index].first == hmm_state);
virtual void GetPdfInfo(const std::vector< int32 > &phones, const std::vector< int32 > &num_pdf_classes, std::vector< std::vector< std::pair< int32, int32 > > > *pdf_info) const =0
GetPdfInfo returns a vector indexed by pdf-id, saying for each pdf which pairs of (phone...
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
std::vector< Tuple > tuples_
Tuples indexed by transition state minus one; the tuples are in sorted order which allows us to do th...
A structure defined inside HmmTopology to represent a HMM state.
int32 PairToTransitionId(int32 trans_state, int32 trans_index) const
void MleUpdate(const Vector< double > &stats, const MleTransitionUpdateConfig &cfg, BaseFloat *objf_impr_out, BaseFloat *count_out)
Does Maximum Likelihood estimation.
A class for storing topology information for phones.
std::vector< int32 > id2pdf_id_
void ComputeTuplesNotHmm(const ContextDependencyInterface &ctx_dep)
void ReadBasicType(std::istream &is, bool binary, T *t)
ReadBasicType is the name of the read function for bool, integer types, and floating-point types...
int32 TransitionStateToSelfLoopPdfClass(int32 trans_state) const
int32 TransitionStateToForwardPdfClass(int32 trans_state) const
int32 TransitionStateToForwardPdf(int32 trans_state) const
void ComputeTuplesIsHmm(const ContextDependencyInterface &ctx_dep)
int32 TransitionStateToHmmState(int32 trans_state) const
int32 TransitionIdToPdfClass(int32 trans_id) const
int32 SelfLoopOf(int32 trans_state) const
int32 num_pdfs_
This is actually one plus the highest-numbered pdf we ever got back from the tree (but the tree numbe...
int32 TupleToTransitionState(int32 phone, int32 hmm_state, int32 pdf, int32 self_loop_pdf) const
void ReadToken(std::istream &is, bool binary, std::string *str)
ReadToken gets the next token and puts it in str (exception on failure).
void Read(std::istream &is, bool binary)
Vector< BaseFloat > log_probs_
For each transition-id, the corresponding log-prob. Indexed by transition-id.
std::vector< HmmState > TopologyEntry
TopologyEntry is a typedef that represents the topology of a single (prototype) state.
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq's (removes duplicates) from a vector.
static const int32 kNoPdf
A constant used in the HmmTopology class as the pdf-class kNoPdf, which is used when a HMM-state is n...
void ComputeTuples(const ContextDependencyInterface &ctx_dep)
int32 NumPdfClasses(int32 phone) const
Returns the number of pdf-classes for this phone; throws exception if phone not covered by this topol...
void Print(std::ostream &os, const std::vector< std::string > &phone_names, const Vector< double > *occs=NULL)
Print will print the transition model in a human-readable way, for purposes of human inspection...
void Write(std::ostream &os, bool binary) const
bool GetPhonesForPdfs(const TransitionModel &trans_model, const std::vector< int32 > &pdfs, std::vector< int32 > *phones)
Works out which phones might correspond to the given pdfs.
int32 NumTransitionIds() const
Returns the total number of transition-ids (note, these are one-based).
void ExpectToken(std::istream &is, bool binary, const char *token)
ExpectToken tries to read in the given token, and throws an exception on failure. ...
void Read(std::istream &is, bool binary)
int32 TransitionIdToHmmState(int32 trans_id) const
int32 NumTransitionIndices(int32 trans_state) const
Returns the number of transition-indices for a particular transition-state.
bool IsSelfLoop(int32 trans_id) const
std::vector< int32 > id2state_
For each transition-id, the corresponding transition state (indexed by transition-id).
const TopologyEntry & TopologyForPhone(int32 phone) const
Returns the topology entry (i.e.
BaseFloat GetTransitionLogProb(int32 trans_id) const
TransitionModel()
Constructor that takes no arguments: typically used prior to calling Read.
std::vector< std::pair< int32, BaseFloat > > transitions
A list of transitions, indexed by what we call a 'transition-index'.
int32 TransitionIdToTransitionState(int32 trans_id) const
bool Compatible(const TransitionModel &other) const
returns true if all the integer class members are identical (but does not compare the transition prob...
#define KALDI_PARANOID_ASSERT(cond)
void WriteToken(std::ostream &os, bool binary, const char *token)
The WriteToken functions are for writing nonempty sequences of non-space characters.
MatrixIndexT Dim() const
Returns the dimension of the vector.
void Scale(Real alpha)
Multiplies all elements by this constant.
std::vector< int32 > state2id_
Gives the first transition_id of each transition-state; indexed by the transition-state.
void MapUpdateShared(const Vector< double > &stats, const MapTransitionUpdateConfig &cfg, BaseFloat *objf_impr_out, BaseFloat *count_out)
This version of the MapUpdate() function is for if the user specifies –share-for-pdfs=true.
int32 TransitionStateToPhone(int32 trans_state) const
Real Sum() const
Returns sum of the elements.
const std::vector< int32 > & GetPhones() const
Returns a reference to a sorted, unique list of phones covered by the topology (these phones will be ...
context-dep-itf.h provides a link between the tree-building code in ../tree/, and the FST code in ...
void Write(std::ostream &os, bool binary) const
void ComputeDerivedOfProbs()
BaseFloat GetTransitionLogProbIgnoringSelfLoops(int32 trans_id) const
Returns the log-probability of a particular non-self-loop transition after subtracting the probabilit...
#define KALDI_ASSERT(cond)
void WriteBasicType(std::ostream &os, bool binary, T t)
WriteBasicType is the name of the write function for bool, integer types, and floating-point types...
bool GetPdfsForPhones(const TransitionModel &trans_model, const std::vector< int32 > &phones, std::vector< int32 > *pdfs)
Works out which pdfs might correspond to the given phones.
bool IsSortedAndUniq(const std::vector< T > &vec)
Returns true if the vector is sorted and contains each element only once.
bool IsFinal(int32 trans_id) const
int32 TransitionIdToPhone(int32 trans_id) const
int32 NumTransitionStates() const
Returns the total number of transition-states (note, these are one-based).
BaseFloat GetTransitionProb(int32 trans_id) const
Vector< BaseFloat > non_self_loop_log_probs_
For each transition-state, the log of (1 - self-loop-prob).
void MapUpdate(const Vector< double > &stats, const MapTransitionUpdateConfig &cfg, BaseFloat *objf_impr_out, BaseFloat *count_out)
Does Maximum A Posteriori (MAP) estimation.
BaseFloat GetNonSelfLoopLogProb(int32 trans_state) const
Returns the log-prob of the non-self-loop probability mass for this transition state.
int32 TransitionStateToSelfLoopPdf(int32 trans_state) const
int32 TransitionIdToTransitionIndex(int32 trans_id) const
void MleUpdateShared(const Vector< double > &stats, const MleTransitionUpdateConfig &cfg, BaseFloat *objf_impr_out, BaseFloat *count_out)
This version of the Update() function is for if the user specifies –share-for-pdfs=true.