Skip to content
Snippets Groups Projects
Select Git revision
  • 58bfc6817c490646f29096772c2494dbbeaacf04
  • master default protected
  • loss
  • producer
4 results

readingMachine.md

Blame
  • macaon_train.cpp 11.05 KiB
    /// @file macaon_train.cpp
    /// @author Franck Dary
    /// @version 1.0
    /// @date 2018-08-07
    
    #include <cstdio>
    #include <cstdlib>
    #include <boost/program_options.hpp>
    #include "BD.hpp"
    #include "Config.hpp"
    #include "TransitionMachine.hpp"
    #include "Trainer.hpp"
    #include "ProgramParameters.hpp"
    
    namespace po = boost::program_options;
    
    /// @brief Get the list of mandatory and optional program arguments.
    ///
    /// @return The lists.
    po::options_description getOptionsDescription()
    {
      po::options_description desc("Command-Line Arguments ");
    
      po::options_description req("Required");
      req.add_options()
        ("expName", po::value<std::string>()->required(),
          "Name of this experiment")
        ("templateName", po::value<std::string>()->required(),
          "Name of the template folder")
        ("tm", po::value<std::string>()->required(),
          "File describing the Tape Machine we will train")
        ("bd", po::value<std::string>()->required(),
          "BD file that describes the multi-tapes buffer")
        ("mcd", po::value<std::string>()->required(),
          "MCD file that describes the input")
        ("train,T", po::value<std::string>()->required(),
          "Training corpus formated according to the MCD");
    
      po::options_description opt("Optional");
      opt.add_options()
        ("help,h", "Produce this help message")
        ("debug,d", "Print infos on stderr")
        ("optimizer", po::value<std::string>()->default_value("amsgrad"),
          "The learning algorithm to use : amsgrad | adam | sgd")
        ("dev", po::value<std::string>()->default_value(""),
          "Development corpus formated according to the MCD")
        ("lang", po::value<std::string>()->default_value("fr"),
          "Language you are working with")
        ("nbiter,n", po::value<int>()->default_value(5),
          "Number of training epochs (iterations)")
        ("iterationSize", po::value<int>()->default_value(-1),
          "The number of examples for each iteration. -1 means the whole training set")
        ("lr", po::value<float>()->default_value(0.001),
          "Learning rate of the optimizer")
        ("seed,s", po::value<int>()->default_value(100),
          "The random seed that will initialize RNG")
        ("nbTrain", po::value<int>()->default_value(0),
          "The number of models that will be trained, with only the random seed changing")
        ("duplicates", po::value<bool>()->default_value(true),
          "Remove identical training examples")
        ("showFeatureRepresentation", po::value<bool>()->default_value(false),
          "For each state of the Config, show its feature representation")
        ("interactive", po::value<bool>()->default_value(true),
          "Is the shell interactive ? Display advancement informations")
        ("randomEmbeddings", po::value<bool>()->default_value(false),
          "When activated, the embeddings will be randomly initialized")
        ("sequenceDelimiterTape", po::value<std::string>()->default_value("EOS"),
          "The name of the buffer's tape that contains the delimiter token for a sequence")
        ("sequenceDelimiter", po::value<std::string>()->default_value("1"),
          "The value of the token that act as a delimiter for sequences")
        ("printTime", "Print time on stderr")
        ("shuffle", po::value<bool>()->default_value(true),
          "Shuffle examples after each iteration");
    
      po::options_description oracle("Oracle related options");
      oracle.add_options()
        ("epochd", po::value<int>()->default_value(3),
          "Number of the first epoch where the oracle will be dynamic")
        ("proba", po::value<float>()->default_value(0.9),
          "The probability that the dynamic oracle will chose the predicted action");
    
      po::options_description ams("Amsgrad family optimizers");
      ams.add_options()
        ("b1", po::value<float>()->default_value(0.9),
          "beta1 parameter for the Amsgtad or Adam optimizer")
        ("b2", po::value<float>()->default_value(0.999),
          "beta2 parameter for the Amsgtad or Adam optimizer")
        ("bias", po::value<float>()->default_value(1e-8),
          "bias parameter for the Amsgtad or Adam  or Adagrad optimizer");
    
      desc.add(req).add(opt).add(oracle).add(ams);
    
      return desc;
    }
    
    /// @brief Store the program arguments inside a variables_map
    ///
    /// @param od The description of all the possible options.
    /// @param argc The number of arguments given to this program.
    /// @param argv The values of arguments given to this program.
    ///
    /// @return The variables map
    po::variables_map checkOptions(po::options_description & od, int argc, char ** argv)
    {
      po::variables_map vm;
    
      try {po::store(po::parse_command_line(argc, argv, od), vm);}
      catch(std::exception& e)
      {
        std::cerr << "Error: " << e.what() << "\n";
        od.print(std::cerr);
        exit(1);
      }
    
      if (vm.count("help"))
      {
        std::cout << od << "\n";
        exit(0);
      }
    
      try {po::notify(vm);}
      catch(std::exception& e)
      {
        std::cerr << "Error: " << e.what() << "\n";
        od.print(std::cerr);
        exit(1);
      }
    
      return vm;
    }
    
    /// @brief Set all the usefull paths relative to expPath
    void updatePaths()
    {
      const char * MACAON_DIR = std::getenv("MACAON_DIR");
      std::string slash = "/";
      ProgramParameters::langPath = MACAON_DIR + slash + ProgramParameters::lang + slash;
      ProgramParameters::expPath = ProgramParameters::langPath + "bin/" + ProgramParameters::expName + slash;
      ProgramParameters::templatePath = ProgramParameters::langPath + ProgramParameters::templateName + slash;
      ProgramParameters::tmFilename = ProgramParameters::expPath + ProgramParameters::tmName;
      ProgramParameters::bdFilename = ProgramParameters::expPath + ProgramParameters::bdName;
      ProgramParameters::mcdFilename = ProgramParameters::expPath + ProgramParameters::mcdName;
      ProgramParameters::trainFilename = ProgramParameters::expPath + ProgramParameters::trainName;
      ProgramParameters::devFilename = ProgramParameters::expPath + ProgramParameters::devName;
      ProgramParameters::newTemplatePath = ProgramParameters::langPath + "bin/" + ProgramParameters::baseExpName + slash;
    }
    
    /// @brief Create the folder containing the current experiment from the template frolder
    void createExpPath()
    {
    std::string decode = "\
    #! /bin/bash\n\
    \n\
    if [ \"$#\" -lt 2 ]; then\n\
     echo \"Usage : $0 input mcd\"\n\
     exit\n\
    fi\n\
    \n\
    INPUT=$1\n\
    MCD=$2\n\
    \n\
    shift\n\
    shift\n\
    ARGS=\"\"\n\
    for arg in \"$@\"\n\
    do\n\
      ARGS=\"$ARGS $arg\"\n\
    done\n\
    \n\
    macaon_decode --lang " + ProgramParameters::lang +  " --tm machine.tm --bd test.bd -I $INPUT --mcd $MCD --expName " + ProgramParameters::expName + "$ARGS";
    
      if (system(("rm -r " + ProgramParameters::expPath + " 2> /dev/null").c_str())){}
      if (system(("mkdir " + ProgramParameters::expPath).c_str())){}
      if (system(("cp -r " + ProgramParameters::newTemplatePath + "* " + ProgramParameters::expPath + ".").c_str())){}
      if (system(("echo \'" + decode + "\' > " + ProgramParameters::expPath + "decode.sh").c_str())){}
      if (system(("chmod +x " + ProgramParameters::expPath + "decode.sh").c_str())){}
      if (system(("ln -f -s " + ProgramParameters::expPath + "decode.sh " + ProgramParameters::langPath + "bin/maca_tm_" + ProgramParameters::expName).c_str())){}
    }
    
    /// @brief Train a model according to all the ProgramParameters
    void launchTraining()
    {
      TransitionMachine transitionMachine(true);
    
      BD trainBD(ProgramParameters::bdFilename, ProgramParameters::mcdFilename);
      Config trainConfig(trainBD);
      trainConfig.readInput(ProgramParameters::trainFilename);
    
      std::unique_ptr<BD> devBD;
      std::unique_ptr<Config> devConfig;
    
      std::unique_ptr<Trainer> trainer;
    
      if(ProgramParameters::devFilename.empty())
      {
        trainer.reset(new Trainer(transitionMachine, trainBD, trainConfig));
      }
      else
      {
        devBD.reset(new BD(ProgramParameters::bdFilename, ProgramParameters::mcdFilename));
        devConfig.reset(new Config(*devBD.get()));
        devConfig->readInput(ProgramParameters::devFilename);
        trainer.reset(new Trainer(transitionMachine, trainBD, trainConfig, devBD.get(), devConfig.get()));
      }
    
      trainer->train();
    }
    
    void createTemplatePath()
    {
      if (system(("rm -r " + ProgramParameters::newTemplatePath + " 2> /dev/null").c_str())){}
      if (system(("mkdir " + ProgramParameters::newTemplatePath).c_str())){}
      if (system(("cp -r " + ProgramParameters::templatePath + "* " + ProgramParameters::newTemplatePath + ".").c_str())){}
    }
    
    void removeTemplatePath()
    {
      if (system(("rm -r " + ProgramParameters::newTemplatePath + " 2> /dev/null").c_str())){}
    }
    
    /// @brief Train a TransitionMachine to predict and add information to a structured input file, by using annotated examples.
    ///
    /// @param argc The number of arguments given to this program.
    /// @param argv[] Array of arguments given to this program.
    ///
    /// @return 0 if there was no crash.
    int main(int argc, char * argv[])
    {
      auto od = getOptionsDescription();
    
      po::variables_map vm = checkOptions(od, argc, argv);
    
      ProgramParameters::expName = vm["expName"].as<std::string>();
      ProgramParameters::baseExpName = ProgramParameters::expName;
      ProgramParameters::templateName = vm["templateName"].as<std::string>();
      ProgramParameters::tmName = vm["tm"].as<std::string>();
      ProgramParameters::bdName = vm["bd"].as<std::string>();
      ProgramParameters::mcdName = vm["mcd"].as<std::string>();
      ProgramParameters::debug = vm.count("debug") == 0 ? false : true;
      ProgramParameters::printTime = vm.count("printTime") == 0 ? false : true;
      ProgramParameters::trainName = vm["train"].as<std::string>();
      ProgramParameters::devName = vm["dev"].as<std::string>();
      ProgramParameters::lang = vm["lang"].as<std::string>();
      ProgramParameters::nbIter = vm["nbiter"].as<int>();
      ProgramParameters::seed = vm["seed"].as<int>();
      ProgramParameters::nbTrain = vm["nbTrain"].as<int>();
      ProgramParameters::removeDuplicates = vm["duplicates"].as<bool>();
      ProgramParameters::interactive = vm["interactive"].as<bool>();
      ProgramParameters::shuffleExamples = vm["shuffle"].as<bool>();
      ProgramParameters::randomEmbeddings = vm["randomEmbeddings"].as<bool>();
      ProgramParameters::sequenceDelimiterTape = vm["sequenceDelimiterTape"].as<std::string>();
      ProgramParameters::sequenceDelimiter = vm["sequenceDelimiter"].as<std::string>();
      ProgramParameters::learningRate = vm["lr"].as<float>();
      ProgramParameters::beta1 = vm["b1"].as<float>();
      ProgramParameters::beta2 = vm["b2"].as<float>();
      ProgramParameters::bias = vm["bias"].as<float>();
      ProgramParameters::optimizer = vm["optimizer"].as<std::string>();
      ProgramParameters::dynamicEpoch = vm["epochd"].as<int>();
      ProgramParameters::dynamicProbability = vm["proba"].as<float>();
      ProgramParameters::showFeatureRepresentation = vm["showFeatureRepresentation"].as<bool>();
      ProgramParameters::iterationSize = vm["iterationSize"].as<int>();
    
      if (ProgramParameters::nbTrain)
      {
        updatePaths();
        createTemplatePath();
        for (int i = 0; i < ProgramParameters::nbTrain; i++)
        {
          fprintf(stderr, "Training number %d / %d :\n", i+1, ProgramParameters::nbTrain);
          ProgramParameters::expName = ProgramParameters::baseExpName + "_" + std::to_string(i);
          updatePaths();
          createExpPath();
          Dict::deleteDicts();
          launchTraining();
        }
        removeTemplatePath();
      }
      else
      {
        updatePaths();
        ProgramParameters::newTemplatePath = ProgramParameters::templatePath;
        createExpPath();
        Dict::deleteDicts();
        launchTraining();
      }
    
      return 0;
    }