Home | History | Annotate | Download | only in clib
      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