tenfourfox/media/pocketsphinx/src/allphone_search.c
Cameron Kaiser c9b2922b70 hello FPR
2017-04-19 00:56:45 -07:00

914 lines
27 KiB
C

/* ====================================================================
* Copyright (c) 2014 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 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.
*
* ====================================================================
*
*/
/*
* allphone_search.c -- Search for phonetic decoding.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sphinxbase/err.h>
#include <sphinxbase/ckd_alloc.h>
#include <sphinxbase/strfuncs.h>
#include <sphinxbase/pio.h>
#include <sphinxbase/cmd_ln.h>
#include "pocketsphinx_internal.h"
#include "allphone_search.h"
static ps_lattice_t *
allphone_search_lattice(ps_search_t * search)
{
//cap
return NULL;
}
static int
allphone_search_prob(ps_search_t * search)
{
return 0;
}
static void
allphone_backtrace(allphone_search_t * allphs, int32 f);
static void
allphone_search_seg_free(ps_seg_t * seg)
{
ckd_free(seg);
}
static void
allphone_search_fill_iter(ps_seg_t *seg, phseg_t *phseg)
{
seg->sf = phseg->sf;
seg->ef = phseg->ef;
seg->ascr = phseg->score;
seg->lscr = phseg->tscore;
seg->word = bin_mdef_ciphone_str(ps_search_acmod(seg->search)->mdef, phseg->ci);
}
static ps_seg_t *
allphone_search_seg_next(ps_seg_t * seg)
{
phseg_iter_t *itor = (phseg_iter_t *) seg;
phseg_t *phseg;
itor->seg = itor->seg->next;
if (itor->seg == NULL) {
allphone_search_seg_free(seg);
return NULL;
}
phseg = gnode_ptr(itor->seg);
allphone_search_fill_iter(seg, phseg);
return seg;
}
static ps_segfuncs_t fsg_segfuncs = {
/* seg_next */ allphone_search_seg_next,
/* seg_free */ allphone_search_seg_free
};
static ps_seg_t *
allphone_search_seg_iter(ps_search_t * search, int32 * out_score)
{
allphone_search_t *allphs = (allphone_search_t *) search;
phseg_iter_t *iter;
allphone_backtrace(allphs, allphs->frame - 1);
if (allphs->segments == NULL)
return NULL;
iter = ckd_calloc(1, sizeof(phseg_iter_t));
iter->base.vt = &fsg_segfuncs;
iter->base.search = search;
iter->seg = allphs->segments;
allphone_search_fill_iter((ps_seg_t *)iter, gnode_ptr(iter->seg));
return (ps_seg_t *) iter;
}
static ps_searchfuncs_t allphone_funcs = {
/* name: */ "allphone",
/* start: */ allphone_search_start,
/* step: */ allphone_search_step,
/* finish: */ allphone_search_finish,
/* reinit: */ allphone_search_reinit,
/* free: */ allphone_search_free,
/* lattice: */ allphone_search_lattice,
/* hyp: */ allphone_search_hyp,
/* prob: */ allphone_search_prob,
/* seg_iter: */ allphone_search_seg_iter,
};
/**
* Find PHMM node with same senone sequence and tmat id as the given triphone.
* Return ptr to PHMM node if found, NULL otherwise.
*/
static phmm_t *
phmm_lookup(allphone_search_t * allphs, s3pid_t pid)
{
phmm_t *p;
bin_mdef_t *mdef;
phmm_t **ci_phmm;
mdef = ((ps_search_t *) allphs)->acmod->mdef;
ci_phmm = allphs->ci_phmm;
for (p = ci_phmm[bin_mdef_pid2ci(mdef, pid)]; p; p = p->next) {
if (mdef_pid2tmatid(mdef, p->pid) == mdef_pid2tmatid(mdef, pid))
if (mdef_pid2ssid(mdef, p->pid) == mdef_pid2ssid(mdef, pid))
return p;
}
//not found
return NULL;
}
static int32
phmm_link(allphone_search_t * allphs)
{
s3cipid_t ci, rc;
phmm_t *p, *p2;
int32 *rclist;
int32 i, n_link;
plink_t *l;
bin_mdef_t *mdef;
phmm_t **ci_phmm;
mdef = ((ps_search_t *) allphs)->acmod->mdef;
ci_phmm = allphs->ci_phmm;
rclist = (int32 *) ckd_calloc(mdef->n_ciphone + 1, sizeof(int32));
/* Create successor links between PHMM nodes */
n_link = 0;
for (ci = 0; ci < mdef->n_ciphone; ci++) {
for (p = ci_phmm[ci]; p; p = p->next) {
/* Build rclist for p */
i = 0;
for (rc = 0; rc < mdef->n_ciphone; rc++) {
if (bitvec_is_set(p->rc, rc))
rclist[i++] = rc;
}
rclist[i] = BAD_S3CIPID;
/* For each rc in rclist, transition to PHMMs for rc if left context = ci */
for (i = 0; IS_S3CIPID(rclist[i]); i++) {
for (p2 = ci_phmm[rclist[i]]; p2; p2 = p2->next) {
if (bitvec_is_set(p2->lc, ci)) {
/* transition from p to p2 */
l = (plink_t *) ckd_calloc(1, sizeof(*l));
l->phmm = p2;
l->next = p->succlist;
p->succlist = l;
n_link++;
}
}
}
}
}
ckd_free(rclist);
return n_link;
}
/**
* Build net from phone HMMs
*/
static int
phmm_build(allphone_search_t * allphs)
{
phmm_t *p, **pid2phmm;
bin_mdef_t *mdef;
int32 lrc_size;
uint32 *lc, *rc;
s3pid_t pid;
s3cipid_t ci;
s3cipid_t *filler;
int n_phmm, n_link;
int i, nphone;
mdef = ((ps_search_t *) allphs)->acmod->mdef;
allphs->ci_phmm =
(phmm_t **) ckd_calloc(bin_mdef_n_ciphone(mdef), sizeof(phmm_t *));
pid2phmm =
(phmm_t **) ckd_calloc(bin_mdef_n_phone(mdef), sizeof(phmm_t *));
/* For each unique ciphone/triphone entry in mdef, create a PHMM node */
n_phmm = 0;
nphone = allphs->ci_only ? bin_mdef_n_ciphone(mdef) : bin_mdef_n_phone(mdef);
E_INFO("Building PHMM net of %d phones\n", nphone);
for (pid = 0; pid < nphone; pid++) {
if ((p = phmm_lookup(allphs, pid)) == NULL) {
//not found, should be created
p = (phmm_t *) ckd_calloc(1, sizeof(*p));
hmm_init(allphs->hmmctx, &(p->hmm), FALSE,
mdef_pid2ssid(mdef, pid), mdef->phone[pid].tmat);
p->pid = pid;
p->ci = bin_mdef_pid2ci(mdef, pid);
p->succlist = NULL;
p->next = allphs->ci_phmm[p->ci];
allphs->ci_phmm[p->ci] = p;
n_phmm++;
}
pid2phmm[pid] = p;
}
/* Fill out bitvecs of each PHMM node, alloc continuous memory chunk for context bitvectors */
lrc_size = bitvec_size(bin_mdef_n_ciphone(mdef));
lc = ckd_calloc(n_phmm * 2 * lrc_size, sizeof(bitvec_t));
rc = lc + (n_phmm * lrc_size);
for (ci = 0; ci < mdef->n_ciphone; ci++) {
for (p = allphs->ci_phmm[ci]; p; p = p->next) {
p->lc = lc;
lc += lrc_size;
p->rc = rc;
rc += lrc_size;
}
}
/* Fill out lc and rc bitmaps (remember to map all fillers to each other!!) */
filler =
(s3cipid_t *) ckd_calloc(bin_mdef_n_ciphone(mdef) + 1,
sizeof(s3cipid_t));
/* Connect fillers */
i = 0;
for (ci = 0; ci < bin_mdef_n_ciphone(mdef); ci++) {
p = pid2phmm[ci];
bitvec_set_all(p->lc, bin_mdef_n_ciphone(mdef));
bitvec_set_all(p->rc, bin_mdef_n_ciphone(mdef));
if (mdef->phone[ci].info.ci.filler) {
filler[i++] = ci;
}
}
filler[i] = BAD_S3CIPID;
/* Loop over cdphones only if ci_only is not set */
for (pid = bin_mdef_n_ciphone(mdef); pid < nphone;
pid++) {
p = pid2phmm[pid];
if (mdef->phone[mdef->phone[pid].info.cd.ctx[1]].info.ci.filler) {
for (i = 0; IS_S3CIPID(filler[i]); i++)
bitvec_set(p->lc, filler[i]);
}
else
bitvec_set(p->lc, mdef->phone[pid].info.cd.ctx[1]);
if (mdef->phone[mdef->phone[pid].info.cd.ctx[2]].info.ci.filler) {
for (i = 0; IS_S3CIPID(filler[i]); i++)
bitvec_set(p->rc, filler[i]);
}
else
bitvec_set(p->rc, mdef->phone[pid].info.cd.ctx[2]);
}
ckd_free(pid2phmm);
ckd_free(filler);
/* Create links between PHMM nodes */
n_link = phmm_link(allphs);
E_INFO("%d nodes, %d links\n", n_phmm, n_link);
return 0;
}
static void
phmm_free(allphone_search_t * allphs)
{
s3cipid_t ci;
bin_mdef_t *mdef;
if (!allphs->ci_phmm)
//nothing to free
return;
ckd_free(allphs->ci_phmm[0]->lc);
mdef = ((ps_search_t *) allphs)->acmod->mdef;
for (ci = 0; ci < mdef_n_ciphone(mdef); ++ci) {
phmm_t *p, *next;
for (p = allphs->ci_phmm[ci]; p; p = next) {
plink_t *l, *lnext;
next = p->next;
for (l = p->succlist; l; l = lnext) {
lnext = l->next;
ckd_free(l);
}
hmm_deinit(&(p->hmm));
ckd_free(p);
}
}
ckd_free(allphs->ci_phmm);
}
/** Evaluate active PHMMs */
static int32
phmm_eval_all(allphone_search_t * allphs, const int16 * senscr)
{
s3cipid_t ci;
phmm_t *p;
int32 best;
bin_mdef_t *mdef;
phmm_t **ci_phmm;
mdef = ((ps_search_t *) allphs)->acmod->mdef;
ci_phmm = allphs->ci_phmm;
best = WORST_SCORE;
hmm_context_set_senscore(allphs->hmmctx, senscr);
for (ci = 0; ci < mdef->n_ciphone; ci++) {
for (p = ci_phmm[(unsigned) ci]; p; p = p->next) {
if (hmm_frame(&(p->hmm)) == allphs->frame) {
int32 score;
allphs->n_hmm_eval++;
score = hmm_vit_eval((hmm_t *) p);
if (score > best)
best = score;
}
}
}
return best;
}
static void
phmm_exit(allphone_search_t * allphs, int32 best)
{
s3cipid_t ci;
phmm_t *p;
int32 th, nf;
history_t *h;
blkarray_list_t *history;
bin_mdef_t *mdef;
int32 curfrm;
phmm_t **ci_phmm;
int32 *ci2lmwid;
th = best + allphs->pbeam;
history = allphs->history;
mdef = ps_search_acmod(allphs)->mdef;
curfrm = allphs->frame;
ci_phmm = allphs->ci_phmm;
ci2lmwid = allphs->ci2lmwid;
nf = curfrm + 1;
for (ci = 0; ci < mdef->n_ciphone; ci++) {
for (p = ci_phmm[(unsigned) ci]; p; p = p->next) {
if (hmm_frame(&(p->hmm)) == curfrm) {
if (hmm_bestscore(&(p->hmm)) >= th) {
h = (history_t *) ckd_calloc(1, sizeof(*h));
h->ef = curfrm;
h->phmm = p;
h->hist = hmm_out_history(&(p->hmm));
h->score = hmm_out_score(&(p->hmm));
if (!allphs->lm) {
h->tscore = allphs->inspen;
}
else {
if (h->hist > 0) {
int32 n_used;
history_t *pred =
blkarray_list_get(history, h->hist);
if (pred->hist > 0) {
history_t *pred_pred =
blkarray_list_get(history,
h->hist);
h->tscore =
ngram_tg_score(allphs->lm,
ci2lmwid
[pred_pred->phmm->ci],
ci2lmwid[pred->
phmm->ci],
ci2lmwid[p->ci],
&n_used) >>
SENSCR_SHIFT;
}
else {
h->tscore =
ngram_bg_score(allphs->lm,
ci2lmwid
[pred->phmm->ci],
ci2lmwid[p->ci],
&n_used) >>
SENSCR_SHIFT;
}
}
else {
/*
* This is the beginning SIL and in srch_allphone_begin()
* it's inscore is set to 0.
*/
h->tscore = 0;
}
}
blkarray_list_append(history, h);
/* Mark PHMM active in next frame */
hmm_frame(&(p->hmm)) = nf;
}
else {
/* Reset state scores */
hmm_clear(&(p->hmm));
}
}
}
}
}
static void
phmm_trans(allphone_search_t * allphs, int32 best,
int32 frame_history_start)
{
history_t *h;
phmm_t *from, *to;
plink_t *l;
int32 newscore, nf, curfrm;
int32 *ci2lmwid;
int32 hist_idx;
curfrm = allphs->frame;
nf = curfrm + 1;
ci2lmwid = allphs->ci2lmwid;
/* Transition from exited nodes to initial states of HMMs */
for (hist_idx = frame_history_start;
hist_idx < blkarray_list_n_valid(allphs->history); hist_idx++) {
h = blkarray_list_get(allphs->history, hist_idx);
from = h->phmm;
for (l = from->succlist; l; l = l->next) {
int32 tscore;
to = l->phmm;
/* No LM, just use uniform (insertion penalty). */
if (!allphs->lm)
tscore = allphs->inspen;
/* If they are not in the LM, kill this
* transition. */
else if (ci2lmwid[to->ci] == NGRAM_INVALID_WID)
continue;
else {
int32 n_used;
if (h->hist > 0) {
history_t *pred =
blkarray_list_get(allphs->history, h->hist);
tscore =
ngram_tg_score(allphs->lm,
ci2lmwid[pred->phmm->ci],
ci2lmwid[from->ci],
ci2lmwid[to->ci],
&n_used) >> SENSCR_SHIFT;
}
else {
tscore = ngram_bg_score(allphs->lm,
ci2lmwid[from->ci],
ci2lmwid[to->ci],
&n_used) >> SENSCR_SHIFT;
}
}
newscore = h->score + tscore;
if ((newscore > best + allphs->beam)
&& (newscore > hmm_in_score(&(to->hmm)))) {
hmm_enter(&(to->hmm), newscore, hist_idx, nf);
}
}
}
}
ps_search_t *
allphone_search_init(ngram_model_t * lm,
cmd_ln_t * config,
acmod_t * acmod, dict_t * dict, dict2pid_t * d2p)
{
int i;
bin_mdef_t *mdef;
allphone_search_t *allphs;
static char *lmname = "default";
allphs = (allphone_search_t *) ckd_calloc(1, sizeof(*allphs));
ps_search_init(ps_search_base(allphs), &allphone_funcs, config, acmod,
dict, d2p);
mdef = acmod->mdef;
allphs->hmmctx = hmm_context_init(bin_mdef_n_emit_state(mdef),
acmod->tmat->tp, NULL, mdef->sseq);
if (allphs->hmmctx == NULL) {
ps_search_free(ps_search_base(allphs));
return NULL;
}
allphs->ci_only = cmd_ln_boolean_r(config, "-allphone_ci");
allphs->lw = cmd_ln_float32_r(config, "-lw");
phmm_build(allphs);
if (lm) {
//language model is defined
allphs->lm = ngram_model_set_init(config, &lm, &lmname, NULL, 1);
if (!allphs->lm) {
E_ERROR
("Failed to initialize ngram model set for phoneme decoding");
allphone_search_free((ps_search_t *) allphs);
return NULL;
}
allphs->ci2lmwid =
(int32 *) ckd_calloc(mdef->n_ciphone,
sizeof(*allphs->ci2lmwid));
for (i = 0; i < mdef->n_ciphone; i++) {
allphs->ci2lmwid[i] =
ngram_wid(allphs->lm,
(char *) bin_mdef_ciphone_str(mdef, i));
/* Map filler phones to silence if not found */
if (allphs->ci2lmwid[i] == NGRAM_INVALID_WID
&& bin_mdef_ciphone_str(mdef, i))
allphs->ci2lmwid[i] =
ngram_wid(allphs->lm,
(char *) bin_mdef_ciphone_str(mdef,
mdef_silphone
(mdef)));
}
}
else {
E_WARN
("Failed to load language model specified in -allphone, doing unconstrained phone-loop decoding\n");
allphs->inspen =
(int32) (logmath_log
(acmod->lmath, cmd_ln_float32_r(config, "-pip"))
* allphs->lw) >> SENSCR_SHIFT;
}
allphs->n_tot_frame = 0;
allphs->frame = -1;
allphs->segments = NULL;
/* Get search pruning parameters */
allphs->beam
=
(int32) logmath_log(acmod->lmath,
cmd_ln_float64_r(config, "-beam"))
>> SENSCR_SHIFT;
allphs->pbeam
=
(int32) logmath_log(acmod->lmath,
cmd_ln_float64_r(config, "-pbeam"))
>> SENSCR_SHIFT;
/* LM related weights/penalties */
allphs->history = blkarray_list_init();
/* Acoustic score scale for posterior probabilities. */
allphs->ascale = 1.0 / cmd_ln_float32_r(config, "-ascale");
E_INFO("Allphone(beam: %d, pbeam: %d)\n", allphs->beam, allphs->pbeam);
ptmr_init(&allphs->perf);
return (ps_search_t *) allphs;
}
int
allphone_search_reinit(ps_search_t * search, dict_t * dict,
dict2pid_t * d2p)
{
allphone_search_t *allphs = (allphone_search_t *) search;
/* Free old dict2pid, dict */
ps_search_base_reinit(search, dict, d2p);
if (!allphs->lm) {
E_WARN
("-lm argument missing; doing unconstrained phone-loop decoding\n");
allphs->inspen =
(int32) (logmath_log
(search->acmod->lmath,
cmd_ln_float32_r(search->config,
"-pip")) *
allphs->lw) >> SENSCR_SHIFT;
}
return 0;
}
void
allphone_search_free(ps_search_t * search)
{
allphone_search_t *allphs = (allphone_search_t *) search;
double n_speech = (double)allphs->n_tot_frame
/ cmd_ln_int32_r(ps_search_config(allphs), "-frate");
E_INFO("TOTAL fwdflat %.2f CPU %.3f xRT\n",
allphs->perf.t_tot_cpu,
allphs->perf.t_tot_cpu / n_speech);
E_INFO("TOTAL fwdflat %.2f wall %.3f xRT\n",
allphs->perf.t_tot_elapsed,
allphs->perf.t_tot_elapsed / n_speech);
ps_search_deinit(search);
hmm_context_free(allphs->hmmctx);
phmm_free(allphs);
if (allphs->lm)
ngram_model_free(allphs->lm);
if (allphs->ci2lmwid)
ckd_free(allphs->ci2lmwid);
blkarray_list_free(allphs->history);
ckd_free(allphs);
}
int
allphone_search_start(ps_search_t * search)
{
allphone_search_t *allphs;
bin_mdef_t *mdef;
s3cipid_t ci;
phmm_t *p;
allphs = (allphone_search_t *) search;
mdef = search->acmod->mdef;
/* Reset all HMMs. */
for (ci = 0; ci < bin_mdef_n_ciphone(mdef); ci++) {
for (p = allphs->ci_phmm[(unsigned) ci]; p; p = p->next) {
hmm_clear(&(p->hmm));
}
}
allphs->n_hmm_eval = 0;
allphs->n_sen_eval = 0;
/* Free history nodes, if any */
blkarray_list_reset(allphs->history);
/* Initialize start state of the SILENCE PHMM */
allphs->frame = 0;
ci = bin_mdef_silphone(mdef);
if (NOT_S3CIPID(ci))
E_FATAL("Cannot find CI-phone %s\n", S3_SILENCE_CIPHONE);
for (p = allphs->ci_phmm[ci]; p && (p->pid != ci); p = p->next);
if (!p)
E_FATAL("Cannot find HMM for %s\n", S3_SILENCE_CIPHONE);
hmm_enter(&(p->hmm), 0, 0, allphs->frame);
ptmr_reset(&allphs->perf);
ptmr_start(&allphs->perf);
return 0;
}
static void
allphone_search_sen_active(allphone_search_t * allphs)
{
acmod_t *acmod;
bin_mdef_t *mdef;
phmm_t *p;
int32 ci;
acmod = ps_search_acmod(allphs);
mdef = acmod->mdef;
acmod_clear_active(acmod);
for (ci = 0; ci < bin_mdef_n_ciphone(mdef); ci++)
for (p = allphs->ci_phmm[ci]; p; p = p->next)
if (hmm_frame(&(p->hmm)) == allphs->frame)
acmod_activate_hmm(acmod, &(p->hmm));
}
int
allphone_search_step(ps_search_t * search, int frame_idx)
{
int32 bestscr, frame_history_start;
const int16 *senscr;
allphone_search_t *allphs = (allphone_search_t *) search;
acmod_t *acmod = search->acmod;
if (!acmod->compallsen)
allphone_search_sen_active(allphs);
senscr = acmod_score(acmod, &frame_idx);
allphs->n_sen_eval += acmod->n_senone_active;
bestscr = phmm_eval_all(allphs, senscr);
frame_history_start = blkarray_list_n_valid(allphs->history);
phmm_exit(allphs, bestscr);
phmm_trans(allphs, bestscr, frame_history_start);
allphs->frame++;
return 0;
}
static int32
ascore(allphone_search_t * allphs, history_t * h)
{
int32 score = h->score;
if (h->hist > 0) {
history_t *pred = blkarray_list_get(allphs->history, h->hist);
score -= pred->score;
}
return score - h->tscore;
}
static void
allphone_clear_segments(allphone_search_t * allphs)
{
gnode_t *gn;
for (gn = allphs->segments; gn; gn = gn->next) {
ckd_free(gnode_ptr(gn));
}
glist_free(allphs->segments);
allphs->segments = NULL;
}
static void
allphone_backtrace(allphone_search_t * allphs, int32 f)
{
int32 best, hist_idx, best_idx;
int32 frm, last_frm;
history_t *h;
phseg_t *s;
/* Clear old list */
allphone_clear_segments(allphs);
frm = last_frm = f;
/* Find the first history entry for the requested frame */
hist_idx = blkarray_list_n_valid(allphs->history) - 1;
while (hist_idx > 0) {
h = blkarray_list_get(allphs->history, hist_idx);
if (h->ef <= f) {
frm = last_frm = h->ef;
break;
}
hist_idx--;
}
if (hist_idx < 0)
return;
/* Find bestscore */
best = (int32) 0x80000000;
best_idx = -1;
while (frm == last_frm && hist_idx > 0) {
h = blkarray_list_get(allphs->history, hist_idx);
frm = h->ef;
if (h->score > best && frm == last_frm) {
best = h->score;
best_idx = hist_idx;
}
hist_idx--;
}
if (best_idx < 0)
return;
/* Backtrace */
while (best_idx > 0) {
h = blkarray_list_get(allphs->history, best_idx);
s = (phseg_t *) ckd_calloc(1, sizeof(phseg_t));
s->ci = h->phmm->ci;
s->sf =
(h->hist >
0) ? ((history_t *) blkarray_list_get(allphs->history,
h->hist))->ef + 1 : 0;
s->ef = h->ef;
s->score = ascore(allphs, h);
s->tscore = h->tscore;
allphs->segments = glist_add_ptr(allphs->segments, s);
best_idx = h->hist;
}
return;
}
int
allphone_search_finish(ps_search_t * search)
{
allphone_search_t *allphs;
int32 cf, n_hist;
allphs = (allphone_search_t *) search;
allphs->n_tot_frame += allphs->frame;
n_hist = blkarray_list_n_valid(allphs->history);
E_INFO
("%d frames, %d HMMs (%d/fr), %d senones (%d/fr), %d history entries (%d/fr)\n",
allphs->frame, allphs->n_hmm_eval,
(allphs->frame > 0) ? allphs->n_hmm_eval / allphs->frame : 0,
allphs->n_sen_eval,
(allphs->frame > 0) ? allphs->n_sen_eval / allphs->frame : 0,
n_hist, (allphs->frame > 0) ? n_hist / allphs->frame : 0);
/* Now backtrace. */
allphone_backtrace(allphs, allphs->frame - 1);
/* Print out some statistics. */
ptmr_stop(&allphs->perf);
/* This is the number of frames processed. */
cf = ps_search_acmod(allphs)->output_frame;
if (cf > 0) {
double n_speech = (double) (cf + 1)
/ cmd_ln_int32_r(ps_search_config(allphs), "-frate");
E_INFO("allphone %.2f CPU %.3f xRT\n",
allphs->perf.t_cpu, allphs->perf.t_cpu / n_speech);
E_INFO("allphone %.2f wall %.3f xRT\n",
allphs->perf.t_elapsed, allphs->perf.t_elapsed / n_speech);
}
return 0;
}
char const *
allphone_search_hyp(ps_search_t * search, int32 * out_score,
int32 * out_is_final)
{
allphone_search_t *allphs;
phseg_t *p;
gnode_t *gn;
const char *phone_str;
bin_mdef_t *mdef;
int len, hyp_idx, phone_idx;
allphs = (allphone_search_t *) search;
mdef = search->acmod->mdef;
/* Create hypothesis */
if (search->hyp_str)
ckd_free(search->hyp_str);
search->hyp_str = NULL;
allphone_backtrace(allphs, allphs->frame - 1);
if (allphs->segments == NULL) {
return NULL;
}
len = glist_count(allphs->segments) * 10; // maximum length of one phone with spacebar
search->hyp_str = (char *) ckd_calloc(len, sizeof(*search->hyp_str));
hyp_idx = 0;
for (gn = allphs->segments; gn; gn = gn->next) {
p = gnode_ptr(gn);
phone_str = bin_mdef_ciphone_str(mdef, p->ci);
phone_idx = 0;
while (phone_str[phone_idx] != '\0')
search->hyp_str[hyp_idx++] = phone_str[phone_idx++];
search->hyp_str[hyp_idx++] = ' ';
}
search->hyp_str[--hyp_idx] = '\0';
E_INFO("Hyp: %s\n", search->hyp_str);
return search->hyp_str;
}