📄 search_bestfirst_v1.c
字号:
/** * @file search_bestfirst_v1.c * * <JA> * @brief 妈2パスのViterbi遍换および簿棱スコア纷换 (光庐惹) * * ここでは·妈2パスにおいて玫瑚面の簿棱のViterbiスコアの构糠遍换· * 肌帽胳とのトレリス儡鲁·および簿棱のスコア纷换を乖う簇眶が年盗されて * います. * * 帽胳儡鲁婶の帽胳粗不燎茨董巴赂拉は·光庐な backscan アルゴリズムに * よって乖われます. このファイルで年盗されている簇眶は·config.h において * PASS2_STRICT_IWCD が undef であるときに蝗脱されます. 嫡に惧淡が define * されているときは·search_bestfirst_v2.c の簇眶が脱いられます. * * Backscan アルゴリズムでは·デコ〖ディングの光庐步のため· * 肌帽胳とその涟の帽胳の儡鲁爬について·≈帽胳粗不燎コンテキストの觅变借妄∽ * を乖ないます¨ * * -# 糠簿棱の栏喇(next_word())では·肌帽胳の呵稿の不燎の宝コンテキスト * のみが雇胃される. * -# その帽胳粗の窗链な不燎茨董巴赂拉は·その簿棱がいったんスタックに * 掐った稿もう办刨 POP されたときに scan_word() にて猖めて纷换する. * * 簿棱栏喇箕にはすべての栏喇簿棱に滦して巴赂纷换を乖なず·あとでスコアが * 光く POP された簿棱についてのみ浩纷换を乖ないます. このため借妄が * 光庐步されますが·簿棱スコア纷换(next_word())において肌帽胳儡鲁婶尸の * 茨董巴赂拉が雇胃されないので, 玫瑚面のスコアに疙汗が栏じる眷圭があります. * * 悸刘について: * * -# next_word() では·肌帽胳の呵稿の不燎のみを宝コンテキスト(=鸥倡傅 * 帽胳の呵介の不燎)を雇胃して恃步させ·トレリス儡鲁爬の叫蜗澄唯を滇める. * -# scan_word() では·糠帽胳婶尸ともう1つ涟の帽胳の呵介の不燎を恃步 * させ·scan する. そのため糠帽胳婶尸だけでなく·そのもう办不燎涟まで * scan の滦据となる. この "1-phoneme backscan" を乖なうため, * 称簿棱ノ〖ドは呵姜HMM觉轮の涟羹きスコア (NODEにおける g[]) だけでなく· * その backscan 倡幌爬(もう1つ涟の帽胳の呵介の不燎の缄涟)のスコア * も瘦赂しておく涩妥がある (NODE における g_prev[]). * * なお·1不燎のみからなる帽胳では backscan 倡幌爬と帽胳董肠が脚なることを * 雇胃する涩妥があるため·悸刘はもう警し剩花になる. * </JA> * * <EN> * @brief Viterbi path update and scoring on the second pass (fast version) * * This file has functions for score calculations on the 2nd pass. * It includes Viterbi path update calculation of a hypothesis, calculations * of scores and word trellis connection at word expansion. * * The cross-word triphone will be computed not at word expansion time, * but at later pop up for rapid decoding. This is called "backscan" * altgorithm. These functions are enabled when PASS2_STRICT_IWCD is * UNDEFINED in config.h. If defined, "nextscan" functions in * search_bestfirst_v2.c are used instead. * * Here we use "delayed cross-word context handling" method * for connection of next word and last word of the hypothesis for * speeding up decoding: * * -# Only right context of the tail phone in the next word is considered * when generating a new hypothesis (next_word()). * * -# The whole context dependency will be fully computed when the * hypothesis is once pushed to stack and later popped in scan_word(). * * This method avoid computing full context-dependency handling for all * generated hypothesis in next_word(), and only re-compute it after * primising ones are popped from stack later. This speeds up decoding. * But since the context dependency is not considered in the total hypothesis * score (computed in next_word()). * * The actual implimentation: * * -# In nextword(), the tail phone in the new word is modified considering * the right context (= head phone in the last word of source hypothesis), * and the outprob on the connection point between backtrellis and forward * trellis is computed using the triphone. * * -# In scan_word(), not only the new word but also the head phone in the * previous word should be modified and re-scanned. * To realize this '1-phoneme backscan' procedure, hypothesis nodes * have to keep forward scores not only at the last HMM state (g[] in * NODE), but also at the backscan restart point (= before the head * phone in the previous word, g_prev[] in NODE). * * Note that the actual implementation becomes a little more complicated * to handle 1-phoneme words... * </EN> * * @author Akinobu Lee * @date Sun Sep 11 23:54:53 2005 * * $Revision: 1.4 $ * *//* * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology * All rights reserved */#include <julius/julius.h>#ifndef PASS2_STRICT_IWCD#undef TCD ///< Define if want triphone debug messages/**********************************************************************//************ 簿棱ノ〖ドの答塑拎侯 ************//************ Basic functions for hypothesis node handling ************//**********************************************************************/#undef STOCKER_DEBUG#ifdef STOCKER_DEBUGstatic int stocked_num = 0;static int reused_num = 0;static int new_num = 0;static int request_num = 0;#endif/** * <JA> * 簿棱ノ〖ドを悸狠にメモリ惧から豺庶する. * * @param node [in] 簿棱ノ〖ド * </JA> * <EN> * Free a hypothesis node actually. * * @param node [in] hypothesis node * </EN> */static voidfree_node_exec(NODE *node){ if (node == NULL) return; free(node->g); if (node->g_prev != NULL) free(node->g_prev);#ifdef GRAPHOUT_PRECISE_BOUNDARY if (node->region->graphout) { free(node->wordend_frame); free(node->wordend_gscore); }#endif free(node);}/** * <JA> * 簿棱ノ〖ドの网脱を姜位してリサイクル脱にストックする * * @param node [in] 簿棱ノ〖ド * </JA> * <EN> * Stock an unused hypothesis node for recycle. * * @param node [in] hypothesis node * </EN> * * @callgraph * @callergraph */voidfree_node(NODE *node){ if (node == NULL) return; if (node->region->graphout) { if (node->prevgraph != NULL && node->prevgraph->saved == FALSE) { wordgraph_free(node->prevgraph); } } /* save to stocker */ node->next = node->region->pass2.stocker_root; node->region->pass2.stocker_root = node;#ifdef STOCKER_DEBUG stocked_num++;#endif}/** * <JA> * リサイクル脱ノ〖ド呈羌杆を鄂にする. * * @param s [in] stack decoding work area * * </JA> * <EN> * Clear the node stocker for recycle. * * @param s [in] stack decoding work area * * </EN> * @callgraph * @callergraph */voidclear_stocker(StackDecode *s){ NODE *node, *tmp; node = s->stocker_root; while(node) { tmp = node->next; free_node_exec(node); node = tmp; } s->stocker_root = NULL;#ifdef STOCKER_DEBUG jlog("DEBUG: %d times requested, %d times newly allocated, %d times reused\n", request_num, new_num, reused_num); stocked_num = 0; reused_num = 0; new_num = 0; request_num = 0;#endif}/** * <JA> * 簿棱をコピ〖する. * * @param dst [out] コピ〖黎の簿棱 * @param src [in] コピ〖傅の簿棱 * * @return @a dst を手す. * </JA> * <EN> * Copy the content of node to another. * * @param dst [out] target hypothesis * @param src [in] source hypothesis * * @return the value of @a dst. * </EN> * @callgraph * @callergraph */NODE *cpy_node(NODE *dst, NODE *src){ int peseqlen; peseqlen = src->region->peseqlen; dst->next = src->next; dst->prev = src->prev; memcpy(dst->g, src->g, sizeof(LOGPROB) * peseqlen); memcpy(dst->seq, src->seq, sizeof(WORD_ID) * MAXSEQNUM);#ifdef CM_SEARCH#ifdef CM_MULTIPLE_ALPHA { int w; for(w=0;w<src->seqnum;w++) { memcpy(dst->cmscore[w], src->cmscore[w], sizeof(LOGPROB) * src->region->config->annotate.cm_alpha_num); } } #else memcpy(dst->cmscore, src->cmscore, sizeof(LOGPROB) * MAXSEQNUM);#endif#endif /* CM_SEARCH */ dst->seqnum = src->seqnum; dst->score = src->score; dst->bestt = src->bestt; dst->estimated_next_t = src->estimated_next_t; dst->endflag = src->endflag; dst->state = src->state; dst->tre = src->tre; if (src->g_prev != NULL) { // ccd_flag == TRUE memcpy(dst->g_prev, src->g_prev, sizeof(LOGPROB) * peseqlen); dst->last_ph = src->last_ph; dst->last_ph_sp_attached = src->last_ph_sp_attached; dst->lscore = src->lscore; } dst->totallscore = src->totallscore; dst->final_g = src->final_g;#ifdef VISUALIZE dst->popnode = src->popnode;#endif if (src->region->graphout) {#ifdef GRAPHOUT_PRECISE_BOUNDARY memcpy(dst->wordend_frame, src->wordend_frame, sizeof(short) * peseqlen); memcpy(dst->wordend_gscore, src->wordend_gscore, sizeof(LOGPROB) * peseqlen);#endif dst->prevgraph = src->prevgraph; dst->lastcontext = src->lastcontext;#ifndef GRAPHOUT_PRECISE_BOUNDARY dst->tail_g_score = src->tail_g_score;#endif } return(dst);}/** * <JA> * 糠たな簿棱ノ〖ドを充り烧ける. もし呈羌杆に笆涟活脱されなくなった * ノ〖ドがある眷圭はそれを浩网脱する. なければ糠たに充り烧ける. * * @param r [in] 千急借妄インスタンス * * @return 糠たに充り烧けられた簿棱ノ〖ドへのポインタを手す. * </JA> * <EN> * Allocate a new hypothesis node. If the node stocker is not empty, * the one in the stocker is re-used. Otherwise, allocate as new. * * @param r [in] recognition process instance * * @return pointer to the newly allocated node. * </EN> * @callgraph * @callergraph */NODE *newnode(RecogProcess *r){ NODE *tmp; int i; int peseqlen; peseqlen = r->peseqlen;#ifdef STOCKER_DEBUG request_num++;#endif if ((tmp = r->pass2.stocker_root) != NULL) { /* re-use ones in the stocker */ r->pass2.stocker_root = tmp->next;#ifdef STOCKER_DEBUG stocked_num--; reused_num++;#endif } else { /* allocate new */ tmp =(NODE *)mymalloc(sizeof(NODE)); tmp->g = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen); if (r->ccd_flag) { tmp->g_prev = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen); } else { tmp->g_prev = NULL; }#ifdef GRAPHOUT_PRECISE_BOUNDARY if (r->graphout) { tmp->wordend_frame = (short *)mymalloc(sizeof(short) * peseqlen); tmp->wordend_gscore = (LOGPROB *)mymalloc(sizeof(LOGPROB) * peseqlen); }#endif#ifdef STOCKER_DEBUG new_num++;#endif } /* clear the data */ /*bzero(tmp,sizeof(NODE));*/ tmp->next=NULL; tmp->prev=NULL; tmp->last_ph = NULL; tmp->last_ph_sp_attached = FALSE; if (r->ccd_flag) { if (r->lmtype == LM_PROB) { tmp->lscore = LOG_ZERO; tmp->totallscore = LOG_ZERO; } else if (r->lmtype == LM_DFA) { tmp->lscore = 0.0; tmp->totallscore = 0.0; } } tmp->endflag = FALSE; tmp->seqnum = 0; for(i=0;i<peseqlen;i++) { tmp->g[i] = LOG_ZERO; } if (r->ccd_flag) { for(i=0;i<peseqlen;i++) { tmp->g_prev[i] = LOG_ZERO; } } tmp->final_g = LOG_ZERO;#ifdef VISUALIZE tmp->popnode = NULL;#endif tmp->tre = NULL; if (r->graphout) { tmp->prevgraph = NULL; tmp->lastcontext = NULL; } tmp->region = r; return(tmp);}/**********************************************************************//************ 涟羹きトレリス鸥倡と锑刨纷换 ***************//************ Expand trellis and update forward viterbi ***************//**********************************************************************//** * <JA> * 1帽胳尸のトレリス纷换脱のワ〖クエリアを澄瘦. * * @param r [in] 千急借妄インスタンス * * </JA> * <EN> * Allocate work area for trellis computation of a word. * * @param r [in] recognition process instance * * </EN> * @callgraph * @callergraph */voidmalloc_wordtrellis(RecogProcess *r){ int maxwn; StackDecode *dwrk;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -