s3_dag.c

来自「CMU大名鼎鼎的SPHINX-3大词汇量连续语音识别系统」· C语言 代码 · 共 943 行 · 第 1/2 页

C
943
字号
/* ==================================================================== * Copyright (c) 1995-2004 Carnegie Mellon University.  All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer.  * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * This work was supported in part by funding from the Defense Advanced  * Research Projects Agency and the National Science Foundation of the  * United States of America, and the CMU Sphinx Speech Consortium. * * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ==================================================================== * *//* * dag.c -- DAG search * * ********************************************** * CMU ARPA Speech Project * * Copyright (c) 1996 Carnegie Mellon University. * ALL RIGHTS RESERVED. * ********************************************** *  * HISTORY *  * 28-Jul-04    ARCHAN at Carnegie Mellon Unversity *              First adapted from s3.               *  * 08-Sep-97	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University * 		Added .Z compression option to lattice files. *  * 04-Jun-97	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University * 		Added dag_chk_linkscr(). *  * 22-Nov-96	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University * 		Implemented -maxedge argument to control memory usage. *  * 21-Nov-96	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University * 		Added -maxlmop and -maxlpf options to abort utterance if exceeded. *  * 08-Nov-96	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University * 		Added exact reporting of word sequence and scores from dag_search. * 		For this, added daglink_t.bypass, daglink_t.lscr, daglink_t.src, and * 		added bypass argument to dag_link and dag_bypass_link, and changed * 		dag_backtrace to find exact best path. *  * 05-Nov-96	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University * 		Added -dagfudge and -min_endfr parameter handling. *  * 03-Sep-96	M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University * 		Started. *//** \file s3_dag.c    \brief Engined for s3.0 dag */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <s3types.h>#include "s3_dag.h"#include "mdef.h"#include "tmat.h"#include "dict.h"#include "lm.h"#include "fillpen.h"#include "search.h"#include "logs3.h"static dag_t dag;static s3wid_t startwid;	/* Begin silence */static s3wid_t finishwid;	/* End silence *//* Global variables : Hack! */dict_t *dict;		/* The dictionary */fillpen_t *fpen;         /* The fillpenalty data structure */lm_t *lm;                /* Global variables */s3lmwid_t *dict2lmwid;	/* Mapping from decoding dictionary wid's to lm ones.  They may not be the same! */static srch_hyp_t *hyp = NULL;	/* The final recognition result */static int32 maxlmop;		/* Max LM ops allowed before utterance aborted */static int32 lmop;		/* #LM ops actually made */static int32 maxedge;		/* Max #edges in DAG allowed before utterance aborted *//* Get rid of old hyp, if any */static void hyp_free ( void ){    srch_hyp_t *tmphyp;        while (hyp) {	tmphyp = hyp->next;	listelem_free ((char *)hyp, sizeof(srch_hyp_t));	hyp = tmphyp;    }}static int32 filler_word (s3wid_t w){    if ((w == startwid) || (w == finishwid))	return 0;    if ((w >= dict->filler_start) && (w <= dict->filler_end))	return 1;    return 0;}void dag_init (dict_t* _dict ){  dict = _dict;    /* Some key word ids */    startwid = dict_wordid (dict, S3_START_WORD);    finishwid = dict_wordid (dict,S3_FINISH_WORD);    if ((NOT_S3WID(startwid)) || (NOT_S3WID(finishwid)))	E_FATAL("%s or %s missing from dictionary\n", S3_START_WORD, S3_FINISH_WORD);    /* Initialize DAG structure */    dag.list = NULL;    /* Set limit on max DAG edges allowed after which utterance is aborted */    maxedge = *((int32 *) cmd_ln_access ("-maxedge"));}/* * Link two DAG nodes with the given arguments * Return value: 0 if successful, -1 if maxedge limit exceeded. */static int32 dag_link (dagnode_t *pd, dagnode_t *d, int32 ascr, int32 ef, daglink_t *byp){    daglink_t *l;        /* Link d into successor list for pd */    if (pd) {	/* Special condition for root node which doesn't have a predecessor */	l = (daglink_t *) listelem_alloc (sizeof(daglink_t));	l->node = d;	l->src = pd;	l->bypass = byp;	/* This is a FORWARD link!! */	l->ascr = ascr;	l->pscr = (int32)0x80000000;	l->pscr_valid = 0;	l->history = NULL;	l->ef = ef;	l->next = pd->succlist;	pd->succlist = l;    }    /* Link pd into predecessor list for d */    l = (daglink_t *) listelem_alloc (sizeof(daglink_t));    l->node = pd;    l->src = d;    l->bypass = byp;		/* This is a FORWARD link!! */    l->ascr = ascr;    l->pscr = (int32)0x80000000;    l->pscr_valid = 0;    l->history = NULL;    l->ef = ef;    l->next = d->predlist;    d->predlist = l;    dag.nlink++;    return (dag.nlink > maxedge) ? -1 : 0;}static daglink_t *find_succlink (dagnode_t *src, dagnode_t *dst){    daglink_t *l;    for (l = src->succlist; l && (l->node != dst); l = l->next);    return l;}static daglink_t *find_predlink (dagnode_t *src, dagnode_t *dst){    daglink_t *l;    for (l = src->predlist; l && (l->node != dst); l = l->next);    return l;}/* * Like dag_link but check if link already exists.  If so, replace if new score better. * Return value: 0 if successful, -1 if maxedge limit exceeded. */static int32 dag_update_link (dagnode_t *pd, dagnode_t *d, int32 ascr,			      int32 ef, daglink_t *byp){    daglink_t *l, *r;    l = find_succlink (pd, d);    if (! l)	return (dag_link (pd, d, ascr, ef, byp));    if (l->ascr < ascr) {	r = find_predlink (d, pd);	assert (r && (r->ascr == l->ascr));	l->ascr = r->ascr = ascr;	l->ef = r->ef = ef;	l->bypass = r->bypass = byp;    }        return 0;}static int32 dag_param_read (FILE *fp, char *param, int32 *lineno){    char line[1024], wd[1024];    int32 n;        while (fgets (line, 1024, fp) != NULL) {	(*lineno)++;	if (line[0] == '#')	    continue;	if ((sscanf (line, "%s %d", wd, &n) == 2) && (strcmp (wd, param) == 0))	    return n;    }    return -1;}/* * Remove filler nodes from DAG by replacing each link TO a filler with links * to its successors.  In principle, successors can be fillers and the process * must be repeated.  But removing fillers in the order in which they appear in * dag.list ensures that succeeding fillers have already been eliminated. * Return value: 0 if successful; -1 if DAG maxedge limit exceeded. */static int32 dag_remove_filler_nodes ( void ){    dagnode_t *d, *pnode, *snode;    daglink_t *plink, *slink;    int32 ascr=0;        assert(dag.list);    for (d = dag.list; d; d = d->alloc_next) {	if (! filler_word (d->wid))	    continue;		/* Replace each link TO d with links to d's successors */	for (plink = d->predlist; plink; plink = plink->next) {	    pnode = plink->node;	    ascr = plink->ascr; 	    ascr += fillpen(fpen,dict_basewid (dict,d->wid));	    	    /* Link this predecessor of d to successors of d */	    for (slink = d->succlist; slink; slink = slink->next) {		snode = slink->node;		/* Link only to non-filler successors; fillers have been eliminated */		if (! filler_word (snode->wid)) {		    /* Update because a link may already exist */		    if (dag_update_link (pnode, snode,					 ascr + slink->ascr, plink->ef, slink) < 0)			return -1;		}	    }	}    }    return 0;}/* * Load a DAG from a file: each unique <word-id,start-frame> is a node, i.e. with * a single start time but it can represent several end times.  Links are created * whenever nodes are adjacent in time. * dagnodes_list = linear list of DAG nodes allocated, ordered such that nodes earlier * in the list can follow nodes later in the list, but not vice versa:  Let two DAG * nodes d1 and d2 have start times sf1 and sf2, and end time ranges [fef1..lef1] and * [fef2..lef2] respectively.  If d1 appears later than d2 in dag.list, then * fef2 >= fef1, because d2 showed up later in the word lattice.  If there is a DAG * edge from d1 to d2, then sf1 > fef2.  But fef2 >= fef1, so sf1 > fef1.  Reductio ad * absurdum. * Return value: 0 if successful, -1 otherwise. */int32 s3dag_dag_load (char *file){    FILE *fp;    char line[16384], wd[1024];    int32 nfrm, nnode, sf, fef, lef, ef, lineno;    int32 i, j, k, l, final, seqid, from, to, ascr;    int32 fudge, min_ef_range;    dagnode_t *d, *pd, *tail, **darray;    s3wid_t w;    struct lat_s {	dagnode_t *node;	int32 ef;	int32 ascr;    } *lat;		/* Lattice (bptable) entries in each frame */    int32 *frm2lat;	/* frm2lat[f] = first lattice entry for frame f */    float32 lb, f32arg;    int32 ispipe;        dag.list = NULL;    dag.nlink = 0;    dag.nbypass =0;        tail = NULL;    darray = NULL;    lat = NULL;    frm2lat = NULL;    lineno = 0;        E_INFO("Reading DAG file: %s\n", file);    if ((fp = fopen_compchk (file, &ispipe)) == NULL) {	E_ERROR("fopen_compchk(%s) failed\n", file);	return -1;    }        /* Read and verify logbase (ONE BIG HACK!!) */    if (fgets (line, sizeof(line), fp) == NULL) {	E_ERROR ("Premature EOF(%s)\n", file);	goto load_error;    }    if (strncmp (line, "# getcwd: ", 10) != 0) {	E_ERROR ("%s does not begin with '# getcwd: '\n", file);	goto load_error;    }    if (fgets (line, sizeof(line), fp) == NULL) {	E_ERROR ("Premature EOF(%s)\n", file);	goto load_error;    }    if ((strncmp (line, "# -logbase ", 11) != 0) || (sscanf (line+11, "%f", &lb) != 1)) {	E_WARN ("%s: Cannot find -logbase in header\n", file);    } else {	f32arg = *((float32 *) cmd_ln_access ("-logbase"));	if ((lb <= 1.0) || (lb > 2.0) || (f32arg <= 1.0) || (f32arg > 2.0))	    E_ERROR ("%s: logbases out of range; cannot be verified\n", file);	else {	    int32 orig, this;	    float64 diff;	    	    orig = logs3 (lb - 1.0);	    this = logs3 (f32arg - 1.0);	    diff = ((orig - this) * 1000.0) / orig;	    if (diff < 0)		diff = -diff;	    	    if (diff > 1.0)		/* Hack!! Hardwired tolerance limits on logbase */		E_ERROR ("%s: logbase inconsistent: %e\n", file, lb);	}    }        /* Min. endframes value that a node must persist for it to be not ignored */    min_ef_range = *((int32 *) cmd_ln_access ("-min_endfr"));        /* Read Frames parameter */    nfrm = dag_param_read (fp, "Frames", &lineno);    if (nfrm <= 0) {	E_ERROR("Frames parameter missing or invalid\n");	goto load_error;    }    dag.nfrm = nfrm;        /* Read Nodes parameter */    lineno = 0;    nnode = dag_param_read (fp, "Nodes", &lineno);    if (nnode <= 0) {	E_ERROR("Nodes parameter missing or invalid\n");	goto load_error;    }        /* Read nodes */    darray = (dagnode_t **) ckd_calloc (nnode, sizeof(dagnode_t *));    for (i = 0; i < nnode; i++) {	if (fgets (line, 1024, fp) == NULL) {	    E_ERROR ("Premature EOF(%s)\n", file);	    goto load_error;	}	lineno++;		if ((k = sscanf (line, "%d %s %d %d %d", &seqid, wd, &sf, &fef, &lef)) != 5) {	    E_ERROR("Bad line: %s\n", line);	    goto load_error;	}	w = dict_wordid (dict,wd);	if (NOT_S3WID(w)) {	    E_ERROR("Unknown word: %s\n", line);	    goto load_error;	}		if (seqid != i) {	    E_ERROR("Seqno error: %s\n", line);	    goto load_error;	}		d = (dagnode_t *) listelem_alloc (sizeof(dagnode_t));	darray[i] = d;		d->wid = w;	d->seqid = seqid;	d->sf = sf;	d->fef = fef;	d->lef = lef;	d->reachable = 0;	d->succlist = NULL;	d->predlist = NULL;	d->alloc_next = NULL;		if (! dag.list)	    dag.list = d;	else	    tail->alloc_next = d;	tail = d;    }    /* Read initial node ID */    k = dag_param_read (fp, "Initial", &lineno);    if ((k < 0) || (k >= nnode)) {	E_ERROR("Initial node parameter missing or invalid\n");	goto load_error;    }    dag.entry.node = darray[k];    dag.entry.ascr = 0;    dag.entry.next = NULL;    dag.entry.pscr_valid = 0;        /* Read final node ID */    k = dag_param_read (fp, "Final", &lineno);    if ((k < 0) || (k >= nnode)) {	E_ERROR("Final node parameter missing or invalid\n");	goto load_error;    }    dag.exit.node = darray[k];    dag.exit.ascr = 0;    dag.exit.next = NULL;    dag.exit.pscr_valid = 0;    dag.exit.bypass = NULL;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?