lm3g_model.c
/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* ====================================================================
* Copyright (c) 1999-2007 Carnegie Mellon University. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* This work was supported in part by funding from the Defense Advanced
* Research Projects Agency and the National Science Foundation of the
* United States of America, and the CMU Sphinx Speech Consortium.
*
* THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ====================================================================
*
*/
/*
* \file lm3g_model.c Core Sphinx 3-gram code used in
* DMP/DMP32/ARPA (for now) model code.
*
* Author: A cast of thousands, probably.
*/
#include <string.h>
#include <assert.h>
#include <limits.h>
#include "sphinxbase/listelem_alloc.h"
#include "sphinxbase/ckd_alloc.h"
#include "sphinxbase/err.h"
#include "lm3g_model.h"
void
lm3g_tginfo_free(ngram_model_t *base, lm3g_model_t *lm3g)
{
if (lm3g->tginfo == NULL)
return;
listelem_alloc_free(lm3g->le);
ckd_free(lm3g->tginfo);
}
void
lm3g_tginfo_reset(ngram_model_t *base, lm3g_model_t *lm3g)
{
if (lm3g->tginfo == NULL)
return;
listelem_alloc_free(lm3g->le);
memset(lm3g->tginfo, 0, base->n_counts[0] * sizeof(tginfo_t *));
lm3g->le = listelem_alloc_init(sizeof(tginfo_t));
}
void
lm3g_apply_weights(ngram_model_t *base,
lm3g_model_t *lm3g,
float32 lw, float32 wip, float32 uw)
{
int32 log_wip, log_uw, log_uniform_weight;
int i;
/* Precalculate some log values we will like. */
log_wip = logmath_log(base->lmath, wip);
log_uw = logmath_log(base->lmath, uw);
log_uniform_weight = logmath_log(base->lmath, 1.0 - uw);
for (i = 0; i < base->n_counts[0]; ++i) {
int32 prob1, bo_wt, n_used;
/* Backoff weights just get scaled by the lw. */
bo_wt = (int32)(lm3g->unigrams[i].bo_wt1.l / base->lw);
/* Unscaling unigram probs is a bit more complicated, so punt
* it back to the general code. */
prob1 = ngram_ng_prob(base, i, NULL, 0, &n_used);
/* Now compute the new scaled probabilities. */
lm3g->unigrams[i].bo_wt1.l = (int32)(bo_wt * lw);
if (strcmp(base->word_str[i], "<s>") == 0) { /* FIXME: configurable start_sym */
/* Apply language weight and WIP */
lm3g->unigrams[i].prob1.l = (int32)(prob1 * lw) + log_wip;
}
else {
/* Interpolate unigram probability with uniform. */
prob1 += log_uw;
prob1 = logmath_add(base->lmath, prob1, base->log_uniform + log_uniform_weight);
/* Apply language weight and WIP */
lm3g->unigrams[i].prob1.l = (int32)(prob1 * lw) + log_wip;
}
}
for (i = 0; i < lm3g->n_prob2; ++i) {
int32 prob2;
/* Can't just punt this back to general code since it is quantized. */
prob2 = (int32)((lm3g->prob2[i].l - base->log_wip) / base->lw);
lm3g->prob2[i].l = (int32)(prob2 * lw) + log_wip;
}
if (base->n > 2) {
for (i = 0; i < lm3g->n_bo_wt2; ++i) {
lm3g->bo_wt2[i].l = (int32)(lm3g->bo_wt2[i].l / base->lw * lw);
}
for (i = 0; i < lm3g->n_prob3; i++) {
int32 prob3;
/* Can't just punt this back to general code since it is quantized. */
prob3 = (int32)((lm3g->prob3[i].l - base->log_wip) / base->lw);
lm3g->prob3[i].l = (int32)(prob3 * lw) + log_wip;
}
}
/* Store updated values in the model. */
base->log_wip = log_wip;
base->log_uw = log_uw;
base->log_uniform_weight = log_uniform_weight;
base->lw = lw;
}
int32
lm3g_add_ug(ngram_model_t *base,
lm3g_model_t *lm3g, int32 wid, int32 lweight)
{
int32 score;
/* This would be very bad if this happened! */
assert(!NGRAM_IS_CLASSWID(wid));
/* Reallocate unigram array. */
lm3g->unigrams = ckd_realloc(lm3g->unigrams,
sizeof(*lm3g->unigrams) * base->n_1g_alloc);
memset(lm3g->unigrams + base->n_counts[0], 0,
(base->n_1g_alloc - base->n_counts[0]) * sizeof(*lm3g->unigrams));
/* Reallocate tginfo array. */
lm3g->tginfo = ckd_realloc(lm3g->tginfo,
sizeof(*lm3g->tginfo) * base->n_1g_alloc);
memset(lm3g->tginfo + base->n_counts[0], 0,
(base->n_1g_alloc - base->n_counts[0]) * sizeof(*lm3g->tginfo));
/* FIXME: we really ought to update base->log_uniform *and*
* renormalize all the other unigrams. This is really slow, so I
* will probably just provide a function to renormalize after
* adding unigrams, for anyone who really cares. */
/* This could be simplified but then we couldn't do it in logmath */
score = lweight + base->log_uniform + base->log_uw;
score = logmath_add(base->lmath, score,
base->log_uniform + base->log_uniform_weight);
lm3g->unigrams[wid].prob1.l = score;
/* This unigram by definition doesn't participate in any bigrams,
* so its backoff weight and bigram pointer are both undefined. */
lm3g->unigrams[wid].bo_wt1.l = 0;
lm3g->unigrams[wid].bigrams = 0;
/* Finally, increase the unigram count */
++base->n_counts[0];
/* FIXME: Note that this can actually be quite bogus due to the
* presence of class words. If wid falls outside the unigram
* count, increase it to compensate, at the cost of no longer
* really knowing how many unigrams we have :( */
if (wid >= base->n_counts[0])
base->n_counts[0] = wid + 1;
return score;
}
#define INITIAL_SORTED_ENTRIES MAX_UINT16
void
init_sorted_list(sorted_list_t * l)
{
l->list = ckd_calloc(INITIAL_SORTED_ENTRIES, sizeof(sorted_entry_t));
l->list[0].val.l = INT_MIN;
l->list[0].lower = 0;
l->list[0].higher = 0;
l->free = 1;
l->size = INITIAL_SORTED_ENTRIES;
}
void
free_sorted_list(sorted_list_t * l)
{
free(l->list);
}
lmprob_t *
vals_in_sorted_list(sorted_list_t * l)
{
lmprob_t *vals;
int32 i;
vals = ckd_calloc(l->free, sizeof(lmprob_t));
for (i = 0; i < l->free; i++)
vals[i] = l->list[i].val;
return (vals);
}
int32
sorted_id(sorted_list_t * l, int32 *val)
{
int32 i = 0;
for (;;) {
if (*val == l->list[i].val.l)
return (i);
if (*val < l->list[i].val.l) {
if (l->list[i].lower == 0) {
if (l->free >= l->size) {
int newsize = l->size + INITIAL_SORTED_ENTRIES;
l->list = ckd_realloc(l->list, sizeof(sorted_entry_t) * newsize);
memset(l->list + l->size,
0, INITIAL_SORTED_ENTRIES * sizeof(sorted_entry_t));
l->size = newsize;
}
l->list[i].lower = l->free;
(l->free)++;
i = l->list[i].lower;
l->list[i].val.l = *val;
return (i);
}
else
i = l->list[i].lower;
}
else {
if (l->list[i].higher == 0) {
if (l->free >= l->size) {
int newsize = l->size + INITIAL_SORTED_ENTRIES;
l->list = ckd_realloc(l->list, sizeof(sorted_entry_t) * newsize);
memset(l->list + l->size,
0, INITIAL_SORTED_ENTRIES * sizeof(sorted_entry_t));
l->size = newsize;
}
l->list[i].higher = l->free;
(l->free)++;
i = l->list[i].higher;
l->list[i].val.l = *val;
return (i);
}
else
i = l->list[i].higher;
}
}
}
unigram_s::bo_wt1
lmprob_t bo_wt1
Unigram backoff weight.
Definition: lm3g_model.h:93
lm3g_model_s::le
listelem_alloc_t * le
List element allocator for tginfo.
Definition: lm3g_model.h:156
ngram_ng_prob
SPHINXBASE_EXPORT int32 ngram_ng_prob(ngram_model_t *model, int32 wid, int32 *history, int32 n_hist, int32 *n_used)
Quick "raw" probability lookup for a general N-Gram.
Definition: ngram_model.c:570
ngram_model_s::log_uniform
int32 log_uniform
Log of uniform (0-gram) probability.
Definition: ngram_model_internal.h:70
ckd_calloc
#define ckd_calloc(n, sz)
Macros to simplify the use of above functions.
Definition: ckd_alloc.h:248
sorted_entry_s::val
lmprob_t val
value being kept in this node
Definition: lm3g_model.h:69
lm3g_model_s::n_prob3
int32 n_prob3
prob3 size
Definition: lm3g_model.h:151
ngram_model_s::word_str
char ** word_str
Unigram names.
Definition: ngram_model_internal.h:73
ckd_alloc.h
Sphinx's memory allocation/deallocation routines.
ngram_model_s::log_uniform_weight
int32 log_uniform_weight
Log of uniform weight (i.e.
Definition: ngram_model_internal.h:71
lm3g_model_s::prob2
lmprob_t * prob2
Table of actual bigram probs.
Definition: lm3g_model.h:146
logmath_log
SPHINXBASE_EXPORT int logmath_log(logmath_t *lmath, float64 p)
Convert linear floating point number to integer log in base B.
Definition: logmath.c:447
ngram_model_s::n_counts
int32 * n_counts
Counts for 1, 2, 3, ...
Definition: ngram_model_internal.h:57
ckd_free
SPHINXBASE_EXPORT void ckd_free(void *ptr)
Test and free a 1-D array.
Definition: ckd_alloc.c:241
unigram_s::bigrams
int32 bigrams
Index of 1st entry in lm_t.bigrams[].
Definition: lm3g_model.h:94
lm3g_model_s::n_bo_wt2
int32 n_bo_wt2
bo_wt2 size
Definition: lm3g_model.h:149
ngram_model_s::n_1g_alloc
int32 n_1g_alloc
Number of allocated word strings (for new word addition)
Definition: ngram_model_internal.h:58
lm3g_model_s::prob3
lmprob_t * prob3
Table of actual trigram probs.
Definition: lm3g_model.h:150
tginfo_s
Trigram information cache.
Definition: lm3g_model.h:129
lm3g_model_s
Common internal structure for Sphinx 3-gram models.
Definition: lm3g_model.h:142
listelem_alloc.h
Fast memory allocator for uniformly sized objects.
ngram_model_s::n
uint8 n
This is an n-gram model (1, 2, 3, ...).
Definition: ngram_model_internal.h:61
err.h
Implementation of logging routines.
sorted_list_t
The sorted list.
Definition: lm3g_model.h:82
ngram_model_s::lmath
logmath_t * lmath
Log-math object.
Definition: ngram_model_internal.h:66
sorted_entry_s::lower
uint32 lower
index of another entry.
Definition: lm3g_model.h:70
ngram_model_s::log_uw
int32 log_uw
Log of unigram weight.
Definition: ngram_model_internal.h:69
unigram_s::prob1
lmprob_t prob1
Unigram probability.
Definition: lm3g_model.h:92
lm3g_model_s::bo_wt2
lmprob_t * bo_wt2
Table of actual bigram backoff weights.
Definition: lm3g_model.h:148
listelem_alloc_init
SPHINXBASE_EXPORT listelem_alloc_t * listelem_alloc_init(size_t elemsize)
Initialize and return a list element allocator.
Definition: listelem_alloc.c:87
ngram_model_s::lw
float32 lw
Language model scaling factor.
Definition: ngram_model_internal.h:67
sorted_entry_s
Bigram probs and bo-wts, and trigram probs are kept in separate tables rather than within the bigram_...
Definition: lm3g_model.h:68
ngram_model_s
Common implementation of ngram_model_t.
Definition: ngram_model_internal.h:55
lmprob_t
Type used to store language model probabilities.
Definition: lm3g_model.h:54
sorted_list_t::free
int32 free
first free element in list
Definition: lm3g_model.h:84
ckd_realloc
#define ckd_realloc(ptr, sz)
Macro for ckd_realloc
Definition: ckd_alloc.h:258
lm3g_model_s::tginfo
tginfo_t ** tginfo
tginfo[lw2] is head of linked list of trigram information for some cached subset of bigrams (*...
Definition: lm3g_model.h:154
lm3g_model_s::n_prob2
int32 n_prob2
prob2 size
Definition: lm3g_model.h:147
ngram_model_s::log_wip
int32 log_wip
Log of word insertion penalty.
Definition: ngram_model_internal.h:68
logmath_add
SPHINXBASE_EXPORT int logmath_add(logmath_t *lmath, int logb_p, int logb_q)
Add two values in log space (i.e.
Definition: logmath.c:392
listelem_alloc_free
SPHINXBASE_EXPORT void listelem_alloc_free(listelem_alloc_t *le)
Finalize and release all memory associated with a list element allocator.
Definition: listelem_alloc.c:121
sorted_entry_s::higher
uint32 higher
index of another entry.
Definition: lm3g_model.h:73