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