From aaac9f8ee73ba59b72609af9a78b167312a6dac7 Mon Sep 17 00:00:00 2001 From: graehl Date: Sat, 7 Aug 2010 02:24:51 +0000 Subject: propagation of feature name+debug from factory, return correct features array for fsa ffs git-svn-id: https://ws10smt.googlecode.com/svn/trunk@486 ec762483-ff6d-05da-a07a-a48fb63a330f --- decoder/cdec_ff.cc | 6 ++++-- decoder/fdict.cc | 14 ++++++++++++++ decoder/fdict.h | 3 +++ decoder/ff.cc | 2 +- decoder/ff.h | 17 ++++++++++++++++- decoder/ff_factory.h | 12 ++++++++---- decoder/ff_from_fsa.h | 21 ++++++++++++++++----- decoder/ff_fsa.h | 27 +++++++++++++++++++-------- decoder/ff_fsa_data.h | 26 ++++++++++++++++++++++---- decoder/ff_fsa_dynamic.h | 29 ++++++++++++++++++++++++----- decoder/ff_lm.cc | 3 ++- decoder/ff_lm_fsa.h | 7 +++++++ decoder/ff_sample_fsa.h | 12 ++++++++---- decoder/perro.sh | 2 +- 14 files changed, 145 insertions(+), 36 deletions(-) (limited to 'decoder') diff --git a/decoder/cdec_ff.cc b/decoder/cdec_ff.cc index 6edac126..1ef50eb1 100644 --- a/decoder/cdec_ff.cc +++ b/decoder/cdec_ff.cc @@ -13,8 +13,12 @@ #include "ff_register.h" void register_feature_functions() { + RegisterFsaImpl(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 + RegisterFsaDynToFF(); RegisterFF(); RegisterFF(); @@ -23,8 +27,6 @@ void register_feature_functions() { //TODO: worthless example target FSA ffs. remove later ff_registry.Register(new FFFactory); // same as WordPenalty, but implemented using ff_fsa - RegisterFsaImpl(true,false); - ff_registry.Register(new FFFactory >); ff_registry.Register(new FFFactory >); //TODO: use for all features the new Register which requires static FF::usage(false,false) give name diff --git a/decoder/fdict.cc b/decoder/fdict.cc index 65187685..baa0b552 100644 --- a/decoder/fdict.cc +++ b/decoder/fdict.cc @@ -2,12 +2,26 @@ #include "stdlib.h" //for malloc (need on cygwin); todo and std::malloc #include +#include using namespace std; Dict FD::dict_; bool FD::frozen_ = false; +std::string FD::Convert(std::vector const& v) { + return Convert(&*v.begin(),&*v.end()); +} + +std::string FD::Convert(WordID const *b,WordID const* e) { + ostringstream o; + for (WordID const* i=b;ib) o << ' '; + o << FD::Convert(*i); + } + return o.str(); +} + static int HexPairValue(const char * code) { int value = 0; const char * pch = code; diff --git a/decoder/fdict.h b/decoder/fdict.h index c4236580..f9673023 100644 --- a/decoder/fdict.h +++ b/decoder/fdict.h @@ -20,6 +20,9 @@ struct FD { static inline const std::string& Convert(const WordID& w) { return dict_.Convert(w); } + static std::string Convert(WordID const *i,WordID const* e); + static std::string Convert(std::vector const& v); + // Escape any string to a form that can be used as the name // of a weight in a weights file static std::string Escape(const std::string& s); diff --git a/decoder/ff.cc b/decoder/ff.cc index a23f1655..5c52ca2b 100644 --- a/decoder/ff.cc +++ b/decoder/ff.cc @@ -46,7 +46,7 @@ Features ModelSet::all_features(std::ostream *warn,bool warn0) { string const& ffname=ff.name_; FFS si=ff.features(); if (si.empty()) { - WARNFF(ffname<<" doesn't yet report any feature IDs - implement features() method?"); + 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 +# define DBGINIT(a) do { std::cerr< #include #include "fdict.h" @@ -19,6 +27,12 @@ class FeatureFunction { public: std::string name_; // set by FF factory using usage() bool debug_; // also set by FF factory checking param for immediate initial "debug" + //called after constructor, but before name_ and debug_ have been set + virtual void Init() { DBGINIT("default FF::Init name="< and . + protected: virtual void FinalTraversalFeatures(const void* residual_state, FeatureVector* final_features) const; diff --git a/decoder/ff_factory.h b/decoder/ff_factory.h index 102e709c..5eb68c8b 100644 --- a/decoder/ff_factory.h +++ b/decoder/ff_factory.h @@ -42,7 +42,9 @@ struct FactoryBase : public UntypedFactory { template struct FFFactory : public FactoryBase { FP Create(std::string param) const { - return FP(new FF(param)); + FF *ret=new FF(param); + ret->Init(); + return FP(ret); } virtual std::string usage(bool params,bool verbose) const { return FF::usage(params,verbose); @@ -54,7 +56,9 @@ struct FFFactory : public FactoryBase { template struct FsaFactory : public FactoryBase { FP Create(std::string param) const { - return FP(new FF(param)); + FF *ret=new FF(param); + ret->Init(); + return FP(ret); } virtual std::string usage(bool params,bool verbose) const { return FF::usage(params,verbose); @@ -94,8 +98,8 @@ struct FactoryRegistry : public UntypedFactoryRegistry { if (debug) cerr<<"debug enabled for "<(*it->second).Create(param); - res->name_ = ffname; - res->debug_ = debug; + res->init_name_debug(ffname,debug); + // could add a res->Init() here instead of in Create if we wanted feature id to potentially differ based on the registered name rather than static usage() - of course, specific feature ids can be computed on the basis of feature param as well; this only affects the default single feature id=name return res; } }; diff --git a/decoder/ff_from_fsa.h b/decoder/ff_from_fsa.h index 2c339aa8..ec1a28fa 100755 --- a/decoder/ff_from_fsa.h +++ b/decoder/ff_from_fsa.h @@ -30,14 +30,21 @@ class FeatureFunctionFromFsa : public FeatureFunction { public: FeatureFunctionFromFsa(std::string const& param) : ff(param) { debug_=true; // because factory won't set until after we construct. - Init(); } static std::string usage(bool args,bool verbose) { return Impl::usage(args,verbose); } + void init_name_debug(std::string const& n,bool debug) { + FeatureFunction::init_name_debug(n,debug); + ff.init_name_debug(n,debug); + } - Features features() const { return ff.features(); } + // this should override + Features features() const { + DBGINIT("FeatureFunctionFromFsa features() name="<(*this); } + Impl & d() { return static_cast(*this); } + + // this will get called by factory - override if you have multiple or dynamically named features. note: may be called repeatedly + void Init() { + Init(name()); + DBGINIT("base (single feature) FsaFeatureFunctionBase::Init name="< Bytes; -// stuff I see no reason to have virtual. but there's a diamond inheritance problem to solve now when type erasing the CRTP impl wrapper. virtual inheritance would slow things? +// stuff I see no reason to have virtual. but because it's impossible (w/o virtual inheritance to have dynamic fsa ff know where the impl's data starts, implemented a sync (copy) method that needs to be called. init_name_debug was already necessary to keep state in sync between ff and ff_from_fsa, so no sync should be needed after it. supposing all modifications were through setters, then no explicit sync call would ever be needed; updates could be mirrored. struct FsaFeatureFunctionData { + void init_name_debug(std::string const& n,bool debug) { + name_=n; + debug_=debug; + } //HACK for diamond inheritance (w/o costing performance) FsaFeatureFunctionData *sync_to_; void sync() const { // call this if you modify any fields after your constructor is done - if (sync_to_) *sync_to_=*this; + + if (sync_to_) { + DBGINIT("sync to "<<*sync_to_); + *sync_to_=*this; + DBGINIT("synced result="<<*sync_to_<< " from this="<<*this); + } else { + DBGINIT("nobody to sync to - from FeatureFunctionData this="<<*this); + } + } + + friend std::ostream &operator<<(std::ostream &o,FsaFeatureFunctionData const& d) { + o << "[FSA "<" for lm. diff --git a/decoder/ff_fsa_dynamic.h b/decoder/ff_fsa_dynamic.h index 2a26676d..d03fddee 100755 --- a/decoder/ff_fsa_dynamic.h +++ b/decoder/ff_fsa_dynamic.h @@ -26,10 +26,14 @@ struct FsaFeatureFunction : public FsaFeatureFunctionData { virtual void *ScanPhraseAccumBounce(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,void *cs,void *ns,Accum *accum) const = 0; virtual int early_score_words(SentenceMetadata const& smeta,Hypergraph::Edge const& edge,WordID const* i, WordID const* end,Accum *accum) const { return 0; } + // called after constructor, before use + virtual void Init() = 0; virtual std::string usage_v(bool param,bool verbose) const { return FeatureFunction::usage_helper("unnamed_dynamic_fsa_feature","","",param,verbose); } - + virtual void init_name_debug(std::string const& n,bool debug) { + FsaFeatureFunctionData::init_name_debug(n,debug); + } virtual void print_state(std::ostream &o,void const*state) const { FsaFeatureFunctionData::print_state(o,state); @@ -49,10 +53,13 @@ struct FsaFeatureFunction : public FsaFeatureFunctionData { // you might be wondering: why do this? answer: it's cool, and it means that the bottom-up ff over ff_fsa wrapper doesn't go through multiple layers of dynamic dispatch // usage: typedef FsaFeatureFunctionDynamic MyFsaDyn; template -struct FsaFeatureFunctionDynamic : public FsaFeatureFunction,Impl { +struct FsaFeatureFunctionDynamic : public FsaFeatureFunction { static const bool simple_phrase_score=Impl::simple_phrase_score; - Impl& d() { return static_cast(*this); } - Impl const& d() const { return static_cast(*this); } + Impl& d() { return impl;//static_cast(*this); + } + Impl const& d() const { return impl; + //static_cast(*this); + } int markov_order() const { return d().markov_order(); } virtual void ScanAccum(SentenceMetadata const& smeta,Hypergraph::Edge const& edge, @@ -92,11 +99,23 @@ struct FsaFeatureFunctionDynamic : public FsaFeatureFunction,Impl { return d().print_state(o,state); } - FsaFeatureFunctionDynamic(std::string const& param) : Impl(param) { + void init_name_debug(std::string const& n,bool debug) { + FsaFeatureFunction::init_name_debug(n,debug); + d().init_name_debug(n,debug); + } + + virtual void Init() { d().sync_to_=(FsaFeatureFunction*)this; + d().Init(); d().sync(); } + FsaFeatureFunctionDynamic(std::string const& param) : impl(param) { + Init(); + } +private: + Impl impl; + }; diff --git a/decoder/ff_lm.cc b/decoder/ff_lm.cc index 61d845d6..f3e65cb7 100644 --- a/decoder/ff_lm.cc +++ b/decoder/ff_lm.cc @@ -609,12 +609,13 @@ void LanguageModelFsa::set_ngram_order(int i) { //TODO: reevaluate whether state space comes cleared by allocator or not. } } + sync(); // for dynamic markov_order copy etc } LanguageModelFsa::LanguageModelFsa(string const& param) { int lmorder; pimpl_ = make_lm_impl(param,&lmorder,&fid_); - InitHaveFid(); + Init(); floor_=pimpl_->floor_; set_ngram_order(lmorder); } diff --git a/decoder/ff_lm_fsa.h b/decoder/ff_lm_fsa.h index 1c8ebdad..d2df943e 100755 --- a/decoder/ff_lm_fsa.h +++ b/decoder/ff_lm_fsa.h @@ -115,8 +115,15 @@ struct LanguageModelFsa : public FsaFeatureFunctionBase { // impl details: void set_ngram_order(int i); // if you build ff_from_fsa first, then increase this, you will get memory overflows. otherwise, it's the same as a "-o i" argument to constructor + // note: if you adjust ngram_order, ff_from_fsa won't notice. + double floor_; // log10prob minimum used (e.g. unk words) + // because we might have a custom fid due to lm name option: + void Init() { + InitHaveFid(); + } + private: int ngram_order_; int ctxlen_; // 1 less than above diff --git a/decoder/ff_sample_fsa.h b/decoder/ff_sample_fsa.h index 40a32bae..20d64b16 100755 --- a/decoder/ff_sample_fsa.h +++ b/decoder/ff_sample_fsa.h @@ -14,12 +14,14 @@ struct WordPenaltyFsa : public FsaFeatureFunctionBase { } WordPenaltyFsa(std::string const& param) { - Init(); +#if 0 + Init(); // gets called by factory already return; //below are all defaults: set_state_bytes(0); start.clear(); h_start.clear(); - } +#endif + } // move from state to next_state after seeing word x, while emitting features->add_value(fid,val) possibly with duplicates. state and next_state may be same memory. Featval Scan1(WordID w,void const* state,void *next_state) const { return 1; @@ -32,7 +34,8 @@ struct SameFirstLetter : public FsaFeatureFunctionBase { SameFirstLetter(std::string const& param) : FsaFeatureFunctionBase(1,singleton_sentence("END")) // 1 byte of state, scan final (single) symbol "END" to get final state cost { - start[0]='a'; h_start[0]=0; Init(); + start[0]='a'; h_start[0]=0; +// Init(); } int markov_order() const { return 1; } Featval Scan1(WordID w,void const* old_state,void *new_state) const { @@ -82,6 +85,7 @@ struct LongerThanPrev : public FsaFeatureFunctionBase { } int markov_order() const { return 1; } LongerThanPrev(std::string const& param) : Base(sizeof(int)/* ,singleton_sentence(TD::se) */) { +#if 0 Init(); if (0) { // all this is done in constructor already set_state_bytes(sizeof(int)); @@ -96,7 +100,7 @@ struct LongerThanPrev : public FsaFeatureFunctionBase { assert(h_start.size()==sizeof(int)); state(start.begin())=999999; state(h_start.begin())=4; // estimate: anything >4 chars is usually longer than previous - +#endif } Featval Scan1(WordID w,void const* from,void *next_state) const { diff --git a/decoder/perro.sh b/decoder/perro.sh index 8df71855..836ad07f 100755 --- a/decoder/perro.sh +++ b/decoder/perro.sh @@ -1 +1 @@ -$gdb $cdec -k 30 --show_features -c fsa-hiero.ini -i perro.ur +$gdb $cdec -k 30 --show_features -c fsa-hiero.ini -i perro.ur "$@" -- cgit v1.2.3