/**
* @file outprob.c
*
*
* @brief 音響尤度計算の実行および状態レベルキャッシュ
*
* %HMM の状態の出力確率(対数尤度)を計算します.状態の型(単語末端の
* pseudo %HMM set かどうか)にしたがっていくつか定義されていますが,
* 全て下位の outprob_state() を呼びます.outprob_state() は
* 必要な情報を OP_ で始まる大域変数に格納し,calc_outprob_state() を呼び
* 出します.calc_outprob_state() は関数のポインタであり,実体は tied-mixture
* モデルの場合 calc_tied_mix(), それ以外の場合は calc_mix() となります.
* (GMS を使用する場合は gms_state())になります.
*
* 状態レベルの音響尤度キャッシュが行なわれます.キャッシュは 状態 x
* 入力フレームで格納され,必要な長さにしたがって伸長されます.このキャッシュは
* 第2パスの計算でも用いるため,全時間に渡って記録されています.
*
* なお tied-mixture の場合はコードブックレベルでのキャッシュも同時に
* 行なわれます.これについては calc_tied_mix.c をご覧下さい.
*
*
*
* @brief Computation of acoustic likelihood in %HMM state, with state-level cache
*
* This file defines functions to compute output log probability of
* %HMM state. Several functions are defined for each state type (whether
* it is on word edge and a part of pseudo HMM), and all of them calls
* outprob_state() to get the log probability of a %HMM state. The
* outprob_state() will set the needed values to the global variables
* that begins with "OP_", and call calc_outprob_state(). The
* calc_outprob_state() is actually a function pointer, and the entity is
* either calc_tied_mix() for tied-mixture model and calc_mix() for others.
* (If you use GMS, the entity will be gms_state() instead.)
*
* The state scores will be cached here.
* The 2-dimension cache array of state and
* input frame are used to store the computed scores. They will be expanded
* when needed. Thus the scores will be cached for all input frame because
* they will also be used in the 2nd pass of recognition process.
*
* When using a tied-mixture model, codebook-level cache will be also done
* in addition to this state-level cache. See calc_tied_mix.c for details.
*
*
* @author Akinobu LEE
* @date Fri Feb 18 18:45:21 2005
*
* $Revision: 1.5 $
*
*/
/*
* Copyright (c) 1991-2012 Kawahara Lab., Kyoto University
* Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
* Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology
* All rights reserved
*/
#include
#include
#include
#include
#include
#include
#define LOG_UNDEF (LOG_ZERO - 1) ///< Value to be used as the initial cache value
/**
* Initialize the cache data, should be called once on startup.
*
* @param wrk [i/o] HMM computation work area
*
* @return TRUE on success, FALSE on failure.
*/
boolean
outprob_cache_init(HMMWork *wrk)
{
wrk->statenum = wrk->OP_hmminfo->totalstatenum;
wrk->outprob_cache = NULL;
wrk->outprob_allocframenum = 0;
wrk->OP_time = -1;
wrk->croot = NULL;
return TRUE;
}
/**
* Prepare cache for the next input, by clearing the existing cache.
*
* @param wrk [i/o] HMM computation work area
*
* @return TRUE on success, FALSE on failure.
*/
boolean
outprob_cache_prepare(HMMWork *wrk)
{
int s,t;
/* clear already allocated area */
for (t = 0; t < wrk->outprob_allocframenum; t++) {
for (s = 0; s < wrk->statenum; s++) {
wrk->outprob_cache[t][s] = LOG_UNDEF;
}
}
return TRUE;
}
/**
* Expand the cache to time axis if needed.
*
* @param wrk [i/o] HMM computation work area
* @param reqframe [in] required frame length
*/
static void
outprob_cache_extend(HMMWork *wrk, int reqframe)
{
int newnum;
int size;
int t, s;
LOGPROB *tmpp;
/* if enough length are already allocated, return immediately */
if (reqframe < wrk->outprob_allocframenum) return;
/* allocate per certain period */
newnum = reqframe + 1;
if (newnum < wrk->outprob_allocframenum + OUTPROB_CACHE_PERIOD) newnum = wrk->outprob_allocframenum + OUTPROB_CACHE_PERIOD;
size = (newnum - wrk->outprob_allocframenum) * wrk->statenum;
/* allocate */
if (wrk->outprob_cache == NULL) {
wrk->outprob_cache = (LOGPROB **)mymalloc(sizeof(LOGPROB *) * newnum);
} else {
wrk->outprob_cache = (LOGPROB **)myrealloc(wrk->outprob_cache, sizeof(LOGPROB *) * newnum);
}
tmpp = (LOGPROB *)mybmalloc2(sizeof(LOGPROB) * size, &(wrk->croot));
/* clear the new part */
for(t = wrk->outprob_allocframenum; t < newnum; t++) {
wrk->outprob_cache[t] = &(tmpp[(t - wrk->outprob_allocframenum) * wrk->statenum]);
for (s = 0; s < wrk->statenum; s++) {
wrk->outprob_cache[t][s] = LOG_UNDEF;
}
}
/*jlog("outprob cache: %d->%d\n", outprob_allocframenum, newnum);*/
wrk->outprob_allocframenum = newnum;
}
/**
* Free work area for cache.
*
* @param wrk [i/o] HMM computation work area
*
*/
void
outprob_cache_free(HMMWork *wrk)
{
if (wrk->croot != NULL) mybfree2(&(wrk->croot));
if (wrk->outprob_cache != NULL) free(wrk->outprob_cache);
}
/**
* @brief Compute output probability of a state.
*
* Set the needed values to the global variables
* that begins with "OP_", and call calc_outprob_state(). The
* calc_outprob_state() is actually a function pointer, and the entity is
* either calc_tied_mix() for tied-mixture model and calc_mix() for others.
* (If you use GMS, the entity will be gms_state() instead.)
*
* The state-level cache is also consulted here.
*
* @param wrk [i/o] HMM computation work area
* @param t [in] time frame
* @param stateinfo [in] state information to compute the output probability
* @param param [in] input parameter vectors
*
* @return output log probability.
*/
LOGPROB
outprob_state(HMMWork *wrk, int t, HTK_HMM_State *stateinfo, HTK_Param *param)
{
LOGPROB outp;
int sid;
int i, d;
sid = stateinfo->id;
/* set global values for outprob functions to access them */
wrk->OP_state = stateinfo;
wrk->OP_state_id = sid;
wrk->OP_param = param;
if (wrk->OP_time != t) {
wrk->OP_last_time = wrk->OP_time;
wrk->OP_time = t;
for(d=0,i=0;iOP_nstream;i++) {
wrk->OP_vec_stream[i] = &(param->parvec[t][d]);
d += wrk->OP_veclen_stream[i];
}
outprob_cache_extend(wrk, t); /* extend cache if needed */
wrk->last_cache = wrk->outprob_cache[t]; /* reduce 2-d array access */
}
/* consult cache */
if ((outp = wrk->last_cache[sid]) == LOG_UNDEF) {
outp = wrk->last_cache[sid] = (*(wrk->calc_outprob_state))(wrk);
}
return(outp);
}
/**
* Initialize work area for outprob_cd_nbest().
*
* @param wrk [i/o] HMM computation work area
* @param num [in] number of top states to be calculated.
*/
void
outprob_cd_nbest_init(HMMWork *wrk, int num)
{
wrk->cd_nbest_maxprobs = (LOGPROB *)mymalloc(sizeof(LOGPROB) * num);
wrk->cd_nbest_maxn = num;
}
/**
* Free work area for outprob_cd_nbest().
*
* @param wrk [i/o] HMM computation work area
*
*/
void
outprob_cd_nbest_free(HMMWork *wrk)
{
free(wrk->cd_nbest_maxprobs);
}
/**
* Return average of N-beat outprob for pseudo state set.
*
* @param wrk [i/o] HMM computation work area
* @param t [in] input frame
* @param lset [in] pseudo state set
* @param param [in] input parameter data
*
* @return outprob log probability, average of top N states in @a lset.
*/
static LOGPROB
outprob_cd_nbest(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
{
LOGPROB prob;
int i, k, n;
n = 0;
for(i=0;inum;i++) {
prob = outprob_state(wrk, t, lset->s[i], param);
/*jlog("\t\t%d:%f\n", i, prob);*/
if (prob <= LOG_ZERO) continue;
if (n == 0 || prob <= wrk->cd_nbest_maxprobs[n-1]) {
if (n == wrk->cd_nbest_maxn) continue;
wrk->cd_nbest_maxprobs[n] = prob;
n++;
} else {
for(k=0; k wrk->cd_nbest_maxprobs[k]) {
memmove(&(wrk->cd_nbest_maxprobs[k+1]), &(wrk->cd_nbest_maxprobs[k]),
sizeof(LOGPROB) * (n - k - ( (n == wrk->cd_nbest_maxn) ? 1 : 0)));
wrk->cd_nbest_maxprobs[k] = prob;
break;
}
}
if (n < wrk->cd_nbest_maxn) n++;
}
}
prob = 0.0;
for(i=0;icd_nbest_maxprobs[i]);*/
prob += wrk->cd_nbest_maxprobs[i];
}
return(prob/(float)n);
}
/**
* Return maximum outprob of the pseudo state set.
*
* @param wrk [i/o] HMM computation work area
* @param t [in] input frame
* @param lset [in] pseudo state set
* @param param [in] input parameter data
*
* @return maximum output log probability among states in @a lset.
*/
static LOGPROB
outprob_cd_max(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
{
LOGPROB maxprob, prob;
int i;
maxprob = LOG_ZERO;
for(i=0;inum;i++) {
prob = outprob_state(wrk, t, lset->s[i], param);
if (maxprob < prob) maxprob = prob;
}
return(maxprob);
}
/**
* Return average outprob of the pseudo state set.
*
* @param wrk [i/o] HMM computation work area
* @param t [in] input frame
* @param lset [in] pseudo state set
* @param param [in] input parameter data
*
* @return average output log probability of states in @a lset.
*/
static LOGPROB
outprob_cd_avg(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
{
LOGPROB sum, p;
int i,j;
sum = 0.0;
j = 0;
for(i=0;inum;i++) {
p = outprob_state(wrk, t, lset->s[i], param);
if (p > LOG_ZERO) {
sum += p;
j++;
}
}
return(sum/(float)j);
}
/**
* Compute the log output probability of a pseudo state set.
*
* @param wrk [i/o] HMM computation work area
* @param t [in] input frame
* @param lset [in] pseudo state set
* @param param [in] input parameter data
*
* @return the computed log output probability.
*/
LOGPROB
outprob_cd(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
{
LOGPROB ret;
/* select computation method */
switch(wrk->OP_hmminfo->cdset_method) {
case IWCD_AVG:
ret = outprob_cd_avg(wrk, t, lset, param);
break;
case IWCD_MAX:
ret = outprob_cd_max(wrk, t, lset, param);
break;
case IWCD_NBEST:
ret = outprob_cd_nbest(wrk, t, lset, param);
break;
}
return(ret);
}
/**
* Top function to compute the output probability of a HMM state.
*
* @param wrk [i/o] HMM computation work area
* @param t [in] input frame
* @param hmmstate [in] HMM state
* @param param [in] input parameter data
*
* @return the computed log output probability.
*/
LOGPROB
outprob(HMMWork *wrk, int t, HMM_STATE *hmmstate, HTK_Param *param)
{
if (hmmstate->is_pseudo_state) {
return(outprob_cd(wrk, t, hmmstate->out.cdset, param));
} else {
return(outprob_state(wrk, t, hmmstate->out.state, param));
}
}