| | #include <vector> |
| | #include "BilingualLM.h" |
| | #include "moses/ScoreComponentCollection.h" |
| |
|
| | using namespace std; |
| |
|
| | namespace Moses |
| | { |
| |
|
| | |
| | BilingualLM::BilingualLM(const std::string &line) |
| | : StatefulFeatureFunction(1, line), |
| | word_factortype(0) |
| | { |
| | FactorCollection& factorFactory = FactorCollection::Instance(); |
| | BOS_factor = factorFactory.AddFactor(BOS_); |
| | BOS_word.SetFactor(0, BOS_factor); |
| | EOS_factor = factorFactory.AddFactor(EOS_); |
| | EOS_word.SetFactor(0, EOS_factor); |
| |
|
| | } |
| |
|
| | void BilingualLM::Load(AllOptions::ptr const& opts) |
| | { |
| | m_options = opts; |
| | ReadParameters(); |
| | loadModel(); |
| | } |
| |
|
| | |
| | |
| | void BilingualLM::requestPrevTargetNgrams( |
| | const Hypothesis &cur_hypo, int amount, std::vector<int> &words) const |
| | { |
| | const Hypothesis * prev_hyp = cur_hypo.GetPrevHypo(); |
| | int found = 0; |
| |
|
| | while (prev_hyp && found != amount) { |
| | const TargetPhrase& currTargetPhrase = prev_hyp->GetCurrTargetPhrase(); |
| | for (int i = currTargetPhrase.GetSize() - 1; i> -1; i--) { |
| | if (found != amount) { |
| | const Word& word = currTargetPhrase.GetWord(i); |
| | words[found] = getNeuralLMId(word, false); |
| | found++; |
| | } else { |
| | return; |
| | } |
| | } |
| |
|
| | prev_hyp = prev_hyp->GetPrevHypo(); |
| | } |
| |
|
| | int neuralLM_wordID = getNeuralLMId(BOS_word, false); |
| | for (int i = found; i < amount; i++) { |
| | words[i] = neuralLM_wordID; |
| | } |
| | } |
| |
|
| | |
| | |
| | void BilingualLM::getTargetWords( |
| | const Hypothesis &cur_hypo, |
| | const TargetPhrase &targetPhrase, |
| | int current_word_index, |
| | std::vector<int> &words) const |
| | { |
| | |
| | int additional_needed = current_word_index - target_ngrams; |
| | if (additional_needed < 0) { |
| | additional_needed = -additional_needed; |
| | std::vector<int> prev_words(additional_needed); |
| | requestPrevTargetNgrams(cur_hypo, additional_needed, prev_words); |
| | for (int i = additional_needed - 1; i >= 0; i--) { |
| | words.push_back(prev_words[i]); |
| | } |
| | } |
| |
|
| | if (words.size() > 0) { |
| | |
| | |
| | for (int i = 0; i <= current_word_index; i++) { |
| | const Word& word = targetPhrase.GetWord(i); |
| | words.push_back(getNeuralLMId(word, false)); |
| | } |
| | } else { |
| | |
| | for (int i = current_word_index - target_ngrams; i <= current_word_index; i++) { |
| | const Word& word = targetPhrase.GetWord(i); |
| | words.push_back(getNeuralLMId(word, false)); |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | size_t BilingualLM::selectMiddleAlignment( |
| | const set<size_t>& alignment_links) const |
| | { |
| |
|
| | set<size_t>::iterator it = alignment_links.begin(); |
| | for (size_t i = 0; i < (alignment_links.size() - 1) / 2; ++i) { |
| | ++it; |
| | } |
| |
|
| | return *it; |
| | } |
| |
|
| | void BilingualLM::getSourceWords( |
| | const TargetPhrase &targetPhrase, |
| | int targetWordIdx, |
| | const Sentence &source_sent, |
| | const Range &sourceWordRange, |
| | std::vector<int> &words) const |
| | { |
| | |
| |
|
| | |
| | const AlignmentInfo& alignments = targetPhrase.GetAlignTerm(); |
| |
|
| | |
| | |
| | std::set<size_t> last_word_al; |
| | for (int j = 0; j < targetPhrase.GetSize(); j++) { |
| | |
| | if ((targetWordIdx + j) < targetPhrase.GetSize()) { |
| | last_word_al = alignments.GetAlignmentsForTarget(targetWordIdx + j); |
| | if (!last_word_al.empty()) { |
| | break; |
| | } |
| | } |
| |
|
| | |
| | if ((targetWordIdx - j) >= 0) { |
| | last_word_al = alignments.GetAlignmentsForTarget(targetWordIdx - j); |
| | if (!last_word_al.empty()) { |
| | break; |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| |
|
| | |
| | |
| | |
| | UTIL_THROW_IF2(last_word_al.size() == 0, |
| | "A target phrase with no alignments detected! " << targetPhrase << "Check if there is something wrong with your phrase table."); |
| | size_t source_center_index = selectMiddleAlignment(last_word_al); |
| | |
| | size_t phrase_start_pos = sourceWordRange.GetStartPos(); |
| | |
| | size_t source_word_mid_idx = phrase_start_pos + source_center_index; |
| |
|
| | appendSourceWordsToVector(source_sent, words, source_word_mid_idx); |
| | } |
| |
|
| | size_t BilingualLM::getState(const Hypothesis& cur_hypo) const |
| | { |
| | const TargetPhrase &targetPhrase = cur_hypo.GetCurrTargetPhrase(); |
| | size_t hashCode = 0; |
| |
|
| | |
| | int additional_needed = targetPhrase.GetSize() - target_ngrams; |
| | if (additional_needed < 0) { |
| | additional_needed = -additional_needed; |
| | std::vector<int> prev_words(additional_needed); |
| | requestPrevTargetNgrams(cur_hypo, additional_needed, prev_words); |
| | for (int i = additional_needed - 1; i >= 0; i--) { |
| | boost::hash_combine(hashCode, prev_words[i]); |
| | } |
| |
|
| | |
| | for (int i = 0; i < targetPhrase.GetSize(); i++) { |
| | const Word& word = targetPhrase.GetWord(i); |
| | int neuralLM_wordID = getNeuralLMId(word, false); |
| | boost::hash_combine(hashCode, neuralLM_wordID); |
| | } |
| | } else { |
| | |
| | for (int i = targetPhrase.GetSize() - target_ngrams; i < targetPhrase.GetSize(); i++) { |
| | const Word& word = targetPhrase.GetWord(i); |
| | int neuralLM_wordID = getNeuralLMId(word, false); |
| |
|
| | boost::hash_combine(hashCode, neuralLM_wordID); |
| | } |
| | } |
| |
|
| | return hashCode; |
| | } |
| |
|
| | FFState* BilingualLM::EvaluateWhenApplied( |
| | const Hypothesis& cur_hypo, |
| | const FFState* prev_state, |
| | ScoreComponentCollection* accumulator) const |
| | { |
| | Manager& manager = cur_hypo.GetManager(); |
| | const Sentence& source_sent = static_cast<const Sentence&>(manager.GetSource()); |
| |
|
| | |
| | std::vector<int> source_words; |
| | source_words.reserve(source_ngrams); |
| | std::vector<int> target_words; |
| | target_words.reserve(target_ngrams); |
| |
|
| | float value = 0; |
| | const TargetPhrase& currTargetPhrase = cur_hypo.GetCurrTargetPhrase(); |
| | const Range& sourceWordRange = cur_hypo.GetCurrSourceWordsRange(); |
| |
|
| | |
| | for (int i = 0; i < currTargetPhrase.GetSize(); i++) { |
| | getSourceWords( |
| | currTargetPhrase, i, source_sent, sourceWordRange, source_words); |
| | getTargetWords(cur_hypo, currTargetPhrase, i, target_words); |
| | value += Score(source_words, target_words); |
| |
|
| | |
| | source_words.clear(); |
| | target_words.clear(); |
| | } |
| |
|
| | size_t new_state = getState(cur_hypo); |
| | accumulator->PlusEquals(this, value); |
| |
|
| | return new BilingualLMState(new_state); |
| | } |
| |
|
| | void BilingualLM::getAllTargetIdsChart(const ChartHypothesis& cur_hypo, size_t featureID, std::vector<int>& wordIds) const |
| | { |
| | const TargetPhrase targetPhrase = cur_hypo.GetCurrTargetPhrase(); |
| |
|
| | for (int i = 0; i < targetPhrase.GetSize(); i++) { |
| | if (targetPhrase.GetWord(i).IsNonTerminal()) { |
| | const ChartHypothesis * prev_hypo = cur_hypo.GetPrevHypo(targetPhrase.GetAlignNonTerm().GetNonTermIndexMap()[i]); |
| | const BilingualLMState * prev_state = static_cast<const BilingualLMState *>(prev_hypo->GetFFState(featureID)); |
| | const std::vector<int> prevWordIDs = prev_state->GetWordIdsVector(); |
| | for (std::vector<int>::const_iterator it = prevWordIDs.begin(); it!= prevWordIDs.end(); it++) { |
| | wordIds.push_back(*it); |
| | } |
| | } else { |
| | wordIds.push_back(getNeuralLMId(targetPhrase.GetWord(i), false)); |
| | } |
| | } |
| | } |
| |
|
| | void BilingualLM::getAllAlignments(const ChartHypothesis& cur_hypo, size_t featureID, std::vector<int>& word_alignments) const |
| | { |
| | const TargetPhrase targetPhrase = cur_hypo.GetCurrTargetPhrase(); |
| | int source_word_mid_idx; |
| |
|
| | |
| | const AlignmentInfo& alignments = targetPhrase.GetAlignTerm(); |
| |
|
| | |
| | std::vector<int> absolute_source_position (cur_hypo.GetCurrSourceRange().GetNumWordsCovered(), 0); |
| |
|
| | absolute_source_position[0] = cur_hypo.GetCurrSourceRange().GetStartPos(); |
| | |
| | for (int i = 0; i < targetPhrase.GetSize(); i++) { |
| | if (targetPhrase.GetWord(i).IsNonTerminal()) { |
| | const ChartHypothesis * prev_hypo = cur_hypo.GetPrevHypo(targetPhrase.GetAlignNonTerm().GetNonTermIndexMap()[i]); |
| | absolute_source_position[targetPhrase.GetAlignNonTerm().GetNonTermIndexMap2()[i]] = prev_hypo->GetCurrSourceRange().GetEndPos(); |
| | } |
| | } |
| |
|
| | |
| | for (int i = 0; i != absolute_source_position.size(); i++) { |
| | if (i && absolute_source_position[i] == 0) { |
| | absolute_source_position[i] = absolute_source_position[i-1] + 1; |
| | } |
| | } |
| |
|
| | for (int i = 0; i < targetPhrase.GetSize(); i++) { |
| | |
| | |
| | if (targetPhrase.GetWord(i).IsNonTerminal()) { |
| | |
| | const ChartHypothesis * prev_hypo = cur_hypo.GetPrevHypo(targetPhrase.GetAlignNonTerm().GetNonTermIndexMap()[i]); |
| | const BilingualLMState * prev_state = static_cast<const BilingualLMState *>(prev_hypo->GetFFState(featureID)); |
| | const std::vector<int> prevWordAls = prev_state->GetWordAlignmentVector(); |
| | for (std::vector<int>::const_iterator it = prevWordAls.begin(); it!= prevWordAls.end(); it++) { |
| | word_alignments.push_back(*it); |
| | } |
| | } else { |
| | bool resolvedIndexis = false; |
| | std::set<size_t> word_al = alignments.GetAlignmentsForTarget(i); |
| | if (word_al.empty()) { |
| | for (int j = 1; j < targetPhrase.GetSize(); j++) { |
| | |
| | |
| | if ((i+j) < targetPhrase.GetSize()) { |
| | |
| | if (targetPhrase.GetWord(i + j).IsNonTerminal()) { |
| | const ChartHypothesis * prev_hypo = cur_hypo.GetPrevHypo(targetPhrase.GetAlignNonTerm().GetNonTermIndexMap()[i+j]); |
| | const BilingualLMState * prev_state = static_cast<const BilingualLMState *>(prev_hypo->GetFFState(featureID)); |
| | source_word_mid_idx = prev_state->GetWordAlignmentVector().front(); |
| | resolvedIndexis = true; |
| | break; |
| | } |
| | word_al = alignments.GetAlignmentsForTarget(i + j); |
| | if (!word_al.empty()) { |
| | break; |
| | } |
| | } |
| |
|
| | if ((i - j) >= 0) { |
| | |
| | if (targetPhrase.GetWord(i - j).IsNonTerminal()) { |
| | const ChartHypothesis * prev_hypo = cur_hypo.GetPrevHypo(targetPhrase.GetAlignNonTerm().GetNonTermIndexMap()[i-j]); |
| | const BilingualLMState * prev_state = static_cast<const BilingualLMState *>(prev_hypo->GetFFState(featureID)); |
| | source_word_mid_idx = prev_state->GetWordAlignmentVector().back(); |
| | resolvedIndexis = true; |
| | break; |
| | } |
| |
|
| | word_al = alignments.GetAlignmentsForTarget(i - j); |
| | if (!word_al.empty()) { |
| | break; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | if (!resolvedIndexis) { |
| | |
| | |
| | UTIL_THROW_IF2(word_al.size() == 0, |
| | "A target phrase with no alignments detected! " << targetPhrase << "Check if there is something wrong with your phrase table."); |
| | size_t source_center_index = selectMiddleAlignment(word_al); |
| | |
| | source_word_mid_idx = absolute_source_position[source_center_index]; |
| | } |
| | word_alignments.push_back(source_word_mid_idx); |
| | } |
| | } |
| |
|
| | } |
| |
|
| | size_t BilingualLM::getStateChart(std::vector<int>& neuralLMids) const |
| | { |
| | size_t hashCode = 0; |
| | for (int i = neuralLMids.size() - target_ngrams; i < neuralLMids.size(); i++) { |
| | int neuralLM_wordID; |
| | if (i < 0) { |
| | neuralLM_wordID = getNeuralLMId(BOS_word, false); |
| | } else { |
| | neuralLM_wordID = neuralLMids[i]; |
| | } |
| | boost::hash_combine(hashCode, neuralLM_wordID); |
| | } |
| | return hashCode; |
| | } |
| |
|
| | void BilingualLM::getTargetWordsChart( |
| | std::vector<int>& neuralLMids, |
| | int current_word_index, |
| | std::vector<int>& words, |
| | bool sentence_begin) const |
| | { |
| |
|
| | for (int i = current_word_index - target_ngrams; i <= current_word_index; i++) { |
| | if (i < 0) { |
| | if (sentence_begin) { |
| | words.push_back(getNeuralLMId(BOS_word, false)); |
| | } else { |
| | words.push_back(getNeuralLMId(getNullWord(), false)); |
| | } |
| | } else { |
| | words.push_back(neuralLMids[i]); |
| | } |
| | } |
| | } |
| |
|
| | void BilingualLM::appendSourceWordsToVector(const Sentence &source_sent, std::vector<int> &words, int source_word_mid_idx) const |
| | { |
| | |
| | |
| | |
| | int begin_idx; |
| | int end_idx; |
| |
|
| | if (source_ngrams % 2 == 0) { |
| | begin_idx = source_word_mid_idx - source_ngrams / 2 + 1; |
| | end_idx = source_word_mid_idx + source_ngrams / 2; |
| | } else { |
| | begin_idx = source_word_mid_idx - (source_ngrams - 1) / 2; |
| | end_idx = source_word_mid_idx + (source_ngrams - 1) / 2; |
| | } |
| |
|
| | |
| | for (int j = begin_idx; j <= end_idx; j++) { |
| | int neuralLM_wordID; |
| | if (j < 0) { |
| | neuralLM_wordID = getNeuralLMId(BOS_word, true); |
| | } else if (j >= source_sent.GetSize()) { |
| | neuralLM_wordID = getNeuralLMId(EOS_word, true); |
| | } else { |
| | const Word& word = source_sent.GetWord(j); |
| | neuralLM_wordID = getNeuralLMId(word, true); |
| | } |
| | words.push_back(neuralLM_wordID); |
| | } |
| | } |
| |
|
| | FFState* BilingualLM::EvaluateWhenApplied( |
| | const ChartHypothesis& cur_hypo, |
| | int featureID, |
| | ScoreComponentCollection* accumulator) const |
| | { |
| | |
| | std::vector<int> source_words; |
| | source_words.reserve(source_ngrams); |
| | std::vector<int> target_words; |
| | target_words.reserve(target_ngrams+1); |
| |
|
| | float value = 0; |
| | const TargetPhrase& currTargetPhrase = cur_hypo.GetCurrTargetPhrase(); |
| |
|
| | std::vector<int> neuralLMids; |
| | std::vector<int> alignments; |
| | |
| | int future_size = currTargetPhrase.GetNumTerminals(); |
| | for (int i =0; i<currTargetPhrase.GetNumNonTerminals(); i++) { |
| | const ChartHypothesis * prev_hypo = cur_hypo.GetPrevHypo(i); |
| | future_size += prev_hypo->GetCurrTargetPhrase().GetSize(); |
| | } |
| | neuralLMids.reserve(future_size); |
| | alignments.reserve(future_size); |
| |
|
| | getAllTargetIdsChart(cur_hypo, featureID, neuralLMids); |
| | getAllAlignments(cur_hypo, featureID, alignments); |
| |
|
| | bool sentence_begin = false; |
| | if (neuralLMids[0] == getNeuralLMId(BOS_word, false)) { |
| | sentence_begin = true; |
| | } |
| |
|
| | |
| | const ChartManager& manager = cur_hypo.GetManager(); |
| | const Sentence& source_sent = static_cast<const Sentence&>(manager.GetSource()); |
| |
|
| | for (int i = 0; i < neuralLMids.size(); i++) { |
| |
|
| | |
| | appendSourceWordsToVector(source_sent, source_words, alignments[i]); |
| | getTargetWordsChart(neuralLMids, i, target_words, sentence_begin); |
| |
|
| | value += Score(source_words, target_words); |
| |
|
| | |
| | source_words.clear(); |
| | target_words.clear(); |
| |
|
| | } |
| | size_t new_state = getStateChart(neuralLMids); |
| |
|
| | |
| | for (std::vector<const ChartHypothesis*>::const_iterator iter = cur_hypo.GetPrevHypos().begin(); iter != cur_hypo.GetPrevHypos().end(); ++iter) { |
| | const ChartHypothesis &prevHypo = **iter; |
| | value -= (prevHypo.GetScoreBreakdown().GetScoreForProducer(this)); |
| | } |
| |
|
| | accumulator->PlusEquals(this, value); |
| |
|
| | return new BilingualLMState(new_state, alignments, neuralLMids); |
| | } |
| |
|
| | void BilingualLM::SetParameter(const std::string& key, const std::string& value) |
| | { |
| | if (key == "path") { |
| | m_filePath = value; |
| | } else { |
| | StatefulFeatureFunction::SetParameter(key, value); |
| | } |
| | } |
| |
|
| | } |
| |
|
| |
|