📄 word_fsg.c
字号:
* Add silence and noise filler words to the FSG. * Return the number of transitions added.. */static int32word_fsg_add_filler(word_fsg_t * fsg, float32 silprob, float32 fillprob){ int32 src; int32 wid, silwid, n_word; int32 n_trans; int32 logsilp, logfillp; E_INFO("Adding filler words to FSG\n"); assert(fsg); silwid = kb_get_word_id("SIL"); n_word = word_dict->dict_entry_count; logsilp = (int32) (LOG(silprob) * fsg->lw); logfillp = (int32) (LOG(fillprob) * fsg->lw); /* * Add silence and filler word self-loop transitions to each state. * NOTE: No check to see if these words already exist in FSG! */ n_trans = 0; if (silwid >= 0) { for (src = 0; src < fsg->n_state; src++) { word_fsg_trans_add(fsg, src, src, logsilp, silwid); n_trans++; if (fillprob > 0.0) { /* Add other filler (noise) words */ for (wid = silwid + 1; wid < n_word; wid++) { word_fsg_trans_add(fsg, src, src, logfillp, wid); n_trans++; } } } } return n_trans;}/* * Compute the left and right context CIphone sets for each state. * (Needed for building the phone HMM net using cross-word triphones. Invoke * after computing null transitions closure.) */static voidword_fsg_lc_rc(word_fsg_t * fsg){ int32 s, d, i, j; int32 n_ci; gnode_t *gn; word_fsglink_t *l; int32 silcipid; int32 endwid; int32 len; endwid = kb_get_word_id(cmd_ln_str("-lmendsym")); silcipid = phone_to_id("SIL", TRUE); assert(silcipid >= 0); n_ci = phoneCiCount(); if (n_ci > 127) { E_FATAL ("#phones(%d) > 127; cannot use int8** for word_fsg_t.{lc,rc}\n", n_ci); } /* * fsg->lc[s] = set of left context CIphones for state s. Similarly, rc[s] * for right context CIphones. */ fsg->lc = (int8 **) ckd_calloc_2d(fsg->n_state, n_ci + 1, sizeof(int8)); fsg->rc = (int8 **) ckd_calloc_2d(fsg->n_state, n_ci + 1, sizeof(int8)); for (s = 0; s < fsg->n_state; s++) { for (d = 0; d < fsg->n_state; d++) { for (gn = fsg->trans[s][d]; gn; gn = gnode_next(gn)) { l = (word_fsglink_t *) gnode_ptr(gn); assert(l->wid >= 0); /* * Add the first CIphone of l->wid to the rclist of state s, and * the last CIphone to lclist of state d. * (Filler phones are a pain to deal with. There is no direct * marking of a filler phone; but only filler words are supposed to * use such phones, so we use that fact. HACK!! FRAGILE!!) */ if (dict_is_filler_word(word_dict, l->wid) || (l->wid == endwid)) { /* Filler phone; use silence phone as context */ fsg->rc[s][silcipid] = 1; fsg->lc[d][silcipid] = 1; } else { len = dict_pronlen(word_dict, l->wid); fsg->rc[s][dict_ciphone(word_dict, l->wid, 0)] = 1; fsg->lc[d][dict_ciphone(word_dict, l->wid, len - 1)] = 1; } } } /* * Add SIL phone to the lclist and rclist of each state. Strictly * speaking, only needed at start and final states, respectively, but * all states considered since the user may change the start and final * states. In any case, most applications would have a silence self * loop at each state, hence these would be needed anyway. */ fsg->lc[s][silcipid] = 1; fsg->rc[s][silcipid] = 1; } /* * Propagate lc and rc lists past null transitions. (Since FSG contains * null transitions closure, no need to worry about a chain of successive * null transitions. Right??) */ for (s = 0; s < fsg->n_state; s++) { for (d = 0; d < fsg->n_state; d++) { l = fsg->null_trans[s][d]; if (l) { /* * lclist(d) |= lclist(s), because all the words ending up at s, can * now also end at d, becoming the left context for words leaving d. */ for (i = 0; i < n_ci; i++) fsg->lc[d][i] |= fsg->lc[s][i]; /* * Similarly, rclist(s) |= rclist(d), because all the words leaving d * can equivalently leave s, becoming the right context for words * ending up at s. */ for (i = 0; i < n_ci; i++) fsg->rc[s][i] |= fsg->rc[d][i]; } } } /* Convert the bit-vector representation into a list */ for (s = 0; s < fsg->n_state; s++) { j = 0; for (i = 0; i < n_ci; i++) { if (fsg->lc[s][i]) { fsg->lc[s][j] = i; j++; } } fsg->lc[s][j] = -1; /* Terminate the list */ j = 0; for (i = 0; i < n_ci; i++) { if (fsg->rc[s][i]) { fsg->rc[s][j] = i; j++; } } fsg->rc[s][j] = -1; /* Terminate the list */ }}word_fsg_t *word_fsg_load(s2_fsg_t * fsg, boolean use_altpron, boolean use_filler, float32 silprob, float32 fillprob, float32 lw){ word_fsg_t *word_fsg; s2_fsg_trans_t *trans; int32 n_trans, n_null_trans, n_alt_trans, n_filler_trans, n_unk; int32 wid; int32 logp; glist_t nulls; int32 i, j; assert(fsg); /* Some error checking */ if (lw <= 0.0) E_WARN("Unusual language-weight value: %.3e\n", lw); if (use_filler && ((silprob < 0.0) || (fillprob < 0.0))) { E_ERROR("silprob/fillprob must be >= 0\n"); return NULL; } if ((fsg->n_state <= 0) || ((fsg->start_state < 0) || (fsg->start_state >= fsg->n_state)) || ((fsg->final_state < 0) || (fsg->final_state >= fsg->n_state))) { E_ERROR("Bad #states/start_state/final_state values: %d/%d/%d\n", fsg->n_state, fsg->start_state, fsg->final_state); return NULL; } for (trans = fsg->trans_list; trans; trans = trans->next) { if ((trans->from_state < 0) || (trans->from_state >= fsg->n_state) || (trans->to_state < 0) || (trans->to_state >= fsg->n_state) || (trans->prob <= 0) || (trans->prob > 1.0)) { E_ERROR("Bad transition: P(%d -> %d) = %e\n", trans->from_state, trans->to_state, trans->prob); return NULL; } } word_fsg = (word_fsg_t *) ckd_calloc(1, sizeof(word_fsg_t)); word_fsg->name = ckd_salloc(fsg->name ? fsg->name : ""); word_fsg->n_state = fsg->n_state; word_fsg->start_state = fsg->start_state; word_fsg->final_state = fsg->final_state; word_fsg->use_altpron = use_altpron; word_fsg->use_filler = use_filler; word_fsg->lw = lw; word_fsg->lc = NULL; word_fsg->rc = NULL; /* Allocate non-epsilon transition matrix array */ word_fsg->trans = (glist_t **) ckd_calloc_2d(word_fsg->n_state, word_fsg->n_state, sizeof(glist_t)); /* Allocate epsilon transition matrix array */ word_fsg->null_trans = (word_fsglink_t ***) ckd_calloc_2d(word_fsg->n_state, word_fsg->n_state, sizeof(word_fsglink_t *)); /* Process transitions */ n_null_trans = 0; n_alt_trans = 0; n_filler_trans = 0; n_unk = 0; nulls = NULL; for (trans = fsg->trans_list, n_trans = 0; trans; trans = trans->next, n_trans++) { /* Convert prob to logs2prob and apply language weight */ logp = (int32) (LOG(trans->prob) * lw); /* Check if word is in dictionary */ if (trans->word) { wid = kb_get_word_id(trans->word); if (wid < 0) { E_ERROR("Unknown word '%s'; ignored\n", trans->word); n_unk++; } else if (use_altpron) { wid = dictid_to_baseid(word_dict, wid); assert(wid >= 0); } } else wid = -1; /* Null transition */ /* Add transition to word_fsg structure */ i = trans->from_state; j = trans->to_state; if (wid < 0) { if (word_fsg_null_trans_add(word_fsg, i, j, logp) == 1) { n_null_trans++; nulls = glist_add_ptr(nulls, (void *) word_fsg->null_trans[i][j]); } } else { word_fsg_trans_add(word_fsg, i, j, logp, wid); /* Add transitions for alternative pronunciations, if any */ if (use_altpron) { for (wid = dict_next_alt(word_dict, wid); wid >= 0; wid = dict_next_alt(word_dict, wid)) { word_fsg_trans_add(word_fsg, i, j, logp, wid); n_alt_trans++; n_trans++; } } } } /* Add silence and noise filler word transitions if specified */ if (use_filler) { n_filler_trans = word_fsg_add_filler(word_fsg, silprob, fillprob); n_trans += n_filler_trans; } E_INFO ("FSG: %d states, %d transitions (%d null, %d alt, %d filler, %d unknown)\n", word_fsg->n_state, n_trans, n_null_trans, n_alt_trans, n_filler_trans, n_unk);#if __FSG_DBG__ E_INFO("FSG before NULL closure:\n"); word_fsg_write(word_fsg, stdout);#endif /* Null transitions closure */ nulls = word_fsg_null_trans_closure(word_fsg, nulls); glist_free(nulls);#if __FSG_DBG__ E_INFO("FSG after NULL closure:\n"); word_fsg_write(word_fsg, stdout);#endif /* Compute left and right context CIphone lists for each state */ word_fsg_lc_rc(word_fsg);#if __FSG_DBG__ E_INFO("FSG after lc/rc:\n"); word_fsg_write(word_fsg, stdout);#endif return word_fsg;}static voids2_fsg_free(s2_fsg_t * fsg){ s2_fsg_trans_t *trans; trans = fsg->trans_list; while (trans) { fsg->trans_list = trans->next; ckd_free((void *) trans->word); ckd_free((void *) trans); trans = fsg->trans_list; } ckd_free((void *) fsg->name); ckd_free((void *) fsg);}word_fsg_t *word_fsg_read(FILE * fp, boolean use_altpron, boolean use_filler, float32 silprob, float32 fillprob, float32 lw){ s2_fsg_t *fsg; /* "External" FSG structure */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -