1 /*---------------------------------------------------------------------------*
2 * swimodel.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20 #ifndef _RTT
21 #include <stdio.h>
22 #endif
23 #include <math.h>
24 #include <stdlib.h>
25 #include <assert.h>
26
27 #include "prelib.h"
28 #include "hmmlib.h"
29 #include "portable.h"
30 #include "errhndl.h"
31
32 #include "log_add.h"
33 #include "swimodel.h"
34
35
36 #define MTAG NULL
37
38
39 /*--------------------------------------------------------------*
40 * *
41 * *
42 * *
43 *--------------------------------------------------------------*/
44
45 /* the looping cost lookup table. This table was generated empirically
46 by looking at resulting residency distributions, trying to make them
47 look roughly like normal distributions centered at the average state
48 durations */
49
50 const char loop_cost_table [128][6] = {
51 {0,0,0,0,0,0},
52 {13,15,16,16,16,16},
53 {12,13,14,14,14,14},
54 {11,12,13,13,13,13},
55 {10,12,12,12,12,12},
56 {10,11,11,12,12,12},
57 {10,11,11,11,11,11},
58 {10,11,11,11,11,11},
59 {9,11,11,11,11,11},
60 {9,10,11,11,11,11},
61 {9,10,10,10,10,10},
62 {9,10,10,10,10,10},
63 {9,10,10,10,10,10},
64 {9,10,10,10,10,10},
65 {9,10,10,10,10,10},
66 {9,10,10,10,10,10},
67 {9,10,10,10,10,10},
68 {8,10,10,10,10,10},
69 {8,10,10,10,10,10},
70 {8,10,10,10,10,10},
71 {8,10,10,10,10,10},
72 {8,10,10,10,10,10},
73 {8,10,10,10,10,10},
74 {7,10,10,10,10,10},
75 {7,10,10,10,10,10},
76 {7,10,10,10,10,10},
77 {6,10,10,10,10,10},
78 {6,10,10,10,10,10},
79 {6,10,10,10,10,10},
80 {5,10,10,10,10,10},
81 {5,10,10,10,10,10},
82 {4,10,10,10,10,10},
83 {4,9,10,10,10,10},
84 {3,9,10,10,10,10},
85 {2,9,10,10,10,10},
86 {2,9,10,10,10,10},
87 {2,9,10,10,10,10},
88 {1,9,10,10,10,10},
89 {1,9,10,10,10,10},
90 {1,9,10,10,10,10},
91 {0,9,10,10,10,10},
92 {0,9,10,10,10,10},
93 {0,9,10,10,10,10},
94 {0,8,10,10,10,10},
95 {0,8,10,10,10,10},
96 {0,8,10,10,10,10},
97 {0,7,10,10,10,10},
98 {0,7,10,10,10,10},
99 {0,6,10,10,10,10},
100 {0,5,10,10,10,10},
101 {0,5,10,10,10,10},
102 {0,4,10,10,10,10},
103 {0,3,10,10,10,10},
104 {0,2,10,10,10,10},
105 {0,2,10,10,10,10},
106 {0,1,10,10,10,10},
107 {0,1,9,10,10,10},
108 {0,0,9,10,10,10},
109 {0,0,9,10,10,10},
110 {0,0,9,10,10,10},
111 {0,0,9,10,10,10},
112 {0,0,9,10,10,10},
113 {0,0,9,10,10,10},
114 {0,0,9,10,10,10},
115 {0,0,9,10,10,10},
116 {0,0,8,10,10,10},
117 {0,0,8,10,10,10},
118 {0,0,7,10,10,10},
119 {0,0,6,10,10,10},
120 {0,0,6,10,10,10},
121 {0,0,5,10,10,10},
122 {0,0,4,10,10,10},
123 {0,0,3,10,10,10},
124 {0,0,2,10,10,10},
125 {0,0,1,10,10,10},
126 {0,0,1,10,10,10},
127 {0,0,0,10,10,10},
128 {0,0,0,10,10,10},
129 {0,0,0,9,10,10},
130 {0,0,0,9,10,10},
131 {0,0,0,9,10,10},
132 {0,0,0,9,10,10},
133 {0,0,0,9,10,10},
134 {0,0,0,9,10,10},
135 {0,0,0,9,10,10},
136 {0,0,0,9,10,10},
137 {0,0,0,8,10,10},
138 {0,0,0,8,10,10},
139 {0,0,0,7,10,10},
140 {0,0,0,6,10,10},
141 {0,0,0,5,10,10},
142 {0,0,0,3,10,10},
143 {0,0,0,2,10,10},
144 {0,0,0,1,10,10},
145 {0,0,0,1,10,10},
146 {0,0,0,0,10,10},
147 {0,0,0,0,10,10},
148 {0,0,0,0,10,10},
149 {0,0,0,0,10,10},
150 {0,0,0,0,10,10},
151 {0,0,0,0,9,10},
152 {0,0,0,0,9,10},
153 {0,0,0,0,9,10},
154 {0,0,0,0,9,10},
155 {0,0,0,0,9,10},
156 {0,0,0,0,9,10},
157 {0,0,0,0,9,10},
158 {0,0,0,0,8,10},
159 {0,0,0,0,7,10},
160 {0,0,0,0,6,10},
161 {0,0,0,0,5,10},
162 {0,0,0,0,3,10},
163 {0,0,0,0,2,10},
164 {0,0,0,0,1,10},
165 {0,0,0,0,0,10},
166 {0,0,0,0,0,10},
167 {0,0,0,0,0,10},
168 {0,0,0,0,0,10},
169 {0,0,0,0,0,10},
170 {0,0,0,0,0,10},
171 {0,0,0,0,0,10},
172 {0,0,0,0,0,9},
173 {0,0,0,0,0,9},
174 {0,0,0,0,0,9},
175 {0,0,0,0,0,9},
176 {0,0,0,0,0,9},
177 {0,0,0,0,0,9},
178 {0,0,0,0,0,8}
179 };
180
181 /* the transition cost lookup table. This table was generated empirically
182 by looking at resulting residency distributions, trying to make them
183 look roughly like normal distributions centered at the average state
184 durations */
185
186 const char trans_cost_table [128][6] = {
187 {0,0,0,0,0,0},
188 {0,0,0,0,0,0},
189 {0,0,0,0,0,0},
190 {0,0,0,0,0,0},
191 {0,0,0,0,0,0},
192 {0,0,0,0,0,0},
193 {0,0,0,0,0,0},
194 {1,0,0,0,0,0},
195 {1,0,0,0,0,0},
196 {1,0,0,0,0,0},
197 {1,0,0,0,0,0},
198 {1,0,0,0,0,0},
199 {1,0,0,0,0,0},
200 {1,0,0,0,0,0},
201 {1,0,0,0,0,0},
202 {1,0,0,0,0,0},
203 {1,0,0,0,0,0},
204 {1,0,0,0,0,0},
205 {1,0,0,0,0,0},
206 {1,0,0,0,0,0},
207 {2,0,0,0,0,0},
208 {2,0,0,0,0,0},
209 {2,0,0,0,0,0},
210 {2,0,0,0,0,0},
211 {2,0,0,0,0,0},
212 {2,0,0,0,0,0},
213 {2,0,0,0,0,0},
214 {3,0,0,0,0,0},
215 {3,0,0,0,0,0},
216 {3,0,0,0,0,0},
217 {3,0,0,0,0,0},
218 {4,0,0,0,0,0},
219 {4,0,0,0,0,0},
220 {4,0,0,0,0,0},
221 {5,0,0,0,0,0},
222 {5,0,0,0,0,0},
223 {6,1,0,0,0,0},
224 {6,1,0,0,0,0},
225 {7,1,0,0,0,0},
226 {7,1,0,0,0,0},
227 {8,1,0,0,0,0},
228 {8,1,0,0,0,0},
229 {9,1,0,0,0,0},
230 {10,1,0,0,0,0},
231 {10,1,0,0,0,0},
232 {11,2,0,0,0,0},
233 {12,2,0,0,0,0},
234 {13,2,0,0,0,0},
235 {13,2,0,0,0,0},
236 {14,3,0,0,0,0},
237 {15,3,0,0,0,0},
238 {15,3,0,0,0,0},
239 {16,4,0,0,0,0},
240 {17,4,0,0,0,0},
241 {17,5,0,0,0,0},
242 {18,6,0,0,0,0},
243 {18,6,0,0,0,0},
244 {19,7,0,0,0,0},
245 {19,8,0,0,0,0},
246 {19,9,0,0,0,0},
247 {20,10,0,0,0,0},
248 {20,11,0,0,0,0},
249 {20,12,0,0,0,0},
250 {20,13,0,0,0,0},
251 {21,14,1,0,0,0},
252 {21,15,1,0,0,0},
253 {21,16,1,0,0,0},
254 {21,17,1,0,0,0},
255 {22,18,2,0,0,0},
256 {22,19,2,0,0,0},
257 {22,19,2,0,0,0},
258 {22,20,3,0,0,0},
259 {22,20,3,0,0,0},
260 {23,21,4,0,0,0},
261 {23,21,5,0,0,0},
262 {23,22,6,0,0,0},
263 {23,22,7,0,0,0},
264 {23,23,8,0,0,0},
265 {23,23,9,0,0,0},
266 {23,23,10,0,0,0},
267 {24,23,12,0,0,0},
268 {24,24,13,0,0,0},
269 {24,24,14,0,0,0},
270 {24,24,16,0,0,0},
271 {24,24,17,0,0,0},
272 {24,24,18,0,0,0},
273 {25,24,20,0,0,0},
274 {25,25,21,1,0,0},
275 {25,25,22,1,0,0},
276 {25,25,22,1,0,0},
277 {25,25,23,2,0,0},
278 {25,25,24,2,0,0},
279 {25,25,24,3,0,0},
280 {25,25,25,3,0,0},
281 {26,26,25,4,0,0},
282 {26,26,25,5,0,0},
283 {26,26,25,6,0,0},
284 {26,26,26,8,0,0},
285 {26,26,26,9,0,0},
286 {26,26,26,11,0,0},
287 {26,26,26,13,0,0},
288 {27,27,26,15,0,0},
289 {27,27,27,17,0,0},
290 {27,27,27,18,0,0},
291 {27,27,27,20,0,0},
292 {27,27,27,22,0,0},
293 {27,27,27,23,0,0},
294 {27,27,27,24,0,0},
295 {27,27,27,25,0,0},
296 {27,27,27,26,1,0},
297 {28,28,28,26,1,0},
298 {28,28,28,27,1,0},
299 {28,28,28,27,2,0},
300 {28,28,28,27,3,0},
301 {28,28,28,28,3,0},
302 {28,28,28,28,5,0},
303 {28,28,28,28,6,0},
304 {28,28,28,28,8,0},
305 {28,28,28,28,10,0},
306 {29,29,29,29,12,0},
307 {29,29,29,29,14,0},
308 {29,29,29,29,16,0},
309 {29,29,29,29,19,0},
310 {29,29,29,29,21,0},
311 {29,29,29,29,23,0},
312 {29,29,29,29,24,0},
313 {29,29,29,29,26,0},
314 {29,29,29,29,27,0}
315 };
316
317 /*--------------------------------------------------------------*
318 * *
319 * *
320 * *
321 *--------------------------------------------------------------*/
322
load_short(PFile * fp)323 static short load_short(PFile* fp)
324 {
325 short v;
326 pfread(&v, sizeof(short), 1, fp);
327 return v;
328 }
329
load_swimodel(const char * filename)330 const SWIModel* load_swimodel(const char *filename)
331 {
332 int i;
333 SWIModel *swimodel = NULL;
334 const void* file = NULL;
335
336 #ifdef SREC_ENGINE_VERBOSE_LOGGING
337 PLogMessage("load_swimodel: loaded %s", filename);
338 #endif
339 swimodel = (SWIModel*) CALLOC(1, sizeof(SWIModel), "clib.models.base");
340
341 if (mmap_zip(filename, &swimodel->mmap_zip_data, &swimodel->mmap_zip_size)) {
342 PLogError("load_swimodel: mmap_zip failed for %s\n", filename);
343 goto CLEANUP;
344 }
345 file = swimodel->mmap_zip_data;
346
347 swimodel->num_hmmstates = *(const short*)file;
348 file += sizeof(short);
349 swimodel->num_dims = *(const short*)file;
350 file += sizeof(short);
351 swimodel->num_pdfs = *(const short*)file;
352 file += sizeof(short);
353
354 SWIhmmState* hmmstates = (SWIhmmState*) CALLOC(swimodel->num_hmmstates, sizeof(SWIhmmState), "clib.models.states");
355 swimodel->hmmstates = hmmstates;
356
357 const short* num_pdfs_in_model = (const short*)file;
358 file += sizeof(short) * swimodel->num_hmmstates;
359
360 swimodel->allmeans = (const featdata*)file;
361 file += sizeof(featdata) * swimodel->num_pdfs * swimodel->num_dims;
362
363 swimodel->allweights = (const wtdata*)file;
364 file += sizeof(wtdata) * swimodel->num_pdfs;
365
366 swimodel->avg_state_durations = (const featdata*)file;
367 file += sizeof(featdata) * swimodel->num_hmmstates;
368
369 if (file > swimodel->mmap_zip_data + swimodel->mmap_zip_size) {
370 PLogError("load_swimodel: not enough data in %s", filename);
371 goto CLEANUP;
372 }
373
374 #ifdef SREC_ENGINE_VERBOSE_LOGGING
375 PLogMessage("loaded models %s num_hmmstates %d num_dims %d num_pdfs %d weights[0] %d\n",
376 filename, swimodel->num_hmmstates, swimodel->num_dims, swimodel->num_pdfs,
377 *swimodel->allweights);
378 #endif
379
380 const featdata* mean_ptr = swimodel->allmeans;
381 const wtdata* weight_ptr = swimodel->allweights;
382
383 for (i = 0;i < swimodel->num_hmmstates;i++)
384 {
385 hmmstates[i].num_pdfs = num_pdfs_in_model[i];
386 hmmstates[i].means = mean_ptr;
387 hmmstates[i].weights = weight_ptr;
388 mean_ptr += swimodel->num_dims * num_pdfs_in_model[i];
389 weight_ptr += num_pdfs_in_model[i];
390 }
391
392 return swimodel;
393
394 CLEANUP:
395 free_swimodel(swimodel);
396 return NULL;
397 }
398
free_swimodel(const SWIModel * swimodel)399 void free_swimodel(const SWIModel* swimodel)
400 {
401 if (!swimodel) return;
402 if (swimodel->mmap_zip_data) munmap_zip(swimodel->mmap_zip_data, swimodel->mmap_zip_size);
403 FREE((void*)swimodel->hmmstates);
404 FREE((void*)swimodel);
405 }
406
Gaussian_Grand_Density_Swimodel(const preprocessed * data,const featdata * means)407 static PINLINE prdata Gaussian_Grand_Density_Swimodel(const preprocessed *data, const featdata *means)
408 /*
409 ** Observation probability function of a Gaussian pdf
410 ** with diagonal covariance matrix.
411 */
412 {
413 prdata pval;
414 prdata diff;
415 const imeldata *dvec;
416 const imeldata *dend;
417 int count;
418
419 dvec = data->seq + data->use_from; /* Move to starting feature element */
420
421 pval = 0;
422 dend = dvec + data->use_dim;
423 count = 0;
424 while (dvec < dend)
425 {
426 diff = *(means++) - *(dvec++);
427 pval -= diff * diff;
428 }
429 pval = data->mul.multable_factor_gaussian
430 * (pval - data->mul.grand_mod_cov_gaussian);
431 return (pval);
432 }
433
mixture_diagonal_gaussian_swimodel(const preprocessed * prep,const SWIhmmState * spd,short num_dims)434 scodata mixture_diagonal_gaussian_swimodel(const preprocessed *prep,
435 const SWIhmmState *spd, short num_dims)
436 /*
437 ** Observation probability function
438 */
439 {
440 int ii;
441 prdata pval, gval;
442
443 prdata dval;
444 const featdata *meanptr;
445 const wtdata *weightptr;
446
447 ASSERT(prep);
448 ASSERT(spd);
449
450 pval = -(prdata) MAX_LOG;
451
452 meanptr = spd->means;
453 weightptr = spd->weights;
454
455 for (ii = 0; ii < spd->num_pdfs; ii++)
456 {
457 gval = ((prdata) * (weightptr++) * prep->add.scale
458 + Gaussian_Grand_Density_Swimodel(prep, meanptr));
459
460 meanptr += num_dims;
461
462 if (pval > gval)
463 {
464 dval = pval - gval;
465 if (dval < prep->add.add_log_limit)
466 pval += log_increment_inline(dval, &prep->add);
467 }
468 else
469 {
470 dval = gval - pval;
471 if (dval < prep->add.add_log_limit)
472 pval = gval + log_increment_inline(dval, &prep->add);
473 else
474 pval = gval;
475 }
476 }
477 ASSERT(pval > ((0x01 << 31) / (prep->mix_score_scale * prep->add.inv_scale)));
478 pval = ((pval * prep->mix_score_scale - 64 * prep->add.scale)
479 * prep->add.inv_scale) >> 19;
480
481 return ((scodata)pval);
482 }
483