hmm-utils-test.cc
Go to the documentation of this file.
1 // hmm/hmm-utils-test.cc
2 
3 // Copyright 2009-2011 Microsoft Corporation
4 // 2015 Johns Hopkins University (author: Daniel Povey)
5 
6 // See ../../COPYING for clarification regarding multiple authors
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 // http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 // MERCHANTABLITY OR NON-INFRINGEMENT.
18 // See the Apache 2 License for the specific language governing permissions and
19 // limitations under the License.
20 
21 #include "hmm/hmm-utils.h"
22 #include "hmm/tree-accu.h"
23 #include "hmm/hmm-test-utils.h"
24 
25 namespace kaldi {
26 
27 
29 
30  int32 word_start_sym = 1, word_end_sym = 2;
31  { // empty test.
32  std::vector<int32> phnx;
33  std::vector<int32> words;
34  std::vector<std::vector<int32> > ans, ans_check;
35  KALDI_ASSERT(ConvertPhnxToProns(phnx, words, word_start_sym,
36  word_end_sym, &ans)
37  && ans == ans_check);
38  }
39 
40  { // test w/ one empty word.
41  std::vector<int32> phnx; phnx.push_back(3);
42  std::vector<int32> words;
43  std::vector<std::vector<int32> > ans;
44  std::vector<std::vector<int32> > ans_check(1);
45  ans_check[0].push_back(0);
46  ans_check[0].push_back(3);
47  KALDI_ASSERT(ConvertPhnxToProns(phnx, words, word_start_sym,
48  word_end_sym, &ans)
49  && ans == ans_check);
50  }
51 
52  { // test w/ one empty word with two phones.
53  std::vector<int32> phnx; phnx.push_back(3); phnx.push_back(4);
54  std::vector<int32> words;
55  std::vector<std::vector<int32> > ans;
56  std::vector<std::vector<int32> > ans_check(1);
57  ans_check[0].push_back(0);
58  ans_check[0].push_back(3);
59  ans_check[0].push_back(4);
60  KALDI_ASSERT(ConvertPhnxToProns(phnx, words, word_start_sym,
61  word_end_sym, &ans)
62  && ans == ans_check);
63  }
64 
65  { // test w/ zero -> should fail.
66  std::vector<int32> phnx; phnx.push_back(3); phnx.push_back(4);
67  phnx.push_back(0);
68  std::vector<int32> words;
69  std::vector<std::vector<int32> > ans;
70  KALDI_ASSERT(!ConvertPhnxToProns(phnx, words, word_start_sym,
71  word_end_sym, &ans));
72  }
73 
74  { // test w/ unexpected word-end -> should fail.
75  std::vector<int32> phnx; phnx.push_back(3); phnx.push_back(4);
76  phnx.push_back(word_end_sym);
77  std::vector<int32> words;
78  std::vector<std::vector<int32> > ans;
79  KALDI_ASSERT(!ConvertPhnxToProns(phnx, words, word_start_sym,
80  word_end_sym, &ans));
81 
82  }
83 
84  { // test w/ word-start but no word-end -> should fail.
85  std::vector<int32> phnx; phnx.push_back(3); phnx.push_back(4);
86  phnx.push_back(word_start_sym);
87  std::vector<int32> words;
88  std::vector<std::vector<int32> > ans;
89  KALDI_ASSERT(!ConvertPhnxToProns(phnx, words, word_start_sym,
90  word_end_sym, &ans));
91 
92  }
93 
94  { // test w/ one empty word then one real word w/ zero phones.
95  std::vector<int32> phnx; phnx.push_back(3); phnx.push_back(4);
96  phnx.push_back(word_start_sym); phnx.push_back(word_end_sym);
97  std::vector<int32> words; words.push_back(100);
98  std::vector<std::vector<int32> > ans;
99  std::vector<std::vector<int32> > ans_check(2);
100  ans_check[0].push_back(0);
101  ans_check[0].push_back(3);
102  ans_check[0].push_back(4);
103  ans_check[1].push_back(100);
104  KALDI_ASSERT(ConvertPhnxToProns(phnx, words, word_start_sym,
105  word_end_sym, &ans)
106  && ans == ans_check);
107  }
108 
109  { // test w/ one empty word then one real word w/ one phone..
110  std::vector<int32> phnx; phnx.push_back(3); phnx.push_back(4);
111  phnx.push_back(word_start_sym); phnx.push_back(5); phnx.push_back(word_end_sym);
112  std::vector<int32> words; words.push_back(100);
113  std::vector<std::vector<int32> > ans;
114  std::vector<std::vector<int32> > ans_check(2);
115  ans_check[0].push_back(0);
116  ans_check[0].push_back(3);
117  ans_check[0].push_back(4);
118  ans_check[1].push_back(100);
119  ans_check[1].push_back(5);
120  KALDI_ASSERT(ConvertPhnxToProns(phnx, words, word_start_sym,
121  word_end_sym, &ans)
122  && ans == ans_check);
123  }
124 
125  { // test w/ ONE real word w/ one phone..
126  std::vector<int32> phnx;
127  phnx.push_back(word_start_sym); phnx.push_back(5); phnx.push_back(word_end_sym);
128  std::vector<int32> words; words.push_back(100);
129  std::vector<std::vector<int32> > ans;
130  std::vector<std::vector<int32> > ans_check(1);
131  ans_check[0].push_back(100);
132  ans_check[0].push_back(5);
133  KALDI_ASSERT(ConvertPhnxToProns(phnx, words, word_start_sym,
134  word_end_sym, &ans)
135  && ans == ans_check);
136  }
137 
138  { // test w/ ONE real word w/ one phone, but no
139  // words supplied-- should fail.
140  std::vector<int32> phnx;
141  phnx.push_back(word_start_sym); phnx.push_back(5); phnx.push_back(word_end_sym);
142  std::vector<int32> words;
143  std::vector<std::vector<int32> > ans;
144  KALDI_ASSERT(!ConvertPhnxToProns(phnx, words, word_start_sym,
145  word_end_sym, &ans));
146  }
147 
148  { // test w/ ONE real word w/ one phone, but two
149  // words supplied-- should fail.
150  std::vector<int32> phnx;
151  phnx.push_back(word_start_sym); phnx.push_back(5); phnx.push_back(word_end_sym);
152  std::vector<int32> words(2, 10);
153  std::vector<std::vector<int32> > ans;
154  KALDI_ASSERT(!ConvertPhnxToProns(phnx, words, word_start_sym,
155  word_end_sym, &ans));
156  }
157 
158  { // test w/ ONE real word w/ one phone, but word-id
159  // is zero-- should fail.
160  std::vector<int32> phnx;
161  phnx.push_back(word_start_sym); phnx.push_back(5); phnx.push_back(word_end_sym);
162  std::vector<int32> words(1, 0);
163  std::vector<std::vector<int32> > ans;
164  KALDI_ASSERT(!ConvertPhnxToProns(phnx, words, word_start_sym,
165  word_end_sym, &ans));
166  }
167 
168  { // test w/ ONE real word w/ two phones, then one
169  // empty word...
170  std::vector<int32> phnx;
171  phnx.push_back(word_start_sym); phnx.push_back(5);
172  phnx.push_back(7); phnx.push_back(word_end_sym);
173  phnx.push_back(10);
174  std::vector<int32> words; words.push_back(100);
175  std::vector<std::vector<int32> > ans;
176  std::vector<std::vector<int32> > ans_check(2);
177  ans_check[0].push_back(100);
178  ans_check[0].push_back(5);
179  ans_check[0].push_back(7);
180  ans_check[1].push_back(0);
181  ans_check[1].push_back(10);
182  KALDI_ASSERT(ConvertPhnxToProns(phnx, words, word_start_sym,
183  word_end_sym, &ans)
184  && ans == ans_check);
185  }
186 }
187 
190  opts.var_floor = RandInt(0, 10);
191  opts.ci_phones_str = "3:2:1";
192  opts.phone_map_rxfilename = "echo 1 2; echo 2 5 |";
193  opts.context_width = RandInt(3, 4);
194  opts.central_position = RandInt(0, 2);
195  AccumulateTreeStatsInfo info(opts);
196  KALDI_ASSERT(info.var_floor == opts.var_floor);
197  KALDI_ASSERT(info.ci_phones.size() == 3 && info.ci_phones[2] == 3);
198  KALDI_ASSERT(info.phone_map.size() == 3 && info.phone_map[2] == 5);
201 }
202 
204  ContextDependency *ctx_dep = NULL;
205  TransitionModel *trans_model = GenRandTransitionModel(&ctx_dep);
206  std::vector<int32> phone_seq;
207  int32 num_phones = RandInt(0, 10);
208  const std::vector<int32> &phone_list = trans_model->GetPhones();
209  for (int32 i = 0; i < num_phones; i++) {
210  int32 rand_phone = phone_list[RandInt(0, phone_list.size() - 1)];
211  phone_seq.push_back(rand_phone);
212  }
213  bool reorder = (RandInt(0, 1) == 0);
214  std::vector<int32> alignment;
215  GenerateRandomAlignment(*ctx_dep, *trans_model, reorder,
216  phone_seq, &alignment);
217  std::vector<std::vector<int32> > split_alignment;
218  SplitToPhones(*trans_model, alignment, &split_alignment);
219  KALDI_ASSERT(split_alignment.size() == phone_seq.size());
220  for (size_t i = 0; i < split_alignment.size(); i++) {
221  KALDI_ASSERT(!split_alignment[i].empty());
222  for (size_t j = 0; j < split_alignment[i].size(); j++) {
223  int32 transition_id = split_alignment[i][j];
224  KALDI_ASSERT(trans_model->TransitionIdToPhone(transition_id) ==
225  phone_seq[i]);
226  }
227  }
228  delete trans_model;
229  delete ctx_dep;
230 }
231 
233  bool old_reorder = (RandInt(0, 1) == 1),
234  new_reorder = (RandInt(0, 1) == 1),
235  new_tree = (RandInt(0, 1) == 1),
236  new_topology = (RandInt(0, 1) == 1);
237  if (!new_tree)
238  new_topology = true;
239 
240  int32 subsample_factor = RandInt(1, 3);
241 
242  KALDI_LOG << " old-reorder = " << old_reorder
243  << ", new-reorder = " << new_reorder
244  << ", new-tree = " << new_tree
245  << ", subsample-factor = " << subsample_factor;
246 
247  std::vector<int32> phones;
248  phones.push_back(1);
249  for (int32 i = 2; i < 20; i++)
250  if (rand() % 2 == 0)
251  phones.push_back(i);
252  int32 N = 2 + rand() % 2, // context-size N is 2 or 3.
253  P = rand() % N; // Central-phone is random on [0, N)
254 
255  std::vector<int32> num_pdf_classes_old,
256  num_pdf_classes_new;
257 
258  ContextDependencyInterface *ctx_dep_old =
259  GenRandContextDependencyLarge(phones, N, P,
260  true, &num_pdf_classes_old),
261  *ctx_dep_new;
262  if (new_tree) {
263  if (new_topology) {
264  ctx_dep_new = GenRandContextDependencyLarge(phones, N, P,
265  true, &num_pdf_classes_new);
266  } else {
267  num_pdf_classes_new = num_pdf_classes_old;
268  ctx_dep_new = MonophoneContextDependency(phones, num_pdf_classes_new);
269  }
270  } else {
271  num_pdf_classes_new = num_pdf_classes_old;
272  ctx_dep_new = ctx_dep_old->Copy();
273  }
274 
275 
276  HmmTopology topo_old = GenRandTopology(phones, num_pdf_classes_old),
277  topo_new = (new_topology ?
278  GenRandTopology(phones, num_pdf_classes_new) : topo_old);
279 
280  TransitionModel trans_model_old(*ctx_dep_old, topo_old),
281  trans_model_new(*ctx_dep_new, topo_new);
282 
283  std::vector<int32> phone_sequence;
284  int32 phone_sequence_length = RandInt(0, 20);
285  for (int32 i = 0; i < phone_sequence_length; i++)
286  phone_sequence.push_back(phones[RandInt(0, phones.size() - 1)]);
287  std::vector<int32> old_alignment;
288  GenerateRandomAlignment(*ctx_dep_old, trans_model_old,
289  old_reorder, phone_sequence,
290  &old_alignment);
291 
292  std::vector<int32> new_alignment;
293 
294  bool ans = ConvertAlignment(trans_model_old, trans_model_new, *ctx_dep_new,
295  old_alignment, subsample_factor, false,
296  new_reorder, NULL, &new_alignment);
297  if(!ans) {
298  KALDI_WARN << "Alignment conversion failed";
299  // make sure it failed for a good reason.
300  KALDI_ASSERT(new_topology || subsample_factor > 1);
301  } else {
302  std::vector<std::vector<int32> > old_split, new_split;
303  bool b1 = SplitToPhones(trans_model_old, old_alignment, &old_split),
304  b2 = SplitToPhones(trans_model_new, new_alignment, &new_split);
305  KALDI_ASSERT(b1 && b2);
306  KALDI_ASSERT(old_split.size() == new_split.size());
307  for (size_t i = 0; i < new_split.size(); i++)
308  KALDI_ASSERT(trans_model_old.TransitionIdToPhone(old_split[i].front()) ==
309  trans_model_new.TransitionIdToPhone(new_split[i].front()));
310  if (!new_topology && subsample_factor == 1) {
311  // we should be able to convert back and it'll be the same.
312  std::vector<int32> old_alignment_copy;
313  bool ans = ConvertAlignment(trans_model_new, trans_model_old, *ctx_dep_old,
314  new_alignment, subsample_factor, false,
315  old_reorder, NULL, &old_alignment_copy);
316  KALDI_ASSERT(ans);
317  KALDI_ASSERT(old_alignment_copy == old_alignment);
318  }
319 
320  }
321  delete ctx_dep_old;
322  delete ctx_dep_new;
323 }
324 
325 
326 }
327 
328 int main() {
330 #ifndef _MSC_VER
332 #endif
333  for (int32 i = 0; i < 2; i++)
335  for (int32 i = 0; i < 5; i++)
337  std::cout << "Test OK.\n";
338 }
339 
int32 words[kMaxOrder]
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
ContextDependency * GenRandContextDependencyLarge(const std::vector< int32 > &phone_ids, int N, int P, bool ensure_all_covered, std::vector< int32 > *hmm_lengths)
GenRandContextDependencyLarge is like GenRandContextDependency but generates a larger tree with speci...
Definition: context-dep.cc:97
A class for storing topology information for phones.
Definition: hmm-topology.h:93
const std::vector< int32 > & GetPhones() const
Returns a sorted, unique list of phones.
void TestAccumulateTreeStatsOptions()
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: hmm-utils.cc:1161
int main()
ContextDependency * MonophoneContextDependency(const std::vector< int32 > &phones, const std::vector< int32 > &phone2num_pdf_classes)
Definition: context-dep.cc:331
std::vector< int32 > phone_map
Definition: tree-accu.h:67
kaldi::int32 int32
virtual ContextDependencyInterface * Copy() const =0
Returns pointer to new object which is copy of current one.
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...
Definition: hmm-utils.cc:723
HmmTopology GenRandTopology(const std::vector< int32 > &phones_in, const std::vector< int32 > &num_pdf_classes)
This method of generating an arbitrary HmmTopology object allows you to specify the number of pdf-cla...
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...
#define KALDI_WARN
Definition: kaldi-error.h:150
void TestSplitToPhones()
std::vector< int32 > ci_phones
Definition: tree-accu.h:65
context-dep-itf.h provides a link between the tree-building code in ../tree/, and the FST code in ...
void TestConvertAlignment()
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
TransitionModel * GenRandTransitionModel(ContextDependency **ctx_dep_out)
#define KALDI_LOG
Definition: kaldi-error.h:153
int32 TransitionIdToPhone(int32 trans_id) const
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 new_is_reordered, const std::vector< int32 > *phone_map, std::vector< int32 > *new_alignment)
ConvertAlignment converts an alignment that was created using one model, to another model...
Definition: hmm-utils.cc:1013
int32 RandInt(int32 min_val, int32 max_val, struct RandomState *state)
Definition: kaldi-math.cc:95
void TestConvertPhnxToProns()