/** * Initialize and setup acoustic computation functions. * * @param wrk [i/o] HMM computation work area * @param hmminfo [in] HMM definition * @param gshmm [in] GMS HMM definition if exist, or NULL if not * @param gms_num [in] number of GMS HMM to compute (valid if gshmm != NULL) * @param gprune_method [in] gaussian pruning method * @param gprune_mixnum [in] number of pdf to compute at a codebook * in gaussian pruning * * @return TRUE on success, FALSE on failure. */ boolean outprob_init(HMMWork *wrk, HTK_HMM_INFO *hmminfo, HTK_HMM_INFO *gshmm, int gms_num, int gprune_method, int gprune_mixnum ) { int i; /* check if variances are inversed */ if (!hmminfo->variance_inversed) { /* here, inverse all variance values for faster computation */ htk_hmm_inverse_variances(hmminfo); hmminfo->variance_inversed = TRUE; } /* check if variances are inversed */ if (gshmm) { if (!gshmm->variance_inversed) { /* here, inverse all variance values for faster computation */ htk_hmm_inverse_variances(gshmm); gshmm->variance_inversed = TRUE; } } /** select functions **/ /* select pruning function to compute likelihood of a mixture component and set the pointer to global */ #ifdef ENABLE_MSD /* currently MSD model works only for non pruning mode */ if (hmminfo->has_msd && gprune_method != GPRUNE_SEL_NONE) { jlog("Error: outprob_init: only \"-gprune none\" is supported when MSD-HMM enabled\n"); return FALSE; } #endif switch(gprune_method) { case GPRUNE_SEL_NONE: wrk->compute_gaussset = gprune_none; wrk->compute_gaussset_init = gprune_none_init; wrk->compute_gaussset_free = gprune_none_free; break; case GPRUNE_SEL_SAFE: wrk->compute_gaussset = gprune_safe; wrk->compute_gaussset_init = gprune_safe_init; wrk->compute_gaussset_free = gprune_safe_free; break; case GPRUNE_SEL_HEURISTIC: wrk->compute_gaussset = gprune_heu; wrk->compute_gaussset_init = gprune_heu_init; wrk->compute_gaussset_free = gprune_heu_free; break; case GPRUNE_SEL_BEAM: wrk->compute_gaussset = gprune_beam; wrk->compute_gaussset_init = gprune_beam_init; wrk->compute_gaussset_free = gprune_beam_free; break; case GPRUNE_SEL_USER: /* assume user functions are already registered to the entries */ break; } /* select caching function to compute output probability of a mixture */ if (hmminfo->is_tied_mixture) { /* check if all mixture PDFs are tied-mixture */ { HTK_HMM_PDF *p; boolean ok_p = TRUE; for (p = hmminfo->pdfstart; p; p = p->next) { if (p->tmix == FALSE) { ok_p = FALSE; break; } } if (ok_p) { jlog("Stat: outprob_init: all mixture PDFs are tied-mixture, use calc_tied_mix()\n"); wrk->calc_outprob = calc_tied_mix; /* enable book-level cache, typically for a tied-mixture model */ } else { jlog("Stat: outprob_init: tied-mixture PDF exist (not all), calc_compound_mix()\n"); wrk->calc_outprob = calc_compound_mix; /* enable book-level cache, typically for a tied-mixture model */ } } } else { jlog("Stat: outprob_init: state-level mixture PDFs, use calc_mix()\n"); wrk->calc_outprob = calc_mix; /* no mixture-level cache, for a shared-state, non tied-mixture model */ } /* select back-off functon for state probability calculation */ if (gshmm != NULL) { wrk->calc_outprob_state = gms_state; /* enable GMS */ } else { wrk->calc_outprob_state = wrk->calc_outprob; /* call mixture outprob directly */ } /* store common variable to global */ wrk->OP_hmminfo = hmminfo; wrk->OP_gshmm = gshmm; /* NULL if GMS not used */ wrk->OP_gprune_num = gprune_mixnum; /* store multi-stream data */ wrk->OP_nstream = hmminfo->opt.stream_info.num; for(i=0;i<wrk->OP_nstream;i++) { wrk->OP_veclen_stream[i] = hmminfo->opt.stream_info.vsize[i]; } /* generate addlog table */ make_log_tbl(); /* initialize work area for mixture component pruning function */ if ((*(wrk->compute_gaussset_init))(wrk) == FALSE) return FALSE; /* OP_gprune may change */ /* initialize work area for book level cache on tied-mixture model */ if (hmminfo->is_tied_mixture) { if (calc_tied_mix_init(wrk) == FALSE) return FALSE; } /* initialize work area for GMS */ if (wrk->OP_gshmm != NULL) { wrk->my_nbest = gms_num; if (gms_init(wrk) == FALSE) return FALSE; } /* initialize cache for all output probabilities */ if (outprob_cache_init(wrk) == FALSE) return FALSE; /* initialize word area for computation of pseudo HMM set when N-max is specified */ if (hmminfo->cdset_method == IWCD_NBEST) { outprob_cd_nbest_init(wrk, hmminfo->cdmax_num); } return TRUE; }
/** * <JA> * GMMの計算のための初期化. 起動時に一度だけ呼ばれる. * * @param recog [i/o] エンジンインスタンス * </JA> * <EN> * Initialization for computing GMM likelihoods. This will be called * once on startup. * * @param recog [i/o] engine instance * </EN> * * @callgraph * @callergraph * */ boolean gmm_init(Recog *recog) { HTK_HMM_INFO *gmm; HTK_HMM_Data *d; GMMCalc *gc; int i; gmm = recog->gmm; /* check GMM format */ /* tied-mixture GMM is not supported */ if (gmm->is_tied_mixture) { jlog("ERROR: gmm_init: tied-mixture GMM is not supported\n"); return FALSE; } /* assume 3 state GMM (only one output state) */ for(d=gmm->start;d;d=d->next) { if (d->state_num > 3) { jlog("ERROR: gmm_init: more than three states (one output state) defined in GMM [%s]\n", d->name); return FALSE; } } /* check if CMN needed */ /* allocate work area */ if (recog->gc == NULL) { gc = (GMMCalc *)mymalloc(sizeof(GMMCalc)); recog->gc = gc; } else { gc = recog->gc; } /* allocate buffers */ gc->gmm_score = (LOGPROB *)mymalloc(sizeof(LOGPROB) * gmm->totalhmmnum); #ifdef GMM_VAD gc->nframe = recog->jconf->detect.gmm_margin; gc->rates = (LOGPROB *)mymalloc(sizeof(LOGPROB) * gc->nframe); #endif gc->is_voice = (boolean *)mymalloc(sizeof(boolean) * gmm->totalhmmnum); i = 0; if (recog->jconf->reject.gmm_reject_cmn_string) { for(d=recog->gmm->start;d;d=d->next) { if (strstr(recog->jconf->reject.gmm_reject_cmn_string, d->name)) { gc->is_voice[i] = FALSE; } else { gc->is_voice[i] = TRUE; } i++; } } else { for(d=recog->gmm->start;d;d=d->next) { gc->is_voice[i] = TRUE; i++; } } /* initialize work area */ gc->OP_nstream = gmm->opt.stream_info.num; for(i=0;i<gc->OP_nstream;i++) { gc->OP_veclen_stream[i] = gmm->opt.stream_info.vsize[i]; } gmm_gprune_safe_init(gc, gmm, recog->jconf->reject.gmm_gprune_num); /* check if variances are inversed */ if (!gmm->variance_inversed) { /* here, inverse all variance values for faster computation */ htk_hmm_inverse_variances(gmm); gmm->variance_inversed = TRUE; } return TRUE; }
/** * @brief Main top routine to read in HTK %HMM definition file. * * A HTK %HMM definition file will be read from @a fp. After reading, * the parameter type is checked and calculate some statistics. * * @param fp [in] file pointer * @param hmm [out] pointer to a %HMM definition structure to store data. * * @return TRUE on success, FALSE on failure. */ boolean rdhmmdef(FILE *fp, HTK_HMM_INFO *hmm) { char macrosw; char *name; /* variances in htkdefs are not inversed yet */ hmm->variance_inversed = FALSE; /* read the first token */ /* read new 1 line */ line = 1; if (getl(buf, MAXBUFLEN, fp) == NULL) { rdhmmdef_token = NULL; } else { rdhmmdef_token = mystrtok_quote(buf, HMMDEF_DELM); } /* the toplevel loop */ while (rdhmmdef_token != NULL) {/* break on EOF */ if (rdhmmdef_token[0] != '~') { /* toplevel commands are always macro */ return FALSE; } macrosw = rdhmmdef_token[1]; read_token(fp); /* read next token after the "~.." */ switch(macrosw) { case 'o': /* global option */ if (set_global_opt(fp,hmm) == FALSE) { return FALSE; } break; case 't': /* transition macro */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_trans_macro(name, fp, hmm); break; case 's': /* state macro */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_state_macro(name, fp, hmm); break; case 'm': /* density (mixture) macro */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_dens_macro(name, fp, hmm); break; case 'h': /* HMM define */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_HMM(name, fp, hmm); break; case 'v': /* Variance macro */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_var_macro(name, fp, hmm); break; case 'w': /* Stream weight macro */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_streamweight_macro(name, fp, hmm); break; case 'r': /* Regression class macro (ignore) */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_regtree_macro(name, fp, hmm); break; case 'p': /* Mixture pdf macro (extension of HTS) */ name = mybstrdup2(rdhmmdef_token, &(hmm->mroot)); if (strlen(name) >= MAX_HMMNAME_LEN) rderr("Macro name too long"); read_token(fp); def_mpdf_macro(name, fp, hmm); break; } } /* convert transition prob to log scale */ conv_log_arc(hmm); jlog("Stat: rdhmmdef: ascii format HMM definition\n"); /* check limitation */ if (check_all_hmm_limit(hmm)) { jlog("Stat: rdhmmdef: limit check passed\n"); } else { jlog("Error: rdhmmdef: cannot handle this HMM due to system limitation\n"); return FALSE; } /* determine whether this model needs multi-path handling */ hmm->need_multipath = htk_hmm_has_several_arc_on_edge(hmm); if (hmm->need_multipath) { jlog("Stat: rdhmmdef: this HMM requires multipath handling at decoding\n"); } else { jlog("Stat: rdhmmdef: this HMM does not need multipath handling\n"); } /* inverse all variance values for faster computation */ if (! hmm->variance_inversed) { htk_hmm_inverse_variances(hmm); hmm->variance_inversed = TRUE; } /* check HMM parameter option type */ if (!check_hmm_options(hmm)) { jlog("Error: rdhmmdef: hmm options check failed\n"); return FALSE; } /* add ID number for all HTK_HMM_State if not assigned */ { HTK_HMM_State *stmp; int n; boolean has_sid; /* caclculate total num and check if has sid */ has_sid = FALSE; n = 0; for (stmp = hmm->ststart; stmp; stmp = stmp->next) { n++; if (n >= MAX_STATE_NUM) { jlog("Error: rdhmmdef: too much states in a model > %d\n", MAX_STATE_NUM); return FALSE; } if (stmp->id != -1) { has_sid = TRUE; } } hmm->totalstatenum = n; if (has_sid) { jlog("Stat: rdhmmdef: <SID> found in the definition\n"); /* check if each state is assigned a valid sid */ if (htk_hmm_check_sid(hmm) == FALSE) { jlog("Error: rdhmmdef: error in SID\n"); return FALSE; } } else { /* assign internal sid (will not be saved) */ jlog("Stat: rdhmmdef: no <SID> embedded\n"); jlog("Stat: rdhmmdef: assign SID by the order of appearance\n"); n = hmm->totalstatenum; for (stmp = hmm->ststart; stmp; stmp = stmp->next) { stmp->id = --n; } } } /* calculate the maximum number of mixture */ { HTK_HMM_State *stmp; int max, s, mix; max = 0; for (stmp = hmm->ststart; stmp; stmp = stmp->next) { for(s=0;s<stmp->nstream;s++) { mix = stmp->pdf[s]->mix_num; if (max < mix) max = mix; } } hmm->maxmixturenum = max; } /* compute total number of HMM models and maximum length */ { HTK_HMM_Data *dtmp; int n, maxlen; n = 0; maxlen = 0; for (dtmp = hmm->start; dtmp; dtmp = dtmp->next) { if (maxlen < dtmp->state_num) maxlen = dtmp->state_num; n++; } hmm->maxstatenum = maxlen; hmm->totalhmmnum = n; } /* compute total number of Gaussians */ { HTK_HMM_Dens *dtmp; int n = 0; for (dtmp = hmm->dnstart; dtmp; dtmp = dtmp->next) { n++; } hmm->totalmixnum = n; } /* check of HMM name length exceed the maximum */ { HTK_HMM_Dens *dtmp; int n = 0; for (dtmp = hmm->dnstart; dtmp; dtmp = dtmp->next) { n++; } hmm->totalmixnum = n; } /* compute total number of mixture PDFs */ { HTK_HMM_PDF *p; int n = 0; for (p = hmm->pdfstart; p; p = p->next) { n++; } hmm->totalpdfnum = n; } /* assign ID number for all HTK_HMM_Trans */ { HTK_HMM_Trans *ttmp; int n = 0; for (ttmp = hmm->trstart; ttmp; ttmp = ttmp->next) { ttmp->id = n++; } hmm->totaltransnum = n; } #ifdef ENABLE_MSD /* check if MSD-HMM */ htk_hmm_check_msd(hmm); #endif return(TRUE); /* success */ }