Classes and functions for creating FSTs from HMMs
Collaboration diagram for Classes and functions for creating FSTs from HMMs:

Classes

struct  HTransducerConfig
 Configuration class for the GetHTransducer() function; see The HTransducerConfig configuration class for context. More...
 
struct  HmmCacheHash
 

Typedefs

typedef unordered_map< std::pair< int32, std::vector< int32 > >, fst::VectorFst< fst::StdArc > *, HmmCacheHashHmmCacheType
 HmmCacheType is a map from (central-phone, sequence of pdf-ids) to FST, used as cache in GetHmmAsFsa, as an optimization. More...
 

Functions

fst::VectorFst< fst::StdArc > * GetHmmAsFsa (std::vector< int32 > context_window, const ContextDependencyInterface &ctx_dep, const TransitionModel &trans_model, const HTransducerConfig &config, HmmCacheType *cache=NULL)
 Called by GetHTransducer() and probably will not need to be called directly; it creates and returns the FST corresponding to the phone. More...
 
fst::VectorFst< fst::StdArc > * GetHmmAsFsaSimple (std::vector< int32 > context_window, const ContextDependencyInterface &ctx_dep, const TransitionModel &trans_model, BaseFloat prob_scale)
 Included mainly as a form of documentation, not used in any other code currently. More...
 
fst::VectorFst< fst::StdArc > * GetHTransducer (const std::vector< std::vector< int32 > > &ilabel_info, const ContextDependencyInterface &ctx_dep, const TransitionModel &trans_model, const HTransducerConfig &config, std::vector< int32 > *disambig_syms_left)
 Returns the H tranducer; result owned by caller. More...
 
void GetIlabelMapping (const std::vector< std::vector< int32 > > &ilabel_info_old, const ContextDependencyInterface &ctx_dep, const TransitionModel &trans_model, std::vector< int32 > *old2new_map)
 GetIlabelMapping produces a mapping that's similar to HTK's logical-to-physical model mapping (i.e. More...
 
void AddSelfLoops (const TransitionModel &trans_model, const std::vector< int32 > &disambig_syms, BaseFloat self_loop_scale, bool reorder, bool check_no_self_loops, fst::VectorFst< fst::StdArc > *fst)
 For context, see AddSelfLoops(). More...
 
void AddTransitionProbs (const TransitionModel &trans_model, const std::vector< int32 > &disambig_syms, BaseFloat transition_scale, BaseFloat self_loop_scale, fst::VectorFst< fst::StdArc > *fst)
 Adds transition-probs, with the supplied scales (see Scaling of transition and acoustic probabilities), to the graph. More...
 
void AddTransitionProbs (const TransitionModel &trans_model, BaseFloat transition_scale, BaseFloat self_loop_scale, Lattice *lat)
 This is as AddSelfLoops(), but operates on a Lattice, where it affects the graph part of the weight (the first element of the pair). More...
 
fst::VectorFst< fst::StdArc > * GetPdfToTransitionIdTransducer (const TransitionModel &trans_model)
 Returns a transducer from pdfs plus one (input) to transition-ids (output). More...
 
void ConvertTransitionIdsToPdfs (const TransitionModel &trans_model, const std::vector< int32 > &disambig_syms, fst::VectorFst< fst::StdArc > *fst)
 Converts all transition-ids in the FST to pdfs plus one. More...
 

Detailed Description

Typedef Documentation

◆ HmmCacheType

typedef unordered_map<std::pair<int32, std::vector<int32> >, fst::VectorFst<fst::StdArc>*, HmmCacheHash> HmmCacheType

HmmCacheType is a map from (central-phone, sequence of pdf-ids) to FST, used as cache in GetHmmAsFsa, as an optimization.

Definition at line 70 of file hmm-utils.h.

Function Documentation

◆ AddSelfLoops()

void AddSelfLoops ( const TransitionModel trans_model,
const std::vector< int32 > &  disambig_syms,
BaseFloat  self_loop_scale,
bool  reorder,
bool  check_no_self_loops,
fst::VectorFst< fst::StdArc > *  fst 
)

For context, see AddSelfLoops().

Expands an FST that has been built without self-loops, and adds the self-loops (it also needs to modify the probability of the non-self-loop ones, as the graph without self-loops was created in such a way that it was stochastic). Note that the disambig_syms will be empty in some recipes (e.g. if you already removed the disambiguation symbols). This function will treat numbers over 10000000 (kNontermBigNumber) the same as disambiguation symbols, assuming they are special symbols for grammar decoding.

Parameters
trans_model[in] Transition model
disambig_syms[in] Sorted, uniq list of disambiguation symbols, required if the graph contains disambiguation symbols but only needed for sanity checks.
self_loop_scale[in] Transition-probability scale for self-loops; c.f. Scaling of transition and acoustic probabilities
reorder[in] If true, reorders the transitions (see Reordering transitions). You'll normally want this to be true.
check_no_self_loops[in] If true, it will check that there are no self-loops in the original graph; you'll normally want this to be true. If false, it will allow them, and will add self-loops after the original self-loop transitions, assuming reorder==true... this happens to be what we want when converting normal to unconstrained chain examples. WARNING: this was added in 2018; if you get a compilation error, add this as 'true', which emulates the behavior of older code.
fst[in, out] The FST to be modified.

Definition at line 602 of file hmm-utils.cc.

References kaldi::AddSelfLoopsNoReorder(), kaldi::AddSelfLoopsReorder(), and KALDI_ASSERT.

Referenced by TrainingGraphCompiler::CompileGraph(), TrainingGraphCompiler::CompileGraphs(), kaldi::CoverageTest(), main(), and kaldi::ScoringTest().

607  {
608  KALDI_ASSERT(fst->Start() != fst::kNoStateId);
609  if (reorder)
610  AddSelfLoopsReorder(trans_model, disambig_syms, self_loop_scale,
611  check_no_self_loops, fst);
612  else
613  AddSelfLoopsNoReorder(trans_model, disambig_syms, self_loop_scale,
614  check_no_self_loops, fst);
615 }
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
static void AddSelfLoopsNoReorder(const TransitionModel &trans_model, const std::vector< int32 > &disambig_syms, BaseFloat self_loop_scale, bool check_no_self_loops, fst::VectorFst< fst::StdArc > *fst)
Definition: hmm-utils.cc:555
static void AddSelfLoopsReorder(const TransitionModel &trans_model, const std::vector< int32 > &disambig_syms, BaseFloat self_loop_scale, bool check_no_self_loops, fst::VectorFst< fst::StdArc > *fst)
Definition: hmm-utils.cc:472
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ AddTransitionProbs() [1/2]

void AddTransitionProbs ( const TransitionModel trans_model,
const std::vector< int32 > &  disambig_syms,
BaseFloat  transition_scale,
BaseFloat  self_loop_scale,
fst::VectorFst< fst::StdArc > *  fst 
)

Adds transition-probs, with the supplied scales (see Scaling of transition and acoustic probabilities), to the graph.

Useful if you want to create a graph without transition probs, then possibly train the model (including the transition probs) but keep the graph fixed, and add back in the transition probs. It assumes the fst has transition-ids on it. It is not an error if the FST has no states (nothing will be done).

Parameters
trans_model[in] The transition model
disambig_syms[in] A list of disambiguation symbols, required if the graph has disambiguation symbols on its input but only used for checks.
transition_scale[in] A scale on transition-probabilities apart from those involving self-loops; see Scaling of transition and acoustic probabilities.
self_loop_scale[in] A scale on self-loop transition probabilities; see Scaling of transition and acoustic probabilities.
fst[in, out] The FST to be modified.

Definition at line 1088 of file hmm-utils.cc.

References kaldi::GetScaledTransitionLogProb(), kaldi::IsSortedAndUniq(), KALDI_ASSERT, KALDI_ERR, TransitionModel::NumTransitionIds(), and fst::Times().

Referenced by main().

1092  {
1093  using namespace fst;
1094  KALDI_ASSERT(IsSortedAndUniq(disambig_syms));
1095  int num_tids = trans_model.NumTransitionIds();
1096  for (StateIterator<VectorFst<StdArc> > siter(*fst);
1097  !siter.Done();
1098  siter.Next()) {
1099  for (MutableArcIterator<VectorFst<StdArc> > aiter(fst, siter.Value());
1100  !aiter.Done();
1101  aiter.Next()) {
1102  StdArc arc = aiter.Value();
1103  StdArc::Label l = arc.ilabel;
1104  if (l >= 1 && l <= num_tids) { // a transition-id.
1105  BaseFloat scaled_log_prob = GetScaledTransitionLogProb(trans_model,
1106  l,
1107  transition_scale,
1108  self_loop_scale);
1109  arc.weight = Times(arc.weight, TropicalWeight(-scaled_log_prob));
1110  } else if (l != 0) {
1111  if (!std::binary_search(disambig_syms.begin(), disambig_syms.end(),
1112  arc.ilabel))
1113  KALDI_ERR << "AddTransitionProbs: invalid symbol " << arc.ilabel
1114  << " on graph input side.";
1115  }
1116  aiter.SetValue(arc);
1117  }
1118  }
1119 }
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
fst::StdArc StdArc
LatticeWeightTpl< FloatType > Times(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2)
#define KALDI_ERR
Definition: kaldi-error.h:147
fst::StdArc::Label Label
float BaseFloat
static BaseFloat GetScaledTransitionLogProb(const TransitionModel &trans_model, int32 trans_id, BaseFloat transition_scale, BaseFloat self_loop_scale)
Definition: hmm-utils.cc:1065
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
bool IsSortedAndUniq(const std::vector< T > &vec)
Returns true if the vector is sorted and contains each element only once.
Definition: stl-utils.h:63

◆ AddTransitionProbs() [2/2]

void AddTransitionProbs ( const TransitionModel trans_model,
BaseFloat  transition_scale,
BaseFloat  self_loop_scale,
Lattice lat 
)

This is as AddSelfLoops(), but operates on a Lattice, where it affects the graph part of the weight (the first element of the pair).

Definition at line 1121 of file hmm-utils.cc.

References kaldi::GetScaledTransitionLogProb(), KALDI_ERR, and TransitionModel::NumTransitionIds().

1124  {
1125  using namespace fst;
1126  int num_tids = trans_model.NumTransitionIds();
1127  for (fst::StateIterator<Lattice> siter(*lat);
1128  !siter.Done();
1129  siter.Next()) {
1130  for (MutableArcIterator<Lattice> aiter(lat, siter.Value());
1131  !aiter.Done();
1132  aiter.Next()) {
1133  LatticeArc arc = aiter.Value();
1134  LatticeArc::Label l = arc.ilabel;
1135  if (l >= 1 && l <= num_tids) { // a transition-id.
1136  BaseFloat scaled_log_prob = GetScaledTransitionLogProb(trans_model,
1137  l,
1138  transition_scale,
1139  self_loop_scale);
1140  // cost is negated log prob.
1141  arc.weight.SetValue1(arc.weight.Value1() - scaled_log_prob);
1142  } else if (l != 0) {
1143  KALDI_ERR << "AddTransitionProbs: invalid symbol " << arc.ilabel
1144  << " on lattice input side.";
1145  }
1146  aiter.SetValue(arc);
1147  }
1148  }
1149 }
fst::ArcTpl< LatticeWeight > LatticeArc
Definition: kaldi-lattice.h:40
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
#define KALDI_ERR
Definition: kaldi-error.h:147
fst::StdArc::Label Label
float BaseFloat
static BaseFloat GetScaledTransitionLogProb(const TransitionModel &trans_model, int32 trans_id, BaseFloat transition_scale, BaseFloat self_loop_scale)
Definition: hmm-utils.cc:1065

◆ ConvertTransitionIdsToPdfs()

void kaldi::ConvertTransitionIdsToPdfs ( const TransitionModel trans_model,
const std::vector< int32 > &  disambig_syms,
fst::VectorFst< fst::StdArc > *  fst 
)

Converts all transition-ids in the FST to pdfs plus one.

Placeholder: not implemented yet!

◆ GetHmmAsFsa()

fst::VectorFst< fst::StdArc > * GetHmmAsFsa ( std::vector< int32 context_window,
const ContextDependencyInterface ctx_dep,
const TransitionModel trans_model,
const HTransducerConfig config,
HmmCacheType cache = NULL 
)

Called by GetHTransducer() and probably will not need to be called directly; it creates and returns the FST corresponding to the phone.

It's actually an acceptor (ilabels equal to olabels), which is why this is called "Fsa" not "Fst". This acceptor does not include self-loops; you have to call AddSelfLoops() for that. (We do that at a later graph compilation phase, for efficiency). The labels on the FSA correspond to transition-ids.

as the symbols. For documentation in context, see The function GetHmmAsFst()

Parameters
context_windowA vector representing the phonetic context; see here for explanation.
ctx_depThe object that contains the phonetic decision-tree
trans_modelThe transition-model object, which provides the mappings to transition-ids and also the transition probabilities.
configConfiguration object, see HTransducerConfig.
cacheObject used as a lookaside buffer to save computation; if it finds that the object it needs is already there, it will just return a pointer value from "cache"– not that this means you have to be careful not to delete things twice.

Definition at line 32 of file hmm-utils.cc.

References fst::ApplyProbabilityScale(), ContextDependencyInterface::CentralPosition(), ContextDependencyInterface::Compute(), ContextDependencyInterface::ContextWidth(), TransitionModel::GetTopo(), TransitionModel::GetTransitionLogProbIgnoringSelfLoops(), rnnlm::i, KALDI_ASSERT, KALDI_ERR, kaldi::kNoPdf, kaldi::Log(), HmmTopology::NumPdfClasses(), TransitionModel::PairToTransitionId(), fst::RemoveEpsLocal(), HmmTopology::TopologyForPhone(), HTransducerConfig::transition_scale, and TransitionModel::TupleToTransitionState().

Referenced by kaldi::GetHTransducer().

37  {
38  using namespace fst;
39 
40  if (static_cast<int32>(phone_window.size()) != ctx_dep.ContextWidth())
41  KALDI_ERR << "Context size mismatch, ilabel-info [from context FST is "
42  << phone_window.size() << ", context-dependency object "
43  "expects " << ctx_dep.ContextWidth();
44 
45  int P = ctx_dep.CentralPosition();
46  int32 phone = phone_window[P];
47  if (phone == 0)
48  KALDI_ERR << "phone == 0. Some mismatch happened, or there is "
49  "a code error.";
50 
51  const HmmTopology &topo = trans_model.GetTopo();
52  const HmmTopology::TopologyEntry &entry = topo.TopologyForPhone(phone);
53 
54  // vector of the pdfs, indexed by pdf-class (pdf-classes must start from zero
55  // and be contiguous).
56  std::vector<int32> pdfs(topo.NumPdfClasses(phone));
57  for (int32 pdf_class = 0;
58  pdf_class < static_cast<int32>(pdfs.size());
59  pdf_class++) {
60  if (! ctx_dep.Compute(phone_window, pdf_class, &(pdfs[pdf_class])) ) {
61  std::ostringstream ctx_ss;
62  for (size_t i = 0; i < phone_window.size(); i++)
63  ctx_ss << phone_window[i] << ' ';
64  KALDI_ERR << "GetHmmAsFsa: context-dependency object could not produce "
65  << "an answer: pdf-class = " << pdf_class << " ctx-window = "
66  << ctx_ss.str() << ". This probably points "
67  "to either a coding error in some graph-building process, "
68  "a mismatch of topology with context-dependency object, the "
69  "wrong FST being passed on a command-line, or something of "
70  " that general nature.";
71  }
72  }
73  std::pair<int32, std::vector<int32> > cache_index(phone, pdfs);
74  if (cache != NULL) {
75  HmmCacheType::iterator iter = cache->find(cache_index);
76  if (iter != cache->end())
77  return iter->second;
78  }
79 
80  VectorFst<StdArc> *ans = new VectorFst<StdArc>;
81 
82  typedef StdArc Arc;
83  typedef Arc::Weight Weight;
84  typedef Arc::StateId StateId;
85  typedef Arc::Label Label;
86 
87  std::vector<StateId> state_ids;
88  for (size_t i = 0; i < entry.size(); i++)
89  state_ids.push_back(ans->AddState());
90  KALDI_ASSERT(state_ids.size() != 0); // Or empty topology entry.
91  ans->SetStart(state_ids[0]);
92  StateId final = state_ids.back();
93  ans->SetFinal(final, Weight::One());
94 
95  for (int32 hmm_state = 0;
96  hmm_state < static_cast<int32>(entry.size());
97  hmm_state++) {
98  int32 forward_pdf_class = entry[hmm_state].forward_pdf_class, forward_pdf;
99  int32 self_loop_pdf_class = entry[hmm_state].self_loop_pdf_class, self_loop_pdf;
100  if (forward_pdf_class == kNoPdf) { // nonemitting state.
101  forward_pdf = kNoPdf;
102  self_loop_pdf = kNoPdf;
103  } else {
104  KALDI_ASSERT(forward_pdf_class < static_cast<int32>(pdfs.size()));
105  KALDI_ASSERT(self_loop_pdf_class < static_cast<int32>(pdfs.size()));
106  forward_pdf = pdfs[forward_pdf_class];
107  self_loop_pdf = pdfs[self_loop_pdf_class];
108  }
109  int32 trans_idx;
110  for (trans_idx = 0;
111  trans_idx < static_cast<int32>(entry[hmm_state].transitions.size());
112  trans_idx++) {
113  BaseFloat log_prob;
114  Label label;
115  int32 dest_state = entry[hmm_state].transitions[trans_idx].first;
116  bool is_self_loop = (dest_state == hmm_state);
117  if (is_self_loop)
118  continue; // We will add self-loops in at a later stage of processing,
119  // not in this function.
120  if (forward_pdf_class == kNoPdf) {
121  // no pdf, hence non-estimated probability.
122  // [would not happen with normal topology] . There is no transition-state
123  // involved in this case.
124  log_prob = Log(entry[hmm_state].transitions[trans_idx].second);
125  label = 0;
126  } else { // normal probability.
127  int32 trans_state =
128  trans_model.TupleToTransitionState(phone, hmm_state, forward_pdf, self_loop_pdf);
129  int32 trans_id =
130  trans_model.PairToTransitionId(trans_state, trans_idx);
131  log_prob = trans_model.GetTransitionLogProbIgnoringSelfLoops(trans_id);
132  // log_prob is a negative number (or zero)...
133  label = trans_id;
134  }
135  // Will add probability-scale later (we may want to push first).
136  ans->AddArc(state_ids[hmm_state],
137  Arc(label, label, Weight(-log_prob), state_ids[dest_state]));
138  }
139  }
140 
141  fst::RemoveEpsLocal(ans); // this is safe and will not blow up.
142 
143  // Now apply probability scale.
144  // We waited till after the possible weight-pushing steps,
145  // because weight-pushing needs "real" weights in order to work.
146  ApplyProbabilityScale(config.transition_scale, ans);
147  if (cache != NULL)
148  (*cache)[cache_index] = ans;
149  return ans;
150 }
fst::StdArc::StateId StateId
void RemoveEpsLocal(MutableFst< Arc > *fst)
RemoveEpsLocal remove some (but not necessarily all) epsilons in an FST, using an algorithm that is g...
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
fst::StdArc StdArc
kaldi::int32 int32
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...
Definition: hmm-topology.h:86
double Log(double x)
Definition: kaldi-math.h:100
#define KALDI_ERR
Definition: kaldi-error.h:147
fst::StdArc::Label Label
void ApplyProbabilityScale(float scale, MutableFst< Arc > *fst)
ApplyProbabilityScale is applicable to FSTs in the log or tropical semiring.
float BaseFloat
fst::StdArc::Weight Weight
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ GetHmmAsFsaSimple()

fst::VectorFst< fst::StdArc > * GetHmmAsFsaSimple ( std::vector< int32 context_window,
const ContextDependencyInterface ctx_dep,
const TransitionModel trans_model,
BaseFloat  prob_scale 
)

Included mainly as a form of documentation, not used in any other code currently.

Creates the acceptor FST with self-loops, and with fewer options.

Definition at line 155 of file hmm-utils.cc.

References ContextDependencyInterface::CentralPosition(), ContextDependencyInterface::Compute(), ContextDependencyInterface::ContextWidth(), TransitionModel::GetTopo(), TransitionModel::GetTransitionLogProb(), rnnlm::i, KALDI_ASSERT, KALDI_ERR, kaldi::kNoPdf, kaldi::Log(), TransitionModel::PairToTransitionId(), HmmTopology::TopologyForPhone(), and TransitionModel::TupleToTransitionState().

Referenced by kaldi::GetRandomAlignmentForPhone().

158  {
159  using namespace fst;
160 
161  if (static_cast<int32>(phone_window.size()) != ctx_dep.ContextWidth())
162  KALDI_ERR <<"Context size mismatch, ilabel-info [from context FST is "
163  <<(phone_window.size())<<", context-dependency object "
164  "expects "<<(ctx_dep.ContextWidth());
165 
166  int P = ctx_dep.CentralPosition();
167  int32 phone = phone_window[P];
168  KALDI_ASSERT(phone != 0);
169 
170  const HmmTopology &topo = trans_model.GetTopo();
171  const HmmTopology::TopologyEntry &entry = topo.TopologyForPhone(phone);
172 
173  VectorFst<StdArc> *ans = new VectorFst<StdArc>;
174 
175  // Create a mini-FST with a superfinal state [in case we have emitting
176  // final-states, which we usually will.]
177  typedef StdArc Arc;
178  typedef Arc::Weight Weight;
179  typedef Arc::StateId StateId;
180  typedef Arc::Label Label;
181 
182  std::vector<StateId> state_ids;
183  for (size_t i = 0; i < entry.size(); i++)
184  state_ids.push_back(ans->AddState());
185  KALDI_ASSERT(state_ids.size() > 1); // Or invalid topology entry.
186  ans->SetStart(state_ids[0]);
187  StateId final = state_ids.back();
188  ans->SetFinal(final, Weight::One());
189 
190  for (int32 hmm_state = 0;
191  hmm_state < static_cast<int32>(entry.size());
192  hmm_state++) {
193  int32 forward_pdf_class = entry[hmm_state].forward_pdf_class, forward_pdf;
194  int32 self_loop_pdf_class = entry[hmm_state].self_loop_pdf_class, self_loop_pdf;
195  if (forward_pdf_class == kNoPdf) { // nonemitting state; not generally used.
196  forward_pdf = kNoPdf;
197  self_loop_pdf = kNoPdf;
198  } else {
199  bool ans = ctx_dep.Compute(phone_window, forward_pdf_class, &forward_pdf);
200  KALDI_ASSERT(ans && "Context-dependency computation failed.");
201  ans = ctx_dep.Compute(phone_window, self_loop_pdf_class, &self_loop_pdf);
202  KALDI_ASSERT(ans && "Context-dependency computation failed.");
203  }
204  int32 trans_idx;
205  for (trans_idx = 0;
206  trans_idx < static_cast<int32>(entry[hmm_state].transitions.size());
207  trans_idx++) {
208  BaseFloat log_prob;
209  Label label;
210  int32 dest_state = entry[hmm_state].transitions[trans_idx].first;
211  if (forward_pdf_class == kNoPdf) {
212  // no pdf, hence non-estimated probability. very unusual case. [would
213  // not happen with normal topology] . There is no transition-state
214  // involved in this case.
215  KALDI_ASSERT(hmm_state != dest_state);
216  log_prob = Log(entry[hmm_state].transitions[trans_idx].second);
217  label = 0;
218  } else { // normal probability.
219  int32 trans_state =
220  trans_model.TupleToTransitionState(phone, hmm_state, forward_pdf, self_loop_pdf);
221  int32 trans_id =
222  trans_model.PairToTransitionId(trans_state, trans_idx);
223  log_prob = prob_scale * trans_model.GetTransitionLogProb(trans_id);
224  // log_prob is a negative number (or zero)...
225  label = trans_id;
226  }
227  ans->AddArc(state_ids[hmm_state],
228  Arc(label, label, Weight(-log_prob), state_ids[dest_state]));
229  }
230  }
231  return ans;
232 }
fst::StdArc::StateId StateId
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
fst::StdArc StdArc
kaldi::int32 int32
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...
Definition: hmm-topology.h:86
double Log(double x)
Definition: kaldi-math.h:100
#define KALDI_ERR
Definition: kaldi-error.h:147
fst::StdArc::Label Label
float BaseFloat
fst::StdArc::Weight Weight
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ GetHTransducer()

fst::VectorFst< fst::StdArc > * GetHTransducer ( const std::vector< std::vector< int32 > > &  ilabel_info,
const ContextDependencyInterface ctx_dep,
const TransitionModel trans_model,
const HTransducerConfig config,
std::vector< int32 > *  disambig_syms_left 
)

Returns the H tranducer; result owned by caller.

Caution: our version of the H transducer does not include self-loops; you have to add those later. See GetHTransducer(). The H transducer has on the input transition-ids, and also possibly some disambiguation symbols, which will be put in disambig_syms. The output side contains the identifiers that are indexes into "ilabel_info" (these represent phones-in-context or disambiguation symbols). The ilabel_info vector allows GetHTransducer to map from symbols to phones-in-context (i.e. phonetic context windows). Any singleton symbols in the ilabel_info vector which are not phones, will be treated as disambiguation symbols. [Not all recipes use these]. The output "disambig_syms_left" will be set to a list of the disambiguation symbols on the input of the transducer (i.e. same symbol type as whatever is on the input of the transducer

Definition at line 254 of file hmm-utils.cc.

References kaldi::DeletePointers(), fst::GetEncodingMultiple(), kaldi::GetHmmAsFsa(), TransitionModel::GetPhones(), rnnlm::j, KALDI_ASSERT, KALDI_ERR, fst::kNontermBigNumber, fst::MakeLoopFst(), kaldi::MakeTrivialAcceptor(), HTransducerConfig::nonterm_phones_offset, TransitionModel::NumTransitionIds(), and kaldi::SortAndUniq().

Referenced by TrainingGraphCompiler::CompileGraph(), TrainingGraphCompiler::CompileGraphs(), and main().

258  {
259  KALDI_ASSERT(ilabel_info.size() >= 1 && ilabel_info[0].size() == 0); // make sure that eps == eps.
260  HmmCacheType cache;
261  // "cache" is an optimization that prevents GetHmmAsFsa repeating work
262  // unnecessarily.
263  using namespace fst;
264  typedef StdArc Arc;
265  typedef Arc::Weight Weight;
266  typedef Arc::StateId StateId;
267  typedef Arc::Label Label;
268 
269  std::vector<const ExpandedFst<Arc>* > fsts(ilabel_info.size(), NULL);
270  std::vector<int32> phones = trans_model.GetPhones();
271 
272  KALDI_ASSERT(disambig_syms_left != 0);
273  disambig_syms_left->clear();
274 
275  int32 first_disambig_sym = trans_model.NumTransitionIds() + 1; // First disambig symbol we can have on the input side.
276  int32 next_disambig_sym = first_disambig_sym;
277 
278  if (ilabel_info.size() > 0)
279  KALDI_ASSERT(ilabel_info[0].size() == 0); // make sure epsilon is epsilon...
280 
281  for (int32 j = 1; j < static_cast<int32>(ilabel_info.size()); j++) { // zero is eps.
282  KALDI_ASSERT(!ilabel_info[j].empty());
283  if (ilabel_info[j][0] < 0 ||
284  (ilabel_info[j][0] == 0 && ilabel_info[j].size() == 1)) {
285  // disambig symbol or special symbol for grammar FSTs.
286  if (ilabel_info[j].size() == 1) {
287  // disambiguation symbol.
288  int32 disambig_sym_left = next_disambig_sym++;
289  disambig_syms_left->push_back(disambig_sym_left);
290  fsts[j] = MakeTrivialAcceptor(disambig_sym_left);
291  } else if (ilabel_info[j].size() == 2) {
292  if (config.nonterm_phones_offset <= 0) {
293  KALDI_ERR << "ilabel-info seems to be for grammar-FST. You need to "
294  "supply the --nonterm-phones-offset option.";
295  }
296  int32 nonterm_phones_offset = config.nonterm_phones_offset,
297  nonterminal = -ilabel_info[j][0],
298  left_context_phone = ilabel_info[j][1];
299  if (nonterminal <= nonterm_phones_offset ||
300  left_context_phone <= 0 ||
301  left_context_phone > nonterm_phones_offset) {
302  KALDI_ERR << "Could not interpret this ilabel-info with "
303  "--nonterm-phones-offset=" << nonterm_phones_offset
304  << ": nonterminal,left-context-phone="
305  << nonterminal << ',' << left_context_phone;
306  }
307  int32 big_number = static_cast<int32>(fst::kNontermBigNumber),
308  encoding_multiple = fst::GetEncodingMultiple(nonterm_phones_offset);
309  int32 encoded_symbol = big_number + nonterminal * encoding_multiple +
310  left_context_phone;
311  fsts[j] = MakeTrivialAcceptor(encoded_symbol);
312  } else {
313  KALDI_ERR << "Could not decode this ilabel_info entry.";
314  }
315  } else { // Real phone-in-context.
316  std::vector<int32> phone_window = ilabel_info[j];
317 
318  VectorFst<Arc> *fst = GetHmmAsFsa(phone_window,
319  ctx_dep,
320  trans_model,
321  config,
322  &cache);
323  fsts[j] = fst;
324  }
325  }
326 
327  VectorFst<Arc> *ans = MakeLoopFst(fsts);
328  SortAndUniq(&fsts); // remove duplicate pointers, which we will have
329  // in general, since we used the cache.
330  DeletePointers(&fsts);
331  return ans;
332 }
fst::StdArc::StateId StateId
void DeletePointers(std::vector< A *> *v)
Deletes any non-NULL pointers in the vector v, and sets the corresponding entries of v to NULL...
Definition: stl-utils.h:184
static fst::VectorFst< fst::StdArc > * MakeTrivialAcceptor(int32 label)
This utility function, used in GetHTransducer(), creates an FSA (finite state acceptor, i.e.
Definition: hmm-utils.cc:239
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
fst::StdArc StdArc
unordered_map< std::pair< int32, std::vector< int32 > >, fst::VectorFst< fst::StdArc > *, HmmCacheHash > HmmCacheType
HmmCacheType is a map from (central-phone, sequence of pdf-ids) to FST, used as cache in GetHmmAsFsa...
Definition: hmm-utils.h:70
kaldi::int32 int32
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq&#39;s (removes duplicates) from a vector.
Definition: stl-utils.h:39
#define KALDI_ERR
Definition: kaldi-error.h:147
VectorFst< Arc > * MakeLoopFst(const std::vector< const ExpandedFst< Arc > *> &fsts)
MakeLoopFst creates an FST that has a state that is both initial and final (weight == Weight::One())...
fst::StdArc::Label Label
fst::StdArc::Weight Weight
fst::VectorFst< fst::StdArc > * GetHmmAsFsa(std::vector< int32 > phone_window, const ContextDependencyInterface &ctx_dep, const TransitionModel &trans_model, const HTransducerConfig &config, HmmCacheType *cache)
Called by GetHTransducer() and probably will not need to be called directly; it creates and returns t...
Definition: hmm-utils.cc:32
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
int32 GetEncodingMultiple(int32 nonterm_phones_offset)

◆ GetIlabelMapping()

void GetIlabelMapping ( const std::vector< std::vector< int32 > > &  ilabel_info_old,
const ContextDependencyInterface ctx_dep,
const TransitionModel trans_model,
std::vector< int32 > *  old2new_map 
)

GetIlabelMapping produces a mapping that's similar to HTK's logical-to-physical model mapping (i.e.

the xwrd.clustered.mlist files). It groups together "logical HMMs" (i.e. in our world, phonetic context windows) that share the same sequence of transition-ids. This can be used in an optional graph-creation step that produces a remapped form of CLG that can be more productively determinized and minimized. This is used in the command-line program make-ilabel-transducer.cc.

Parameters
ilabel_info_old[in] The original ilabel_info vector
ctx_dep[in] The tree
trans_model[in] The transition-model object
old2new_map[out] The output; this vector, which is of size equal to the number of new labels, is a mapping to the old labels such that we could create a vector ilabel_info_new such that ilabel_info_new[i] == ilabel_info_old[old2new_map[i]]

The next variable maps from the (central-phone, pdf-sequence) to the index in ilabel_info_old corresponding to the first phone-in-context that we saw for it. We use this to work out the logical-to-physical mapping. Each time we handle a phone in context, we see if its (central-phone, pdf-sequence) has already been seen; if yes, we map to the original phone-sequence, if no, we create a new "phyiscal-HMM" and there is no mapping.

old2old_map is a map from the old ilabels to themselves (but duplicates are mapped to one unique one.

Definition at line 335 of file hmm-utils.cc.

References ContextDependencyInterface::CentralPosition(), ContextDependencyInterface::Compute(), ContextDependencyInterface::ContextWidth(), TransitionModel::GetTopo(), rnnlm::i, KALDI_ASSERT, KALDI_ERR, HmmTopology::NumPdfClasses(), and kaldi::WriteIntegerVector().

Referenced by main().

338  {
339  KALDI_ASSERT(old2new_map != NULL);
340 
348  std::map<std::pair<int32, std::vector<int32> >, int32 >
349  pair_to_physical;
350 
351  int32 N = ctx_dep.ContextWidth(),
352  P = ctx_dep.CentralPosition();
353  int32 num_syms_old = ilabel_info_old.size();
354 
357  std::vector<int32> old2old_map(num_syms_old);
358  old2old_map[0] = 0;
359  for (int32 i = 1; i < num_syms_old; i++) {
360  const std::vector<int32> &vec = ilabel_info_old[i];
361  if (vec.size() == 1 && vec[0] <= 0) { // disambig.
362  old2old_map[i] = i;
363  } else {
364  KALDI_ASSERT(vec.size() == static_cast<size_t>(N));
365  // work out the vector of context-dependent phone
366  int32 central_phone = vec[P];
367  int32 num_pdf_classes = trans_model.GetTopo().NumPdfClasses(central_phone);
368  std::vector<int32> state_seq(num_pdf_classes); // Indexed by pdf-class
369  for (int32 pdf_class = 0; pdf_class < num_pdf_classes; pdf_class++) {
370  if (!ctx_dep.Compute(vec, pdf_class, &(state_seq[pdf_class]))) {
371  std::ostringstream ss;
372  WriteIntegerVector(ss, false, vec);
373  KALDI_ERR << "tree did not succeed in converting phone window "<<ss.str();
374  }
375  }
376  std::pair<int32, std::vector<int32> > pr(central_phone, state_seq);
377  std::map<std::pair<int32, std::vector<int32> >, int32 >::iterator iter
378  = pair_to_physical.find(pr);
379  if (iter == pair_to_physical.end()) { // first time we saw something like this.
380  pair_to_physical[pr] = i;
381  old2old_map[i] = i;
382  } else { // seen it before. look up in the map, the index we point to.
383  old2old_map[i] = iter->second;
384  }
385  }
386  }
387 
388  std::vector<bool> seen(num_syms_old, false);
389  for (int32 i = 0; i < num_syms_old; i++)
390  seen[old2old_map[i]] = true;
391 
392  // Now work out the elements of old2new_map corresponding to
393  // things that are first in their equivalence class. We're just
394  // compacting the labels to those for which seen[i] == true.
395  int32 cur_id = 0;
396  old2new_map->resize(num_syms_old);
397  for (int32 i = 0; i < num_syms_old; i++)
398  if (seen[i])
399  (*old2new_map)[i] = cur_id++;
400  // fill in the other elements of old2new_map.
401  for (int32 i = 0; i < num_syms_old; i++)
402  (*old2new_map)[i] = (*old2new_map)[old2old_map[i]];
403 }
kaldi::int32 int32
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void WriteIntegerVector(std::ostream &os, bool binary, const std::vector< T > &v)
Function for writing STL vectors of integer types.
Definition: io-funcs-inl.h:198

◆ GetPdfToTransitionIdTransducer()

fst::VectorFst< fst::StdArc > * GetPdfToTransitionIdTransducer ( const TransitionModel trans_model)

Returns a transducer from pdfs plus one (input) to transition-ids (output).

Currenly of use only for testing.

Definition at line 407 of file hmm-utils.cc.

References TransitionModel::NumTransitionIds(), and TransitionModel::TransitionIdToPdf().

Referenced by main().

407  {
408  using namespace fst;
409  VectorFst<StdArc> *ans = new VectorFst<StdArc>;
411  typedef StdArc Arc;
412  ans->AddState();
413  ans->SetStart(0);
414  ans->SetFinal(0, Weight::One());
415  for (int32 tid = 1; tid <= trans_model.NumTransitionIds(); tid++) {
416  int32 pdf = trans_model.TransitionIdToPdf(tid);
417  ans->AddArc(0, Arc(pdf+1, tid, Weight::One(), 0)); // note the offset of 1 on the pdfs.
418  // it's because 0 is a valid pdf.
419  }
420  return ans;
421 }
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
fst::StdArc StdArc
kaldi::int32 int32
fst::StdArc::Weight Weight