📄 fsg_search.c
字号:
fsg_pnode_t *child; CHAN_T *hmm; int32 newscore, thresh, nf; assert(pnode); assert(!fsg_pnode_leaf(pnode)); nf = search->frame + 1; thresh = search->bestscore + search->beam; hmm = fsg_pnode_hmmptr(pnode); for (child = fsg_pnode_succ(pnode); child; child = fsg_pnode_sibling(child)) { newscore = hmm->score[HMM_LAST_STATE] + child->logs2prob; if ((newscore >= thresh) && (newscore > child->hmm.score[0])) { /* Incoming score > pruning threshold and > target's existing score */ if (child->hmm.active < nf) { /* Child node not yet activated; do so */ search->pnode_active_next = glist_add_ptr(search->pnode_active_next, (void *) child); child->hmm.active = nf; } child->hmm.score[0] = newscore; child->hmm.path[0] = hmm->path[HMM_LAST_STATE]; } }}static voidfsg_search_pnode_exit(fsg_search_t * search, fsg_pnode_t * pnode){ CHAN_T *hmm; word_fsglink_t *fl; int32 wid, endwid; fsg_pnode_ctxt_t ctxt; assert(pnode); assert(fsg_pnode_leaf(pnode)); hmm = fsg_pnode_hmmptr(pnode); fl = fsg_pnode_fsglink(pnode); assert(fl); endwid = kb_get_word_id(cmd_ln_str("-lmendsym")); wid = word_fsglink_wid(fl); assert(wid >= 0);#if __FSG_DBG__ E_INFO("[%5d] Exit(%08x) %10d(score) %5d(pred)\n", search->frame, (int32) pnode, hmm->score[HMM_LAST_STATE], hmm->path[HMM_LAST_STATE]);#endif /* * Check if this is filler or single phone word; these do not model right * context (i.e., the exit score applies to all right contexts). */ if (dict_is_filler_word(word_dict, wid) || (wid == endwid) || (dict_pronlen(word_dict, wid) == 1)) { /* Create a dummy context structure that applies to all right contexts */ fsg_pnode_add_all_ctxt(&ctxt); /* Create history table entry for this word exit */ fsg_history_entry_add(search->history, fl, search->frame, hmm->score[HMM_LAST_STATE], hmm->path[HMM_LAST_STATE], pnode->ci_ext, ctxt); } else { /* Create history table entry for this word exit */ fsg_history_entry_add(search->history, fl, search->frame, hmm->score[HMM_LAST_STATE], hmm->path[HMM_LAST_STATE], pnode->ci_ext, pnode->ctxt); }}/* * (Beam) prune the just evaluated HMMs, determine which ones remain * active, which ones transition to successors, which ones exit and * terminate in their respective destination FSM states. * (Executed once per frame.) */voidfsg_search_hmm_prune_prop(fsg_search_t * search){ gnode_t *gn; fsg_pnode_t *pnode; CHAN_T *hmm; int32 thresh, word_thresh, phone_thresh; assert(search->pnode_active_next == NULL); thresh = search->bestscore + search->beam; phone_thresh = search->bestscore + search->pbeam; word_thresh = search->bestscore + search->wbeam; for (gn = search->pnode_active; gn; gn = gnode_next(gn)) { pnode = (fsg_pnode_t *) gnode_ptr(gn); hmm = fsg_pnode_hmmptr(pnode); if (hmm->bestscore >= thresh) { /* Keep this HMM active in the next frame */ if (hmm->active == search->frame) { hmm->active = search->frame + 1; search->pnode_active_next = glist_add_ptr(search->pnode_active_next, (void *) pnode); } else { assert(hmm->active == search->frame + 1); } if (!fsg_pnode_leaf(pnode)) { if (hmm->score[HMM_LAST_STATE] >= phone_thresh) { /* Transition out of this phone into its children */ fsg_search_pnode_trans(search, pnode); } } else { if (hmm->score[HMM_LAST_STATE] >= word_thresh) { /* Transition out of leaf node into destination FSG state */ fsg_search_pnode_exit(search, pnode); } } } }}/* * Propagate newly created history entries through null transitions. */static voidfsg_search_null_prop(fsg_search_t * search){ int32 bpidx, n_entries, thresh, newscore; fsg_hist_entry_t *hist_entry; word_fsglink_t *l; int32 s, d; word_fsg_t *fsg; fsg = search->fsg; thresh = search->bestscore + search->wbeam; /* Which beam really?? */ n_entries = fsg_history_n_entries(search->history); for (bpidx = search->bpidx_start; bpidx < n_entries; bpidx++) { hist_entry = fsg_history_entry_get(search->history, bpidx); l = fsg_hist_entry_fsglink(hist_entry); /* Destination FSG state for history entry */ s = l ? word_fsglink_to_state(l) : word_fsg_start_state(fsg); /* * Check null transitions from d to all other states. (Only need to * propagate one step, since FSG contains transitive closure of null * transitions.) */ for (d = 0; d < word_fsg_n_state(fsg); d++) { l = word_fsg_null_trans(fsg, s, d); if (l) { /* Propagate history entry through this null transition */ newscore = fsg_hist_entry_score(hist_entry) + word_fsglink_logs2prob(l); if (newscore >= thresh) { fsg_history_entry_add(search->history, l, fsg_hist_entry_frame(hist_entry), newscore, bpidx, fsg_hist_entry_lc(hist_entry), fsg_hist_entry_rc(hist_entry)); } } } }}/* * Perform cross-word transitions; propagate each history entry created in this * frame to lextree roots attached to the target FSG state for that entry. */static voidfsg_search_word_trans(fsg_search_t * search){ int32 bpidx, n_entries; fsg_hist_entry_t *hist_entry; word_fsglink_t *l; int32 score, newscore, thresh, nf, d; fsg_pnode_t *root; int32 lc, rc; n_entries = fsg_history_n_entries(search->history); thresh = search->bestscore + search->beam; nf = search->frame + 1; for (bpidx = search->bpidx_start; bpidx < n_entries; bpidx++) { hist_entry = fsg_history_entry_get(search->history, bpidx); assert(hist_entry); score = fsg_hist_entry_score(hist_entry); assert(search->frame == fsg_hist_entry_frame(hist_entry)); l = fsg_hist_entry_fsglink(hist_entry); /* Destination state for hist_entry */ d = l ? word_fsglink_to_state(l) : word_fsg_start_state(search-> fsg); lc = fsg_hist_entry_lc(hist_entry); /* Transition to all root nodes attached to state d */ for (root = fsg_lextree_root(search->lextree, d); root; root = root->sibling) { rc = root->ci_ext; if ((root->ctxt.bv[lc >> 5] & (1 << (lc & 0x001f))) && (hist_entry->rc.bv[rc >> 5] & (1 << (rc & 0x001f)))) { /* * Last CIphone of history entry is in left-context list supported by * target root node, and * first CIphone of target root node is in right context list supported * by history entry; * So the transition can go ahead (if new score is good enough). */ newscore = score + root->logs2prob; if ((newscore >= thresh) && (newscore > root->hmm.score[0])) { if (root->hmm.active < nf) { /* Newly activated node; add to active list */ search->pnode_active_next = glist_add_ptr(search->pnode_active_next, (void *) root); root->hmm.active = nf;#if __FSG_DBG__ E_INFO ("[%5d] WordTrans bpidx[%d] -> pnode[%08x] (activated)\n", search->frame, bpidx, (int32) root);#endif } else {#if __FSG_DBG__ E_INFO ("[%5d] WordTrans bpidx[%d] -> pnode[%08x]\n", search->frame, bpidx, (int32) root);#endif } root->hmm.score[0] = newscore; root->hmm.path[0] = bpidx; } } } }}voidfsg_search_frame_fwd(fsg_search_t * search){ gnode_t *gn; fsg_pnode_t *pnode; CHAN_T *hmm; search->bpidx_start = fsg_history_n_entries(search->history); /* Evaluate all active pnodes (HMMs) */ fsg_search_hmm_eval(search); /* * Prune and propagate the HMMs evaluated; create history entries for * word exits. The words exits are tentative, and may be pruned; make * the survivors permanent via fsg_history_end_frame(). */ fsg_search_hmm_prune_prop(search); fsg_history_end_frame(search->history); /* * Propagate new history entries through any null transitions, creating * new history entries, and then make the survivors permanent. */ fsg_search_null_prop(search); fsg_history_end_frame(search->history); /* * Perform cross-word transitions; propagate each history entry across its * terminating state to the root nodes of the lextree attached to the state. */ fsg_search_word_trans(search); /* * We've now come full circle, HMM and FSG states have been updated for * the next frame. * Update the active lists, deactivate any currently active HMMs that * did not survive into the next frame */ for (gn = search->pnode_active; gn; gn = gnode_next(gn)) { pnode = (fsg_pnode_t *) gnode_ptr(gn); hmm = fsg_pnode_hmmptr(pnode); if (hmm->active == search->frame) { /* This HMM NOT activated for the next frame; reset it */ fsg_psubtree_pnode_deactivate(pnode); } else { assert(hmm->active == (search->frame + 1)); } } /* Free the currently active list */ glist_free(search->pnode_active); /* Make the next-frame active list the current one */ search->pnode_active = search->pnode_active_next; search->pnode_active_next = NULL; /* End of this frame; ready for the next */ (search->frame)++;}static voidfsg_search_hyp_free(fsg_search_t * search){ search_hyp_t *hyp, *nexthyp; for (hyp = search->hyp; hyp; hyp = nexthyp) { nexthyp = hyp->next; ckd_free(hyp); } search->hyp = NULL;}/* * Set all HMMs to inactive, clear active lists, initialize FSM start * state to be the only active node. * (Executed at the start of each utterance.) */voidfsg_search_utt_start(fsg_search_t * search){ int32 silcipid; fsg_pnode_ctxt_t ctxt; /* Reset dynamic adjustment factor for beams */ search->beam_factor = 1.0f; search->beam = search->beam_orig; search->pbeam = search->pbeam_orig; search->wbeam = search->wbeam_orig; silcipid = phone_to_id("SIL", TRUE); /* Initialize EVERYTHING to be inactive */ assert(search->pnode_active == NULL); assert(search->pnode_active_next == NULL); fsg_lextree_utt_start(search->lextree); fsg_history_utt_start(search->history); /* Dummy context structure that allows all right contexts to use this entry */ fsg_pnode_add_all_ctxt(&ctxt); /* Create dummy history entry leading to start state */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -