// $Id$ | |
/*********************************************************************** | |
Moses - factored phrase-based language decoder | |
Copyright (C) 2006 University of Edinburgh | |
This library is free software; you can redistribute it and/or | |
modify it under the terms of the GNU Lesser General Public | |
License as published by the Free Software Foundation; either | |
version 2.1 of the License, or (at your option) any later version. | |
This library is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
Lesser General Public License for more details. | |
You should have received a copy of the GNU Lesser General Public | |
License along with this library; if not, write to the Free Software | |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
***********************************************************************/ | |
//#include "moses/Util.h" | |
//#include "moses/StaticData.h" | |
//#include <iostream> | |
namespace Moses | |
{ | |
/** Constructs a new backward language model. */ | |
// TODO(lane): load_method instead of lazy bool | |
template <class Model> BackwardLanguageModel<Model>::BackwardLanguageModel(const std::string &line, const std::string &file, FactorType factorType, bool lazy) : LanguageModelKen<Model>(line,file,factorType, lazy ? util::LAZY : util::POPULATE_OR_READ) | |
{ | |
// | |
// This space intentionally left blank | |
// | |
} | |
/** | |
* Constructs an empty backward language model state. | |
* | |
* This state will correspond with a translation hypothesis | |
* where no source words have been translated. | |
* | |
* In a forward language model, the language model state of an empty hypothesis | |
* would store the beginning of sentence marker <s>. | |
* | |
* Because this is a backward language model, the language model state returned by this method | |
* instead stores the end of sentence marker </s>. | |
*/ | |
template <class Model> const FFState *BackwardLanguageModel<Model>::EmptyHypothesisState(const InputType &/*input*/) const | |
{ | |
BackwardLMState *ret = new BackwardLMState(); | |
lm::ngram::RuleScore<Model> ruleScore(*m_ngram, ret->state); | |
ruleScore.Terminal(m_ngram->GetVocabulary().EndSentence()); | |
// float score = | |
ruleScore.Finish(); | |
// VERBOSE(1, "BackwardLM EmptyHypothesisState has score " << score); | |
return ret; | |
} | |
/* | |
template <class Model> double BackwardLanguageModel<Model>::Score(FFState *ffState) { | |
BackwardLMState *lmState = static_cast< BackwardLMState* >(ffState); | |
lm::ngram::ChartState &state = lmState->state; | |
lm::ngram::RuleScore<Model> ruleScore(*m_ngram, lmState); | |
return ruleScore.Finish(); | |
} | |
*/ | |
/** | |
* Pre-calculate the n-gram probabilities for the words in the specified phrase. | |
* | |
* Note that when this method is called, we do not have access to the context | |
* in which this phrase will eventually be applied. | |
* | |
* In other words, we know what words are in this phrase, | |
* but we do not know what words will come before or after this phrase. | |
* | |
* The parameters fullScore, ngramScore, and oovCount are all output parameters. | |
* | |
* The value stored in oovCount is the number of words in the phrase | |
* that are not in the language model's vocabulary. | |
* | |
* The sum of the ngram scores for all words in this phrase are stored in fullScore. | |
* | |
* The value stored in ngramScore is similar, but only full-order ngram scores are included. | |
* | |
* This is best shown by example: | |
* | |
* Assume a trigram backward language model and a phrase "a b c d e f g" | |
* | |
* fullScore would represent the sum of the logprob scores for the following values: | |
* | |
* p(g) | |
* p(f | g) | |
* p(e | g f) | |
* p(d | f e) | |
* p(c | e d) | |
* p(b | d c) | |
* p(a | c b) | |
* | |
* ngramScore would represent the sum of the logprob scores for the following values: | |
* | |
* p(g) | |
* p(f | g) | |
* p(e | g f) | |
* p(d | f e) | |
* p(c | e d) | |
* p(b | d c) | |
* p(a | c b) | |
*/ | |
template <class Model> void BackwardLanguageModel<Model>::CalcScore(const Phrase &phrase, float &fullScore, float &ngramScore, size_t &oovCount) const | |
{ | |
fullScore = 0; | |
ngramScore = 0; | |
oovCount = 0; | |
if (!phrase.GetSize()) return; | |
lm::ngram::ChartState discarded_sadly; | |
lm::ngram::RuleScore<Model> scorer(*m_ngram, discarded_sadly); | |
UTIL_THROW_IF2(m_beginSentenceFactor == phrase.GetWord(0).GetFactor(m_factorType), | |
"BackwardLanguageModel does not currently support rules that include <s>" | |
); | |
float before_boundary = 0.0f; | |
int lastWord = phrase.GetSize() - 1; | |
int ngramBoundary = m_ngram->Order() - 1; | |
int boundary = ( lastWord < ngramBoundary ) ? 0 : ngramBoundary; | |
int position; | |
for (position = lastWord; position >= 0; position-=1) { | |
const Word &word = phrase.GetWord(position); | |
UTIL_THROW_IF2(word.IsNonTerminal(), | |
"BackwardLanguageModel does not currently support rules that include non-terminals " | |
); | |
lm::WordIndex index = TranslateID(word); | |
scorer.Terminal(index); | |
if (!index) ++oovCount; | |
if (position==boundary) { | |
before_boundary = scorer.Finish(); | |
} | |
} | |
fullScore = scorer.Finish(); | |
ngramScore = TransformLMScore(fullScore - before_boundary); | |
fullScore = TransformLMScore(fullScore); | |
} | |
/** | |
* Calculate the ngram probabilities for the words at the beginning | |
* (and under some circumstances, also at the end) | |
* of the phrase represented by the provided hypothesis. | |
* | |
* Additionally, calculate a new language model state. | |
* | |
* This is best shown by example: | |
* | |
* Assume a trigram language model. | |
* | |
* Assume the previous phrase was "a b c d e f g", | |
* which means the previous language model state is "g f". | |
* | |
* When the phrase corresponding to "a b c d e f g" was previously processed by CalcScore | |
* the following full-order ngrams would have been calculated: | |
* | |
* p(a | c b) | |
* p(b | d c) | |
* p(c | e d) | |
* p(d | f e) | |
* p(e | g f) | |
* | |
* The following less-than-full-order ngrams would also have been calculated by CalcScore: | |
* | |
* p(f | g) | |
* p(g) | |
* | |
* In this method, we now have access to additional context which may allow | |
* us to compute the full-order ngrams for f and g. | |
* | |
* Assume the new provided hypothesis contains the new phrase "h i j k" | |
* | |
* Given these assumptions, this method is responsible | |
* for calculating the scores for the following: | |
* | |
* p(f | h g) | |
* p(g | i h) | |
* | |
* This method must also calculate and return a new language model state. | |
* | |
* In this example, the returned language model state would be "k j" | |
* | |
* If the provided hypothesis represents the end of a completed translation | |
* (all source words have been translated) | |
* then this method is additionally responsible for calculating the following: | |
* | |
* p(j | <s> k) | |
* p(k | <s>) | |
* | |
*/ | |
template <class Model> FFState *BackwardLanguageModel<Model>::Evaluate(const Hypothesis &hypo, const FFState *ps, ScoreComponentCollection *out) const | |
{ | |
// If the current hypothesis contains zero target words | |
if (!hypo.GetCurrTargetLength()) { | |
// reuse and return the previous state | |
std::auto_ptr<BackwardLMState> ret(new BackwardLMState()); | |
ret->state = static_cast<const BackwardLMState&>(*ps).state; | |
return ret.release(); | |
} else { | |
float returnedScore; | |
FFState *returnedState = this->Evaluate(hypo.GetCurrTargetPhrase(), ps, returnedScore); | |
out->PlusEquals(this, returnedScore); | |
return returnedState; | |
} | |
} | |
template <class Model> FFState *BackwardLanguageModel<Model>::Evaluate(const Phrase &phrase, const FFState *ps, float &returnedScore) const | |
{ | |
returnedScore = 0.0f; | |
const lm::ngram::ChartState &previous = static_cast<const BackwardLMState&>(*ps).state; | |
std::auto_ptr<BackwardLMState> ret(new BackwardLMState()); | |
lm::ngram::RuleScore<Model> scorer(*m_ngram, ret->state); | |
int ngramBoundary = m_ngram->Order() - 1; | |
int lastWord = phrase.GetSize() - 1; | |
// Get scores for words at the end of the previous phrase | |
// that are now adjacent to words at the the beginning of this phrase | |
for (int position=std::min( lastWord, ngramBoundary - 1); position >= 0; position-=1) { | |
const Word &word = phrase.GetWord(position); | |
UTIL_THROW_IF2(word.IsNonTerminal(), | |
"BackwardLanguageModel does not currently support rules that include non-terminals " | |
); | |
lm::WordIndex index = TranslateID(word); | |
scorer.Terminal(index); | |
} | |
scorer.NonTerminal(previous); | |
returnedScore = scorer.Finish(); | |
/* | |
out->PlusEquals(this, score); | |
UTIL_THROW_IF( | |
(1==1), | |
util::Exception, | |
"This method (BackwardLanguageModel<Model>::Evaluate) is not yet fully implemented" | |
); | |
*/ | |
return ret.release(); | |
} | |
LanguageModel *ConstructBackwardLM(const std::string &line, const std::string &file, FactorType factorType, bool lazy) | |
{ | |
lm::ngram::ModelType model_type; | |
if (lm::ngram::RecognizeBinary(file.c_str(), model_type)) { | |
switch(model_type) { | |
case lm::ngram::PROBING: | |
return new BackwardLanguageModel<lm::ngram::ProbingModel>(line, file, factorType, lazy); | |
case lm::ngram::REST_PROBING: | |
return new BackwardLanguageModel<lm::ngram::RestProbingModel>(line, file, factorType, lazy); | |
case lm::ngram::TRIE: | |
return new BackwardLanguageModel<lm::ngram::TrieModel>(line, file, factorType, lazy); | |
case lm::ngram::QUANT_TRIE: | |
return new BackwardLanguageModel<lm::ngram::QuantTrieModel>(line, file, factorType, lazy); | |
case lm::ngram::ARRAY_TRIE: | |
return new BackwardLanguageModel<lm::ngram::ArrayTrieModel>(line, file, factorType, lazy); | |
case lm::ngram::QUANT_ARRAY_TRIE: | |
return new BackwardLanguageModel<lm::ngram::QuantArrayTrieModel>(line, file, factorType, lazy); | |
default: | |
UTIL_THROW2("Unrecognized kenlm model type " << model_type); | |
} | |
} else { | |
return new BackwardLanguageModel<lm::ngram::ProbingModel>(line, file, factorType, lazy); | |
} | |
} | |
} // namespace Moses | |