All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 >
*, HmmCacheHash > 
HmmCacheType
 HmmCacheType is a map from (central-phone, sequence of pdf-ids) to FST, used as cache in GetHmmAsFst, as an optimization. More...
 

Functions

fst::VectorFst< fst::StdArc > * GetHmmAsFst (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 the FST corresponding to the phone. More...
 
fst::VectorFst< fst::StdArc > * GetHmmAsFstSimple (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,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

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 GetHmmAsFst, as an optimization.

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

Function Documentation

void AddSelfLoops ( const TransitionModel &  trans_model,
const std::vector< int32 > &  disambig_syms,
BaseFloat  self_loop_scale,
bool  reorder,
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).

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).
fst[in, out] The FST to be modified.

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

References kaldi::AddSelfLoopsAfter(), kaldi::AddSelfLoopsBefore(), and KALDI_ASSERT.

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

563  {
564  KALDI_ASSERT(fst->Start() != fst::kNoStateId);
565  if (reorder)
566  AddSelfLoopsBefore(trans_model, disambig_syms, self_loop_scale, fst);
567  else
568  AddSelfLoopsAfter(trans_model, disambig_syms, self_loop_scale, fst);
569 }
static void AddSelfLoopsBefore(const TransitionModel &trans_model, const std::vector< int32 > &disambig_syms, BaseFloat self_loop_scale, fst::VectorFst< fst::StdArc > *fst)
Definition: hmm-utils.cc:434
Definition: graph.dox:21
static void AddSelfLoopsAfter(const TransitionModel &trans_model, const std::vector< int32 > &disambig_syms, BaseFloat self_loop_scale, fst::VectorFst< fst::StdArc > *fst)
Definition: hmm-utils.cc:514
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
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 1042 of file hmm-utils.cc.

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

Referenced by main().

1046  {
1047  using namespace fst;
1048  KALDI_ASSERT(IsSortedAndUniq(disambig_syms));
1049  int num_tids = trans_model.NumTransitionIds();
1050  for (StateIterator<VectorFst<StdArc> > siter(*fst);
1051  !siter.Done();
1052  siter.Next()) {
1053  for (MutableArcIterator<VectorFst<StdArc> > aiter(fst, siter.Value());
1054  !aiter.Done();
1055  aiter.Next()) {
1056  StdArc arc = aiter.Value();
1057  StdArc::Label l = arc.ilabel;
1058  if (l >= 1 && l <= num_tids) { // a transition-id.
1059  BaseFloat scaled_log_prob = GetScaledTransitionLogProb(trans_model,
1060  l,
1061  transition_scale,
1062  self_loop_scale);
1063  arc.weight = Times(arc.weight, TropicalWeight(-scaled_log_prob));
1064  } else if (l != 0) {
1065  if (!std::binary_search(disambig_syms.begin(), disambig_syms.end(),
1066  arc.ilabel))
1067  KALDI_ERR << "AddTransitionProbs: invalid symbol " << arc.ilabel
1068  << " on graph input side.";
1069  }
1070  aiter.SetValue(arc);
1071  }
1072  }
1073 }
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:127
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:1019
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
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
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 1075 of file hmm-utils.cc.

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

1078  {
1079  using namespace fst;
1080  int num_tids = trans_model.NumTransitionIds();
1081  for (fst::StateIterator<Lattice> siter(*lat);
1082  !siter.Done();
1083  siter.Next()) {
1084  for (MutableArcIterator<Lattice> aiter(lat, siter.Value());
1085  !aiter.Done();
1086  aiter.Next()) {
1087  LatticeArc arc = aiter.Value();
1088  LatticeArc::Label l = arc.ilabel;
1089  if (l >= 1 && l <= num_tids) { // a transition-id.
1090  BaseFloat scaled_log_prob = GetScaledTransitionLogProb(trans_model,
1091  l,
1092  transition_scale,
1093  self_loop_scale);
1094  // cost is negated log prob.
1095  arc.weight.SetValue1(arc.weight.Value1() - scaled_log_prob);
1096  } else if (l != 0) {
1097  KALDI_ERR << "AddTransitionProbs: invalid symbol " << arc.ilabel
1098  << " on lattice input side.";
1099  }
1100  aiter.SetValue(arc);
1101  }
1102  }
1103 }
fst::ArcTpl< LatticeWeight > LatticeArc
Definition: kaldi-lattice.h:40
Definition: graph.dox:21
#define KALDI_ERR
Definition: kaldi-error.h:127
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:1019
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!

fst::VectorFst< fst::StdArc > * GetHmmAsFst ( 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 the FST corresponding to the phone.

Does not include self-loops; you have to call AddSelfLoops() for that. Result owned by caller. Returns an acceptor (i.e. ilabels, olabels identical) with 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 30 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().

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

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

References kaldi::DeletePointers(), kaldi::GetHmmAsFst(), TransitionModel::GetPhones(), rnnlm::j, KALDI_ASSERT, fst::MakeLoopFst(), TransitionModel::NumTransitionIds(), and kaldi::SortAndUniq().

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

242  {
243  KALDI_ASSERT(ilabel_info.size() >= 1 && ilabel_info[0].size() == 0); // make sure that eps == eps.
244  HmmCacheType cache;
245  // "cache" is an optimization that prevents GetHmmAsFst repeating work
246  // unnecessarily.
247  using namespace fst;
248  typedef StdArc Arc;
249  typedef Arc::Weight Weight;
250  typedef Arc::StateId StateId;
251  typedef Arc::Label Label;
252 
253  std::vector<const ExpandedFst<Arc>* > fsts(ilabel_info.size(), NULL);
254  std::vector<int32> phones = trans_model.GetPhones();
255 
256  KALDI_ASSERT(disambig_syms_left != 0);
257  disambig_syms_left->clear();
258 
259  int32 first_disambig_sym = trans_model.NumTransitionIds() + 1; // First disambig symbol we can have on the input side.
260  int32 next_disambig_sym = first_disambig_sym;
261 
262  if (ilabel_info.size() > 0)
263  KALDI_ASSERT(ilabel_info[0].size() == 0); // make sure epsilon is epsilon...
264 
265  for (int32 j = 1; j < static_cast<int32>(ilabel_info.size()); j++) { // zero is eps.
266  KALDI_ASSERT(!ilabel_info[j].empty());
267  if (ilabel_info[j].size() == 1 &&
268  ilabel_info[j][0] <= 0) { // disambig symbol
269 
270  // disambiguation symbol.
271  int32 disambig_sym_left = next_disambig_sym++;
272  disambig_syms_left->push_back(disambig_sym_left);
273  // get acceptor with one path with "disambig_sym" on it.
274  VectorFst<Arc> *fst = new VectorFst<Arc>;
275  fst->AddState();
276  fst->AddState();
277  fst->SetStart(0);
278  fst->SetFinal(1, Weight::One());
279  fst->AddArc(0, Arc(disambig_sym_left, disambig_sym_left, Weight::One(), 1));
280  fsts[j] = fst;
281  } else { // Real phone-in-context.
282  std::vector<int32> phone_window = ilabel_info[j];
283 
284  VectorFst<Arc> *fst = GetHmmAsFst(phone_window,
285  ctx_dep,
286  trans_model,
287  config,
288  &cache);
289  fsts[j] = fst;
290  }
291  }
292 
293  VectorFst<Arc> *ans = MakeLoopFst(fsts);
294  SortAndUniq(&fsts); // remove duplicate pointers, which we will have
295  // in general, since we used the cache.
296  DeletePointers(&fsts);
297  return ans;
298 }
fst::StdArc::StateId StateId
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 GetHmmAsFst...
Definition: hmm-utils.h:64
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq's (removes duplicates) from a vector.
Definition: stl-utils.h:39
VectorFst< Arc > * MakeLoopFst(const 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
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
fst::VectorFst< fst::StdArc > * GetHmmAsFst(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 the FST corre...
Definition: hmm-utils.cc:30
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:186
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 301 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().

304  {
305  KALDI_ASSERT(old2new_map != NULL);
306 
314  std::map<std::pair<int32, std::vector<int32> >, int32 >
315  pair_to_physical;
316 
317  int32 N = ctx_dep.ContextWidth(),
318  P = ctx_dep.CentralPosition();
319  int32 num_syms_old = ilabel_info_old.size();
320 
323  std::vector<int32> old2old_map(num_syms_old);
324  old2old_map[0] = 0;
325  for (int32 i = 1; i < num_syms_old; i++) {
326  const std::vector<int32> &vec = ilabel_info_old[i];
327  if (vec.size() == 1 && vec[0] <= 0) { // disambig.
328  old2old_map[i] = i;
329  } else {
330  KALDI_ASSERT(vec.size() == static_cast<size_t>(N));
331  // work out the vector of context-dependent phone
332  int32 central_phone = vec[P];
333  int32 num_pdf_classes = trans_model.GetTopo().NumPdfClasses(central_phone);
334  std::vector<int32> state_seq(num_pdf_classes); // Indexed by pdf-class
335  for (int32 pdf_class = 0; pdf_class < num_pdf_classes; pdf_class++) {
336  if (!ctx_dep.Compute(vec, pdf_class, &(state_seq[pdf_class]))) {
337  std::ostringstream ss;
338  WriteIntegerVector(ss, false, vec);
339  KALDI_ERR << "tree did not succeed in converting phone window "<<ss.str();
340  }
341  }
342  std::pair<int32, std::vector<int32> > pr(central_phone, state_seq);
343  std::map<std::pair<int32, std::vector<int32> >, int32 >::iterator iter
344  = pair_to_physical.find(pr);
345  if (iter == pair_to_physical.end()) { // first time we saw something like this.
346  pair_to_physical[pr] = i;
347  old2old_map[i] = i;
348  } else { // seen it before. look up in the map, the index we point to.
349  old2old_map[i] = iter->second;
350  }
351  }
352  }
353 
354  std::vector<bool> seen(num_syms_old, false);
355  for (int32 i = 0; i < num_syms_old; i++)
356  seen[old2old_map[i]] = true;
357 
358  // Now work out the elements of old2new_map corresponding to
359  // things that are first in their equivalence class. We're just
360  // compacting the labels to those for which seen[i] == true.
361  int32 cur_id = 0;
362  old2new_map->resize(num_syms_old);
363  for (int32 i = 0; i < num_syms_old; i++)
364  if (seen[i])
365  (*old2new_map)[i] = cur_id++;
366  // fill in the other elements of old2new_map.
367  for (int32 i = 0; i < num_syms_old; i++)
368  (*old2new_map)[i] = (*old2new_map)[old2old_map[i]];
369 }
#define KALDI_ERR
Definition: kaldi-error.h:127
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
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
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 373 of file hmm-utils.cc.

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

Referenced by main().

373  {
374  using namespace fst;
375  VectorFst<StdArc> *ans = new VectorFst<StdArc>;
377  typedef StdArc Arc;
378  ans->AddState();
379  ans->SetStart(0);
380  ans->SetFinal(0, Weight::One());
381  for (int32 tid = 1; tid <= trans_model.NumTransitionIds(); tid++) {
382  int32 pdf = trans_model.TransitionIdToPdf(tid);
383  ans->AddArc(0, Arc(pdf+1, tid, Weight::One(), 0)); // note the offset of 1 on the pdfs.
384  // it's because 0 is a valid pdf.
385  }
386  return ans;
387 }
Definition: graph.dox:21
fst::StdArc StdArc
fst::StdArc::Weight Weight