// -*- mode: c++; indent-tabs-mode: nil; tab-width:2 -*- /*********************************************************************** 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 ***********************************************************************/ #ifndef moses_ScoreComponentCollection_h #define moses_ScoreComponentCollection_h #include #include #ifdef MPI_ENABLE #include #include #endif #include "moses/FF/FeatureFunction.h" #include "FeatureVector.h" #include "TypeDef.h" #include "Util.h" #include "util/exception.hh" namespace Moses { /** * Smaller version for just 1 FF. */ struct ScorePair { friend std::ostream& operator<<(std::ostream& os, const ScorePair& rhs); std::vector denseScores; std::map sparseScores; ScorePair() { } ScorePair(const std::vector &other) :denseScores(other) { } void PlusEquals(const ScorePair &other); void PlusEquals(const StringPiece &key, float value); void PlusEquals(const std::vector &other) { UTIL_THROW_IF2(denseScores.size() != other.size(), "Number of scores incorrect"); std::transform(denseScores.begin(), denseScores.end(), other.begin(), denseScores.begin(), std::plus()); } }; /*** An unweighted collection of scores for a translation or step in a translation. * * In the factored phrase-based models that are implemented by moses, there are a set of * scores that come from a variety of sources (translation probabilities, language model * probablilities, distortion probabilities, generation probabilities). Furthermore, while * some of these scores may be 0, this number is fixed (and generally quite small, ie, less * than 15), for a given model. * * The values contained in ScoreComponentCollection objects are unweighted scores (log-probs). * * ScoreComponentCollection objects can be added and subtracted, which makes them appropriate * to be the datatype used to return the result of a score computations (in this case they will * have most values set to zero, except for the ones that are results of the indivudal computation * this will then be added into the "running total" in the Hypothesis. In fact, for a score * to be tracked in the hypothesis (and thus to participate in the decoding process), a class * representing that score must extend the ScoreProducer abstract base class. For an example * refer to the DistortionScoreProducer class. */ class ScoreComponentCollection { friend std::ostream& operator<<(std::ostream& os, const ScoreComponentCollection& rhs); friend void swap(ScoreComponentCollection &first, ScoreComponentCollection &second); private: FVector m_scores; public: // typedef std::pair IndexPair; private: // typedef std::map ScoreIndexMap; // static ScoreIndexMap s_scoreIndexes; static size_t s_denseVectorSize; public: // static IndexPair GetIndexes(const FeatureFunction* sp) { // ScoreIndexMap::const_iterator indexIter = s_scoreIndexes.find(sp); // if (indexIter == s_scoreIndexes.end()) { // std::stringstream strme; // strme << "ERROR: FeatureFunction: " << sp->GetScoreProducerDescription() << // " not registered with ScoreIndexMap" << std::endl; // strme << "You must call ScoreComponentCollection.RegisterScoreProducer() " << // " for every FeatureFunction" << std::endl; // UTIL_THROW2(strme.str()); // } // return indexIter->second; // } public: static void ResetCounter() { s_denseVectorSize = 0; } //! Create a new score collection with all values set to 0.0 ScoreComponentCollection(); //! Clone a score collection ScoreComponentCollection(const ScoreComponentCollection& rhs) : m_scores(rhs.m_scores) { } ScoreComponentCollection& operator=( const ScoreComponentCollection& rhs ) { m_scores = rhs.m_scores; return *this; } /** * Register a ScoreProducer with a fixed number of scores, so that it can * be allocated space in the dense part of the feature vector. **/ static void RegisterScoreProducer(FeatureFunction* scoreProducer); /** Load from file */ bool Load(const std::string& filename) { return m_scores.load(filename); } const FVector& GetScoresVector() const { return m_scores; } const std::valarray &getCoreFeatures() const { return m_scores.getCoreFeatures(); } size_t Size() const { return m_scores.size(); } void Resize() { if (m_scores.coreSize() != s_denseVectorSize) { m_scores.resize(s_denseVectorSize); } } /** Create and FVector with the right number of core features */ static FVector CreateFVector() { return FVector(s_denseVectorSize); } void SetToBinaryOf(const ScoreComponentCollection& rhs) { m_scores.setToBinaryOf(rhs.m_scores); } //! Set all values to 0.0 void ZeroAll() { m_scores.clear(); } void MultiplyEquals(float scalar); void DivideEquals(float scalar); void CoreDivideEquals(float scalar); void DivideEquals(const ScoreComponentCollection& rhs); void MultiplyEquals(const ScoreComponentCollection& rhs); void MultiplyEqualsBackoff(const ScoreComponentCollection& rhs, float backoff); void MultiplyEquals(float core_r0, float sparse_r0); void MultiplyEquals(const FeatureFunction* sp, float scalar); size_t GetNumberWeights(const FeatureFunction* sp); void CoreAssign(const ScoreComponentCollection& rhs) { m_scores.coreAssign(rhs.m_scores); } //! add the score in rhs void PlusEquals(const ScoreComponentCollection& rhs) { m_scores += rhs.m_scores; } // add only sparse features void SparsePlusEquals(const ScoreComponentCollection& rhs) { m_scores.sparsePlusEquals(rhs.m_scores); } // add only core features void CorePlusEquals(const ScoreComponentCollection& rhs) { m_scores.corePlusEquals(rhs.m_scores); } void PlusEquals(const FVector& scores) { m_scores += scores; } //! subtract the score in rhs void MinusEquals(const ScoreComponentCollection& rhs) { m_scores -= rhs.m_scores; } //For features which have an unbounded number of components void MinusEquals(const FeatureFunction*sp, const std::string& name, float score) { FName fname(sp->GetScoreProducerDescription(),name); m_scores[fname] -= score; } //For features which have an unbounded number of components void SparseMinusEquals(const std::string& full_name, float score) { FName fname(full_name); m_scores[fname] -= score; } //! Add scores from a single ScoreProducer only //! The length of scores must be equal to the number of score components //! produced by sp void PlusEquals(const FeatureFunction* sp, const ScoreComponentCollection& scores) { size_t i = sp->GetIndex(); size_t stop = i + sp->GetNumScoreComponents(); for (; i < stop; ++i) m_scores[i] += scores.m_scores[i]; } //! Add scores from a single FeatureFunction only //! The length of scores must be equal to the number of score components //! produced by sp void PlusEquals(const FeatureFunction* sp, const std::vector& scores) { UTIL_THROW_IF2(scores.size() != sp->GetNumScoreComponents(), "Number of scores is incorrect"); size_t offset = sp->GetIndex(); for (size_t i = 0; i < scores.size(); ++i) { m_scores[i + offset] += scores[i]; } } void PlusEquals(const FeatureFunction* sp, float scores[]) { size_t numScores = sp->GetNumScoreComponents(); size_t offset = sp->GetIndex(); for (size_t i = 0; i < numScores; ++i) { m_scores[i + offset] += scores[i]; } } //! Special version PlusEquals(ScoreProducer, vector) //! to add the score from a single ScoreProducer that produces //! a single value void PlusEquals(const FeatureFunction* sp, float score) { UTIL_THROW_IF2(sp->GetNumScoreComponents() != 1, "Number of scores is incorrect"); m_scores[sp->GetIndex()] += score; } //For features which have an unbounded number of components void PlusEquals(const FeatureFunction*sp, const StringPiece& name, float score) { FName fname(sp->GetScoreProducerDescription(),name); m_scores[fname] += score; } void PlusEquals(const FeatureFunction* sp, const ScorePair &scorePair); // Add score by index void PlusEquals(size_t index, float score) { m_scores[index] += score; } //For features which have an unbounded number of components void SparsePlusEquals(const std::string& full_name, float score) { FName fname(full_name); m_scores[fname] += score; } void SparsePlusEquals(const FName& fname, float score) { m_scores[fname] += score; } void Assign(const FeatureFunction* sp, const std::vector& scores); //! Special version Assign(ScoreProducer, vector) //! to add the score from a single ScoreProducer that produces //! a single value void Assign(const FeatureFunction* sp, float score) { UTIL_THROW_IF2(sp->GetNumScoreComponents() != 1, "Feature function must must only contain 1 score"); m_scores[sp->GetIndex()] = score; } // Assign score by index void Assign(size_t index, float score) { m_scores[index] = score; } void Assign(const FeatureFunction*sp, const StringPiece &name, float score) { FName fname(sp->GetScoreProducerDescription(),name); m_scores[fname] = score; } //Read sparse features from string void Assign(const FeatureFunction* sp, const std::string &line); // shortcut: setting the value directly using the feature name void Assign(const std::string name, float score) { FName fname(name); m_scores[fname] = score; } float InnerProduct(const ScoreComponentCollection& rhs) const { return m_scores.inner_product(rhs.m_scores); } float PartialInnerProduct(const FeatureFunction* sp, const std::vector& rhs) const { std::vector lhs = GetScoresForProducer(sp); UTIL_THROW_IF2(lhs.size() != rhs.size(), "Number of weights must match number of scores"); return std::inner_product(lhs.begin(), lhs.end(), rhs.begin(), 0.0f); } //! return a vector of all the scores associated with a certain FeatureFunction std::vector GetScoresForProducer(const FeatureFunction* sp) const { size_t components = sp->GetNumScoreComponents(); std::vector res(components); size_t offset = sp->GetIndex(); for (size_t i = 0; i < res.size(); ++i) { res[i] = m_scores[i + offset]; } return res; } //! get subset of scores that belong to a certain sparse ScoreProducer FVector GetVectorForProducer(const FeatureFunction* sp) const; float GetSparseWeight(const FName& featureName) const { return m_scores[featureName]; } void PrintCoreFeatures() { m_scores.printCoreFeatures(); } void ThresholdScaling(float maxValue) { // find (smallest) factor for which all weights are <= maxValue // 0.1 / 0.14 = 0.714285714 // 0.1 / 0.17 = 0.588235294 m_scores.thresholdScale(maxValue); } void CapMax(float maxValue) { // cap all sparse features to maxValue m_scores.capMax(maxValue); } void CapMin(float minValue) { // cap all sparse features to minValue m_scores.capMin(minValue); } // std::pair GetIndexesForProducer(const FeatureFunction* sp) const { // IndexPair indexPair = GetIndexes(sp); // return indexPair; // } //! if a FeatureFunction produces a single score (for example, a language model score) //! this will return it. If not, this method will throw float GetScoreForProducer(const FeatureFunction* sp) const { UTIL_THROW_IF2(sp->GetNumScoreComponents() != 1, "Feature function must must only contain 1 score"); return m_scores[sp->GetIndex()]; } //For features which have an unbounded number of components float GetScoreForProducer (const FeatureFunction* sp, const std::string& name) const { FName fname(sp->GetScoreProducerDescription(),name); return m_scores[fname]; } float GetWeightedScore() const; void ZeroDenseFeatures(const FeatureFunction* sp); void InvertDenseFeatures(const FeatureFunction* sp); void L1Normalise(); float GetL1Norm() const; float GetL2Norm() const; float GetLInfNorm() const; size_t L1Regularize(float lambda); void L2Regularize(float lambda); size_t SparseL1Regularize(float lambda); void SparseL2Regularize(float lambda); void Save(const std::string& filename) const; void Save(std::ostream&, bool multiline=true) const; void IncrementSparseHopeFeatures() { m_scores.incrementSparseHopeFeatures(); } void IncrementSparseFearFeatures() { m_scores.incrementSparseFearFeatures(); } void PrintSparseHopeFeatureCounts(std::ofstream& out) { m_scores.printSparseHopeFeatureCounts(out); } void PrintSparseFearFeatureCounts(std::ofstream& out) { m_scores.printSparseFearFeatureCounts(out); } void PrintSparseHopeFeatureCounts() { m_scores.printSparseHopeFeatureCounts(); } void PrintSparseFearFeatureCounts() { m_scores.printSparseFearFeatureCounts(); } size_t PruneSparseFeatures(size_t threshold) { return m_scores.pruneSparseFeatures(threshold); } size_t PruneZeroWeightFeatures() { return m_scores.pruneZeroWeightFeatures(); } void UpdateConfidenceCounts(ScoreComponentCollection &weightUpdate, bool signedCounts) { m_scores.updateConfidenceCounts(weightUpdate.m_scores, signedCounts); } void UpdateLearningRates(float decay_core, float decay_sparse, ScoreComponentCollection &confidenceCounts, float core_r0, float sparse_r0) { m_scores.updateLearningRates(decay_core, decay_sparse, confidenceCounts.m_scores, core_r0, sparse_r0); } void Merge(const ScoreComponentCollection &other) { m_scores.merge(other.m_scores); } void OutputAllFeatureScores(std::ostream &out, bool with_labels) const; void OutputFeatureScores(std::ostream& out, Moses::FeatureFunction const* ff, std::string &lastName, bool with_labels) const; #ifdef MPI_ENABLE public: friend class boost::serialization::access; private: //serialization template void save(Archive &ar, const unsigned int version) const { ar << m_scores; } template void load(Archive &ar, const unsigned int version) { ar >> m_scores; } BOOST_SERIALIZATION_SPLIT_MEMBER() #endif }; struct SCCPlus { ScoreComponentCollection operator() (const ScoreComponentCollection& lhs, const ScoreComponentCollection& rhs) { ScoreComponentCollection sum(lhs); sum.PlusEquals(rhs); return sum; } }; inline void swap(ScoreComponentCollection &first, ScoreComponentCollection &second) { swap(first.m_scores, second.m_scores); } } #endif