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
50const 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
186const 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
323static short load_short(PFile* fp)
324{
325  short v;
326  pfread(&v, sizeof(short), 1, fp);
327  return v;
328}
329
330const SWIModel* load_swimodel(const char *filename)
331{
332  int i;
333  SWIModel *swimodel = NULL;
334  const char* 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 > (const char*)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
394CLEANUP:
395  free_swimodel(swimodel);
396  return NULL;
397}
398
399void 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
407static 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
434scodata 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