All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Classes and functions related to HMM topology and transition modeling
Collaboration diagram for Classes and functions related to HMM topology and transition modeling:

Modules

 Classes and functions for creating FSTs from HMMs
 

Classes

class  HmmTopology
 A class for storing topology information for phones. More...
 
struct  HmmTopology::HmmState
 A structure defined inside HmmTopology to represent a HMM state. More...
 
struct  MleTransitionUpdateConfig
 
struct  MapTransitionUpdateConfig
 
class  TransitionModel
 
struct  TransitionModel::Tuple
 

Functions

bool SplitToPhones (const TransitionModel &trans_model, const std::vector< int32 > &alignment, std::vector< std::vector< int32 > > *split_alignment)
 SplitToPhones splits up the TransitionIds in "alignment" into their individual phones (one vector per instance of a phone). More...
 
bool ConvertAlignment (const TransitionModel &old_trans_model, const TransitionModel &new_trans_model, const ContextDependencyInterface &new_ctx_dep, const std::vector< int32 > &old_alignment, int32 subsample_factor,bool repeat_frames, bool reorder, const std::vector< int32 > *phone_map,std::vector< int32 > *new_alignment)
 ConvertAlignment converts an alignment that was created using one model, to another model. More...
 
bool ConvertPhnxToProns (const std::vector< int32 > &phnx, const std::vector< int32 > &words, int32 word_start_sym, int32 word_end_sym, std::vector< std::vector< int32 > > *prons)
 
void GetRandomAlignmentForPhone (const ContextDependencyInterface &ctx_dep, const TransitionModel &trans_model, const std::vector< int32 > &phone_window, std::vector< int32 > *alignment)
 
void ChangeReorderingOfAlignment (const TransitionModel &trans_model, std::vector< int32 > *alignment)
 
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. More...
 
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. More...
 

Variables

static const int32 kNoPdf = -1
 A constant used in the HmmTopology class as the pdf-class kNoPdf, which is used when a HMM-state is nonemitting (has no associated PDF). More...
 

Integer mapping functions

int32 TransitionIdToPdf (int32 trans_id) const
 

Detailed Description

Function Documentation

void ChangeReorderingOfAlignment ( const TransitionModel &  trans_model,
std::vector< int32 > *  alignment 
)

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

References TransitionModel::IsSelfLoop(), kaldi::swap(), and TransitionModel::TransitionIdToTransitionState().

Referenced by kaldi::ConvertAlignmentForPhone().

1215  {
1216  int32 start_pos = 0, size = alignment->size();
1217  while (start_pos != size) {
1218  int32 start_tid = (*alignment)[start_pos];
1219  int32 cur_tstate = trans_model.TransitionIdToTransitionState(start_tid);
1220  bool start_is_self_loop = trans_model.IsSelfLoop(start_tid) ? 0 : 1;
1221  int32 end_pos = start_pos + 1;
1222  // If the first instance of this transition-state was a self-loop, then eat
1223  // only non-self-loops of this state; if it was a non-self-loop, then eat
1224  // only self-loops of this state. Imposing this condition on self-loops
1225  // would only actually matter in the rare circumstances that phones can
1226  // have length 1.
1227  while (end_pos != size &&
1228  trans_model.TransitionIdToTransitionState((*alignment)[end_pos]) ==
1229  cur_tstate) {
1230  bool this_is_self_loop = trans_model.IsSelfLoop((*alignment)[end_pos]);
1231  if (!this_is_self_loop) {
1232  if (start_is_self_loop) {
1233  break; // stop before including this transition-id.
1234  } else {
1235  end_pos++;
1236  break; // stop after including this transition-id.
1237  }
1238  }
1239  end_pos++;
1240  }
1241  std::swap((*alignment)[start_pos], (*alignment)[end_pos - 1]);
1242  start_pos = end_pos;
1243  }
1244 }
void swap(basic_filebuf< CharT, Traits > &x, basic_filebuf< CharT, Traits > &y)
bool ConvertAlignment ( const TransitionModel &  old_trans_model,
const TransitionModel &  new_trans_model,
const ContextDependencyInterface &  new_ctx_dep,
const std::vector< int32 > &  old_alignment,
int32  subsample_factor,
bool  repeat_frames,
bool  reorder,
const std::vector< int32 > *  phone_map,
std::vector< int32 > *  new_alignment 
)

ConvertAlignment converts an alignment that was created using one model, to another model.

Returns false if it could not be split to phones (e.g. because the alignment was partial), or because some other error happened, such as we couldn't convert the alignment because there were too few frames for the new topology.

Parameters
old_trans_model[in] The transition model that the original alignment used.
new_trans_model[in] The transition model that we want to use for the new alignment.
new_ctx_dep[in] The new tree
old_alignment[in] The alignment we want to convert
subsample_factor[in] The frame subsampling factor... normally 1, but might be > 1 if we're converting to a reduced-frame-rate system.
repeat_frames[in] Only relevant when subsample_factor != 1 If true, repeat frames of alignment by 'subsample_factor' after alignment conversion, to keep the alignment the same length as the input alignment. [note: we actually do this by interpolating 'subsample_factor' separately generated alignments, to keep the phone boundaries the same as the input where possible.]
reorder[in] True if you want the pdf-ids on the new alignment to be 'reordered'. (vs. the way they appear in the HmmTopology object)
phone_map[in] If non-NULL, map from old to new phones.
new_alignment[out] The converted alignment.

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

References kaldi::ConvertAlignmentInternal(), rnnlm::i, and KALDI_ASSERT.

Referenced by main(), and kaldi::TestConvertAlignment().

975  {
976  if (!repeat_frames || subsample_factor == 1) {
977  return ConvertAlignmentInternal(old_trans_model,
978  new_trans_model,
979  new_ctx_dep,
980  old_alignment,
981  subsample_factor - 1,
982  subsample_factor,
983  new_is_reordered,
984  phone_map,
985  new_alignment);
986  // The value "subsample_factor - 1" for conversion_shift above ensures the
987  // alignments have the same length as the output of 'subsample-feats'
988  } else {
989  std::vector<std::vector<int32> > shifted_alignments(subsample_factor);
990  for (int32 conversion_shift = subsample_factor - 1;
991  conversion_shift >= 0; conversion_shift--) {
992  if (!ConvertAlignmentInternal(old_trans_model,
993  new_trans_model,
994  new_ctx_dep,
995  old_alignment,
996  conversion_shift,
997  subsample_factor,
998  new_is_reordered,
999  phone_map,
1000  &shifted_alignments[conversion_shift]))
1001  return false;
1002  }
1003  KALDI_ASSERT(new_alignment != NULL);
1004  new_alignment->clear();
1005  new_alignment->reserve(old_alignment.size());
1006  int32 max_shifted_ali_length = (old_alignment.size() / subsample_factor)
1007  + (old_alignment.size() % subsample_factor);
1008  for (int32 i = 0; i < max_shifted_ali_length; i++)
1009  for (int32 conversion_shift = subsample_factor - 1;
1010  conversion_shift >= 0; conversion_shift--)
1011  if (i < static_cast<int32>(shifted_alignments[conversion_shift].size()))
1012  new_alignment->push_back(shifted_alignments[conversion_shift][i]);
1013  }
1014  KALDI_ASSERT(new_alignment->size() == old_alignment.size());
1015  return true;
1016 }
static bool ConvertAlignmentInternal(const TransitionModel &old_trans_model, const TransitionModel &new_trans_model, const ContextDependencyInterface &new_ctx_dep, const std::vector< int32 > &old_alignment, int32 conversion_shift, int32 subsample_factor, bool new_is_reordered, const std::vector< int32 > *phone_map, std::vector< int32 > *new_alignment)
This function is the same as 'ConvertAligment', but instead of the 'repeat_frames' option it supports...
Definition: hmm-utils.cc:880
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
bool ConvertPhnxToProns ( const std::vector< int32 > &  phnx,
const std::vector< int32 > &  words,
int32  word_start_sym,
int32  word_end_sym,
std::vector< std::vector< int32 > > *  prons 
)

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

References rnnlm::i, and rnnlm::j.

Referenced by main(), and kaldi::TestConvertPhnxToProns().

1119  {
1120  size_t i = 0, j = 0;
1121 
1122  while (i < phnx.size()) {
1123  if (phnx[i] == 0) return false; // zeros not valid here.
1124  if (phnx[i] == word_start_sym) { // start a word...
1125  std::vector<int32> pron;
1126  if (j >= words.size()) return false; // no word left..
1127  if (words[j] == 0) return false; // zero word disallowed.
1128  pron.push_back(words[j++]);
1129  i++;
1130  while (i < phnx.size()) {
1131  if (phnx[i] == 0) return false;
1132  if (phnx[i] == word_start_sym) return false; // error.
1133  if (phnx[i] == word_end_sym) { i++; break; }
1134  pron.push_back(phnx[i]);
1135  i++;
1136  }
1137  // check we did see the word-end symbol.
1138  if (!(i > 0 && phnx[i-1] == word_end_sym))
1139  return false;
1140  prons->push_back(pron);
1141  } else if (phnx[i] == word_end_sym) {
1142  return false; // error.
1143  } else {
1144  // start a non-word sequence of phones (e.g. opt-sil).
1145  std::vector<int32> pron;
1146  pron.push_back(0); // 0 serves as the word-id.
1147  while (i < phnx.size()) {
1148  if (phnx[i] == 0) return false;
1149  if (phnx[i] == word_start_sym) break;
1150  if (phnx[i] == word_end_sym) return false; // error.
1151  pron.push_back(phnx[i]);
1152  i++;
1153  }
1154  prons->push_back(pron);
1155  }
1156  }
1157  return (j == words.size());
1158 }
int32 words[kMaxOrder]
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.

Will return true if these pdfs correspond *just* to these phones, false if these pdfs are also used by other phones.

Parameters
trans_model[in] Transition-model used to work out this information
phones[in] A sorted, uniq vector that represents a set of phones
pdfs[out] Will be set to a sorted, uniq list of pdf-ids that correspond to one of this set of phones.
Returns
Returns true if all of the pdfs output to "pdfs" correspond to phones from just this set (false if they may be shared with phones outside this set).

Definition at line 843 of file transition-model.cc.

References kaldi::IsSortedAndUniq(), KALDI_ASSERT, TransitionModel::NumTransitionStates(), kaldi::SortAndUniq(), TransitionModel::TransitionStateToForwardPdf(), TransitionModel::TransitionStateToPhone(), and TransitionModel::TransitionStateToSelfLoopPdf().

Referenced by main().

845  {
846  KALDI_ASSERT(IsSortedAndUniq(phones));
847  KALDI_ASSERT(pdfs != NULL);
848  pdfs->clear();
849  for (int32 tstate = 1; tstate <= trans_model.NumTransitionStates(); tstate++) {
850  if (std::binary_search(phones.begin(), phones.end(),
851  trans_model.TransitionStateToPhone(tstate))) {
852  pdfs->push_back(trans_model.TransitionStateToForwardPdf(tstate));
853  pdfs->push_back(trans_model.TransitionStateToSelfLoopPdf(tstate));
854  }
855  }
856  SortAndUniq(pdfs);
857 
858  for (int32 tstate = 1; tstate <= trans_model.NumTransitionStates(); tstate++)
859  if ((std::binary_search(pdfs->begin(), pdfs->end(),
860  trans_model.TransitionStateToForwardPdf(tstate)) ||
861  std::binary_search(pdfs->begin(), pdfs->end(),
862  trans_model.TransitionStateToSelfLoopPdf(tstate)))
863  && !std::binary_search(phones.begin(), phones.end(),
864  trans_model.TransitionStateToPhone(tstate)))
865  return false;
866  return true;
867 }
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq's (removes duplicates) from a vector.
Definition: stl-utils.h:39
#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
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.

Similar to the above GetPdfsForPhones(, ,)

Definition at line 869 of file transition-model.cc.

References kaldi::IsSortedAndUniq(), KALDI_ASSERT, TransitionModel::NumTransitionStates(), kaldi::SortAndUniq(), TransitionModel::TransitionStateToForwardPdf(), TransitionModel::TransitionStateToPhone(), and TransitionModel::TransitionStateToSelfLoopPdf().

Referenced by kaldi::InitAmGmm().

871  {
873  KALDI_ASSERT(phones != NULL);
874  phones->clear();
875  for (int32 tstate = 1; tstate <= trans_model.NumTransitionStates(); tstate++) {
876  if (std::binary_search(pdfs.begin(), pdfs.end(),
877  trans_model.TransitionStateToForwardPdf(tstate)) ||
878  std::binary_search(pdfs.begin(), pdfs.end(),
879  trans_model.TransitionStateToSelfLoopPdf(tstate)))
880  phones->push_back(trans_model.TransitionStateToPhone(tstate));
881  }
882  SortAndUniq(phones);
883 
884  for (int32 tstate = 1; tstate <= trans_model.NumTransitionStates(); tstate++)
885  if (std::binary_search(phones->begin(), phones->end(),
886  trans_model.TransitionStateToPhone(tstate))
887  && !(std::binary_search(pdfs.begin(), pdfs.end(),
888  trans_model.TransitionStateToForwardPdf(tstate)) &&
889  std::binary_search(pdfs.begin(), pdfs.end(),
890  trans_model.TransitionStateToSelfLoopPdf(tstate))) )
891  return false;
892  return true;
893 }
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq's (removes duplicates) from a vector.
Definition: stl-utils.h:39
#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 GetRandomAlignmentForPhone ( const ContextDependencyInterface &  ctx_dep,
const TransitionModel &  trans_model,
const std::vector< int32 > &  phone_window,
std::vector< int32 > *  alignment 
)

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

References ContextDependencyInterface::CentralPosition(), kaldi::GetHmmAsFstSimple(), fst::GetInputSymbols(), TransitionModel::GetTopo(), rnnlm::i, rnnlm::j, KALDI_ASSERT, KALDI_ERR, and HmmTopology::MinLength().

Referenced by kaldi::ConvertAlignmentForPhone().

1164  {
1165  typedef fst::StdArc Arc;
1166  int32 length = alignment->size();
1167  BaseFloat prob_scale = 0.0;
1168  fst::VectorFst<Arc> *fst = GetHmmAsFstSimple(phone_window, ctx_dep,
1169  trans_model, prob_scale);
1170  fst::RmEpsilon(fst);
1171 
1172  fst::VectorFst<Arc> length_constraint_fst;
1173  { // set up length_constraint_fst.
1174  std::vector<int32> symbols;
1175  bool include_epsilon = false;
1176  // note: 'fst' is an acceptor so ilabels == olabels.
1177  GetInputSymbols(*fst, include_epsilon, &symbols);
1178  int32 cur_state = length_constraint_fst.AddState();
1179  length_constraint_fst.SetStart(cur_state);
1180  for (int32 i = 0; i < length; i++) {
1181  int32 next_state = length_constraint_fst.AddState();
1182  for (size_t j = 0; j < symbols.size(); j++) {
1183  length_constraint_fst.AddArc(cur_state,
1184  Arc(symbols[j], symbols[j],
1185  fst::TropicalWeight::One(),
1186  next_state));
1187  }
1188  cur_state = next_state;
1189  }
1190  length_constraint_fst.SetFinal(cur_state, fst::TropicalWeight::One());
1191  }
1192  fst::VectorFst<Arc> composed_fst;
1193  fst::Compose(*fst, length_constraint_fst, &composed_fst);
1194  fst::VectorFst<Arc> single_path_fst;
1195  { // randomly generate a single path.
1196  fst::UniformArcSelector<Arc> selector;
1197  fst::RandGenOptions<fst::UniformArcSelector<Arc> > randgen_opts(selector);
1198  fst::RandGen(composed_fst, &single_path_fst, randgen_opts);
1199  }
1200  if (single_path_fst.NumStates() == 0) {
1201  KALDI_ERR << "Error generating random alignment (wrong length?): "
1202  << "requested length is " << length << " versus min-length "
1203  << trans_model.GetTopo().MinLength(
1204  phone_window[ctx_dep.CentralPosition()]);
1205  }
1206  std::vector<int32> symbol_sequence;
1207  bool ans = fst::GetLinearSymbolSequence<Arc, int32>(
1208  single_path_fst, &symbol_sequence, NULL, NULL);
1209  KALDI_ASSERT(ans && symbol_sequence.size() == length);
1210  symbol_sequence.swap(*alignment);
1211  delete fst;
1212 }
Definition: graph.dox:21
fst::StdArc StdArc
void GetInputSymbols(const Fst< Arc > &fst, bool include_eps, vector< I > *symbols)
GetInputSymbols gets the list of symbols on the input of fst (including epsilon, if include_eps == tr...
float BaseFloat
Definition: kaldi-types.h:29
#define KALDI_ERR
Definition: kaldi-error.h:127
fst::VectorFst< fst::StdArc > * GetHmmAsFstSimple(std::vector< int32 > phone_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. ...
Definition: hmm-utils.cc:153
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
bool SplitToPhones ( const TransitionModel &  trans_model,
const std::vector< int32 > &  alignment,
std::vector< std::vector< int32 > > *  split_alignment 
)

SplitToPhones splits up the TransitionIds in "alignment" into their individual phones (one vector per instance of a phone).

At output, the sum of the sizes of the vectors in split_alignment will be the same as the corresponding sum for "alignment". The function returns true on success. If the alignment appears to be incomplete, e.g. not ending at the end-state of a phone, it will still break it up into phones but it will return false. For more serious errors it will die or throw an exception. This function works out by itself whether the graph was created with "reordering", and just does the right thing.

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

References kaldi::IsReordered(), KALDI_ASSERT, and kaldi::SplitToPhonesInternal().

Referenced by kaldi::AccumulateTreeStats(), kaldi::CompactLatticeToWordProns(), kaldi::ConvertAlignmentInternal(), kaldi::IsPlausibleWord(), main(), kaldi::TestConvertAlignment(), and kaldi::TestSplitToPhones().

679  {
680  KALDI_ASSERT(split_alignment != NULL);
681  split_alignment->clear();
682 
683  bool is_reordered = IsReordered(trans_model, alignment);
684  return SplitToPhonesInternal(trans_model, alignment,
685  is_reordered, split_alignment);
686 }
static bool IsReordered(const TransitionModel &trans_model, const std::vector< int32 > &alignment)
Definition: hmm-utils.cc:579
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169
static bool SplitToPhonesInternal(const TransitionModel &trans_model, const std::vector< int32 > &alignment, bool reordered, std::vector< std::vector< int32 > > *split_output)
Definition: hmm-utils.cc:613
int32 TransitionIdToPdf ( int32  trans_id) const
inline

Definition at line 324 of file transition-model.h.

References TransitionModel::id2pdf_id_, and KALDI_ASSERT.

Referenced by kaldi::AccumulateForUtterance(), DiscriminativeExampleSplitter::CollapseTransitionIds(), DiscriminativeSupervisionSplitter::CollapseTransitionIds(), kaldi::ComputeAmGmmFeatureDeriv(), DiscriminativeExampleSplitter::ComputeFrameInfo(), kaldi::ConvertPosteriorToPdfs(), kaldi::GetPdfToTransitionIdTransducer(), kaldi::LatticeAcousticRescore(), kaldi::nnet1::LatticeAcousticRescore(), NnetDiscriminativeUpdater::LatticeComputations(), kaldi::LatticeForwardBackwardMpeVariants(), DecodableAmDiagGmmRegtreeFmllr::LogLikelihood(), DecodableAmSgmm2::LogLikelihood(), DecodableMatrixScaledMapped::LogLikelihood(), DecodableNnet2Online::LogLikelihood(), DecodableAmNnet::LogLikelihood(), DecodableAmDiagGmmRegtreeMllr::LogLikelihood(), DecodableAmDiagGmm::LogLikelihood(), DecodableAmSgmm2Scaled::LogLikelihood(), DecodableAmNnetParallel::LogLikelihood(), DecodableAmDiagGmmScaled::LogLikelihood(), DecodableMatrixMappedOffset::LogLikelihood(), DecodableAmNnetLoopedOnline::LogLikelihood(), DecodableAmNnetSimple::LogLikelihood(), DecodableAmNnetSimpleLooped::LogLikelihood(), DecodableAmNnetSimpleParallel::LogLikelihood(), DiscriminativeComputation::LookupNnetOutput(), main(), ComparePosteriorByPdfs::operator()(), kaldi::PosteriorToPdfMatrix(), kaldi::RescoreCompactLatticeInternal(), kaldi::nnet3::SetPriors(), and kaldi::nnet2::SetPriors().

324  {
325  KALDI_ASSERT(static_cast<size_t>(trans_id) < id2pdf_id_.size() &&
326  "Likely graph/model mismatch (graph built from wrong model?)");
327  return id2pdf_id_[trans_id];
328 }
std::vector< int32 > id2pdf_id_
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:169

Variable Documentation

const int32 kNoPdf = -1
static

A constant used in the HmmTopology class as the pdf-class kNoPdf, which is used when a HMM-state is nonemitting (has no associated PDF).

Definition at line 87 of file hmm-topology.h.

Referenced by HmmTopology::Check(), TransitionModel::ComputeTuplesIsHmm(), TransitionModel::ComputeTuplesNotHmm(), kaldi::GetHmmAsFst(), kaldi::GetHmmAsFstSimple(), HmmTopology::Read(), kaldi::SplitToPhonesInternal(), and HmmTopology::Write().