1 /**
2 * @file mkwhmm.c
3 *
4 * <JA>
5 * @brief ��������Ѥη��%HMM����������
6 * </JA>
7 *
8 * <EN>
9 * @brief Generate compound %HMM instance for recognition from phoneme sequence.
10 * </EN>
11 *
12 * @author Akinobu LEE
13 * @date Fri Feb 18 18:31:40 2005
14 *
15 * $Revision: 1.3 $
16 *
17 */
18 /*
19 * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
20 * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
21 * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
22 * All rights reserved
23 */
24
25 /* When not a multi-path mode, initial & accept arc will be stripped and
26 trans prob to accept state will be stored in accept_ac_a. */
27
28 #include <sent/stddefs.h>
29 #include <sent/hmm.h>
30
31 /**
32 * Calculate total number of states in a phoneme sequence.
33 *
34 * @param hdseq [in] phoneme sequence as given by pointer list of logical %HMM
35 * @param hdseqlen [in] length of above
36 * @param has_sp [in] indicates where short-pause insertion is possible
37 * @param hmminfo [in] HMM definition
38 *
39 * @return the total number of states in the sequence.
40 */
41 static int
totalstatelen(HMM_Logical ** hdseq,int hdseqlen,boolean * has_sp,HTK_HMM_INFO * hmminfo)42 totalstatelen(HMM_Logical **hdseq, int hdseqlen, boolean *has_sp, HTK_HMM_INFO *hmminfo)
43 {
44 int i, len;
45
46 len = 0;
47 for (i=0;i<hdseqlen;i++) {
48 len += hmm_logical_state_num(hdseq[i]) - 2;
49 if (has_sp) {
50 if (has_sp[i]) {
51 len += hmm_logical_state_num(hmminfo->sp) - 2;
52 }
53 }
54 }
55 if (hmminfo->multipath) {
56 /* add count for the initial and final state */
57 len += 2;
58 }
59 return(len);
60 }
61
62 /**
63 * Add a transition arc on the HMM state.
64 *
65 * @param state [out] HMM state to add the arc
66 * @param arc [in] state id of destination
67 * @param a [in] transition log probability
68 */
69 static void
add_arc(HMM_STATE * state,int arc,LOGPROB a)70 add_arc(HMM_STATE *state, int arc, LOGPROB a)
71 {
72 A_CELL *atmp;
73
74 atmp = (A_CELL *)mymalloc(sizeof(A_CELL));
75 atmp->a = a;
76 atmp->arc = arc;
77 atmp->next = state->ac;
78 state->ac = atmp;
79 }
80
81 /* make word(phrase) HMM from HTK_HMM_INFO */
82 /* LM prob will be assigned for cross-word arcs */
83 /* new HMM is malloced and returned */
84
85 /**
86 * Make a HMM instance for recognition from phoneme sequence, with connection
87 * probabiliry given for each phoneme.
88 *
89 * @param hmminfo [in] HTK %HMM definitions data
90 * @param hdseq [in] phoneme sequence as given by pointer list of logical %HMM
91 * @param hdseqlen [in] length of above
92 * @param has_sp [in] indicates where short-pause insertion is possible
93 * @param lscore [in] list of log probability to be added at the emitting
94 * transition of each phoneme, or NULL if not needed.
95 *
96 * @return newly allocated HMM instance generated from the given data.
97 */
98 HMM *
new_make_word_hmm_with_lm(HTK_HMM_INFO * hmminfo,HMM_Logical ** hdseq,int hdseqlen,boolean * has_sp,LOGPROB * lscore)99 new_make_word_hmm_with_lm(HTK_HMM_INFO *hmminfo, HMM_Logical **hdseq, int hdseqlen, boolean *has_sp, LOGPROB *lscore)
100 {
101 HMM *new;
102 int i,j,n;
103 int afrom, ato;
104 LOGPROB logprob;
105 HTK_HMM_Trans *tr;
106 int state_num;
107
108 if (has_sp) {
109 if (hmminfo->sp == NULL) {
110 jlog("Error: mkwhmm: no short-pause model in hmminfo\n");
111 return NULL;
112 }
113 }
114
115 /* allocate needed states */
116 new = (HMM *)mymalloc(sizeof(HMM));
117 new->len = totalstatelen(hdseq, hdseqlen, has_sp, hmminfo);
118 new->state = (HMM_STATE *)mymalloc(sizeof(HMM_STATE) * new->len);
119 for (i=0;i<new->len;i++) {
120 new->state[i].ac = NULL;
121 new->state[i].is_pseudo_state = FALSE;
122 new->state[i].out.state = NULL;
123 new->state[i].out.cdset = NULL;
124 }
125
126 /* assign outprob informations into the states */
127 n = 0;
128 if (hmminfo->multipath) n++; /* skip first state */
129 for (i = 0; i < hdseqlen; i++) {
130 if (hdseq[i]->is_pseudo) {
131 for (j = 1; j < hdseq[i]->body.pseudo->state_num - 1; j++) {
132 new->state[n].is_pseudo_state = TRUE;
133 new->state[n].out.cdset = &(hdseq[i]->body.pseudo->stateset[j]);
134 n++;
135 }
136 } else {
137 for (j = 1; j < hdseq[i]->body.defined->state_num - 1; j++) {
138 new->state[n].is_pseudo_state = FALSE;
139 new->state[n].out.state = hdseq[i]->body.defined->s[j];
140 n++;
141 }
142 }
143 if (has_sp) {
144 if (has_sp[i]) {
145 /* append sp at the end of the phone */
146 if (hmminfo->sp->is_pseudo) {
147 for (j = 1; j < hmm_logical_state_num(hmminfo->sp) - 1; j++) {
148 new->state[n].is_pseudo_state = TRUE;
149 new->state[n].out.cdset = &(hmminfo->sp->body.pseudo->stateset[j]);
150 n++;
151 }
152 } else {
153 for (j = 1; j < hmm_logical_state_num(hmminfo->sp) - 1; j++) {
154 new->state[n].is_pseudo_state = FALSE;
155 new->state[n].out.state = hmminfo->sp->body.defined->s[j];
156 n++;
157 }
158 }
159 }
160 }
161 }
162
163 /* make transition arcs between each state*/
164 /*
165 * for (i=0;i<hdseq[0]->def->state_num;i++) {
166 * if (i != 1 && (hdseq[0]->def->tr->a[0][i]) != LOG_ZERO) {
167 * jlog("initial state contains more than 1 arc.\n");
168 * }
169 * }
170 */
171
172 if (hmminfo->multipath) {
173
174 int *out_from, *out_from_next;
175 LOGPROB *out_a, *out_a_next;
176 int out_num_prev, out_num_next;
177 out_from = (int *)mymalloc(sizeof(int) * new->len);
178 out_from_next = (int *)mymalloc(sizeof(int) * new->len);
179 out_a = (LOGPROB *)mymalloc(sizeof(LOGPROB) * new->len);
180 out_a_next = (LOGPROB *)mymalloc(sizeof(LOGPROB) * new->len);
181
182 n = 0; /* n points to previous state */
183
184 out_from[0] = 0;
185 out_a[0] = 0.0;
186 out_num_prev = 1;
187 for (i = 0; i < hdseqlen; i++) {
188 state_num = hmm_logical_state_num(hdseq[i]);
189 tr = hmm_logical_trans(hdseq[i]);
190 out_num_next = 0;
191 /* arc from initial state */
192 for (ato = 1; ato < state_num; ato++) {
193 logprob = tr->a[0][ato];
194 if (logprob != LOG_ZERO) {
195 /* expand arc */
196 if (ato == state_num-1) {
197 /* from initial to final ... register all previously registered arcs for next expansion */
198 if (lscore != NULL) logprob += lscore[i];
199 for(j=0;j<out_num_prev;j++) {
200 out_from_next[out_num_next] = out_from[j];
201 out_a_next[out_num_next] = out_a[j] + logprob;
202 out_num_next++;
203 }
204 } else {
205 for(j=0;j<out_num_prev;j++) {
206 add_arc(&(new->state[out_from[j]]), n + ato,
207 out_a[j] + logprob);
208 }
209 }
210 }
211 }
212 /* arc from output state */
213 for(afrom = 1; afrom < state_num - 1; afrom++) {
214 for (ato = 1; ato < state_num; ato++) {
215 logprob = tr->a[afrom][ato];
216 if (logprob != LOG_ZERO) {
217 if (ato == state_num - 1) {
218 /* from output state to final ... register the arc for next expansion */
219 if (lscore != NULL) logprob += lscore[i];
220 out_from_next[out_num_next] = n+afrom;
221 out_a_next[out_num_next++] = logprob;
222 } else {
223 add_arc(&(new->state[n+afrom]), n + ato, logprob);
224 }
225 }
226 }
227 }
228 n += state_num - 2;
229 for(j=0;j<out_num_next;j++) {
230 out_from[j] = out_from_next[j];
231 out_a[j] = out_a_next[j];
232 }
233 out_num_prev = out_num_next;
234
235 /* inter-word short pause handling */
236 if (has_sp && has_sp[i]) {
237
238 out_num_next = 0;
239
240 /* arc from initial state */
241 for (ato = 1; ato < hmm_logical_state_num(hmminfo->sp); ato++) {
242 logprob = hmm_logical_trans(hmminfo->sp)->a[0][ato];
243 if (logprob != LOG_ZERO) {
244 /* to control short pause insertion, transition probability toward
245 the word-end short pause will be given a penalty */
246 logprob += hmminfo->iwsp_penalty;
247 /* expand arc */
248 if (ato == hmm_logical_state_num(hmminfo->sp)-1) {
249 /* from initial to final ... register all previously registered arcs for next expansion */
250 for(j=0;j<out_num_prev;j++) {
251 out_from_next[out_num_next] = out_from[j];
252 out_a_next[out_num_next] = out_a[j] + logprob;
253 out_num_next++;
254 }
255 } else {
256 for(j=0;j<out_num_prev;j++) {
257 add_arc(&(new->state[out_from[j]]), n + ato,
258 out_a[j] + logprob);
259 }
260 }
261 }
262 }
263 /* if short pause model doesn't have a model skip transition, also add it */
264 if (hmm_logical_trans(hmminfo->sp)->a[0][hmm_logical_state_num(hmminfo->sp)-1] == LOG_ZERO) {
265 /* to make insertion sp model to have no effect on the original path,
266 the skip transition probability should be 0.0 (=100%) */
267 logprob = 0.0;
268 for(j=0; j<out_num_prev; j++) {
269 out_from_next[out_num_next] = out_from[j];
270 out_a_next[out_num_next] = out_a[j] + logprob;
271 out_num_next++;
272 }
273 }
274 /* arc from output state */
275 for(afrom = 1; afrom < hmm_logical_state_num(hmminfo->sp) - 1; afrom++) {
276 for (ato = 1; ato < hmm_logical_state_num(hmminfo->sp); ato++) {
277 logprob = hmm_logical_trans(hmminfo->sp)->a[afrom][ato];
278 if (logprob != LOG_ZERO) {
279 if (ato == hmm_logical_state_num(hmminfo->sp) - 1) {
280 /* from output state to final ... register the arc for next expansion */
281 out_from_next[out_num_next] = n+afrom;
282 out_a_next[out_num_next++] = logprob;
283 } else {
284 add_arc(&(new->state[n+afrom]), n + ato, logprob);
285 }
286 }
287 }
288 }
289 n += hmm_logical_state_num(hmminfo->sp) - 2;
290 for(j=0;j<out_num_next;j++) {
291 out_from[j] = out_from_next[j];
292 out_a[j] = out_a_next[j];
293 }
294 out_num_prev = out_num_next;
295 }
296 }
297
298
299 for(j=0;j<out_num_prev;j++) {
300 add_arc(&(new->state[out_from[j]]), new->len-1, out_a[j]);
301 }
302 free(out_from);
303 free(out_from_next);
304 free(out_a);
305 free(out_a_next);
306
307 } else {
308 /* non-multipath version */
309
310 new->accept_ac_a = LOG_ZERO;
311 n = 0;
312 for (i = 0; i < hdseqlen; i++) {
313 state_num = hmm_logical_state_num(hdseq[i]);
314 tr = hmm_logical_trans(hdseq[i]);
315 /* for each phoneme, consult the transition matrix to form HMM instance */
316 for (afrom = 1; afrom < state_num - 1; afrom++) {
317 for (ato = 1; ato < state_num; ato++) {
318 logprob = tr->a[afrom][ato];
319 if (logprob != LOG_ZERO) {
320 /* if emitting transition, add connection probability to the arc */
321 if (ato == state_num - 1 && lscore != NULL){
322 logprob += lscore[i];
323 }
324 if (n + (ato - afrom) >= new->len) { /* arc to accept node */
325 if (new->accept_ac_a != LOG_ZERO) {
326 jlog("Error: mkwhmm: more than 1 arc to accept node found\n");
327 return NULL;
328
329 } else {
330 new->accept_ac_a = logprob;
331 }
332 } else {
333 add_arc(&(new->state[n]), n + (ato - afrom), logprob);
334 }
335 }
336 }
337 n++;
338 }
339 }
340 }
341
342 return (new);
343 }
344
345 /**
346 * Make a HMM instance for recognition from phoneme sequence.
347 *
348 * @param hmminfo [in] HTK %HMM definitions data
349 * @param hdseq [in] phoneme sequence as given by pointer list of logical %HMM
350 * @param hdseqlen [in] length of above
351 * @param has_sp [in] indicates where short-pause insertion is possible
352 *
353 * @return newly allocated HMM instance generated from the given data.
354 */
355 HMM *
new_make_word_hmm(HTK_HMM_INFO * hmminfo,HMM_Logical ** hdseq,int hdseqlen,boolean * has_sp)356 new_make_word_hmm(HTK_HMM_INFO *hmminfo, HMM_Logical **hdseq, int hdseqlen, boolean *has_sp)
357 {
358 return(new_make_word_hmm_with_lm(hmminfo, hdseq, hdseqlen, has_sp, NULL));
359 }
360
361 /**
362 * Free an HMM instance.
363 *
364 * @param d [in] HMM instance to free
365 */
366 void
free_hmm(HMM * d)367 free_hmm(HMM *d)
368 {
369 A_CELL *ac, *atmp;
370 int i;
371
372 for (i=0;i<d->len;i++) {
373 ac = d->state[i].ac;
374 while (ac) {
375 atmp = ac->next;
376 free(ac);
377 ac = atmp;
378 }
379 }
380 free(d->state);
381 free(d);
382 }
383