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 + -
显示快捷键?