julius/outprob_style.c

説明を見る。
00001 
00073 /*
00074  * Copyright (c) 1991-2006 Kawahara Lab., Kyoto University
00075  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00076  * Copyright (c) 2005-2006 Julius project team, Nagoya Institute of Technology
00077  * All rights reserved
00078  */
00079 
00080 #include <julius.h>
00081 
00082 static char rbuf[MAX_HMMNAME_LEN]; 
00083 
00084 #ifdef PASS1_IWCD
00085 
00098 void
00099 outprob_style_cache_init(WCHMM_INFO *wchmm)
00100 {
00101   int n;
00102   for(n=0;n<wchmm->n;n++) {
00103 #ifdef MULTIPATH_VERSION
00104     if (wchmm->state[n].out.state == NULL) continue;
00105 #endif
00106     if (wchmm->outstyle[n] == AS_RSET) {
00107       (wchmm->state[n].out.rset)->cache.state = NULL;
00108     } else if (wchmm->outstyle[n] == AS_LRSET) {
00109       (wchmm->state[n].out.lrset)->cache.state = NULL;
00110     }
00111   }
00112 }
00113 
00114 
00115 /**********************************************************************/
00116 #ifdef CATEGORY_TREE
00117 
00118 static char lccbuf[MAX_HMMNAME_LEN+7]; 
00119 static char lccbuf2[MAX_HMMNAME_LEN+7]; 
00120 
00143 CD_Set *
00144 lcdset_lookup_with_category(WCHMM_INFO *wchmm, HMM_Logical *hmm, WORD_ID category)
00145 {
00146   CD_Set *cd;
00147 
00148   leftcenter_name(hmm->name, lccbuf);
00149   sprintf(lccbuf2, "%s::%04d", lccbuf, category);
00150   if (wchmm->lcdset_category_root != NULL) {
00151     cd = aptree_search_data(lccbuf2, wchmm->lcdset_category_root);
00152     if (strmatch(lccbuf2, cd->name)) {
00153       return cd;
00154     }
00155   }
00156   return NULL;
00157 }
00158 
00208 static void
00209 lcdset_register_with_category(WCHMM_INFO *wchmm, HTK_HMM_INFO *hmminfo, DFA_INFO *dfa, HMM_Logical *hmm, WORD_ID category)
00210 {
00211   CD_Set *ret;
00212   WORD_ID c2, i, w;
00213   HMM_Logical *ltmp;
00214 
00215   int cnt_c, cnt_w, cnt_p;
00216 
00217   if (lcdset_lookup_with_category(wchmm, hmm, category) == NULL) {
00218     leftcenter_name(hmm->name, lccbuf);
00219     sprintf(lccbuf2, "%s::%04d", lccbuf, category);
00220     if (debug2_flag) {
00221       j_printf("category-aware lcdset {%s}...", lccbuf2);
00222     }
00223     cnt_c = cnt_w = cnt_p = 0;
00224     /* search for category that can connect after this category */
00225     for(c2=0;c2<dfa->term_num;c2++) {
00226       if (! dfa_cp(dfa, category, c2)) continue;
00227       /* for each word in the category, register triphone whose right context
00228          is the beginning phones  */
00229       for(i=0;i<dfa->term.wnum[c2];i++) {
00230         w = dfa->term.tw[c2][i];
00231         ltmp = get_right_context_HMM(hmm, winfo->wseq[w][0]->name, hmminfo);
00232         if (ltmp == NULL) {
00233           ltmp = hmm;
00234           if (ltmp->is_pseudo) {
00235             error_missing_right_triphone(hmm, winfo->wseq[w][0]->name);
00236           }
00237         }
00238         if (! ltmp->is_pseudo) {
00239           if (regist_cdset(&(wchmm->lcdset_category_root), ltmp->body.defined, lccbuf2)) {
00240             cnt_p++;
00241           }
00242         }
00243       }
00244       cnt_c++;
00245       cnt_w += dfa->term.wnum[c2];
00246     }
00247     if (debug2_flag) {
00248       j_printf("%d categories (%d words) can follow, %d HMMs registered\n", cnt_c, cnt_w, cnt_p);
00249     }
00250   }
00251 }
00252 
00272 void
00273 lcdset_register_with_category_all(WCHMM_INFO *wchmm, HTK_HMM_INFO *hmminfo, WORD_INFO *winfo, DFA_INFO *dfa)
00274 {
00275   WORD_ID c1, w, w_prev;
00276   int i;
00277   HMM_Logical *ltmp;
00278   
00279   /* (1) 単語終端の音素について */
00280   /*     word end phone */
00281   for(w=0;w<winfo->num;w++) {
00282     ltmp = winfo->wseq[w][winfo->wlen[w]-1];
00283     lcdset_register_with_category(wchmm, hmminfo, dfa, ltmp, winfo->wton[w]);
00284   }
00285   /* (2)1音素単語の場合, 先行しうる単語の終端音素を考慮 */
00286   /*    for one-phoneme word, possible left context should be also considered */
00287   for(w=0;w<winfo->num;w++) {
00288     if (winfo->wlen[w] > 1) continue;
00289     for(c1=0;c1<dfa->term_num;c1++) {
00290       if (! dfa_cp(dfa, c1, winfo->wton[w])) continue;
00291       for(i=0;i<dfa->term.wnum[c1];i++) {
00292         w_prev = dfa->term.tw[c1][i];
00293         ltmp = get_left_context_HMM(winfo->wseq[w][0], winfo->wseq[w_prev][winfo->wlen[w_prev]-1]->name, hmminfo);
00294         if (ltmp == NULL) continue; /* 1音素自身のlcd_setは(1)で作成済 */
00295         if (ltmp->is_pseudo) continue; /* pseudo phone ならlcd_setはいらない */
00296         lcdset_register_with_category(wchmm, hmminfo, dfa, ltmp, winfo->wton[w]);
00297       }
00298     }
00299   }
00300 }
00301 
00317 void
00318 lcdset_remove_with_category_all(WCHMM_INFO *wchmm)
00319 {
00320   free_cdset(&(wchmm->lcdset_category_root));
00321 }
00322 
00323 #endif /* CATEGORY_TREE */
00324 
00325 #endif /* PASS1_IWCD */
00326 
00353 LOGPROB
00354 outprob_style(WCHMM_INFO *wchmm, int node, int last_wid, int t, HTK_Param *param)
00355 {
00356 
00357 #ifndef PASS1_IWCD
00358   
00359   /* if cross-word triphone handling is disabled, we simply compute the
00360      output prob of the state */
00361   return(outprob_state(t, wchmm->state[node].out, param));
00362   
00363 #else  /* PASS1_IWCD */
00364 
00365   /* state type and context cache is considered */
00366   HMM_Logical *ohmm, *rhmm;
00367   RC_INFO *rset;
00368   LRC_INFO *lrset;
00369   CD_Set *lcd;
00370   WORD_INFO *winfo = wchmm->winfo;
00371   HTK_HMM_INFO *hmminfo = wchmm->hmminfo;
00372 
00373   /* the actual computation is different according to their context dependency
00374      handling */
00375   switch(wchmm->outstyle[node]) {
00376   case AS_STATE:
00377     /* normal state (word-internal or context-independent )*/
00378     /* compute as usual */
00379     return(outprob_state(t, wchmm->state[node].out.state, param));
00380   case AS_LSET:
00381     /* node in word end phone */
00382     /* compute approximated value using the state set in pseudo phone */
00383     return(outprob_cd(t, wchmm->state[node].out.lset, param));
00384   case AS_RSET:
00385     /* note in the beginning phone of word */
00386     /* depends on the last word hypothesis to compute the actual triphone */
00387     rset = wchmm->state[node].out.rset;
00388     /* consult cache */
00389     if (rset->cache.state == NULL || rset->lastwid_cache != last_wid) {
00390       /* cache miss...calculate */
00391       /* rset contains either defined biphone or pseudo biphone */
00392       if (last_wid != WORD_INVALID) {
00393         /* lookup triphone with left-context (= last phoneme) */
00394         if ((ohmm = get_left_context_HMM(rset->hmm, (winfo->wseq[last_wid][winfo->wlen[last_wid]-1])->name, hmminfo)) != NULL) {
00395           rhmm = ohmm;
00396         } else {
00397           /* if triphone not found, try to use the bi-phone itself */
00398           rhmm = rset->hmm;
00399           /* If the bi-phone is explicitly specified in hmmdefs/HMMList,
00400              use it.  if both triphone and biphone not found in user-given
00401              hmmdefs/HMMList, use "pseudo" phone, as same as the end of word */
00402           if (debug2_flag) {
00403             if (rhmm->is_pseudo) {
00404             error_missing_left_triphone(rset->hmm, (winfo->wseq[last_wid][winfo->wlen[last_wid]-1])->name);
00405             }
00406           }
00407         }
00408       } else {
00409         /* if last word is WORD_INVALID try to use the bi-phone itself */
00410         rhmm = rset->hmm;
00411         /* If the bi-phone is explicitly specified in hmmdefs/HMMList,
00412            use it.  if not, use "pseudo" phone, as same as the end of word */
00413         if (debug2_flag) {
00414           if (rhmm->is_pseudo) {
00415             error_missing_left_triphone(rset->hmm, (winfo->wseq[last_wid][winfo->wlen[last_wid]-1])->name);
00416           }
00417         }
00418       }
00419       /* rhmm may be a pseudo phone */
00420       /* store to cache */
00421       if (rhmm->is_pseudo) {
00422         rset->last_is_lset  = TRUE;
00423         rset->cache.lset    = &(rhmm->body.pseudo->stateset[rset->state_loc]);
00424       } else {
00425         rset->last_is_lset  = FALSE;
00426         rset->cache.state   = rhmm->body.defined->s[rset->state_loc];
00427       }
00428       rset->lastwid_cache = last_wid;
00429     }
00430     /* calculate outprob and return */
00431     if (rset->last_is_lset) {
00432       return(outprob_cd(t, rset->cache.lset, param));
00433     } else {
00434       return(outprob_state(t, rset->cache.state, param));
00435     }
00436   case AS_LRSET:
00437     /* node in word with only one phoneme --- both beginning and end */
00438     lrset = wchmm->state[node].out.lrset;
00439     if (lrset->cache.state == NULL || lrset->lastwid_cache != last_wid) {
00440       /* cache miss...calculate */
00441       rhmm = lrset->hmm;
00442       /* lookup cdset for given left context (= last phoneme) */
00443       strcpy(rbuf, rhmm->name);
00444       if (last_wid != WORD_INVALID) {
00445         add_left_context(rbuf, (winfo->wseq[last_wid][winfo->wlen[last_wid]-1])->name);
00446       }
00447 #ifdef CATEGORY_TREE
00448       if (!old_iwcd_flag) {
00449         /* use category-indexed cdset */
00450         if (last_wid != WORD_INVALID &&
00451             (ohmm = get_left_context_HMM(rhmm, (winfo->wseq[last_wid][winfo->wlen[last_wid]-1])->name, hmminfo)) != NULL) {
00452           lcd = lcdset_lookup_with_category(wchmm, ohmm, lrset->category);
00453         } else {
00454           lcd = lcdset_lookup_with_category(wchmm, rhmm, lrset->category);
00455         }
00456       } else {
00457         lcd = lcdset_lookup_by_hmmname(hmminfo, rbuf);
00458       }
00459 #else
00460       lcd = lcdset_lookup_by_hmmname(hmminfo, rbuf);
00461 #endif /* CATEGORY_TREE */
00462       if (lcd != NULL) {        /* found, set to cache */
00463         lrset->last_is_lset  = TRUE;
00464         lrset->cache.lset    = &(lcd->stateset[lrset->state_loc]);
00465         lrset->lastwid_cache = last_wid;
00466       } else {
00467         /* no relating lcdset found, falling to normal state */
00468         if (rhmm->is_pseudo) {
00469           lrset->last_is_lset  = TRUE;
00470           lrset->cache.lset    = &(rhmm->body.pseudo->stateset[lrset->state_loc]);
00471           lrset->lastwid_cache = last_wid;
00472         } else {
00473           lrset->last_is_lset  = FALSE;
00474           lrset->cache.state   = rhmm->body.defined->s[lrset->state_loc];
00475           lrset->lastwid_cache = last_wid;
00476         }
00477       }
00478       /*printf("[%s->%s]\n", lrset->hmm->name, rhmm->name);*/
00479     }
00480     /* calculate outprob and return */
00481     if (lrset->last_is_lset) {
00482       return(outprob_cd(t, lrset->cache.lset, param));
00483     } else {
00484       return(outprob_state(t, lrset->cache.state, param));
00485     }
00486   default:
00487     /* should not happen */
00488     j_error("InternalError: no outprob style??\n");
00489     return(LOG_ZERO);
00490   }
00491 
00492 #endif  /* PASS1_IWCD */
00493 
00494 }
00495 
00512 void
00513 error_missing_right_triphone(HMM_Logical *base, char *rc_name)
00514 {
00515   /* only output message */
00516   strcpy(rbuf, base->name);
00517   add_right_context(rbuf, rc_name);
00518   j_printerr("Warning: IW-triphone for word end \"%s\" not found, fallback to pseudo {%s}\n", rbuf, base->name);
00519 }
00520 
00537 void
00538 error_missing_left_triphone(HMM_Logical *base, char *lc_name)
00539 {
00540   /* only output message */
00541   strcpy(rbuf, base->name);
00542   add_left_context(rbuf, lc_name);
00543   j_printerr("Warning: IW-triphone for word head \"%s\" not found, fallback to pseudo {%s}\n", rbuf, base->name);
00544 }

Juliusに対してTue Dec 26 16:19:28 2006に生成されました。  doxygen 1.5.0