📄 hrec.c
字号:
/* ----------------------------------------------------------- *//* *//* ___ *//* |_| | |_/ SPEECH *//* | | | | \ RECOGNITION *//* ========= SOFTWARE */ /* *//* *//* ----------------------------------------------------------- *//* Copyright: Microsoft Corporation *//* 1995-2000 Redmond, Washington USA *//* http://www.microsoft.com *//* *//* Use of this software is governed by a License Agreement *//* ** See the file License for the Conditions of Use ** *//* ** This banner notice must not be removed ** *//* *//* ----------------------------------------------------------- *//* File: HRec.c Viterbi Recognition Engine Library *//* ----------------------------------------------------------- */char *hrec_version = "!HVER!HRec: 3.3 [CUED 28/04/05]";char *hrec_vc_id = "$Id: HRec.c,v 1.1.1.1 2005/05/12 10:52:51 jal58 Exp $";#include "HShell.h"#include "HMem.h"#include "HMath.h"#include "HWave.h"#include "HAudio.h"#include "HParm.h"#include "HLabel.h"#include "HModel.h"#include "HDict.h"#include "HNet.h"#include "HRec.h"#include "HUtil.h"#include "HAdapt.h"/* Trace levels */#define T_NGEN 1/* Checks */#define SANITYstatic int trace=0;static Boolean forceOutput=FALSE;const Token null_token={LZERO,0.0,NULL,NULL};/* Define macros for assessing node type */#define node_hmm(node) ((node)->type & n_hmm)#define node_word(node) ((node)->type == n_word)#define node_tr0(node) ((node)->type & n_tr0)#define node_wd0(node) ((node)->type & n_wd0)/* Reduced storage requirements for merged paths */struct nxtpath{ Path *prev; /* Previous word record */ LogDouble like; /* Likelihood at boundary */ LogFloat lm; /* LM likelihood of current word */ NxtPath *chain; /* Next of NBest Paths */};/* Extra alignments information for state/model level traceback */struct align{ short state; /* State level traceback info */ NetNode *node; /* Node for which alignment information present */ Align *prev; /* Previous align record */ LogDouble like; /* Likelihood upon entering state/model end */ int frame; /* Frame number upon entering state/model end */ Boolean used; /* Reference to struct by current inst */ int usage; /* Times struct ref'd (by align or path) */ Align *link; /* Next align in list */ Align *knil; /* Prev align in list */};/* NBest token handling is kept private */typedef struct reltoken{ LogFloat like; /* Relative Likelihood of token */ LogFloat lm; /* LM likelihood of token */ Path *path; /* Route (word level) through network */}RelToken;/* A tokenset is effectively a state instance */typedef struct tokenset{ short n; /* Number of rtok valid (0==1-best, 1>==N-best) */ RelToken *set; /* Likelihood sorted array[0..nToks] of rtoks */ Token tok; /* Most likely Token in state */}TokenSet;/* Need some null RelTokens */static const RelToken rmax={0.0,0.0,NULL}; /* First rtok same as tok */static const RelToken rnull={LZERO,0.0,NULL}; /* Rest can be LZERO *//* The instances actually store tokens and links etc *//* Instances are stored in creation/token propagation order to allow *//* null/word/tee instances to be connected together and still do propagation *//* in one pass. Only HMMs need extra tokens, others are 1 state */struct _NetInst{ struct _NetInst *link; /* Doubly linked list of instances, forward */ struct _NetInst *knil; /* Doubly linked list of instances, backward */ NetNode *node; /* Position of instance within network */ int flags; /* Flags, active ... */ TokenSet *state; /* TokenSet[0..N-2] in state [1..N-1] for hmm */ TokenSet *exit; /* TokenSet in exit state */ LogFloat wdlk; /* Max likelihood of t=0 path to word end node */ LogFloat max; /* Likelihood for pruning of instance */ Boolean pxd; /* External propagation done this frame */ Boolean ooo; /* Instance potentially out of order */#ifdef SANITY int ipos;#endif};/* HMMSet information is some precomputed limits plus the precomps */typedef struct precomp{ int id; /* Unique identifier for current frame */ LogFloat outp; /* State/mixture output likelihood */}PreComp;struct psetinfo{ MemHeap heap; /* Memory for this set of pre-comps */ HMMSet *hset; /* HMM Set for recognition */ int max; /* Max states in HMM set */ Boolean mixShared; int nsp; PreComp *sPre; /* Array[1..nsp] State PreComps */ int nmp; PreComp *mPre; /* Array[1..nmp] Shared mixture PreComps */ int ntr; short ***seIndexes; /* Array[1..ntr] of seIndexes */ Token *tBuf; /* Buffer Array[2..N-1] of tok for StepHMM1 */ TokenSet *sBuf; /* Buffer Array[2..N-1] of tokset for StepHMM1_N */ short stHeapNum; /* Number of separate state heaps */ short *stHeapIdx; /* Array[1..max] of state to heap index */};/* Private recognition information PRecInfo. (Not visible outside HRec) *//* Contains all status/network/allocation/pruning information for a *//* single network. */struct precinfo { /* Input parameters - Set once and unseen */ Observation *obs; /* Current Observation */ PSetInfo *psi; /* HMMSet information */ Network *net; /* Recognition network */ int nToks; /* Maximum tokens to propagate (0==1) */ Boolean models; /* Keep track of model history */ Boolean states; /* Keep track of state history */ float scale; /* LM (Net probs) scale factor */ LogFloat wordpen; /* Word insertion penalty */ float pscale; /* Pronunciation probs scale factor */ /* Private global info */ int frame; /* Current frame number */ int id; /* Unique observation identifier */ int prid; /* Unique pri identifier */ NetNode *genMaxNode; /* Most likely node in network */ NetNode *wordMaxNode; /* Most likely word end node in network */ Token genMaxTok; /* Most likely token */ Token wordMaxTok; /* Most likely word end token */ LogFloat genThresh; /* Cutoff from global beam */ LogFloat wordThresh; /* Cutoff for word end propagation */ LogFloat nThresh; /* Cutoff for non-best tokens */ LogFloat *qsa; /* Array form performing qsort */ int qsn; /* Sizeof qsa */ MemHeap instHeap; /* Inst heap */ MemHeap *stHeap; /* Array[0..stHeapNum-1] of heaps for states */ MemHeap rTokHeap; /* RelToken heap */ MemHeap pathHeap; /* Path heap */ MemHeap rPthHeap; /* NxtPath heap */ MemHeap alignHeap; /* Align heap */ int npth; /* Current number of path records */ int cpth; /* Number of path records after last collection */ Path pYesRef; /* Head of PathYesRef linked list */ Path pNoRef; /* Head of PathNoRef linked list */ Path pYesTail; /* Tail of PathYesRef linked list */ Path pNoTail; /* Tail of PathNoRef linked list */ int nalign; /* Current number of align records */ int calign; /* Number of align records after last collection */ Align aYesRef; /* Head of AlignYesRef linked list */ Align aNoRef; /* Head of AlignNoRef linked list */ Align aYesTail; /* Tail of AlignYesRef linked list */ Align aNoTail; /* Tail of AlignNoRef linked list */ int nact; /* Number of active instances */ int tact; /* Cummulative number of active instances */ NetInst head; /* Head (oldest) of Inst linked list */ NetInst tail; /* Tail (newest) of Inst linked list */ NetInst *nxtInst; /* Inst used to select next in step sequence */#ifdef SANITY NetInst *start_inst; /* Inst that started a move */ int ipos; /* Current inst position */ int pnlen; /* Number of PathNoRef list */ int pylen; /* Number of PathYesRef list */ int anlen; /* Number of AlignNoRef list */ int aylen; /* Number of AlignYesRef list */#endif};/* Global variable (so we want to get rid of them) */static PRecInfo *pri;static AdaptXForm *inXForm;/* Module Initialisation */static ConfParam *cParm[MAXGLOBS]; /* config parameters */static int nParm = 0;/* EXPORT->InitRec: register module & set configuration parameters */void InitRec(void){ int i; Boolean b; Register(hrec_version,hrec_vc_id); nParm = GetConfig("HREC", TRUE, cParm, MAXGLOBS); if (nParm>0){ if (GetConfInt(cParm,nParm,"TRACE",&i)) trace = i; if (GetConfBool(cParm,nParm,"FORCEOUT",&b)) forceOutput = b; }}/* Basic token merging step used during propagation. */ /* Token in cmp plus extra info from src merged into res. *//* tokens less likely that info.nThresh ignored. */static void TokSetMerge(TokenSet *res,Token *cmp,TokenSet *src){ Path *path; TokenSet tmp; LogFloat diff,like,limit; RelToken *cur,*mch,rtoks[MAX_TOKS]; NetNode *node, *nodes[MAX_TOKS]; int i,nw,k,null,aux;#ifdef SANITY if (res->n==0) HError(8590,"TokSetMerge: Not doing NBest"); if ((res->n!=0 && src->n==0) || (res->n==0 && src->n!=0)) HError(8590,"TokSetMerge: TokenSet size mismatch");#endif /* Do >= to ensure that when equal new token will be used every time in */ /* order to ensure that when propagation is redone paths are replaced. */ if (cmp->like>=res->tok.like) { if (cmp->like>pri->nThresh) { if (res->tok.like>pri->nThresh) { /* Need to exchange res and src */ tmp.tok=res->tok; res->tok=*cmp; for (k=0;k<res->n;k++) rtoks[k]=res->set[k]; for (k=0;k<src->n;k++) res->set[k]=src->set[k]; tmp.n=res->n; res->n=src->n; tmp.set=rtoks; } else { /* Just need to copy src to res */ res->tok=*cmp; for (k=0;k<src->n;k++) res->set[k]=src->set[k]; res->n=src->n; return; } } else return; } else { /* Don't copy src->set just for comparison */ if (cmp->like > pri->nThresh) { tmp.tok=*cmp; tmp.set=src->set; tmp.n=src->n; } else return; }#ifdef SANITY if (tmp.tok.like>res->tok.like) HError(8590,"TokSetMerge: Tokens not exchanged");#endif diff=res->tok.like-tmp.tok.like; for (i=nw=null=0,cur=res->set;i<res->n;i++,cur++) { for (path=cur->path;path!=NULL;path=path->prev) if (path->node->info.pron != NULL) break; if (path==NULL) null=i+1; else { /* allow for NULL nodes in path */ node=path->node; node->aux = i+1; nodes[nw++] = node; } } limit=pri->nThresh-tmp.tok.like; for (i=0,cur=tmp.set;i<tmp.n;i++,cur++) { if (cur->like<limit) break; /* allow for NULL nodes in path */ for (path=cur->path;path!=NULL;path=path->prev) if (path->node->info.pron != NULL) break; if (path==NULL) aux=null, node=NULL; else { node=path->node; aux=node->aux; } like=cur->like-diff; mch=NULL; /* Find matching tok/path if one (still)exists */ if (aux!=0) { for (k=aux-1;k<res->n;k++) { for (path=res->set[k].path;path!=NULL;path=path->prev) if (path->node->info.pron != NULL) break; if (path==NULL) { /* NULL paths match null paths */ if (!node || !node->info.pron->word) { mch=res->set+k; break; } } else if (node && node->info.pron->word) { /* should compare actual net node, not the pron to avoid incorrectly merging two distinct paths */ if (path->node==node) { mch=res->set+k; break; } } } } /* Otherwise match with least likely rtok (creating if possible) */ if (mch==NULL) { if (res->n < pri->nToks) { mch=res->set+res->n++; *mch=rnull; } else mch=res->set+res->n-1; } /* When new rtok beats mch need to replace and re-sort */ if (like > mch->like) { for (mch--;like>mch->like;mch--) {#ifdef SANITY if (mch<=res->set) HError(8590,"TokSetMerge: Tried to shift max token");#endif mch[1]=mch[0]; } mch++; mch->path=cur->path;mch->lm=cur->lm; mch->like=like; } } /* Void lookup information */ for (i=0;i<nw;i++) nodes[i]->aux=0;}/* Caching version of SOutP used when mixPDFs shared */static LogFloat cSOutP(HMMSet *hset, int s, Observation *x, StreamElem *se, int id){ PreComp *pre; LogFloat bx,px,wt,det; int m,vSize; double sum; MixtureElem *me; TMixRec *tr; TMProb *tm; Vector v,tv; switch (hset->hsKind){ case PLAINHS: case SHAREDHS: v=x->fv[s]; me=se->spdf.cpdf+1; if (se->nMix==1){ /* Single Mixture Case */ if (me->mpdf->mIdx>0 && me->mpdf->mIdx<=pri->psi->nmp) pre=pri->psi->mPre+me->mpdf->mIdx; else pre=NULL; if (pre==NULL) { bx= MOutP(ApplyCompFXForm(me->mpdf,v,inXForm,&det,id),me->mpdf); bx += det; } else if (pre->id!=id) { bx= MOutP(ApplyCompFXForm(me->mpdf,v,inXForm,&det,id),me->mpdf); bx += det; pre->id=id; pre->outp=bx; } else bx=pre->outp; } else { bx=LZERO; /* Multi Mixture Case */ for (m=1; m<=se->nMix; m++,me++) { wt = MixLogWeight(hset, me->weight); if (wt>LMINMIX) { if (me->mpdf->mIdx>0 && me->mpdf->mIdx<=pri->psi->nmp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -