diff options
Diffstat (limited to 'decoder')
| -rw-r--r-- | decoder/cdec_ff.cc | 6 | ||||
| -rw-r--r-- | decoder/fdict.cc | 14 | ||||
| -rw-r--r-- | decoder/fdict.h | 3 | ||||
| -rw-r--r-- | decoder/ff.cc | 2 | ||||
| -rw-r--r-- | decoder/ff.h | 17 | ||||
| -rw-r--r-- | decoder/ff_factory.h | 12 | ||||
| -rwxr-xr-x | decoder/ff_from_fsa.h | 21 | ||||
| -rwxr-xr-x | decoder/ff_fsa.h | 27 | ||||
| -rwxr-xr-x | decoder/ff_fsa_data.h | 26 | ||||
| -rwxr-xr-x | decoder/ff_fsa_dynamic.h | 29 | ||||
| -rw-r--r-- | decoder/ff_lm.cc | 3 | ||||
| -rwxr-xr-x | decoder/ff_lm_fsa.h | 7 | ||||
| -rwxr-xr-x | decoder/ff_sample_fsa.h | 12 | ||||
| -rwxr-xr-x | decoder/perro.sh | 2 | 
14 files changed, 145 insertions, 36 deletions
| 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<SameFirstLetter>(true,false); +  RegisterFsaImpl<LongerThanPrev>(true,false);    RegisterFF<LanguageModel>();    RegisterFsaImpl<LanguageModelFsa>(true,false); // same as LM but using fsa wrapper +  ff_registry.Register("LanguageModelFsaDynamic",new FFFactory<FeatureFunctionFromFsa<FsaFeatureFunctionDynamic<LanguageModelFsa> > >); // test correctness of FsaFeatureFunctionDynamic erasure +  RegisterFsaDynToFF<SameFirstLetter>();    RegisterFF<WordPenalty>();    RegisterFF<SourceWordPenalty>(); @@ -23,8 +27,6 @@ void register_feature_functions() {    //TODO: worthless example target FSA ffs.  remove later    ff_registry.Register(new FFFactory<WordPenaltyFromFsa>); // same as WordPenalty, but implemented using ff_fsa -  RegisterFsaImpl<SameFirstLetter>(true,false); -  ff_registry.Register(new FFFactory<FeatureFunctionFromFsa<LongerThanPrev> >);    ff_registry.Register(new FFFactory<FeatureFunctionFromFsa<ShorterThanPrev> >);    //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 <cstdlib> and std::malloc  #include <string> +#include <sstream>  using namespace std;  Dict FD::dict_;  bool FD::frozen_ = false; +std::string FD::Convert(std::vector<WordID> 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;i<e;++i) { +    if (i>b) 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<WordID> 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<si.size();++j) { diff --git a/decoder/ff.h b/decoder/ff.h index 2de3c1fb..e3bfe392 100644 --- a/decoder/ff.h +++ b/decoder/ff.h @@ -1,6 +1,14 @@  #ifndef _FF_H_  #define _FF_H_ +#define DEBUG_INIT 0 +#if DEBUG_INIT +# include <iostream> +# define DBGINIT(a) do { std::cerr<<a<<"\n"; } while(0) +#else +# define DBGINIT(a) +#endif +  #include <vector>  #include <cstring>  #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="<<name_); } +  virtual void init_name_debug(std::string const& n,bool debug) { +    name_=n; +    debug_=debug; +  }    bool debug() const { return debug_; }    FeatureFunction() : state_size_() {}    explicit FeatureFunction(int state_size) : state_size_(state_size) {} @@ -36,7 +50,7 @@ public:    virtual bool rule_feature() const { return false; }    //OVERRIDE THIS: -  virtual Features features() const { return Features(); } +  virtual Features features() const { return single_feature(FD::Convert(name_)); }    // 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 @@ -63,6 +77,7 @@ public:    // if there's some state left when you transition to the goal state, score    // it here.  For example, the language model computes the cost of adding    // <s> and </s>. +  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<class FF>  struct FFFactory : public FactoryBase<FeatureFunction> {    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<FeatureFunction> {  template<class FF>  struct FsaFactory : public FactoryBase<FsaFeatureFunction> {    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 "<<ffname<< " - remaining options: '"<<param<<"'\n";      FP res = dynamic_cast<FB const&>(*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="<<ff.name()<<" features="<<FD::Convert(ff.features())); +    return ff.features(); +  }    // Log because it potentially stores info in edge.  otherwise the same as regular TraversalFeatures.    void TraversalFeaturesLog(const SentenceMetadata& smeta, @@ -227,16 +234,20 @@ public:      assert(left_end(w2,w2+2)==w2+1);    } -private: -  Impl ff; +  // override from FeatureFunction; should be called by factory after constructor.    void Init() { -//    FeatureFunction::name=Impl::usage(false,false); // already achieved by ff_factory.cc +    ff.Init(); +    ff.sync(); +    DBGINIT("base (single feature) FsaFeatureFunctionBase::Init name="<<name_<<" features="<<FD::Convert(features())); +//    FeatureFunction::name_=Impl::usage(false,false); // already achieved by ff_factory.cc      M=ff.markov_order();      ssz=ff.state_bytes();      state_offset=sizeof(WordID)*M;      SetStateSize(ssz+state_offset);      assert(!ssz == !M); // no fsa state <=> markov order 0    } +private: +  Impl ff;    int M; // markov order (ctx len)    FeatureFunctionFromFsa(); // not allowed. diff --git a/decoder/ff_fsa.h b/decoder/ff_fsa.h index e7877dd5..6416151c 100755 --- a/decoder/ff_fsa.h +++ b/decoder/ff_fsa.h @@ -68,18 +68,26 @@ usage: see ff_sample_fsa.h or ff_lm_fsa.h  template <class Impl>  struct FsaFeatureFunctionBase : public FsaFeatureFunctionData { -  // CALL 1 of these MANUALLY  (because feature name(s) may depend on param, it's not done in ctor) -  void Init(std::string const& fname="") { -    fid_=FD::Convert(fname.empty()?name():fname); +  Impl const& d() const { return static_cast<Impl const&>(*this); } +  Impl & d()  { return static_cast<Impl &>(*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="<<name()<<" features="<<FD::Convert(features_)); +  } +  void Init(std::string const& fname) { +    fid_=FD::Convert(fname);      InitHaveFid();    } -  Features features_;    void InitHaveFid() {      features_=FeatureFunction::single_feature(fid_);    } +  Features features() const { +    DBGINIT("FeatureFunctionBase::features() name="<<name()<<" features="<<FD::Convert(features_)); +    return features_; +  } -  Impl const& d() const { return static_cast<Impl const&>(*this); } -  Impl & d()  { return static_cast<Impl &>(*this); }  public:    int fid_; // you can have more than 1 feature of course. @@ -252,8 +260,11 @@ public:    }    // don't set state-bytes etc. in ctor because it may depend on parsing param string -  FsaFeatureFunctionBase(int statesz=0,Sentence const& end_sentence_phrase=Sentence()) : -    FsaFeatureFunctionData(statesz,end_sentence_phrase) {  } +  FsaFeatureFunctionBase(int statesz=0,Sentence const& end_sentence_phrase=Sentence()) +    : FsaFeatureFunctionData(statesz,end_sentence_phrase) +  { +    name_=name(); // should allow FsaDynamic wrapper to get name copied to it with sync +  }  }; diff --git a/decoder/ff_fsa_data.h b/decoder/ff_fsa_data.h index 3252c5ac..2f0c55b8 100755 --- a/decoder/ff_fsa_data.h +++ b/decoder/ff_fsa_data.h @@ -6,17 +6,35 @@  #include "sentences.h"  #include "feature_accum.h"  #include "value_array.h" - +#include "ff.h" //debug  typedef ValueArray<uint8_t> 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 "<<d.name_<<" features="<<FD::Convert(d.features_)<<" start="; +    d.print_state(o,d.start_state()); +    o<<"]"; +    return o;    }    FsaFeatureFunctionData(int statesz=0,Sentence const& end_sentence_phrase=Sentence()) : ssz(statesz),start(statesz),h_start(statesz),end_phrase_(end_sentence_phrase) { @@ -68,8 +86,8 @@ struct FsaFeatureFunctionData        print_hex_byte(o,*i);    } -protected:    Features features_; +protected:    int ssz; // don't forget to set this. default 0 (it may depend on params of course)    Bytes start,h_start; // start state and estimated-features (heuristic) start state.  set these.  default empty.    Sentence end_phrase_; // words appended for final traversal (final state cost is assessed using Scan) e.g. "</s>" 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<MyFsa> MyFsaDyn;  template <class Impl> -struct FsaFeatureFunctionDynamic : public FsaFeatureFunction,Impl { +struct FsaFeatureFunctionDynamic : public FsaFeatureFunction {    static const bool simple_phrase_score=Impl::simple_phrase_score; -  Impl& d() { return static_cast<Impl&>(*this); } -  Impl const& d() const { return static_cast<Impl const&>(*this); } +  Impl& d() { return impl;//static_cast<Impl&>(*this); +  } +  Impl const& d() const { return impl; +    //static_cast<Impl const&>(*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<LanguageModelFsa> {    // 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> {    }    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> {    SameFirstLetter(std::string const& param) : FsaFeatureFunctionBase<SameFirstLetter>(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<LongerThanPrev> {    }    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<LongerThanPrev> {      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 "$@" | 
