void vithist_rescore(vithist_t * vh, ngram_model_t *lm, s3dict_t *dict, dict2pid_t *dict2pid, fillpen_t *fp, s3wid_t wid, int32 ef, int32 score, int32 pred, int32 type, int32 rc) { vithist_entry_t *pve, tve; int32 lwid; int32 se, fe; int32 i; assert(vh->n_frm == ef); if (pred == -1) { /* Always do E_FATAL assuming upper level function take care of error checking. */ E_FATAL ("Hmm->out.history equals to -1 with score %d, some active phone was not computed?\n", score); } /* pve is the previous entry before word with wid or, se an fe is the first to the last entry before pve. So pve is w_{n-1} */ pve = vithist_id2entry(vh, pred); /* Create a temporary entry with all the info currently available */ tve.wid = wid; tve.sf = pve->ef + 1; tve.ef = ef; tve.type = type; tve.valid = 1; tve.ascr = score - pve->path.score; tve.lscr = 0; tve.rc = NULL; tve.n_rc = 0; /* Filler words only have unigram language model scores, so not * much special needs to be done for them. vithist_prune() is * going to prune out most of these later on, anyway. */ if (s3dict_filler_word(dict, wid)) { tve.path.score = score; tve.lscr = fillpen(fp, wid); tve.path.score += tve.lscr; if ((tve.path.score - vh->wbeam) >= vh->bestscore[vh->n_frm]) { tve.path.pred = pred; /* Note that they just propagate the same LM state since * they are not in the LM. */ tve.lmstate.lm3g = pve->lmstate.lm3g; vithist_enter(vh, dict, dict2pid, &tve, rc); } } else { if (pred == 0) { /* Special case for the initial <s> entry */ se = 0; fe = 1; } else { se = vh->frame_start[pve->ef]; fe = vh->frame_start[pve->ef + 1]; } /* Now if it is a word, backtrack again to get all possible previous word So pve becomes the w_{n-2}. */ lwid = ngram_wid(lm, s3dict_wordstr(dict, s3dict_basewid(dict, wid))); tve.lmstate.lm3g.lwid[0] = lwid; /* FIXME: This loop is completely awful. For each entry in * this frame, we scan every entry in the previous frame, * potentially creating a new history entry. This means that * without pruning, the size of the vithist table (and thus * the time taken here) is exponential in the number of * frames! */ for (i = se; i < fe; i++) { pve = vithist_id2entry(vh, i); if (pve->valid) { int n_used; tve.path.score = pve->path.score + tve.ascr; /* Try at all costs to avoid calling ngram_tg_score() * because it is the main time consuming part here * (but as noted above... ugh...) See below as well. */ if ((tve.path.score - vh->wbeam) < vh->bestscore[vh->n_frm]) continue; /* The trigram cache is supposed to make this fast, * but due to the crazy number of times this could be * called, it's still slow compared to a hash * table. */ tve.lscr = ngram_tg_score(lm, lwid, pve->lmstate.lm3g.lwid[0], pve->lmstate.lm3g.lwid[1], &n_used); tve.path.score += tve.lscr; /* A different word exit threshold - we would have to * be inside the general word beam in order to get * here, now we apply a second beam to the *vithist * entries* in this frame. There can be an ungodly * number of them for reasons that aren't entirely * clear to me, so this is kind of a pre-pruning. * NOTE: the "backwards" math here is because * vh->bestscore is frequently MAX_NEG_INT32. ALSO * NOTE: We can't precompute the threshold since the * best score will be updated by vithist_enter(). */ if ((tve.path.score - vh->wbeam) >= vh->bestscore[vh->n_frm]) { tve.path.pred = i; tve.lmstate.lm3g.lwid[1] = pve->lmstate.lm3g.lwid[0]; vithist_enter(vh, dict, dict2pid, &tve, rc); } } } } }
void run_tests(logmath_t *lmath, ngram_model_t *model) { int32 rv, i; TEST_ASSERT(model); TEST_EQUAL(ngram_wid(model, "scylla"), 285); TEST_EQUAL(strcmp(ngram_word(model, 285), "scylla"), 0); rv = ngram_model_read_classdef(model, LMDIR "/100.probdef"); TEST_EQUAL(rv, 0); /* Verify that class word IDs remain the same. */ TEST_EQUAL(ngram_wid(model, "scylla"), 285); TEST_EQUAL(strcmp(ngram_word(model, 285), "scylla"), 0); /* Verify in-class word IDs. */ TEST_EQUAL(ngram_wid(model, "scylla:scylla"), 0x80000000 | 400); /* Verify in-class and out-class unigram scores. */ TEST_EQUAL_LOG(ngram_score(model, "scylla:scylla", NULL), logmath_log10_to_log(lmath, -2.7884) + logmath_log(lmath, 0.4)); TEST_EQUAL_LOG(ngram_score(model, "scooby:scylla", NULL), logmath_log10_to_log(lmath, -2.7884) + logmath_log(lmath, 0.1)); TEST_EQUAL_LOG(ngram_score(model, "scylla", NULL), logmath_log10_to_log(lmath, -2.7884)); TEST_EQUAL_LOG(ngram_score(model, "oh:zero", NULL), logmath_log10_to_log(lmath, -1.9038) + logmath_log(lmath, 0.7)); TEST_EQUAL_LOG(ngram_score(model, "zero", NULL), logmath_log10_to_log(lmath, -1.9038)); /* Verify class bigram scores. */ TEST_EQUAL_LOG(ngram_score(model, "scylla", "on", NULL), logmath_log10_to_log(lmath, -1.2642)); TEST_EQUAL_LOG(ngram_score(model, "scylla:scylla", "on", NULL), logmath_log10_to_log(lmath, -1.2642) + logmath_log(lmath, 0.4)); TEST_EQUAL_LOG(ngram_score(model, "apparently", "scylla", NULL), logmath_log10_to_log(lmath, -0.5172)); TEST_EQUAL_LOG(ngram_score(model, "apparently", "karybdis:scylla", NULL), logmath_log10_to_log(lmath, -0.5172)); TEST_EQUAL_LOG(ngram_score(model, "apparently", "scooby:scylla", NULL), logmath_log10_to_log(lmath, -0.5172)); /* Verify class trigram scores. */ TEST_EQUAL_LOG(ngram_score(model, "zero", "be", "will", NULL), logmath_log10_to_log(lmath, -0.5725)); TEST_EQUAL_LOG(ngram_score(model, "oh:zero", "be", "will", NULL), logmath_log10_to_log(lmath, -0.5725) + logmath_log(lmath, 0.7)); TEST_EQUAL_LOG(ngram_score(model, "should", "variance", "zero", NULL), logmath_log10_to_log(lmath, -0.9404)); TEST_EQUAL_LOG(ngram_score(model, "should", "variance", "zero:zero", NULL), logmath_log10_to_log(lmath, -0.9404)); /* Add words to classes. */ rv = ngram_model_add_class_word(model, "scylla", "scrappy:scylla", 1.0); TEST_ASSERT(rv >= 0); TEST_EQUAL(ngram_wid(model, "scrappy:scylla"), 0x80000196); TEST_EQUAL_LOG(ngram_score(model, "scrappy:scylla", NULL), logmath_log10_to_log(lmath, -2.7884) + logmath_log(lmath, 0.2)); printf("scrappy:scylla %08x %d %f\n", ngram_wid(model, "scrappy:scylla"), ngram_score(model, "scrappy:scylla", NULL), logmath_exp(lmath, ngram_score(model, "scrappy:scylla", NULL))); /* Add a lot of words to a class. */ for (i = 0; i < 129; ++i) { char word[32]; sprintf(word, "%d:scylla", i); rv = ngram_model_add_class_word(model, "scylla", word, 1.0); printf("%s %08x %d %f\n", word, ngram_wid(model, word), ngram_score(model, word, NULL), logmath_exp(lmath, ngram_score(model, word, NULL))); TEST_ASSERT(rv >= 0); TEST_EQUAL(ngram_wid(model, word), 0x80000197 + i); } /* Add a new class. */ { const char *words[] = { "blatz:foobie", "hurf:foobie" }; float32 weights[] = { 0.6, 0.4 }; int32 foobie_prob; rv = ngram_model_add_class(model, "[foobie]", 1.0, words, weights, 2); TEST_ASSERT(rv >= 0); foobie_prob = ngram_score(model, "[foobie]", NULL); TEST_EQUAL_LOG(ngram_score(model, "blatz:foobie", NULL), foobie_prob + logmath_log(lmath, 0.6)); TEST_EQUAL_LOG(ngram_score(model, "hurf:foobie", NULL), foobie_prob + logmath_log(lmath, 0.4)); } }
char * dict_g2p(char const *word_grapheme, ngram_model_t *ngram_g2p_model) { char *final_phone = NULL; int totalh = 0; size_t increment = 1; int word_offset = 0; int j; size_t grapheme_len = 0, final_phoneme_len = 0; glist_t history_list = NULL; gnode_t *gn; int first = 0; const int32 *total_unigrams; struct winner_t winner; const char *word; unigram_t unigram; total_unigrams = ngram_model_get_counts(ngram_g2p_model); int32 wid_sentence = ngram_wid(ngram_g2p_model,"<s>"); // start with sentence history_list = glist_add_int32(history_list, wid_sentence); grapheme_len = strlen(word_grapheme); for (j = 0; j < grapheme_len; j += increment) { winner = dict_get_winner_wid(ngram_g2p_model, word_grapheme, history_list, *total_unigrams, word_offset); increment = winner.length_match; if (increment == 0) { E_ERROR("Error trying to find matching phoneme (%s) Exiting.. \n" , word_grapheme); return NULL; } history_list = glist_add_int32(history_list, winner.winner_wid); totalh = j + 1; word_offset += winner.length_match; final_phoneme_len += winner.len_phoneme; } history_list = glist_reverse(history_list); final_phone = ckd_calloc(1, final_phoneme_len * 2); for (gn = history_list; gn; gn = gnode_next(gn)) { if (!first) { first = 1; continue; } word = ngram_word(ngram_g2p_model, gnode_int32(gn)); if (!word) continue; unigram = dict_split_unigram(word); if (strcmp(unigram.phone, "_") == 0) { if (unigram.word) ckd_free(unigram.word); if (unigram.phone) ckd_free(unigram.phone); continue; } strcat(final_phone, unigram.phone); strcat(final_phone, " "); if (unigram.word) ckd_free(unigram.word); if (unigram.phone) ckd_free(unigram.phone); } if (history_list) glist_free(history_list); return final_phone; }
void run_tests(ngram_model_t *model) { int32 n_used; ngram_tg_score(model, ngram_wid(model, "daines"), ngram_wid(model, "huggins"), ngram_wid(model, "huggins"), &n_used); TEST_EQUAL(n_used, 2); ngram_tg_score(model, ngram_wid(model, "david"), ngram_wid(model, "david"), ngram_wid(model, "david"), &n_used); TEST_EQUAL(n_used, 1); /* Apply weights. */ ngram_model_apply_weights(model, 7.5, 0.5, 1.0); /* -9452 * 7.5 + log(0.5) = -77821 */ TEST_EQUAL_LOG(ngram_score(model, "daines", "huggins", "david", NULL), -77821); /* Recover original score. */ TEST_EQUAL_LOG(ngram_probv(model, "daines", "huggins", "david", NULL), -9452); TEST_EQUAL_LOG(ngram_probv(model, "huggins", "david", NULL), -831); /* Un-apply weights. */ ngram_model_apply_weights(model, 1.0, 1.0, 1.0); TEST_EQUAL_LOG(ngram_score(model, "daines", "huggins", "david", NULL), -9452); TEST_EQUAL_LOG(ngram_score(model, "huggins", "david", NULL), -831); /* Recover original score. */ TEST_EQUAL_LOG(ngram_probv(model, "daines", "huggins", "david", NULL), -9452); /* Pre-weighting, this should give the "raw" score. */ TEST_EQUAL_LOG(ngram_score(model, "daines", "huggins", "david", NULL), -9452); TEST_EQUAL_LOG(ngram_score(model, "huggins", "david", NULL), -831); /* Verify that backoff mode calculations work. */ ngram_bg_score(model, ngram_wid(model, "huggins"), ngram_wid(model, "david"), &n_used); TEST_EQUAL(n_used, 2); ngram_bg_score(model, ngram_wid(model, "blorglehurfle"), ngram_wid(model, "david"), &n_used); TEST_EQUAL(n_used, 1); ngram_bg_score(model, ngram_wid(model, "david"), ngram_wid(model, "david"), &n_used); TEST_EQUAL(n_used, 1); ngram_tg_score(model, ngram_wid(model, "daines"), ngram_wid(model, "huggins"), ngram_wid(model, "david"), &n_used); TEST_EQUAL(n_used, 3); }