~ubuntu-branches/ubuntu/saucy/sphinxtrain/saucy

« back to all changes in this revision

Viewing changes to src/programs/prunetree/main.c

  • Committer: Package Import Robot
  • Author(s): Samuel Thibault
  • Date: 2013-01-02 04:10:21 UTC
  • Revision ID: package-import@ubuntu.com-20130102041021-ynsizmz33fx02hea
Tags: upstream-1.0.8
ImportĀ upstreamĀ versionĀ 1.0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ====================================================================
 
2
 * Copyright (c) 1994-2000 Carnegie Mellon University.  All rights 
 
3
 * reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer. 
 
11
 *
 
12
 * 2. Redistributions in binary form must reproduce the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer in
 
14
 *    the documentation and/or other materials provided with the
 
15
 *    distribution.
 
16
 *
 
17
 * This work was supported in part by funding from the Defense Advanced 
 
18
 * Research Projects Agency and the National Science Foundation of the 
 
19
 * United States of America, and the CMU Sphinx Speech Consortium.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
 
22
 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 
23
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
24
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
 
25
 * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 
28
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 
29
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 
30
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 
31
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
32
 *
 
33
 * ====================================================================
 
34
 *
 
35
 */
 
36
/*********************************************************************
 
37
 *
 
38
 * File: main.c
 
39
 * 
 
40
 * Description: 
 
41
 *    Prune decision trees.
 
42
 *
 
43
 * Author: 
 
44
 * 
 
45
 *********************************************************************/
 
46
 
 
47
#include "parse_cmd_ln.h"
 
48
 
 
49
#include <sphinxbase/ckd_alloc.h>
 
50
#include <sphinxbase/err.h>
 
51
 
 
52
#include <s3/dtree.h>
 
53
#include <s3/model_def_io.h>
 
54
#include <s3/quest.h>
 
55
#include <s3/pset_io.h>
 
56
#include <s3/s3.h>
 
57
#include <sys_compat/file.h>
 
58
 
 
59
#include <assert.h>
 
60
 
 
61
static int
 
62
init(model_def_t **out_mdef,
 
63
     pset_t **out_pset,
 
64
     uint32 *out_n_pset)
 
65
{
 
66
    const char *moddeffn;
 
67
    model_def_t *mdef;
 
68
 
 
69
    const char *psetfn;
 
70
    pset_t *pset;
 
71
    uint32 n_pset;
 
72
 
 
73
    moddeffn = cmd_ln_str("-moddeffn");
 
74
    if (moddeffn == NULL)
 
75
        E_FATAL("Specify -moddeffn\n");
 
76
    E_INFO("Reading: %s\n", moddeffn);
 
77
    if (model_def_read(&mdef, moddeffn) != S3_SUCCESS)
 
78
        return S3_ERROR;
 
79
    *out_mdef = mdef;
 
80
 
 
81
    psetfn = cmd_ln_str("-psetfn");
 
82
    E_INFO("Reading: %s\n", psetfn);
 
83
    *out_pset = pset = read_pset_file(psetfn, mdef->acmod_set, &n_pset);
 
84
    *out_n_pset = n_pset;
 
85
 
 
86
    return S3_SUCCESS;
 
87
}
 
88
 
 
89
#include <s3/heap.h>
 
90
 
 
91
int
 
92
heap_ok(uint32 *hkey,
 
93
        uint32 sz,
 
94
 
 
95
        uint32 *phn,
 
96
        uint32 *st,
 
97
        uint32 *nd,
 
98
        model_def_t *mdef)
 
99
{
 
100
    uint32 i, k_i;
 
101
    uint32 j, k_j;
 
102
    int ok = TRUE;
 
103
 
 
104
    for (i = 0; i < sz-1; i++) {
 
105
        k_i = hkey[i];
 
106
 
 
107
        if (phn[k_i] == NO_ID) {
 
108
            E_ERROR("A hole is on the heap for key %u!\n", k_i);
 
109
 
 
110
            ok = FALSE;
 
111
            continue;
 
112
        }
 
113
 
 
114
        for (j = i+1; j < sz; j++) {
 
115
            k_j = hkey[j];
 
116
 
 
117
            if (phn[k_j] == NO_ID)
 
118
                continue;
 
119
 
 
120
            if ((phn[k_i] == phn[k_j]) &&
 
121
                (st[k_i] == st[k_j]) &&
 
122
                (nd[k_i] == nd[k_j])) {
 
123
                E_ERROR("tree (%s %u) node %u on heap more than once\n",
 
124
                        acmod_set_id2name(mdef->acmod_set, phn[k_i]),
 
125
                        st[k_i],
 
126
                        nd[k_i]);
 
127
                ok = FALSE;
 
128
            }
 
129
        }
 
130
    }
 
131
 
 
132
    if (phn[hkey[sz-1]] == NO_ID) {
 
133
        E_ERROR("A hole is on the heap for key %u!\n", sz-1);
 
134
        
 
135
        ok = FALSE;
 
136
    }
 
137
 
 
138
    return ok;
 
139
}
 
140
 
 
141
static int
 
142
read_phone_trees(model_def_t *mdef,
 
143
                 const char *itreedir,
 
144
                 const char *pname,
 
145
                 uint32 p,
 
146
                 uint32 n_state,
 
147
                 pset_t *pset,
 
148
                 uint32 n_pset,
 
149
                 dtree_t ***out_tree,
 
150
                 uint32 *out_n_seno,
 
151
                 uint32 *out_n_twig,
 
152
                 uint32 *out_n_node)
 
153
{
 
154
    uint32 s;
 
155
 
 
156
    out_tree[p] = (dtree_t **)ckd_calloc(n_state, sizeof(dtree_t *));
 
157
    for (s = 0; s < n_state; s++) {
 
158
        char fn[MAXPATHLEN+1];
 
159
        dtree_t *tr;
 
160
        FILE *fp;
 
161
 
 
162
        sprintf(fn, "%s/%s-%u.dtree",
 
163
                itreedir, pname, s);
 
164
 
 
165
        fp = fopen(fn, "r");
 
166
        if (fp == NULL) {
 
167
            E_FATAL_SYSTEM("Unable to open %s for reading",fn);
 
168
        }
 
169
 
 
170
        out_tree[p][s] = tr = read_final_tree(fp, pset, n_pset);
 
171
 
 
172
        if (tr == NULL) {
 
173
            E_ERROR("Error(s) while reading tree\n");
 
174
            return -1;
 
175
        }
 
176
        else {
 
177
            uint32 n, lt_minocc;
 
178
 
 
179
            lt_minocc = prune_lowcnt(&tr->node[0], cmd_ln_float32("-minocc"));
 
180
            n = 0;
 
181
            reindex(&tr->node[0], &n);
 
182
            *out_n_seno += n = cnt_leaf(&tr->node[0]);
 
183
            E_INFO("%s-%u\t%u [%u < %e]\n",
 
184
                   pname, s, n, lt_minocc,
 
185
                   cmd_ln_float32("-minocc"));
 
186
            *out_n_twig += cnt_twig(&tr->node[0]);
 
187
            *out_n_node += cnt_node(&tr->node[0]);
 
188
        }
 
189
 
 
190
        fclose(fp);
 
191
    }
 
192
    return 0;
 
193
}
 
194
 
 
195
static int
 
196
prune_tree(model_def_t *mdef,
 
197
           pset_t *pset,
 
198
           uint32 n_pset)
 
199
{
 
200
    const char *itreedir;
 
201
    const char *otreedir;
 
202
    char fn[MAXPATHLEN+1];
 
203
    FILE *fp;
 
204
 
 
205
    dtree_t ***tree;    /* Decision trees indexed by phone and state */
 
206
    dtree_t *tr;
 
207
    dtree_node_t *node, *prnt;
 
208
    float32 *twig_heap; /* Heap of wt_ent_dec of split quest */
 
209
    uint32 *twig_hkey;  /* Key's for items in the heap */
 
210
    uint32 *twig_phnid; /* Phone id of items on heap */
 
211
    uint32 *twig_state; /* State id of items on heap */
 
212
    uint32 *twig_nid;   /* Node id of items on heap */
 
213
    uint32 free_key;    /* Next unused heap key */
 
214
    uint32 free_idx;    /* Next unused node index */
 
215
    uint32 n_ci, p, s, n;
 
216
    uint32 *n_state_ci; /* # of state of models in the same base phone class */
 
217
    uint32 n_seno;
 
218
    uint32 n_seno_wanted;
 
219
    uint32 n_twig;
 
220
    uint32 n_node;
 
221
    float32 wt_ent_dec;
 
222
    uint32 key;
 
223
    uint32 sz;
 
224
    uint32 i;
 
225
    int allphones;
 
226
    int err;
 
227
 
 
228
    itreedir = cmd_ln_str("-itreedir");
 
229
    allphones = cmd_ln_int32("-allphones");
 
230
    n_ci = acmod_set_n_ci(mdef->acmod_set);
 
231
 
 
232
    tree = (dtree_t ***)ckd_calloc(n_ci, sizeof(dtree_t **));
 
233
    n_state_ci = (uint32 *)ckd_calloc(n_ci, sizeof(uint32));
 
234
 
 
235
    err = FALSE;
 
236
    if (allphones) {
 
237
        uint32 n_state;
 
238
 
 
239
        n_state = mdef->defn[n_ci].n_state-1;
 
240
        n_state_ci[0] = n_state;
 
241
        n_ci = 1;
 
242
        n_seno = 0;
 
243
        n_twig = 0;
 
244
        if (read_phone_trees(mdef, itreedir, "ALLPHONES", 0, n_state,
 
245
                             pset, n_pset, tree, &n_seno, &n_twig, &n_node) < 0)
 
246
            err = TRUE;
 
247
    }
 
248
    else {
 
249
        for (p = 0, err = FALSE, n_seno = 0, n_twig = 0; p < n_ci; p++) {
 
250
            if (!acmod_set_has_attrib(mdef->acmod_set, (acmod_id_t)p, "filler")) {
 
251
                const char *pname;
 
252
                uint32 n_state;
 
253
 
 
254
                pname = acmod_set_id2name(mdef->acmod_set, (acmod_id_t)p);
 
255
                n_state = mdef->defn[p].n_state-1;
 
256
                n_state_ci[p] = n_state;
 
257
                if (read_phone_trees(mdef, itreedir, pname, p, n_state,
 
258
                                     pset, n_pset, tree,
 
259
                                     &n_seno, &n_twig, &n_node) < 0)
 
260
                    err = TRUE;
 
261
            }
 
262
        }
 
263
    }
 
264
 
 
265
    if (err) {
 
266
        E_ERROR("Error(s) while reading trees; pruning not done\n");
 
267
        return S3_ERROR;
 
268
    }
 
269
 
 
270
    E_INFO("Prior to pruning n_seno= %u\n", n_seno);
 
271
 
 
272
    n_seno_wanted = cmd_ln_int32("-nseno");
 
273
    if (n_seno < n_seno_wanted) {
 
274
        E_WARN("n_seno_wanted= %u, but only %u defined by trees\n",
 
275
               n_seno_wanted, n_seno);
 
276
    }
 
277
 
 
278
    E_INFO("n_twig= %u\n", n_twig);
 
279
    
 
280
    if (n_seno_wanted < n_seno) {
 
281
        /* Heap of wt_ent_dec for each "twig" question */
 
282
        twig_heap  = (float32 *)ckd_calloc(n_twig, sizeof(float32));
 
283
        twig_hkey  = (uint32 *)ckd_calloc(n_twig, sizeof(uint32));
 
284
 
 
285
        twig_phnid = (uint32 *)ckd_calloc(n_twig, sizeof(uint32));
 
286
        twig_state = (uint32 *)ckd_calloc(n_twig, sizeof(uint32));
 
287
        twig_nid   = (uint32 *)ckd_calloc(n_twig, sizeof(uint32));
 
288
    
 
289
        /* Insert all twig questions over all trees into the heap */
 
290
        for (p = 0, free_key = 0; p < n_ci; p++) {
 
291
            for (s = 0; s < n_state_ci[p]; s++) {
 
292
                if (allphones
 
293
                    || !acmod_set_has_attrib(mdef->acmod_set, (acmod_id_t)p, "filler")) {
 
294
                    tr = tree[p][s];
 
295
 
 
296
                    ins_twigs(&tr->node[0],
 
297
                              p, s,
 
298
                              twig_heap,
 
299
                              twig_hkey,
 
300
                              twig_phnid,
 
301
                              twig_state,
 
302
                              twig_nid,
 
303
                              &free_key);
 
304
                }
 
305
            }
 
306
        }
 
307
 
 
308
        E_INFO("Pruning %u nodes\n", n_seno - n_seno_wanted);
 
309
 
 
310
        for (i = n_seno, sz = n_twig; (i > n_seno_wanted) && (sz > 0); i--) {
 
311
#if 0
 
312
            if (!heap_ok(twig_hkey, sz,
 
313
                         twig_phnid, twig_state, twig_nid,
 
314
                         mdef)) {
 
315
                E_FATAL("heap problems; bug.\n");
 
316
            }
 
317
#endif
 
318
 
 
319
            /* extract the top (minimum wt_ent_dec) node off the
 
320
               heap; this is the worst question of the tree. */
 
321
            sz = heap32b_extr_top(&wt_ent_dec, &key,
 
322
                                  twig_heap, twig_hkey, sz, heap32b_min_comp);
 
323
 
 
324
            /* Get the node to prune */
 
325
            p = twig_phnid[key];
 
326
            s = twig_state[key];
 
327
            n = twig_nid[key];
 
328
            tr = tree[p][s];
 
329
            node = get_node(&tr->node[0], n);
 
330
 
 
331
            assert(IS_TWIG(node));
 
332
 
 
333
            /* Make twig node a leaf by pruning its leaves */
 
334
            prune_subtrees(node);
 
335
 
 
336
            assert(IS_LEAF(node));
 
337
 
 
338
            prnt = node->p;
 
339
            if (prnt == NULL) {
 
340
                E_INFO("Root node extracted (%s %u) from heap\n",
 
341
                       acmod_set_id2name(mdef->acmod_set, (acmod_id_t)p), s);
 
342
            }
 
343
 
 
344
            /* Is the parent (if any) now a twig? */
 
345
            if (prnt && IS_TWIG(prnt)) {
 
346
                /* Put it on the heap and reuse the heap-key for the child */
 
347
 
 
348
                twig_nid[key] = prnt->node_id;
 
349
                
 
350
                sz = heap32b_ins(twig_heap, twig_hkey, sz,
 
351
                                 prnt->wt_ent_dec, key, heap32b_min_comp);
 
352
            }
 
353
            else {
 
354
                /* Parent node not a "twig" as a result of pruning */
 
355
 
 
356
                /* Set "holes" to values that are almost certain to
 
357
                 * cause a seg fault if used as an index */
 
358
                twig_phnid[key] = NO_ID;
 
359
                twig_state[key] = NO_ID;
 
360
                twig_nid[key] = NO_ID;
 
361
            }
 
362
        }
 
363
 
 
364
        if ((sz == 0) && (i > n_seno_wanted)) {
 
365
            E_WARN("%u seno's not generated because heap ran out\n", n_seno_wanted);
 
366
        }
 
367
    }
 
368
 
 
369
    otreedir = cmd_ln_str("-otreedir");
 
370
    for (p = 0, n_node = 0; p < n_ci; p++) {
 
371
        const char *pname;
 
372
 
 
373
        if (allphones)
 
374
            pname = "ALLPHONES";
 
375
        else
 
376
            pname = acmod_set_id2name(mdef->acmod_set, (acmod_id_t)p);
 
377
 
 
378
        for (s = 0; s < n_state_ci[p]; s++) {
 
379
            if (allphones
 
380
                || !acmod_set_has_attrib(mdef->acmod_set, (acmod_id_t)p, "filler")) {
 
381
                tr = tree[p][s];
 
382
 
 
383
                free_idx = 0;
 
384
                n_node += n = reindex(&tr->node[0], &free_idx);
 
385
 
 
386
                E_INFO("%s-%u\t%u\n", pname, s, n);
 
387
 
 
388
                sprintf(fn, "%s/%s-%u.dtree", otreedir, pname, s);
 
389
                
 
390
                fp = fopen(fn, "w");
 
391
                if (fp == NULL) {
 
392
                    E_FATAL_SYSTEM("Unable to open %s for writing", fn);
 
393
                }
 
394
                print_final_tree(fp, &tr->node[0], pset);
 
395
                fclose(fp);
 
396
 
 
397
            }
 
398
        }
 
399
    }
 
400
 
 
401
 
 
402
    return S3_SUCCESS;
 
403
}
 
404
 
 
405
int
 
406
main(int argc, char *argv[])
 
407
{
 
408
    model_def_t *mdef = NULL;
 
409
    pset_t *pset = NULL;
 
410
    uint32 n_pset = 0;
 
411
 
 
412
    parse_cmd_ln(argc, argv);
 
413
 
 
414
    if (init(&mdef, &pset, &n_pset) != S3_SUCCESS) {
 
415
        E_FATAL("Initialization failed\n");
 
416
    }
 
417
 
 
418
    prune_tree(mdef, pset, n_pset);
 
419
    
 
420
    return 0;
 
421
}
 
422
 
 
423
/*
 
424
 * Log record.  Maintained by RCS.
 
425
 *
 
426
 * $Log$
 
427
 * Revision 1.7  2005/06/13  22:18:22  dhdfu
 
428
 * Add -allphones arguments to decision tree and state tying code.  Allows senones to be shared across multiple base phones (though they are currently still restricted to the same state).  This can improve implicit pronunciation modeling in some cases, such as grapheme-based models, though it usually has little effect.  Building the big trees can take a very long time.
 
429
 * 
 
430
 * Revision 1.6  2004/07/21 19:17:26  egouvea
 
431
 * Changed the license terms to make it the same as sphinx2 and sphinx3.
 
432
 *
 
433
 * Revision 1.5  2004/06/17 19:17:24  arthchan2003
 
434
 * Code Update for silence deletion and standardize the name for command -line arguments
 
435
 *
 
436
 * Revision 1.4  2001/04/05 20:02:31  awb
 
437
 * *** empty log message ***
 
438
 *
 
439
 * Revision 1.3  2000/11/25 22:03:03  awb
 
440
 * *** empty log message ***
 
441
 *
 
442
 * Revision 1.2  2000/09/29 22:35:14  awb
 
443
 * *** empty log message ***
 
444
 *
 
445
 * Revision 1.1  2000/09/24 21:38:32  awb
 
446
 * *** empty log message ***
 
447
 *
 
448
 * Revision 1.1  97/07/16  11:36:22  eht
 
449
 * Initial revision
 
450
 * 
 
451
 *
 
452
 */