From 78a5f4297dcfce6c4a904322c2e989b612a6105a Mon Sep 17 00:00:00 2001 From: "graehl@gmail.com" Date: Sat, 7 Aug 2010 08:35:19 +0000 Subject: cdec -A "LanguageModelFsa lm.gz" works git-svn-id: https://ws10smt.googlecode.com/svn/trunk@490 ec762483-ff6d-05da-a07a-a48fb63a330f --- decoder/apply_fsa_models.cc | 5 ++- decoder/apply_fsa_models.h | 5 ++- decoder/apply_models.cc | 4 +-- decoder/cdec.cc | 22 ++++++++---- decoder/cdec_ff.cc | 16 +++++---- decoder/ff.cc | 46 ++++-------------------- decoder/ff.h | 52 +++++++++++++++++++++++++-- decoder/ff_factory.cc | 11 ++---- decoder/ff_from_fsa.h | 10 ++++-- decoder/ff_fsa.h | 6 ++++ decoder/ff_fsa_data.h | 5 ++- decoder/ff_fsa_dynamic.h | 87 +++++++++++++++++++++++++++++++++++++++++++-- decoder/ff_register.h | 8 +++-- decoder/filelib.h | 8 ++--- decoder/fsa-hiero.ini | 3 +- decoder/null_deleter.h | 9 +++++ 16 files changed, 213 insertions(+), 84 deletions(-) create mode 100755 decoder/null_deleter.h (limited to 'decoder') diff --git a/decoder/apply_fsa_models.cc b/decoder/apply_fsa_models.cc index 27773b0d..01de62d3 100755 --- a/decoder/apply_fsa_models.cc +++ b/decoder/apply_fsa_models.cc @@ -1,6 +1,7 @@ #include "apply_fsa_models.h" #include "hg.h" #include "ff_fsa_dynamic.h" +#include "ff_from_fsa.h" #include "feature_vector.h" #include "stringlib.h" #include "apply_models.h" @@ -27,7 +28,9 @@ struct ApplyFsa { } void ApplyBottomUp() { assert(cfg.IsBottomUp()); - vector ffs; + FeatureFunctionFromFsa buff(&fsa); + buff.Init(); // mandatory to call this (normally factory would do it) + vector ffs(1,&buff); ModelSet models(weights, ffs); IntersectionConfiguration i(cfg.BottomUpAlgorithm(),cfg.pop_limit); ApplyModelSet(ih,smeta,models,i,oh); diff --git a/decoder/apply_fsa_models.h b/decoder/apply_fsa_models.h index 64ebab39..3dce5e82 100755 --- a/decoder/apply_fsa_models.h +++ b/decoder/apply_fsa_models.h @@ -23,7 +23,10 @@ struct ApplyFsaBy { int algorithm; std::string name() const; friend inline std::ostream &operator << (std::ostream &o,ApplyFsaBy const& c) { - return o << c.name(); + o << c.name(); + if (c.algorithm==BU_CUBE) + o << "("< max_pl_for_large && in.nodes_.size() > 80000) { diff --git a/decoder/cdec.cc b/decoder/cdec.cc index 72f0b95e..29070a69 100644 --- a/decoder/cdec.cc +++ b/decoder/cdec.cc @@ -68,7 +68,7 @@ inline string str(char const* name,po::variables_map const& conf) { shared_ptr make_ff(string const& ffp,bool verbose_feature_functions,char const* pre="") { string ff, param; SplitCommandAndParam(ffp, &ff, ¶m); - cerr << "Feature: " << ff; + cerr << pre << "feature: " << ff; if (param.size() > 0) cerr << " (with config parameters '" << param << "')\n"; else cerr << " (no config parameters)\n"; shared_ptr pf = ff_registry.Create(ff, param); @@ -470,7 +470,9 @@ int main(int argc, char** argv) { vector > pffs,prelm_only_ffs; vector late_ffs,prelm_ffs; if (conf.count("feature_function") > 0) { - const vector& add_ffs = conf["feature_function"].as >(); + vector add_ffs; +// const vector& add_ffs = conf["feature_function"].as >(); + store_conf(conf,"feature_function",&add_ffs); for (int i = 0; i < add_ffs.size(); ++i) { pffs.push_back(make_ff(add_ffs[i],verbose_feature_functions)); FeatureFunction const* p=pffs.back().get(); @@ -484,7 +486,9 @@ int main(int argc, char** argv) { } } if (conf.count("prelm_feature_function") > 0) { - const vector& add_ffs = conf["prelm_feature_function"].as >(); + vector add_ffs; + store_conf(conf,"prelm_feature_function",&add_ffs); +// const vector& add_ffs = conf["prelm_feature_function"].as >(); for (int i = 0; i < add_ffs.size(); ++i) { prelm_only_ffs.push_back(make_ff(add_ffs[i],verbose_feature_functions,"prelm-only ")); prelm_ffs.push_back(prelm_only_ffs.back().get()); @@ -494,12 +498,16 @@ int main(int argc, char** argv) { vector > fsa_ffs; vector fsa_names; store_conf(conf,"fsa_feature_function",&fsa_names); + for (int i=0;i1) { //FIXME: support N fsa ffs. cerr<<"Only the first fsa FF will be used (FIXME).\n"; - fsa_names.resize(1); - for (int i=0;idescribe()<(true,false); - RegisterFsaImpl(true,false); - RegisterFF(); - RegisterFsaImpl(true,false); // same as LM but using fsa wrapper - ff_registry.Register("LanguageModelFsaDynamic",new FFFactory > >); // test correctness of FsaFeatureFunctionDynamic erasure + //TODO: these are worthless example target FSA ffs. remove later + RegisterFsaImpl(true); + RegisterFsaImpl(true); + RegisterFsaImpl(true); +// ff_registry.Register("LanguageModelFsaDynamic",new FFFactory > >); // to test correctness of FsaFeatureFunctionDynamic erasure + RegisterFsaDynToFF(); + RegisterFsaImpl(true); // same as LM but using fsa wrapper RegisterFsaDynToFF(); + RegisterFF(); + RegisterFF(); RegisterFF(); RegisterFF(); RegisterFF(); - //TODO: worthless example target FSA ffs. remove later ff_registry.Register(new FFFactory); // same as WordPenalty, but implemented using ff_fsa - ff_registry.Register(new FFFactory >); //TODO: use for all features the new Register which requires static FF::usage(false,false) give name #ifdef HAVE_RANDLM diff --git a/decoder/ff.cc b/decoder/ff.cc index 5c52ca2b..68249b42 100644 --- a/decoder/ff.cc +++ b/decoder/ff.cc @@ -36,47 +36,10 @@ Features FeatureFunction::single_feature(WordID feat) { } Features ModelSet::all_features(std::ostream *warn,bool warn0) { - typedef Features FFS; - FFS ffs; -#define WARNFF(x) do { if (warn) { *warn << "WARNING: "<< x ; *warn< FFM; - FFM ff_from; - for (unsigned i=0;i= weights_.size()) - weights_.resize(fid+1); - if (warn0 || fid) { - pair i_new=ff_from.insert(FFM::value_type(fid,ffname)); - if (i_new.second) { - if (fid) - ffs.push_back(fid); - else - WARNFF("Feature id 0 for "<second); - } - } - } - if (n0) - WARNFF(ffname<<" (models["< #include "fdict.h" #include "hg.h" +#include "feature_vector.h" class SentenceMetadata; class FeatureFunction; // see definition below @@ -54,7 +55,7 @@ public: // returns the number of bytes of context that this feature function will // (maximally) use. By default, 0 ("stateless" models in Hiero/Joshua). // NOTE: this value is fixed for the instance of your class, you cannot - // use different amounts of memory for different nodes in the forest. + // use different amounts of memory for different nodes in the forest. this will be read as soon as you create a ModelSet, then fixed forever on inline int NumBytesContext() const { return state_size_; } // Compute the feature values and (if this applies) the estimates of the @@ -196,6 +197,52 @@ class ArityPenalty : public FeatureFunction { const double value_; }; +void show_features(Features const& features,DenseWeightVector const& weights,std::ostream &out,std::ostream &warn,bool warn_zero_wt=true); //show features and weights + +template +Features all_features(std::vector const& models_,DenseWeightVector &weights_,std::ostream *warn=0,bool warn_fid_0=false) { + using namespace std; + Features ffs; +#define WARNFF(x) do { if (warn) { *warn << "WARNING: "<< x << endl; } } while(0) + typedef map FFM; + FFM ff_from; + for (unsigned i=0;iname_; + Features si=models_[i]->features(); + if (si.empty()) { + WARNFF(ffname<<" doesn't yet report any feature IDs - either supply feature weight, or use --no_freeze_feature_set, or implement features() method"); + } + unsigned n0=0; + for (unsigned j=0;j= weights_.size()) + weights_.resize(fid+1); + if (warn_fid_0 || fid) { + pair i_new=ff_from.insert(FFM::value_type(fid,ffname)); + if (i_new.second) { + if (fid) + ffs.push_back(fid); + else + WARNFF("Feature id 0 for "<second); + } + } + } + if (n0) + WARNFF(ffname<<" (models["< +void show_all_features(std::vector const& models_,DenseWeightVector &weights_,std::ostream &out,std::ostream &warn,bool warn_fid_0=true,bool warn_zero_wt=true) { + return show_features(all_features(models_,weights_,&warn,warn_fid_0),weights_,out,warn,warn_zero_wt); +} + + // this class is a set of FeatureFunctions that can be used to score, rescore, // etc. a (translation?) forest class ModelSet { @@ -224,7 +271,8 @@ class ModelSet { bool stateless() const { return !state_size_; } Features all_features(std::ostream *warnings=0,bool warn_fid_zero=false); // this will warn about duplicate features as well (one function overwrites the feature of another). also resizes weights_ so it is large enough to hold the (0) weight for the largest reported feature id. since 0 is a NULL feature id, it's never included. if warn_fid_zero, then even the first 0 id is - void show_features(std::ostream &out,std::ostream &warn,bool warn_zero_wt=true); //show features and weights + void show_features(std::ostream &out,std::ostream &warn,bool warn_zero_wt=true); + private: std::vector models_; std::vector weights_; diff --git a/decoder/ff_factory.cc b/decoder/ff_factory.cc index 767cc675..25d37648 100644 --- a/decoder/ff_factory.cc +++ b/decoder/ff_factory.cc @@ -17,10 +17,9 @@ void UntypedFactoryRegistry::clear() { reg_.clear(); } -bool UntypedFactoryRegistry::parse_debug(std::string & param) { +bool UntypedFactoryRegistry::parse_debug(std::string & p) { int pl=debug_pre.size(); bool space=false; - std::string p=param; bool debug=match_begin(p,debug_pre)&& (p.size()==pl || (space=(p[pl]==' '))); if (debug) @@ -70,13 +69,7 @@ FsaFFRegistry fsa_ff_registry; FFRegistry ff_registry; /* -namespace { -struct null_deleter -{ - template - void operator()(F const& f) const { } -}; - +#include "null_deleter.h" boost::shared_ptr global_fsa_ff_registry(&fsa_ff_registry,null_deleter()); boost::shared_ptr global_ff_registry(&ff_registry,null_deleter()); */ diff --git a/decoder/ff_from_fsa.h b/decoder/ff_from_fsa.h index ec1a28fa..26aca048 100755 --- a/decoder/ff_from_fsa.h +++ b/decoder/ff_from_fsa.h @@ -28,7 +28,12 @@ class FeatureFunctionFromFsa : public FeatureFunction { typedef WordID *W; typedef WordID const* WP; public: - FeatureFunctionFromFsa(std::string const& param) : ff(param) { + template + FeatureFunctionFromFsa(I const& param) : ff(param) { + debug_=true; // because factory won't set until after we construct. + } + template + FeatureFunctionFromFsa(I & param) : ff(param) { debug_=true; // because factory won't set until after we construct. } @@ -234,7 +239,7 @@ public: assert(left_end(w2,w2+2)==w2+1); } - // override from FeatureFunction; should be called by factory after constructor. + // override from FeatureFunction; should be called by factory after constructor. we'll also call in our own ctor void Init() { ff.Init(); ff.sync(); @@ -246,6 +251,7 @@ public: SetStateSize(ssz+state_offset); assert(!ssz == !M); // no fsa state <=> markov order 0 } + private: Impl ff; int M; // markov order (ctx len) diff --git a/decoder/ff_fsa.h b/decoder/ff_fsa.h index 6416151c..18e90bf1 100755 --- a/decoder/ff_fsa.h +++ b/decoder/ff_fsa.h @@ -91,6 +91,12 @@ struct FsaFeatureFunctionBase : public FsaFeatureFunctionData { public: int fid_; // you can have more than 1 feature of course. + std::string describe() const { + std::ostringstream o; + o<<*this; + return o.str(); + } + // can override to different return type, e.g. just return feats: Featval describe_features(FeatureVector const& feats) const { return feats.get(fid_); diff --git a/decoder/ff_fsa_data.h b/decoder/ff_fsa_data.h index 2f0c55b8..e60bce45 100755 --- a/decoder/ff_fsa_data.h +++ b/decoder/ff_fsa_data.h @@ -20,7 +20,6 @@ struct FsaFeatureFunctionData FsaFeatureFunctionData *sync_to_; void sync() const { // call this if you modify any fields after your constructor is done - if (sync_to_) { DBGINIT("sync to "<<*sync_to_); *sync_to_=*this; @@ -31,7 +30,7 @@ struct FsaFeatureFunctionData } friend std::ostream &operator<<(std::ostream &o,FsaFeatureFunctionData const& d) { - o << "[FSA "< + FsaFeatureFunctionDynamic(I const& param) : impl(param) { Init(); } private: Impl impl; +}; + +// constructor takes ptr or shared_ptr to Impl, otherwise same as above - note: not virtual +template +struct FsaFeatureFunctionPimpl : public FsaFeatureFunctionData { + typedef boost::shared_ptr Pimpl; + static const bool simple_phrase_score=Impl::simple_phrase_score; + Impl const& d() const { return *p_; } + int markov_order() const { return d().markov_order(); } + + std::string describe() const { + return d().describe(); + } + + void ScanAccum(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, + WordID w,void const* state,void *next_state,Accum *a) const { + return d().ScanAccum(smeta,edge,w,state,next_state,a); + } + + void ScanPhraseAccum(SentenceMetadata const& smeta,Hypergraph::Edge const & edge, + WordID const* i, WordID const* end, + void const* state,void *next_state,Accum *a) const { + return d().ScanPhraseAccum(smeta,edge,i,end,state,next_state,a); + } + + void ScanPhraseAccumOnly(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, + WordID const* i, WordID const* end, + void const* state,Accum *a) const { + return d().ScanPhraseAccumOnly(smeta,edge,i,end,state,a); + } + + void *ScanPhraseAccumBounce(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,void *cs,void *ns,Accum *a) const { + return d().ScanPhraseAccumBounce(smeta,edge,i,end,cs,ns,a); + } + int early_score_words(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,Accum *accum) const { + return d().early_score_words(smeta,edge,i,end,accum); + } + + static std::string usage(bool param,bool verbose) { + return Impl::usage(param,verbose); + } + + std::string usage_v(bool param,bool verbose) const { + return Impl::usage(param,verbose); + } + + void print_state(std::ostream &o,void const*state) const { + return d().print_state(o,state); + } + +#if 0 + // this and Init() don't touch p_ because we want to leave the original alone. + void init_name_debug(std::string const& n,bool debug) { + FsaFeatureFunctionData::init_name_debug(n,debug); + } +#endif + void Init() { + p_=hold_pimpl_.get(); +#if 0 + d().sync_to_=static_cast(this); + d().Init(); +#endif + *static_cast(this)=d(); + } + + FsaFeatureFunctionPimpl(Impl const* const p) : hold_pimpl_(p,null_deleter()) { + Init(); + } + FsaFeatureFunctionPimpl(Pimpl const& p) : hold_pimpl_(p) { + Init(); + } +private: + Impl const* p_; + Pimpl hold_pimpl_; }; +typedef FsaFeatureFunctionPimpl FsaFeatureFunctionFwd; // allow ff_from_fsa for an existing dynamic-type ff (as opposed to usual register a wrapped known-type FSA in ff_register, which is more efficient) +//typedef FsaFeatureFunctionDynamic DynamicFsaFeatureFunctionFwd; //if you really need to have a dynamic fsa facade that's also a dynamic fsa //TODO: combine 2 (or N) FsaFeatureFunction (type erased) diff --git a/decoder/ff_register.h b/decoder/ff_register.h index f0828ca3..70e1c1c6 100755 --- a/decoder/ff_register.h +++ b/decoder/ff_register.h @@ -36,11 +36,15 @@ inline void RegisterFF() { } template -inline void RegisterFsaDynToFF(bool prefix=true) { +inline void RegisterFsaDynToFF(std::string name,bool prefix=true) { typedef FsaFeatureFunctionDynamic DynFsa; - std::string name=FsaImpl::usage(false,false); ff_registry.Register(prefix?"DynamicFsa"+name:name,new FFFactory >); } +template +inline void RegisterFsaDynToFF(bool prefix=true) { + RegisterFsaDynToFF(FsaImpl::usage(false,false),prefix); +} + #endif diff --git a/decoder/filelib.h b/decoder/filelib.h index af66dd05..4da4bc4f 100644 --- a/decoder/filelib.h +++ b/decoder/filelib.h @@ -8,6 +8,7 @@ #include #include #include "gzstream.h" +#include "null_deleter.h" bool FileExists(const std::string& file_name); bool DirectoryExists(const std::string& dir_name); @@ -15,9 +16,6 @@ bool DirectoryExists(const std::string& dir_name); // reads from standard in if filename is - // uncompresses if file ends with .gz // otherwise, reads from a normal file -struct file_null_deleter { - void operator()(void*) const {} -}; template struct BaseFile { @@ -57,7 +55,7 @@ class ReadFile : public BaseFile { void Init(const std::string& filename) { filename_=filename; if (is_std()) { - ps_=PS(&std::cin,file_null_deleter()); + ps_=PS(&std::cin,null_deleter()); } else { if (!FileExists(filename)) { std::cerr << "File does not exist: " << filename << std::endl; @@ -85,7 +83,7 @@ class WriteFile : public BaseFile { void Init(const std::string& filename) { filename_=filename; if (is_std()) { - ps_=PS(&std::cout,file_null_deleter()); + ps_=PS(&std::cout,null_deleter()); } else { char const* file=filename_.c_str(); // just in case the gzstream keeps using the filename for longer than the constructor, e.g. inflateReset2. warning in valgrind that I'm hoping will disappear - it makes no sense. ps_=PS(EndsWith(filename, ".gz") ? diff --git a/decoder/fsa-hiero.ini b/decoder/fsa-hiero.ini index 19f88421..3eb8b3d2 100755 --- a/decoder/fsa-hiero.ini +++ b/decoder/fsa-hiero.ini @@ -1,7 +1,6 @@ formalism=scfg +fsa_feature_function=LanguageModelFsa debug lm.gz -n LM scfg_extra_glue_grammar=glue-lda.scfg -feature_function=ShorterThanPrev debug -feature_function=LongerThanPrev grammar=grammar.hiero show_tree_structure=true weights=weights.hiero diff --git a/decoder/null_deleter.h b/decoder/null_deleter.h new file mode 100755 index 00000000..082ab453 --- /dev/null +++ b/decoder/null_deleter.h @@ -0,0 +1,9 @@ +#ifndef NULL_DELETER_H +#define NULL_DELETER_H + +struct null_deleter { + void operator()(void*) const {} + void operator()(void const*) const {} +}; + +#endif -- cgit v1.2.3