word-align-lattice-lexicon-test.cc
Go to the documentation of this file.
1 // lat/word-align-lattice-lexicon-test.cc
2 
3 // Copyright 2015 Johns Hopkins University (Author: Daniel Povey)
4 
5 // See ../../COPYING for clarification regarding multiple authors
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
15 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
16 // MERCHANTABLITY OR NON-INFRINGEMENT.
17 // See the Apache 2 License for the specific language governing permissions and
18 // limitations under the License.
19 
21 #include "fstext/lattice-utils.h"
22 #include "fstext/fst-test-utils.h"
23 #include "lat/kaldi-lattice.h"
24 #include "lat/lattice-functions.h"
25 #include "hmm/hmm-test-utils.h"
27 
28 namespace kaldi {
29 
30 // This function generates a lexicon in the same format that
31 // WordAlignLatticeLexicon uses: (original-word-id), (new-word-id), (phone-seq).
32 void GenerateLexicon(const std::vector<int32> &phones,
33  bool allow_zero_words,
34  bool allow_empty_word,
35  bool allow_multiple_prons,
36  std::vector<std::vector<int32> > *lexicon) {
37  KALDI_ASSERT(!phones.empty());
38  lexicon->clear();
39  int32 num_words = RandInt(1, 20);
40  for (int32 word = 1; word <= num_words; word++) {
41  int32 num_prons = RandInt(1, (allow_multiple_prons ? 2 : 1));
42  bool is_zero_word = allow_zero_words && (RandInt(1, 5) == 1);
43 
44  for (int32 j = 0; j < num_prons; j++) {
45  // don't allow empty pron if this word isn't labeled in the lattice (zero word,
46  // like optional silence). This doesn't make sense.
47  int32 pron_length = RandInt(((allow_empty_word && !is_zero_word) ? 0 : 1),
48  4);
49  std::vector<int32> this_entry;
50  this_entry.push_back(is_zero_word ? 0 : word);
51  this_entry.push_back(word);
52  for (int32 p = 0; p < pron_length; p++)
53  this_entry.push_back(phones[RandInt(0, phones.size() - 1)]);
54  lexicon->push_back(this_entry);
55  }
56  }
57  SortAndUniq(lexicon);
58  // randomize the order.
59  std::random_shuffle(lexicon->begin(), lexicon->end());
60 
61 
62  for (size_t i = 0; i < lexicon->size(); i++) {
63  if ((*lexicon)[i].size() > 2) {
64  // ok, this lexicon has at least one nonempty word: potentially OK. Do
65  // further check that the info object doesn't complain.
66  try {
67  WordAlignLatticeLexiconInfo info(*lexicon);
68  return; // OK, we're satisfied with this lexicon.
69  } catch (...) {
70  break; // will re-try, see below.
71  }
72  }
73  }
74  // there were no nonempty words in the lexicon -> try again.
75  // recursing is the easiest way.
76  GenerateLexicon(phones, allow_zero_words, allow_empty_word, allow_multiple_prons,
77  lexicon);
78 
79 
80 }
81 
82 
83 static void PrintLexicon(const std::vector<std::vector<int32> > &lexicon) {
84  KALDI_LOG << "Lexicon is: ";
85  for (size_t i = 0; i < lexicon.size(); i++) {
86  KALDI_ASSERT(lexicon[i].size() >= 2);
87  const std::vector<int32> &entry = lexicon[i];
88  std::cerr << entry[0] << "\t" << entry[1] << "\t";
89  for (size_t j = 2; j < entry.size(); j++)
90  std::cerr << entry[j] << " ";
91  std::cerr << "\n";
92  }
93 }
94 
95 static void PrintWordsAndPhones(const std::vector<int32> &words,
96  const std::vector<int32> &phones) {
97  std::ostringstream word_str, phone_str;
98  for (size_t i = 0; i < words.size(); i++)
99  word_str << words[i] << " ";
100  for (size_t i = 0; i < phones.size(); i++)
101  phone_str << phones[i] << " ";
102  KALDI_LOG << "Word-sequence is: " << word_str.str();
103  KALDI_LOG << "Phone-sequence is: " << phone_str.str();
104 }
105 
106 
107 // generates a phone and word sequence together from the lexicon. Not
108 // guaranteed nonempty.
109 void GenerateWordAndPhoneSequence(std::vector<std::vector<int32> > &lexicon,
110  std::vector<int32> *phone_seq,
111  std::vector<int32> *word_seq) {
112  int32 num_words = RandInt(0, 5);
113  phone_seq->clear();
114  word_seq->clear();
115  for (int32 i = 0; i < num_words; i++) {
116  const std::vector<int32> &lexicon_entry =
117  lexicon[RandInt(0, lexicon.size() - 1)];
118  // the zeroth element of 'lexicon_entry' is how it appears in
119  // the lattice prior to word alignment.
120  int32 word = lexicon_entry[0];
121  if (word != 0) word_seq->push_back(word);
122  // add everything from position 2 in the lexicon entry, to the
123  // phone sequence.
124  phone_seq->insert(phone_seq->end(),
125  lexicon_entry.begin() + 2,
126  lexicon_entry.end());
127  }
128 }
129 
130 
131 
132 void GenerateCompactLatticeRandomly(const std::vector<int32> &alignment,
133  const std::vector<int32> &words,
134  CompactLattice *clat) {
135  clat->DeleteStates();
136  clat->AddState();
137  clat->SetStart(0);
138  int32 cur_state = 0;
139  size_t word_start = 0, alignment_start = 0,
140  num_words = words.size(), num_transition_ids = alignment.size();
141  for (; word_start < num_words; word_start++) {
142  int32 word = words[word_start];
143  int32 ali_length = RandInt(0, num_transition_ids - alignment_start);
144  std::vector<int32> this_ali(ali_length);
145  for (int32 i = 0; i < ali_length; i++)
146  this_ali[i] = alignment[alignment_start + i];
147  alignment_start += ali_length;
148  CompactLatticeWeight weight(LatticeWeight::One(), this_ali);
149  int32 ilabel = word;
150  int32 next_state = clat->AddState();
151  CompactLatticeArc arc(ilabel, ilabel, weight, next_state);
152  clat->AddArc(cur_state, arc);
153  cur_state = next_state;
154  }
155  if (alignment_start < alignment.size()) {
156  int32 ali_length = num_transition_ids - alignment_start;
157  std::vector<int32> this_ali(ali_length);
158  for (int32 i = 0; i < ali_length; i++)
159  this_ali[i] = alignment[alignment_start + i];
160  alignment_start += ali_length;
161  CompactLatticeWeight weight(LatticeWeight::One(), this_ali);
162  int32 ilabel = 0;
163  int32 next_state = clat->AddState();
164  CompactLatticeArc arc(ilabel, ilabel, weight, next_state);
165  clat->AddArc(cur_state, arc);
166  cur_state = next_state;
167  }
168  clat->SetFinal(cur_state, CompactLatticeWeight::One());
169 }
170 
171 
172 
174  ContextDependency *ctx_dep;
175  TransitionModel *trans_model = GenRandTransitionModel(&ctx_dep);
176  bool allow_zero_words = true;
177  bool allow_empty_word = true;
178  bool allow_multiple_prons = true;
179 
180  const std::vector<int32> &phones = trans_model->GetPhones();
181  std::vector<std::vector<int32> > lexicon;
182  GenerateLexicon(phones, allow_zero_words, allow_empty_word,
183  allow_multiple_prons, &lexicon);
184 
185  std::vector<int32> phone_seq;
186  std::vector<int32> word_seq;
187  while (phone_seq.empty())
188  GenerateWordAndPhoneSequence(lexicon, &phone_seq, &word_seq);
189 
190  PrintLexicon(lexicon);
191  PrintWordsAndPhones(word_seq, phone_seq);
192 
193  std::vector<int32> alignment;
194  bool reorder = (RandInt(0, 1) == 0);
195  GenerateRandomAlignment(*ctx_dep, *trans_model, reorder,
196  phone_seq, &alignment);
197 
198  CompactLattice clat;
199  GenerateCompactLatticeRandomly(alignment, word_seq, &clat);
200 
201  KALDI_LOG << "clat is ";
202  WriteCompactLattice(std::cerr, false, clat);
203 
205  WordAlignLatticeLexiconInfo lexicon_info(lexicon);
206  opts.test = true; // we rely on the self-test code that's activated when we
207  // do this.
208  opts.allow_duplicate_paths = true;
209  opts.reorder = reorder;
210  CompactLattice aligned_clat;
211  bool ans = WordAlignLatticeLexicon(clat, *trans_model, lexicon_info, opts,
212  &aligned_clat);
213  KALDI_LOG << "Aligned clat is ";
214  WriteCompactLattice(std::cerr, false, aligned_clat);
215  KALDI_ASSERT(ans);
216 
217  Lattice lat;
218  ConvertLattice(clat, &lat);
219  int32 n = 1000; // a maximum.
220  Lattice nbest_lat;
221  std::vector<Lattice> nbest_lats;
222  fst::ShortestPath(lat, &nbest_lat, n);
223  fst::ConvertNbestToVector(nbest_lat, &nbest_lats);
224  KALDI_LOG << "Word-aligned lattice has " << nbest_lats.size() << " paths.";
225 
226  delete ctx_dep;
227  delete trans_model;
228 }
229 
230 } // end namespace kaldi
231 
232 int main() {
233  for (int32 i = 0; i < 3; i++)
235  std::cout << "Tests succeeded\n";
236 }
237 
int32 words[kMaxOrder]
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
void GenerateCompactLatticeRandomly(const std::vector< int32 > &alignment, const std::vector< int32 > &words, CompactLattice *clat)
const std::vector< int32 > & GetPhones() const
Returns a sorted, unique list of phones.
static const LatticeWeightTpl One()
kaldi::int32 int32
bool WordAlignLatticeLexicon(const CompactLattice &lat, const TransitionModel &tmodel, const WordAlignLatticeLexiconInfo &lexicon_info, const WordAlignLatticeLexiconOpts &opts, CompactLattice *lat_out)
Align lattice so that each arc has the transition-ids on it that correspond to the word that is on th...
void SortAndUniq(std::vector< T > *vec)
Sorts and uniq&#39;s (removes duplicates) from a vector.
Definition: stl-utils.h:39
void GenerateWordAndPhoneSequence(std::vector< std::vector< int32 > > &lexicon, std::vector< int32 > *phone_seq, std::vector< int32 > *word_seq)
void ConvertNbestToVector(const Fst< Arc > &fst, std::vector< VectorFst< Arc > > *fsts_out)
This function converts an FST with a special structure, which is output by the OpenFst functions Shor...
static const CompactLatticeWeightTpl< WeightType, IntType > One()
struct rnnlm::@11::@12 n
void ConvertLattice(const ExpandedFst< ArcTpl< Weight > > &ifst, MutableFst< ArcTpl< CompactLatticeWeightTpl< Weight, Int > > > *ofst, bool invert)
Convert lattice from a normal FST to a CompactLattice FST.
fst::VectorFst< LatticeArc > Lattice
Definition: kaldi-lattice.h:44
void GenerateRandomAlignment(const ContextDependencyInterface &ctx_dep, const TransitionModel &trans_model, bool reorder, const std::vector< int32 > &phone_sequence, std::vector< int32 > *alignment)
For use in test code, this function generates an alignment (a sequence of transition-ids) correspondi...
void GenerateLexicon(const std::vector< int32 > &phones, bool allow_zero_words, bool allow_empty_word, bool allow_multiple_prons, std::vector< std::vector< int32 > > *lexicon)
fst::VectorFst< CompactLatticeArc > CompactLattice
Definition: kaldi-lattice.h:46
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
This class extracts some information from the lexicon and stores it in a suitable form for the word-a...
bool WriteCompactLattice(std::ostream &os, bool binary, const CompactLattice &t)
static void PrintLexicon(const std::vector< std::vector< int32 > > &lexicon)
fst::ArcTpl< CompactLatticeWeight > CompactLatticeArc
Definition: kaldi-lattice.h:42
TransitionModel * GenRandTransitionModel(ContextDependency **ctx_dep_out)
static void PrintWordsAndPhones(const std::vector< int32 > &words, const std::vector< int32 > &phones)
#define KALDI_LOG
Definition: kaldi-error.h:153
int32 RandInt(int32 min_val, int32 max_val, struct RandomState *state)
Definition: kaldi-math.cc:95