📄 gmm.c
字号:
/** * @file gmm.c * * <JA> * @brief GMM による掐蜗逮笛およびVAD * * Gaussian Mixture Model (GMM) が弹瓢箕に回年された眷圭·Julius/Julian は * 掐蜗券厦に滦してフレ〖ムごとにスコアを纷换し·その芜姥スコアを换叫する. * これはGMMに答づく掐蜗不兰の券厦浮沮および逮笛に脱いられる. 悸狠の纷换は * 妈1パスの千急借妄と事乖してリアルタイムに乖なわれ·妈1パス姜位と票箕に * 冯蔡が叫蜗される. * * GMMのスコア纷换には Gaussian pruning の safe algorithm が脱いられ· * 称フレ〖ムにおいて惧疤 N 改だけが赖しく评られるように纷换される. * ただし奶撅の千急脱不读モデルの眷圭と佰なり·木涟フレ〖ムの界疤攫鼠は * 脱いていない. * * GMM_VAD 年盗箕は·惧淡の掐蜗逮笛に裁えて·short-pause segmentation と * 票じ先寥にを脱いた VAD が乖われる. * </JA> * * <EN> * @brief Input rejection and VAD using GMM * * When a Gaussian Mixture Model (GMM) is specified on startup, Julius/Julian * will compute the frame-wise likelihoods of each GMM for given inputs, * and produces the accumulated scores for each. Then the input rejection is * determined from the value. Actually, the recognition will be computed * on-line concurrently with the 1st pass, and the result will be got as * soon as the 1st pass ends. * * Gaussian pruning is performed using the safe algorithm in the computation * of GMM scores. In each frame, pruning will be done to fully compute only * the top N Gaussians. The algorithm is slightly simpler than AM computation, * i.e. the score order of the previous frame is not used here. * * When GMM_VAD is defined, a GMM-based VAD will be enabled in addition to * the input rejection, using the scheme of short-pause segmentation. * </EN> * * @author Akinobu LEE * @date Tue Mar 15 05:14:10 2005 * * $Revision: 1.4 $ * *//* * Copyright (c) 2003-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>#undef MES/** * <JA> * Gaussianのスコアを纷换貉みGaussianリストのどの疤弥に赁掐すべきかを手す. * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param score [in] 赁掐したいスコア * @param len [in] 附哼のリストの墓さ * * @return リスト柒の赁掐疤弥 * </JA> * <EN> * Return insertion point where a computed Gaussian score should be * inserted in current list of computed Gaussians. * * @param gc [i/o] work area for GMM calculation * @param score [in] a score to be inserted * @param len [in] current length of the list * * @return index to insert the value at the list. * </EN> */static intgmm_find_insert_point(GMMCalc *gc, LOGPROB score, int len){ /* binary search on score */ int left = 0; int right = len - 1; int mid; while (left < right) { mid = (left + right) / 2; if (gc->OP_calced_score[mid] > score) { left = mid + 1; } else { right = mid; } } return(left);}/** * <JA> * あるGaussianの纷换冯蔡を纷换貉みGaussianリストに呈羌する. * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param id [in] Gaussian の GMM 柒での戎规 * @param score [in] その Gaussian の纷换された不读锑刨 * @param len [in] 附哼のリストの墓さ∈附哼呈羌されている Gaussian の眶∷ * * @return 呈羌稿のリストの墓さ. * </JA> * <EN> * Store a Gaussian likelihood to the list of computed Gaussians. * * @param gc [i/o] work area for GMM calculation * @param id [in] id of a Gaussian in the GMM to be stored * @param score [in] the likelihood of the Gaussian to be stored * @param len [in] current list length (= current number of Gaussians in cache) * * @return the current length of list after the storing. * </EN> */static intgmm_cache_push(GMMCalc *gc, int id, LOGPROB score, int len){ int insertp; if (len == 0) { /* first one */ gc->OP_calced_score[0] = score; gc->OP_calced_id[0] = id; return(1); } if (gc->OP_calced_score[len-1] >= score) { /* bottom */ if (len < gc->OP_gprune_num) { /* append to bottom */ gc->OP_calced_score[len] = score; gc->OP_calced_id[len] = id; len++; } return len; } if (gc->OP_calced_score[0] < score) { insertp = 0; } else { insertp = gmm_find_insert_point(gc, score, len); } if (len < gc->OP_gprune_num) { memmove(&(gc->OP_calced_score[insertp+1]), &(gc->OP_calced_score[insertp]), sizeof(LOGPROB)*(len - insertp)); memmove(&(gc->OP_calced_id[insertp+1]), &(gc->OP_calced_id[insertp]), sizeof(int)*(len - insertp)); } else if (insertp < len - 1) { memmove(&(gc->OP_calced_score[insertp+1]), &(gc->OP_calced_score[insertp]), sizeof(LOGPROB)*(len - insertp - 1)); memmove(&(gc->OP_calced_id[insertp+1]), &(gc->OP_calced_id[insertp]), sizeof(int)*(len - insertp - 1)); } gc->OP_calced_score[insertp] = score; gc->OP_calced_id[insertp] = id; if (len < gc->OP_gprune_num) len++; return(len);}/** * <JA> * 附哼のフレ〖ムの掐蜗ベクトルに滦する Gaussian の叫蜗澄唯を纷换する. * Gaussian pruning は乖なわない. * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param binfo [in] Gaussian * * @return 叫蜗澄唯の滦眶猛 * </JA> * <EN> * Compute an output probability of a Gaussian for the input vector of * current frame. No Gaussian pruning is performed in this function. * * @param gc [i/o] work area for GMM calculation * @param binfo [in] Gaussian * * @return the log output probability. * </EN> */static LOGPROBgmm_compute_g_base(GMMCalc *gc, HTK_HMM_Dens *binfo){ VECT tmp, x; VECT *mean; VECT *var; VECT *vec = gc->OP_vec; short veclen = gc->OP_veclen; if (binfo == NULL) return(LOG_ZERO); mean = binfo->mean; var = binfo->var->vec; tmp = 0.0; for (; veclen > 0; veclen--) { x = *(vec++) - *(mean++); tmp += x * x * *(var++); } return((tmp + binfo->gconst) * -0.5);}/** * <JA> * 附哼のフレ〖ムの掐蜗ベクトルに滦する Gaussian の叫蜗澄唯を纷换する. * 纷换箕には盖年しきい猛による safe pruning を乖なう. * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param binfo [in] Gaussian * @param thres [in] safe pruning のための晦储りしきい猛 * * @return 叫蜗澄唯の滦眶猛 * </JA> * <EN> * Compute an output probability of a Gaussian for the input vector of * current frame. Safe pruning is performed in this function. * * @param gc [i/o] work area for GMM calculation * @param binfo [in] Gaussian * @param thres [in] pruning threshold for safe pruning * * @return the log output probability. * </EN> */static LOGPROBgmm_compute_g_safe(GMMCalc *gc, HTK_HMM_Dens *binfo, LOGPROB thres){ VECT tmp, x; VECT *mean; VECT *var; VECT *vec = gc->OP_vec; short veclen = gc->OP_veclen; VECT fthres = thres * (-2.0); if (binfo == NULL) return(LOG_ZERO); mean = binfo->mean; var = binfo->var->vec; tmp = binfo->gconst; for (; veclen > 0; veclen--) { x = *(vec++) - *(mean++); tmp += x * x * *(var++); if (tmp > fthres) return LOG_ZERO; } return(tmp * -0.5);}/** * <JA> * GMM纷换における Gaussian pruning のためのワ〖クエリアを澄瘦する * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param hmminfo [in] HMM 菇陇挛 * @param prune_num [in] Gaussian pruning において纷换する惧疤ガウス尸邵眶 * </JA> * <EN> * Allocate work area for Gaussian pruning for GMM calculation. * * @param gc [i/o] work area for GMM calculation * @param hmminfo [in] HMM structure * @param prune_num [in] number of top Gaussians to be computed at the pruning * </EN> */static voidgmm_gprune_safe_init(GMMCalc *gc, HTK_HMM_INFO *hmminfo, int prune_num){ /* store the pruning num to local area */ gc->OP_gprune_num = prune_num; /* maximum Gaussian set size = maximum mixture size * nstream */ gc->OP_calced_maxnum = hmminfo->maxmixturenum * gc->OP_nstream; /* allocate memory for storing list of currently computed Gaussian in a frame */ gc->OP_calced_score = (LOGPROB *)mymalloc(sizeof(LOGPROB) * gc->OP_calced_maxnum); gc->OP_calced_id = (int *)mymalloc(sizeof(int) * gc->OP_calced_maxnum);}/** * <JA> * @brief ガウス尸邵礁圭柒の称ガウス尸邵の附フレ〖ムに滦する叫蜗澄唯を纷换する. * * Gaussian pruning により·悸狠には惧疤 N 改のみを瘦沮する晦储りが乖なわれ· * スコアの你いガウス尸邵は纷换されない. * * 纷换冯蔡は纷换貉みGaussianリスト (OP_calced_score, OP_calced_id) に * 呈羌される. * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param g [in] ガウス尸邵礁圭 * @param gnum [in] @a g の墓さ * </JA> * <EN> * @brief Compute scores for a set of Gaussians with Gaussian pruning for * the current frame. * * Gaussian pruning will be performed to guarantee only the top N Gaussians * to be fully computed. The results will be stored in the list of * computed Gaussians in OP_calced_score and OP_calced_id. * * @param gc [i/o] work area for GMM calculation * @param g [in] set of Gaussians * @param gnum [in] length of @a g * </EN> */static voidgmm_gprune_safe(GMMCalc *gc, HTK_HMM_Dens **g, int gnum){ int i, num = 0; LOGPROB score, thres; thres = LOG_ZERO; for (i = 0; i < gnum; i++) { if (num < gc->OP_gprune_num) { score = gmm_compute_g_base(gc, g[i]); } else { score = gmm_compute_g_safe(gc, g[i], thres); if (score <= thres) continue; } num = gmm_cache_push(gc, i, score, num); thres = gc->OP_calced_score[num-1]; } gc->OP_calced_num = num;}/** * <JA> * あるGMM觉轮の附フレ〖ムに滦する叫蜗澄唯を纷换する. * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param state [in] GMM 觉轮 * * @return 叫蜗澄唯の滦眶スコア * </JA> * <EN> * Compute the output probability of a GMM state for the current frame. * * @param gc [i/o] work area for GMM calculation * @param state [in] GMM state * * @return the log probability. * </EN> */static LOGPROBgmm_calc_mix(GMMCalc *gc, HTK_HMM_State *state){ int i; LOGPROB logprob, logprobsum; int s; PROB stream_weight; /* compute Gaussian set */ logprobsum = 0.0; for(s=0;s<gc->OP_nstream;s++) { /* set stream weight */ if (state->w) stream_weight = state->w->weight[s]; else stream_weight = 1.0; /* setup storage pointer for this mixture pdf */ gc->OP_vec = gc->OP_vec_stream[s]; gc->OP_veclen = gc->OP_veclen_stream[s]; /* compute output probabilities */ gmm_gprune_safe(gc, state->pdf[s]->b, state->pdf[s]->mix_num); /* computed Gaussians will be set in: score ... OP_calced_score[0..OP_calced_num] id ... OP_calced_id[0..OP_calced_num] */ /* sum */ for(i=0;i<gc->OP_calced_num;i++) { gc->OP_calced_score[i] += state->pdf[s]->bweight[gc->OP_calced_id[i]]; } /* add log probs */ logprob = addlog_array(gc->OP_calced_score, gc->OP_calced_num); /* if outprob of a stream is zero, skip this stream */ if (logprob <= LOG_ZERO) continue; /* sum all the obtained mixture scores */ logprobsum += logprob * stream_weight; } if (logprobsum == 0.0) return(LOG_ZERO); /* no valid stream */ if (logprobsum <= LOG_ZERO) return(LOG_ZERO); /* lowest == LOG_ZERO */ return (logprob * INV_LOG_TEN);}/** * <JA> * 掐蜗の回年フレ〖ムにおけるGMM觉轮のスコアを滇めるメイン簇眶. * * @param gc [i/o] GMM纷换脱ワ〖クエリア * @param t [in] 纷换するフレ〖ム * @param stateinfo [in] GMM觉轮 * @param param [in] 掐蜗ベクトル废误 * * @return 叫蜗澄唯の滦眶スコア * </JA> * <EN> * Main function to compute the output probability of a GMM state for * the specified input frame. * * @param gc [i/o] work area for GMM calculation * @param t [in] time frame on which the output probability should be computed * @param stateinfo [in] GMM state * @param param [in] input vector sequence * * @return the log output probability. * </EN> */static LOGPROBoutprob_state_nocache(GMMCalc *gc, int t, HTK_HMM_State *stateinfo, HTK_Param *param){ int d, i; /* set global values for outprob functions to access them */ for(d=0,i=0;i<gc->OP_nstream;i++) { gc->OP_vec_stream[i] = &(param->parvec[t][d]); d += gc->OP_veclen_stream[i]; } return(gmm_calc_mix(gc, stateinfo));}/************************************************************************//* global functions *//** * <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 * */booleangmm_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) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -