1 /**
2  * @file   outprob.c
3  *
4  * <JA>
5  * @brief  �������ٷ׻��μ¹Ԥ���Ӿ��֥�٥륭��å���
6  *
7  * %HMM �ξ��֤ν��ϳ�Ψ���п����١ˤ�׻����ޤ������֤η���ñ����ü��
8  * pseudo %HMM set ���ɤ����ˤˤ������äƤ����Ĥ��������Ƥ��ޤ�����
9  * ���Ʋ��̤� outprob_state() ��ƤӤޤ���outprob_state() ��
10  * ɬ�פʾ���� OP_ �ǻϤޤ�����ѿ��˳�Ǽ����calc_outprob_state() ��Ƥ�
11  * �Ф��ޤ���calc_outprob_state() �ϴؿ��Υݥ����Ǥ��ꡤ���Τ� tied-mixture
12  * ��ǥ�ξ�� calc_tied_mix(), ����ʳ��ξ��� calc_mix() �Ȥʤ�ޤ���
13  * ��GMS ����Ѥ������ gms_state()�ˤˤʤ�ޤ���
14  *
15  * ���֥�٥�β������٥���å��夬�Ԥʤ��ޤ�������å���� ���� x
16  * ���ϥե졼��dz�Ǽ���졤ɬ�פ�Ĺ���ˤ������äƿ�Ĺ����ޤ������Υ���å����
17  * ��2�ѥ��η׻��Ǥ��Ѥ��뤿�ᡤ�����֤��ϤäƵ�Ͽ����Ƥ��ޤ���
18  *
19  * �ʤ� tied-mixture �ξ��ϥ����ɥ֥å���٥�ǤΥ���å����Ʊ����
20  * �Ԥʤ��ޤ�������ˤĤ��Ƥ� calc_tied_mix.c ������������
21  * </JA>
22  *
23  * <EN>
24  * @brief  Computation of acoustic likelihood in %HMM state, with state-level cache
25  *
26  * This file defines functions to compute output log probability of
27  * %HMM state.  Several functions are defined for each state type (whether
28  * it is on word edge and a part of pseudo HMM), and all of them calls
29  * outprob_state() to get the log probability of a %HMM state.  The
30  * outprob_state() will set the needed values to the global variables
31  * that begins with "OP_", and call calc_outprob_state().  The
32  * calc_outprob_state() is actually a function pointer, and the entity is
33  * either calc_tied_mix() for tied-mixture model and calc_mix() for others.
34  * (If you use GMS, the entity will be gms_state() instead.)
35  *
36  * The state scores will be cached here.
37  * The 2-dimension cache array of state and
38  * input frame are used to store the computed scores.  They will be expanded
39  * when needed.  Thus the scores will be cached for all input frame because
40  * they will also be used in the 2nd pass of recognition process.
41  *
42  * When using a tied-mixture model, codebook-level cache will be also done
43  * in addition to this state-level cache.  See calc_tied_mix.c for details.
44  * </EN>
45  *
46  * @author Akinobu LEE
47  * @date   Fri Feb 18 18:45:21 2005
48  *
49  * $Revision: 1.3 $
50  *
51  */
52 /*
53  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
54  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
55  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
56  * All rights reserved
57  */
58 
59 #include <sent/stddefs.h>
60 #include <sent/speech.h>
61 #include <sent/htk_hmm.h>
62 #include <sent/htk_param.h>
63 #include <sent/hmm.h>
64 #include <sent/hmm_calc.h>
65 
66 
67 
68 #define LOG_UNDEF (LOG_ZERO - 1) ///< Value to be used as the initial cache value
69 
70 /**
71  * Initialize the cache data, should be called once on startup.
72  *
73  * @param wrk [i/o] HMM computation work area
74  *
75  * @return TRUE on success, FALSE on failure.
76  */
77 boolean
outprob_cache_init(HMMWork * wrk)78 outprob_cache_init(HMMWork *wrk)
79 {
80   wrk->statenum = wrk->OP_hmminfo->totalstatenum;
81   wrk->outprob_cache = NULL;
82   wrk->outprob_allocframenum = 0;
83   wrk->OP_time = -1;
84   wrk->croot = NULL;
85   return TRUE;
86 }
87 
88 /**
89  * Prepare cache for the next input, by clearing the existing cache.
90  *
91  * @param wrk [i/o] HMM computation work area
92  *
93  * @return TRUE on success, FALSE on failure.
94  */
95 boolean
outprob_cache_prepare(HMMWork * wrk)96 outprob_cache_prepare(HMMWork *wrk)
97 {
98   int s,t;
99 
100   /* clear already allocated area */
101   for (t = 0; t < wrk->outprob_allocframenum; t++) {
102     for (s = 0; s < wrk->statenum; s++) {
103       wrk->outprob_cache[t][s] = LOG_UNDEF;
104     }
105   }
106 
107   return TRUE;
108 }
109 
110 /**
111  * Expand the cache to time axis if needed.
112  *
113  * @param wrk [i/o] HMM computation work area
114  * @param reqframe [in] required frame length
115  */
116 static void
outprob_cache_extend(HMMWork * wrk,int reqframe)117 outprob_cache_extend(HMMWork *wrk, int reqframe)
118 {
119   int newnum;
120   int size;
121   int t, s;
122   LOGPROB *tmpp;
123 
124   /* if enough length are already allocated, return immediately */
125   if (reqframe < wrk->outprob_allocframenum) return;
126 
127   /* allocate per certain period */
128   newnum = reqframe + 1;
129   if (newnum < wrk->outprob_allocframenum + OUTPROB_CACHE_PERIOD) newnum = wrk->outprob_allocframenum + OUTPROB_CACHE_PERIOD;
130   size = (newnum - wrk->outprob_allocframenum) * wrk->statenum;
131 
132   /* allocate */
133   if (wrk->outprob_cache == NULL) {
134     wrk->outprob_cache = (LOGPROB **)mymalloc(sizeof(LOGPROB *) * newnum);
135   } else {
136     wrk->outprob_cache = (LOGPROB **)myrealloc(wrk->outprob_cache, sizeof(LOGPROB *) * newnum);
137   }
138   tmpp = (LOGPROB *)mybmalloc2(sizeof(LOGPROB) * size, &(wrk->croot));
139   /* clear the new part */
140   for(t = wrk->outprob_allocframenum; t < newnum; t++) {
141     wrk->outprob_cache[t] = &(tmpp[(t - wrk->outprob_allocframenum) * wrk->statenum]);
142     for (s = 0; s < wrk->statenum; s++) {
143       wrk->outprob_cache[t][s] = LOG_UNDEF;
144     }
145   }
146 
147   /*jlog("outprob cache: %d->%d\n", outprob_allocframenum, newnum);*/
148   wrk->outprob_allocframenum = newnum;
149 }
150 
151 /**
152  * Free work area for cache.
153  *
154  * @param wrk [i/o] HMM computation work area
155  *
156  */
157 void
outprob_cache_free(HMMWork * wrk)158 outprob_cache_free(HMMWork *wrk)
159 {
160   if (wrk->croot != NULL) mybfree2(&(wrk->croot));
161   if (wrk->outprob_cache != NULL) free(wrk->outprob_cache);
162 }
163 
164 
165 /**
166  * @brief  Compute output probability of a state.
167  *
168  * Set the needed values to the global variables
169  * that begins with "OP_", and call calc_outprob_state().  The
170  * calc_outprob_state() is actually a function pointer, and the entity is
171  * either calc_tied_mix() for tied-mixture model and calc_mix() for others.
172  * (If you use GMS, the entity will be gms_state() instead.)
173  *
174  * The state-level cache is also consulted here.
175  *
176  * @param wrk [i/o] HMM computation work area
177  * @param t [in] time frame
178  * @param stateinfo [in] state information to compute the output probability
179  * @param param [in] input parameter vectors
180  *
181  * @return output log probability.
182  */
183 LOGPROB
outprob_state(HMMWork * wrk,int t,HTK_HMM_State * stateinfo,HTK_Param * param)184 outprob_state(HMMWork *wrk, int t, HTK_HMM_State *stateinfo, HTK_Param *param)
185 {
186   LOGPROB outp;
187   int sid;
188   int i, d;
189 
190   sid = stateinfo->id;
191 
192   /* set global values for outprob functions to access them */
193   wrk->OP_state = stateinfo;
194   wrk->OP_state_id = sid;
195   wrk->OP_param = param;
196   if (wrk->OP_time != t) {
197     wrk->OP_last_time = wrk->OP_time;
198     wrk->OP_time = t;
199     for(d=0,i=0;i<wrk->OP_nstream;i++) {
200       wrk->OP_vec_stream[i] = &(param->parvec[t][d]);
201       d += wrk->OP_veclen_stream[i];
202     }
203 
204     outprob_cache_extend(wrk, t);	/* extend cache if needed */
205     wrk->last_cache = wrk->outprob_cache[t]; /* reduce 2-d array access */
206   }
207 
208   /* consult cache */
209   if ((outp = wrk->last_cache[sid]) == LOG_UNDEF) {
210     outp = wrk->last_cache[sid] = (*(wrk->calc_outprob_state))(wrk);
211   }
212   return(outp);
213 }
214 
215 /**
216  * Initialize work area for outprob_cd_nbest().
217  *
218  * @param wrk [i/o] HMM computation work area
219  * @param num [in] number of top states to be calculated.
220  */
221 void
outprob_cd_nbest_init(HMMWork * wrk,int num)222 outprob_cd_nbest_init(HMMWork *wrk, int num)
223 {
224   wrk->cd_nbest_maxprobs = (LOGPROB *)mymalloc(sizeof(LOGPROB) * num);
225   wrk->cd_nbest_maxn = num;
226 }
227 
228 /**
229  * Free work area for outprob_cd_nbest().
230  *
231  * @param wrk [i/o] HMM computation work area
232  *
233  */
234 void
outprob_cd_nbest_free(HMMWork * wrk)235 outprob_cd_nbest_free(HMMWork *wrk)
236 {
237   free(wrk->cd_nbest_maxprobs);
238 }
239 
240 /**
241  * Return average of N-beat outprob for pseudo state set.
242  *
243  * @param wrk [i/o] HMM computation work area
244  * @param t [in] input frame
245  * @param lset [in] pseudo state set
246  * @param param [in] input parameter data
247  *
248  * @return outprob log probability, average of top N states in @a lset.
249  */
250 static LOGPROB
outprob_cd_nbest(HMMWork * wrk,int t,CD_State_Set * lset,HTK_Param * param)251 outprob_cd_nbest(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
252 {
253   LOGPROB prob;
254   int i, k, n;
255 
256   n = 0;
257   for(i=0;i<lset->num;i++) {
258     prob = outprob_state(wrk, t, lset->s[i], param);
259     /*jlog("\t\t%d:%f\n", i, prob);*/
260     if (prob <= LOG_ZERO) continue;
261     if (n == 0 || prob <= wrk->cd_nbest_maxprobs[n-1]) {
262       if (n == wrk->cd_nbest_maxn) continue;
263       wrk->cd_nbest_maxprobs[n] = prob;
264       n++;
265     } else {
266       for(k=0; k<n; k++) {
267 	if (prob > wrk->cd_nbest_maxprobs[k]) {
268 	  memmove(&(wrk->cd_nbest_maxprobs[k+1]), &(wrk->cd_nbest_maxprobs[k]),
269 		  sizeof(LOGPROB) * (n - k - ( (n == wrk->cd_nbest_maxn) ? 1 : 0)));
270 	  wrk->cd_nbest_maxprobs[k] = prob;
271 	  break;
272 	}
273       }
274       if (n < wrk->cd_nbest_maxn) n++;
275     }
276   }
277   prob = 0.0;
278   for(i=0;i<n;i++) {
279     /*jlog("\t\t\t- %d: %f\n", i, wrk->cd_nbest_maxprobs[i]);*/
280     prob += wrk->cd_nbest_maxprobs[i];
281   }
282   return(prob/(float)n);
283 }
284 
285 /**
286  * Return maximum outprob of the pseudo state set.
287  *
288  * @param wrk [i/o] HMM computation work area
289  * @param t [in] input frame
290  * @param lset [in] pseudo state set
291  * @param param [in] input parameter data
292  *
293  * @return maximum output log probability among states in @a lset.
294  */
295 static LOGPROB
outprob_cd_max(HMMWork * wrk,int t,CD_State_Set * lset,HTK_Param * param)296 outprob_cd_max(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
297 {
298   LOGPROB maxprob, prob;
299   int i;
300 
301   maxprob = LOG_ZERO;
302   for(i=0;i<lset->num;i++) {
303     prob = outprob_state(wrk, t, lset->s[i], param);
304     if (maxprob < prob) maxprob = prob;
305   }
306   return(maxprob);
307 }
308 
309 /**
310  * Return average outprob of the pseudo state set.
311  *
312  * @param wrk [i/o] HMM computation work area
313  * @param t [in] input frame
314  * @param lset [in] pseudo state set
315  * @param param [in] input parameter data
316  *
317  * @return average output log probability of states in @a lset.
318  */
319 static LOGPROB
outprob_cd_avg(HMMWork * wrk,int t,CD_State_Set * lset,HTK_Param * param)320 outprob_cd_avg(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
321 {
322   LOGPROB sum, p;
323   int i,j;
324   sum = 0.0;
325   j = 0;
326   for(i=0;i<lset->num;i++) {
327     p = outprob_state(wrk, t, lset->s[i], param);
328     if (p > LOG_ZERO) {
329       sum += p;
330       j++;
331     }
332   }
333   return(sum/(float)j);
334 }
335 
336 /**
337  * Compute the log output probability of a pseudo state set.
338  *
339  * @param wrk [i/o] HMM computation work area
340  * @param t [in] input frame
341  * @param lset [in] pseudo state set
342  * @param param [in] input parameter data
343  *
344  * @return the computed log output probability.
345  */
346 LOGPROB
outprob_cd(HMMWork * wrk,int t,CD_State_Set * lset,HTK_Param * param)347 outprob_cd(HMMWork *wrk, int t, CD_State_Set *lset, HTK_Param *param)
348 {
349   LOGPROB ret;
350 
351   /* select computation method */
352   switch(wrk->OP_hmminfo->cdset_method) {
353   case IWCD_AVG:
354     ret = outprob_cd_avg(wrk, t, lset, param);
355     break;
356   case IWCD_MAX:
357     ret = outprob_cd_max(wrk, t, lset, param);
358     break;
359   case IWCD_NBEST:
360     ret = outprob_cd_nbest(wrk, t, lset, param);
361     break;
362   }
363   return(ret);
364 }
365 
366 
367 /**
368  * Top function to compute the output probability of a HMM state.
369  *
370  * @param wrk [i/o] HMM computation work area
371  * @param t [in] input frame
372  * @param hmmstate [in] HMM state
373  * @param param [in] input parameter data
374  *
375  * @return the computed log output probability.
376  */
377 LOGPROB
outprob(HMMWork * wrk,int t,HMM_STATE * hmmstate,HTK_Param * param)378 outprob(HMMWork *wrk, int t, HMM_STATE *hmmstate, HTK_Param *param)
379 {
380   if (hmmstate->is_pseudo_state) {
381     return(outprob_cd(wrk, t, hmmstate->out.cdset, param));
382   } else {
383     return(outprob_state(wrk, t, hmmstate->out.state, param));
384   }
385 }
386