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 323 static short load_short(PFile* fp) 324 { 325 short v; 326 pfread(&v, sizeof(short), 1, fp); 327 return v; 328 } 329 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 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 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 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