s3_align.c
来自「CMU大名鼎鼎的SPHINX-3大词汇量连续语音识别系统」· C语言 代码 · 共 1,294 行 · 第 1/3 页
C
1,294 行
build_pred_ci (prev_end, pred_ci); /* Predecessor CI list for fillers */ build_succ_ci (w, 0, succ_ci); /* Successor CI list for fillers */ new_end = NULL; for (i = 0; IS_S3WID(fillwid[i]); i++) { for (fw = fillwid[i]; IS_S3WID(fw); fw = dict->word[fw].alt) { tmp_end = append_word (fw, prev_end, pred_ci, succ_ci); for (node = tmp_end; node->next; node = node->next); node->next = new_end; new_end = tmp_end; } } /* Augment prev_end with new_end for filler words added above */ for (node = prev_end; node->next; node = node->next); node->next = new_end; } /* Add w */ build_pred_ci (prev_end, pred_ci); /* Predecessor CI list for w */ build_succ_ci (nextw, append_filler, succ_ci); /* Successor CI list for w */ new_end = NULL; for (; IS_S3WID(w); w = dict->word[w].alt) { tmp_end = append_word (w, prev_end, pred_ci, succ_ci); for (node = tmp_end; node->next; node = node->next); node->next = new_end; new_end = tmp_end; } return (new_end);}#if _DEBUG_ALIGN_static void dump_pnode_info (pnode_t *p){ if (NOT_S3WID(p->wid)) printf ("%s", (p->id == -1) ? "<head>" : "<tail>"); else printf ("%s.%d.", dict_wordstr(p->wid), p->pos, mdef_ciphone_str (mdef, p->ci)); printf ("%s", IS_CIPID(p->lc) ? mdef_ciphone_str (mdef, p->lc) : "-"); printf ("(%s)", IS_CIPID(p->ci) ? mdef_ciphone_str (mdef, p->ci) : "-"); printf ("%s", IS_CIPID(p->rc) ? mdef_ciphone_str (mdef, p->rc) : "-");}static void dump_pnode_succ_dag (pnode_t *p){ plink_t *l; for (l = p->succlist; l; l = l->next) { dump_pnode_info (p); printf ("\t\t"); dump_pnode_info (l->node); printf (";\n"); }}static void dump_pnode_succ (pnode_t *p){ plink_t *l; printf (" %5d", p->id); if (IS_S3WID(p->wid)) printf (" %20s %02d %6d %4s", dict_wordstr(p->wid), p->pos, p->pid, mdef_ciphone_str (mdef, p->ci)); else printf (" %20s %02d %6d %4s", "<phead>", 0, BAD_S3PID, ""); printf (" %4s %4s", IS_CIPID(p->lc) ? mdef_ciphone_str (mdef, p->lc) : "-", IS_CIPID(p->rc) ? mdef_ciphone_str (mdef, p->rc) : "-"); printf ("\t"); for (l = p->succlist; l; l = l->next) printf (" %5d", l->node->id); printf ("\n");}static void dump_pdag ( void ){ pnode_t *p; printf ("SUCCESSOR LIST (DAG format):\n"); printf (".GS 5 5 fill\n"); dump_pnode_succ_dag (&phead); for (p = pnode_list; p; p = p->alloc_next) dump_pnode_succ_dag (p); printf (".GE\n"); printf ("SUCCESSOR LIST:\n"); dump_pnode_succ (&phead); for (p = pnode_list; p; p = p->alloc_next) dump_pnode_succ (p);}#endif/** * Append an snode to a list of snodes (maintained in a list of slinks). */static slink_t *append_snode (slink_t *list, snode_t *node, int32 prob){ slink_t *l; l = (slink_t *) listelem_alloc (sizeof(slink_t)); l->node = node; l->next = list; l->prob = prob; return l;}/** * Link source and destination state nodes. */static void link_snodes (snode_t *src, snode_t *dst, int32 prob){ src->succlist = append_snode (src->succlist, dst, prob); dst->predlist = append_snode (dst->predlist, src, prob);}/** * Remove src->dst link and return the associated prob. */static int32 un_slink_succ (snode_t *src, snode_t *dst){ slink_t *l, *prevl; int32 prob; /* Find link from src to dst */ prevl = NULL; for (l = src->succlist; l && (l->node != dst); l = l->next) prevl = l; assert (l); /* The link must exist */ if (! prevl) src->succlist = l->next; else prevl->next = l->next; prob = l->prob; listelem_free ((char *)l, sizeof(slink_t)); return prob;}static void slinks_free (slink_t *l){ slink_t *tmp; while (l) { tmp = l->next; listelem_free ((char *) l, sizeof(slink_t)); l = tmp; }}/** * Build a state-level DAG from the phone-level one. This DAG is the one actually * searched. */static int32 build_state_dag ( void ){ pnode_t *p; plink_t *pl; snode_t *s, *fs; slink_t *sl; int32 n_state, final_state; int32 i, j; int32 **tp, prob; n_state = mdef->n_emit_state + 1; final_state = n_state - 1; for (p = pnode_list; p; p = p->alloc_next) { /* Allocate states for p */ s = (snode_t *) ckd_calloc (n_state, sizeof(snode_t)); p->startstate = s; for (i = 0; i < n_state; i++) { s[i].pnode = p; s[i].succlist = NULL; s[i].predlist = NULL; s[i].score = S3_LOGPROB_ZERO; s[i].hist = NULL; s[i].active_frm = -1; /* s[i].sen = mdef->phone[p->pid].state[i]; */ s[i].sen = mdef->sseq[mdef->phone[p->pid].ssid][i]; s[i].state = i; } /* Create transitions between states */ tp = tmat->tp[mdef->phone[p->pid].tmat]; for (i = 0; i < final_state; i++) { /* #from states excludes final state */ for (j = 0; j < n_state; j++) { if (tp[i][j] > S3_LOGPROB_ZERO) /* Link from i to j */ link_snodes (s+i, s+j, tp[i][j]); } } } /* Eliminate non-emitting nodes (final states of HMMs) from state DAG structure */ for (p = pnode_list; p; p = p->alloc_next) { fs = p->startstate + final_state; assert (! fs->succlist); /* * Link predecessor states of fs to start states of followers of parent pnode * with the appropriate prob. (Avoid linking to the dummy node ptail). */ for (sl = fs->predlist; sl; sl = sl->next) { /* Unlink successor link between this predecessor and final state */ prob = un_slink_succ (sl->node, fs); /* Link this predecessor to start states of successor phones */ for (pl = p->succlist; pl; pl = pl->next) { if (pl->node->startstate) link_snodes (sl->node, pl->node->startstate, prob); else link_snodes (sl->node, &stail, prob); } } slinks_free (fs->predlist); fs->predlist = NULL; } /* Link shead to initial states */ for (pl = phead.succlist; pl; pl = pl->next) link_snodes (&shead, pl->node->startstate, 0); return 0;}static void destroy_state_dag ( void ){ pnode_t *p; snode_t *s; int32 i, n_state; n_state = mdef->n_emit_state + 1; for (p = pnode_list; p; p = p->alloc_next) { if ((s = p->startstate) != NULL) { /* Maybe NULL if state dag not built */ for (i = 0; i < n_state; i++) { slinks_free (s[i].succlist); slinks_free (s[i].predlist); } ckd_free (s); p->startstate = NULL; } } slinks_free (shead.succlist); slinks_free (stail.predlist);}#if _DEBUG_ALIGN_static void dump_snode_succ (snode_t *s){ slink_t *l; pnode_t *p; p = s->pnode; printf (" %5d.%d\t", p->id, s->state); for (l = s->succlist; l; l = l->next) printf (" %5d.%d(%7d)", l->node->pnode->id, l->node->state, l->prob); printf ("\n");}static void dump_sdag ( void ){ pnode_t *p; snode_t *s; int32 i; printf ("STATE DAG:\n"); for (p = pnode_list; p; p = p->alloc_next) { s = p->startstate; for (i = 0; i <= mdef->n_emit_state; i++) dump_snode_succ (s+i); }}static void dump_sent_hmm ( void ){ dump_pdag (); dump_sdag (); E_INFO("%d pnodes, %d snodes\n", n_pnode, n_pnode * mdef->n_emit_state);}#endif/** * Build a sentence HMM for the given transcription (wordstr). A two-level DAG is * built: phone-level and state-level. * - <s> and </s> always added at the beginning and end of sentence to form an * augmented transcription. * - Optional <sil> and noise words added between words in the augmented * transcription. * wordstr must contain only the transcript; no extraneous stuff such as utterance-id. * Phone-level HMM structure has replicated nodes to allow for different left and right * context CI phones; hence, each pnode corresponds to a unique triphone in the sentence * HMM. * Return 0 if successful, <0 if any error (eg, OOV word encountered). */int32 align_build_sent_hmm (char *wordstr){ s3wid_t w, nextw; int32 k, oov; pnode_t *word_end, *node; char *wd, delim, *wdcopy = NULL; /* Initialize dummy head and tail entries of sent hmm */ phead.wid = BAD_S3WID; phead.ci = BAD_S3CIPID; phead.lc = BAD_S3CIPID; /* No predecessor */ phead.rc = BAD_S3CIPID; /* Any phone can follow head */ phead.pid = BAD_S3PID; phead.succlist = NULL; phead.predlist = NULL; phead.next = NULL; /* Will ultimately be the head of list of all pnodes */ phead.id = -1; /* Hardwired */ phead.startstate = NULL; ptail.wid = BAD_S3WID; ptail.ci = BAD_S3CIPID; ptail.lc = BAD_S3CIPID; /* Any phone can precede tail */ ptail.rc = BAD_S3CIPID; /* No successor */ ptail.pid = BAD_S3PID; ptail.succlist = NULL; ptail.predlist = NULL; ptail.next = NULL; ptail.id = -2; /* Hardwired */ ptail.startstate = NULL; n_pnode = 0; pnode_list = NULL; oov = 0; /* State-level DAG initialization should be here in case the build is aborted */ shead.pnode = &phead; shead.succlist = NULL; shead.predlist = NULL; shead.sen = BAD_S3SENID; shead.state = mdef->n_emit_state; shead.hist = NULL; stail.pnode = &ptail; stail.succlist = NULL; stail.predlist = NULL; stail.sen = BAD_S3SENID; stail.state = 0; stail.hist = NULL; /* Obtain the first transcript word */ k = nextword (wordstr, " \t\n", &wd, &delim); if (k < 0) nextw = finishwid; else { wordstr = wd + k; wdcopy = ckd_salloc (wd); *wordstr = delim; nextw = dict_wordid (dict, wdcopy); if (IS_S3WID(nextw)) nextw = dict_basewid (dict, nextw); } /* Create node(s) for <s> before any transcript word */ word_end = append_transcript_word (startwid, &phead, nextw, 0, 1); /* Append each word in transcription to partial sent HMM created so far */ while (k >= 0) { w = nextw; if (NOT_S3WID(w)) { E_ERROR("%s not in dictionary\n", wdcopy); oov = 1; /* Hack!! Temporarily set w to some dummy just to run through sentence */ w = finishwid; } ckd_free (wdcopy); k = nextword (wordstr, " \t\n", &wd, &delim); if (k < 0) nextw = finishwid; else { wordstr = wd + k; wdcopy = ckd_salloc (wd); *wordstr = delim; nextw = dict_wordid (dict, wdcopy); if (IS_S3WID(nextw)) nextw = dict_basewid (dict, nextw); } word_end = append_transcript_word (w, word_end, nextw, 1, 1); } if (oov) return -1; /* Append phone HMMs for </s> at the end; link to tail node */ word_end = append_transcript_word (finishwid, word_end, BAD_S3WID, 1, 0); for (node = word_end; node; node = node->next) link_pnodes (node, &ptail); /* Build state-level DAG from the phone-level one */ build_state_dag (); /* Dag must begin and end at shead and stail, respectively */ assert (shead.succlist); assert (stail.predlist); assert (! shead.predlist); assert (! stail.succlist);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?