/** * <JA> * 全ての単語末用カテゴリ付き pseudo phone set を生成する. * 辞書上のすべての単語について,その末尾に登場しうるカテゴリ付き pseudo phone * set を生成する(文法認識用). * * @param wchmm [i/o] 木構造化辞書情報 * </JA> * <EN> * Generate all possible category-indexed pseudo phone sets for * grammar recognition. * * @param wchmm [i/o] tree lexicon * </EN> * @callgraph * @callergraph */ void lcdset_register_with_category_all(WCHMM_INFO *wchmm) { WORD_INFO *winfo; WORD_ID c1, w, w_prev; int i; HMM_Logical *ltmp; winfo = wchmm->winfo; /* (1) 単語終端の音素について */ /* word end phone */ for(w=0;w<winfo->num;w++) { ltmp = winfo->wseq[w][winfo->wlen[w]-1]; lcdset_register_with_category(wchmm, ltmp, winfo->wton[w]); } /* (2)1音素単語の場合, 先行しうる単語の終端音素を考慮 */ /* for one-phoneme word, possible left context should be also considered */ for(w=0;w<winfo->num;w++) { if (winfo->wlen[w] > 1) continue; for(c1=0;c1<wchmm->dfa->term_num;c1++) { if (! dfa_cp(wchmm->dfa, c1, winfo->wton[w])) continue; for(i=0;i<wchmm->dfa->term.wnum[c1];i++) { w_prev = wchmm->dfa->term.tw[c1][i]; ltmp = get_left_context_HMM(winfo->wseq[w][0], winfo->wseq[w_prev][winfo->wlen[w_prev]-1]->name, wchmm->hmminfo); if (ltmp == NULL) continue; /* 1音素自身のlcd_setは(1)で作成済 */ if (ltmp->is_pseudo) continue; /* pseudo phone ならlcd_setはいらない */ lcdset_register_with_category(wchmm, ltmp, winfo->wton[w]); } } } }
/** * <JA> * @brief 単語末用カテゴリ付き pseudo phone set を生成する. * * Julian では,ある単語に後続可能な単語集合は文法によって制限される. よって, * 単語末尾から次に後続しうる単語先頭音素の種類も文法によって限定 * される. そこで,与えられた辞書上で,単語のカテゴリごとに,後続しうる先頭音素 * をカテゴリ対情報から作成し,それらをカテゴリ付き pseudo phone set として * 定義して単語終端に用いることで,Julian における単語間トライフォンの * 近似誤差を小さくすることができる. * * この phone set の名前は通常の "a-k" などと異なり "a-k::38" となる * (数字はカテゴリID). ここでは,辞書を検索して可能なすべてのカテゴリ付き * pseudo phone set を,生成する. これは通常の pseudo phone set とは別に * 保持され,単語末端のみで使用される. * * @param wchmm [i/o] 木構造化辞書 * @param hmm [in] これから登録する単語の終端の論理HMM * @param category [in] これから登録する単語の文法カテゴリID * * </JA> * <EN> * @brief Make a category-indexed context-dependent (pseudo) state set * for word ends. * * In Julian, the word-end pseudo triphone set can be shrinked by using the * category-pair constraint, since the number of possible right-context * phones on the word end will be smaller than all phone. This shrinking not * only saves computation time but also improves recognition since the * approximated value will be closer to the actual value. * * For example, if a word belongs to category ID 38 and has a phone "a-k" * at word end, CD_Set "a-k::38" is generated and assigned to the * phone instead of normal CD_Set "a-k". The "a-k::38" set consists * of triphones whose right context are the beginning phones within * possibly fllowing categories. These will be separated from the normal * pseudo phone set. * * @param wchmm [i/o] tree lexicon * @param hmm [in] logical HMM at the end of a word, of which the * category-indexed pseudo state set will be generated. * @param category [in] category ID of the word. * * </EN> */ static void lcdset_register_with_category(WCHMM_INFO *wchmm, HMM_Logical *hmm, WORD_ID category) { WORD_ID c2, i, w; HMM_Logical *ltmp; int cnt_c, cnt_w, cnt_p; if (lcdset_lookup_with_category(wchmm, hmm, category) == NULL) { leftcenter_name(hmm->name, wchmm->lccbuf); sprintf(wchmm->lccbuf2, "%s::%04d", wchmm->lccbuf, category); if (debug2_flag) { jlog("DEBUG: category-aware lcdset {%s}...", wchmm->lccbuf2); } cnt_c = cnt_w = cnt_p = 0; /* search for category that can connect after this category */ for(c2=0;c2<wchmm->dfa->term_num;c2++) { if (! dfa_cp(wchmm->dfa, category, c2)) continue; /* for each word in the category, register triphone whose right context is the beginning phones */ for(i=0;i<wchmm->dfa->term.wnum[c2];i++) { w = wchmm->dfa->term.tw[c2][i]; ltmp = get_right_context_HMM(hmm, wchmm->winfo->wseq[w][0]->name, wchmm->hmminfo); if (ltmp == NULL) { ltmp = hmm; if (ltmp->is_pseudo) { error_missing_right_triphone(hmm, wchmm->winfo->wseq[w][0]->name); } } if (! ltmp->is_pseudo) { if (regist_cdset(&(wchmm->lcdset_category_root), ltmp->body.defined, wchmm->lccbuf2, &(wchmm->lcdset_mroot))) { cnt_p++; } } } cnt_c++; cnt_w += wchmm->dfa->term.wnum[c2]; } if (debug2_flag) { jlog("%d categories (%d words) can follow, %d HMMs registered\n", cnt_c, cnt_w, cnt_p); } } }
/** * <JA> * @brief 文法による単語内決定的 factoring * * Julian において CATEGORY_TREE が定義されているとき(デフォルト), * 木構造化辞書はカテゴリ単位(すなわち構文制約の記述単位)で構築されるため, * 第1パスでの言語モデルであるカテゴリ対制約は単語の始終端で適用できる. * * この CATEGORY_TREE が定義されていない場合,木構造化辞書は * 辞書全体で単一の木が作られるため,カテゴリ対制約は N-gram (Julius) と * 同様に単語内で factoring と同様の機構で適用される必要がある. * * この関数は CATEGORY_TREE が定義されていないときに,上記の factoring * (決定的 factoring と呼ばれる)を行なうために提供されている. * * @param wchmm [in] 木構造化辞書 * @param lastword [in] 直前単語 * @param node [in] ノード番号 * * @return カテゴリ制約上その枝への遷移が許されれば TRUE, 不可能であれば FALSE * </JA> * <EN> * @brief Deterministic factoring for grammar-based recognition (Julian) * * If CATEGORY_TREE is defined (this is default) on Julian, the tree lexicon * will be organized per category and the category-pair constraint used * in the 1st pass can be applied statically at cross-word transition. * * If the CATEGORY_TREE is not defined, a single tree lexicon will be * constucted for a whole dictionary. In this case, the category-pair * constraint should be applied dynamically in the word-internal transition, * like the factoring scheme with N-gram (Julius). * * This function provides such word-internal factoring for grammar-based * recognition (called deterministic factoring) when CATEGORY_TREE is * undefined in Julian. * * @param wchmm [in] tree lexicon * @param lastword [in] last word * @param node [in] node ID to check the constraint * * @return TRUE if the transition to the branch is allowed on the category-pair * constraint, or FALSE if not allowed. * </EN> * * @callgraph * @callergraph * */ boolean can_succeed(WCHMM_INFO *wchmm, WORD_ID lastword, int node) { int lc; int i; int s; /* return TRUE if at least one subtree word can connect */ s = wchmm->state[node].scid; if (lastword == WORD_INVALID) { /* case at beginning-of-word */ for (i = 0; i < wchmm->sclen[s]; i++) { if (dfa_cp_begin(wchmm->dfa, wchmm->sclist[s][i]) == TRUE) return(TRUE); } return(FALSE); } else { lc = wchmm->winfo->wton[lastword]; for (i = 0; i < wchmm->sclen[s]; i++) { if (dfa_cp(wchmm->dfa, lc, wchmm->sclist[s][i]) == TRUE) return(TRUE); } return(FALSE); } }