Refactor configuration [Part II]. (#4577)

* Refactor configuration [Part II].

* General changes:
** Remove `Init` methods to avoid ambiguity.
** Remove `Configure(std::map<>)` to avoid redundant copying and prepare for
   parameter validation. (`std::vector` is returned from `InitAllowUnknown`).
** Add name to tree updaters for easier debugging.

* Learner changes:
** Make `LearnerImpl` the only source of configuration.

    All configurations are stored and carried out by `LearnerImpl::Configure()`.

** Remove booster in C API.

    Originally kept for "compatibility reason", but did not state why.  So here
    we just remove it.

** Add a `metric_names_` field in `LearnerImpl`.
** Remove `LazyInit`.  Configuration will always be lazy.
** Run `Configure` before every iteration.

* Predictor changes:
** Allocate both cpu and gpu predictor.
** Remove cpu_predictor from gpu_predictor.

    `GBTree` is now used to dispatch the predictor.

** Remove some GPU Predictor tests.

* IO

No IO changes.  The binary model format stability is tested by comparing
hashing value of save models between two commits
This commit is contained in:
Jiaming Yuan
2019-07-20 08:34:56 -04:00
committed by GitHub
parent ad1192e8a3
commit f0064c07ab
69 changed files with 669 additions and 761 deletions

View File

@@ -10,6 +10,9 @@
#include <dmlc/omp.h>
#include <cmath>
#include <iostream>
#include <vector>
#include <string>
#include <utility>
/*!
* \brief string flag for R library, to leave hooks when needed.
@@ -199,6 +202,8 @@ using GradientPairPrecise = detail::GradientPairInternal<double>;
* associative. */
using GradientPairInteger = detail::GradientPairInternal<int64_t>;
using Args = std::vector<std::pair<std::string, std::string> >;
/*! \brief small eps gap for minimum split decision. */
const bst_float kRtEps = 1e-6f;

View File

@@ -29,19 +29,11 @@ namespace xgboost {
*/
class GradientBooster {
protected:
LearnerTrainParam const* learner_param_;
GenericParameter const* learner_param_;
public:
/*! \brief virtual destructor */
virtual ~GradientBooster() = default;
/*!
* \brief set configuration from pair iterators.
* \param begin The beginning iterator.
* \param end The end iterator.
* \tparam PairIter iterator<std::pair<std::string, std::string> >
*/
template<typename PairIter>
inline void Configure(PairIter begin, PairIter end);
/*!
* \brief Set the configuration of gradient boosting.
* User must call configure once before InitModel and Training.
@@ -159,18 +151,11 @@ class GradientBooster {
*/
static GradientBooster* Create(
const std::string& name,
LearnerTrainParam const* gparam,
GenericParameter const* gparam,
const std::vector<std::shared_ptr<DMatrix> >& cache_mats,
bst_float base_margin);
};
// implementing configure.
template<typename PairIter>
inline void GradientBooster::Configure(PairIter begin, PairIter end) {
std::vector<std::pair<std::string, std::string> > vec(begin, end);
this->Configure(vec);
}
/*!
* \brief Registry entry for tree updater.
*/

View File

@@ -11,36 +11,20 @@
#include <string>
namespace xgboost {
enum class DataSplitMode : int {
kAuto = 0, kCol = 1, kRow = 2
};
} // namespace xgboost
DECLARE_FIELD_ENUM_CLASS(xgboost::DataSplitMode);
namespace xgboost {
struct LearnerTrainParam : public dmlc::Parameter<LearnerTrainParam> {
struct GenericParameter : public dmlc::Parameter<GenericParameter> {
// stored random seed
int seed;
// whether seed the PRNG each iteration
bool seed_per_iteration;
// data split mode, can be row, col, or none.
DataSplitMode dsplit;
// number of threads to use if OpenMP is enabled
// if equals 0, use system default
int nthread;
// flag to disable default metric
int disable_default_eval_metric;
// primary device.
int gpu_id;
// number of devices to use, -1 implies using all available devices.
int n_gpus;
std::string booster;
// declare parameters
DMLC_DECLARE_PARAMETER(LearnerTrainParam) {
DMLC_DECLARE_PARAMETER(GenericParameter) {
DMLC_DECLARE_FIELD(seed).set_default(0).describe(
"Random number seed during training.");
DMLC_DECLARE_FIELD(seed_per_iteration)
@@ -49,17 +33,8 @@ struct LearnerTrainParam : public dmlc::Parameter<LearnerTrainParam> {
"Seed PRNG determnisticly via iterator number, "
"this option will be switched on automatically on distributed "
"mode.");
DMLC_DECLARE_FIELD(dsplit)
.set_default(DataSplitMode::kAuto)
.add_enum("auto", DataSplitMode::kAuto)
.add_enum("col", DataSplitMode::kCol)
.add_enum("row", DataSplitMode::kRow)
.describe("Data split mode for distributed training.");
DMLC_DECLARE_FIELD(nthread).set_default(0).describe(
"Number of threads to use.");
DMLC_DECLARE_FIELD(disable_default_eval_metric)
.set_default(0)
.describe("flag to disable default metric. Set to >0 to disable");
DMLC_DECLARE_FIELD(gpu_id)
.set_default(0)
.describe("The primary GPU device ordinal.");
@@ -69,9 +44,6 @@ struct LearnerTrainParam : public dmlc::Parameter<LearnerTrainParam> {
.describe("Deprecated, please use distributed training with one "
"process per GPU. "
"Number of GPUs to use for multi-gpu algorithms.");
DMLC_DECLARE_FIELD(booster)
.set_default("gbtree")
.describe("Gradient booster used for training.");
}
};
} // namespace xgboost

View File

@@ -24,6 +24,7 @@
#include <vector>
namespace xgboost {
/*!
* \brief Learner class that does training and prediction.
* This is the user facing module of xgboost training.
@@ -45,25 +46,9 @@ class Learner : public rabit::Serializable {
/*! \brief virtual destructor */
~Learner() override = default;
/*!
* \brief set configuration from pair iterators.
* \param begin The beginning iterator.
* \param end The end iterator.
* \tparam PairIter iterator<std::pair<std::string, std::string> >
* \brief Configure Learner based on set parameters.
*/
template<typename PairIter>
inline void Configure(PairIter begin, PairIter end);
/*!
* \brief Set the configuration of gradient boosting.
* User must call configure once before InitModel and Training.
*
* \param cfg configurations on both training and model parameters.
*/
virtual void Configure(const std::vector<std::pair<std::string, std::string> >& cfg) = 0;
/*!
* \brief Initialize the model using the specified configurations via Configure.
* An model have to be either Loaded or initialized before Update/Predict/Save can be called.
*/
virtual void InitModel() = 0;
virtual void Configure() = 0;
/*!
* \brief load model from stream
* \param fi input stream.
@@ -121,10 +106,27 @@ class Learner : public rabit::Serializable {
bool pred_contribs = false,
bool approx_contribs = false,
bool pred_interactions = false) = 0;
/*!
* \brief Set multiple parameters at once.
*
* \param args parameters.
*/
virtual void SetParams(Args const& args) = 0;
/*!
* \brief Set parameter for booster
*
* The property will NOT be saved along with booster
*
* \param key The key of parameter
* \param value The value of parameter
*/
virtual void SetParam(const std::string& key, const std::string& value) = 0;
/*!
* \brief Set additional attribute to the Booster.
*
* The property will be saved along the booster.
*
* \param key The key of the property.
* \param value The value of the property.
*/
@@ -148,8 +150,6 @@ class Learner : public rabit::Serializable {
* \return vector of attribute name strings.
*/
virtual std::vector<std::string> GetAttrNames() const = 0;
virtual LearnerTrainParam const& GetLearnerTrainParameter() const = 0;
/*!
* \return whether the model allow lazy checkpoint in rabit.
*/
@@ -161,24 +161,9 @@ class Learner : public rabit::Serializable {
* \param format the format to dump the model in
* \return a vector of dump for boosters.
*/
std::vector<std::string> DumpModel(const FeatureMap& fmap,
bool with_stats,
std::string format) const;
/*!
* \brief online prediction function, predict score for one instance at a time
* NOTE: use the batch prediction interface if possible, batch prediction is usually
* more efficient than online prediction
* This function is NOT threadsafe, make sure you only call from one thread.
*
* \param inst the instance you want to predict
* \param output_margin whether to only predict margin value instead of transformed prediction
* \param out_preds output vector to hold the predictions
* \param ntree_limit limit the number of trees used in prediction
*/
inline void Predict(const SparsePage::Inst &inst,
bool output_margin,
HostDeviceVector<bst_float> *out_preds,
unsigned ntree_limit = 0) const;
virtual std::vector<std::string> DumpModel(const FeatureMap& fmap,
bool with_stats,
std::string format) const = 0;
/*!
* \brief Create a new instance of learner.
* \param cache_data The matrix to cache the prediction.
@@ -186,6 +171,7 @@ class Learner : public rabit::Serializable {
*/
static Learner* Create(const std::vector<std::shared_ptr<DMatrix> >& cache_data);
virtual GenericParameter const& GetGenericParameter() const = 0;
/*!
* \brief Get configuration arguments currently stored by the learner
* \return Key-value pairs representing configuration arguments
@@ -202,26 +188,8 @@ class Learner : public rabit::Serializable {
/*! \brief The evaluation metrics used to evaluate the model. */
std::vector<std::unique_ptr<Metric> > metrics_;
/*! \brief Training parameter. */
LearnerTrainParam tparam_;
GenericParameter generic_param_;
};
// implementation of inline functions.
inline void Learner::Predict(const SparsePage::Inst& inst,
bool output_margin,
HostDeviceVector<bst_float>* out_preds,
unsigned ntree_limit) const {
gbm_->PredictInstance(inst, &out_preds->HostVector(), ntree_limit);
if (!output_margin) {
obj_->PredTransform(out_preds);
}
}
// implementing configure.
template<typename PairIter>
inline void Learner::Configure(PairIter begin, PairIter end) {
std::vector<std::pair<std::string, std::string> > vec(begin, end);
this->Configure(vec);
}
} // namespace xgboost
#endif // XGBOOST_LEARNER_H_

View File

@@ -20,7 +20,7 @@ namespace xgboost {
*/
class LinearUpdater {
protected:
LearnerTrainParam const* learner_param_;
GenericParameter const* learner_param_;
public:
/*! \brief virtual destructor */
@@ -29,7 +29,7 @@ class LinearUpdater {
* \brief Initialize the updater with given arguments.
* \param args arguments to the objective function.
*/
virtual void Init(
virtual void Configure(
const std::vector<std::pair<std::string, std::string> >& args) = 0;
/**
@@ -40,7 +40,6 @@ class LinearUpdater {
* \param model Model to be updated.
* \param sum_instance_weight The sum instance weights, used to normalise l1/l2 penalty.
*/
virtual void Update(HostDeviceVector<GradientPair>* in_gpair, DMatrix* data,
gbm::GBLinearModel* model,
double sum_instance_weight) = 0;
@@ -49,7 +48,7 @@ class LinearUpdater {
* \brief Create a linear updater given name
* \param name Name of the linear updater.
*/
static LinearUpdater* Create(const std::string& name, LearnerTrainParam const*);
static LinearUpdater* Create(const std::string& name, GenericParameter const*);
};
/*!

View File

@@ -66,14 +66,9 @@ class ConsoleLogger : public BaseLogger {
static ConsoleLoggerParam param_;
LogVerbosity cur_verbosity_;
static void Configure(const std::map<std::string, std::string>& args);
public:
template <typename ArgIter>
static void Configure(ArgIter begin, ArgIter end) {
std::map<std::string, std::string> args(begin, end);
Configure(args);
}
static void Configure(Args const& args);
static LogVerbosity GlobalVerbosity();
static LogVerbosity DefaultVerbosity();

View File

@@ -26,7 +26,7 @@ namespace xgboost {
*/
class Metric {
protected:
LearnerTrainParam const* tparam_;
GenericParameter const* tparam_;
public:
/*!
@@ -35,17 +35,6 @@ class Metric {
*/
virtual void Configure(
const std::vector<std::pair<std::string, std::string> >& args) {}
/*!
* \brief set configuration from pair iterators.
* \param begin The beginning iterator.
* \param end The end iterator.
* \tparam PairIter iterator<std::pair<std::string, std::string> >
*/
template<typename PairIter>
inline void Configure(PairIter begin, PairIter end) {
std::vector<std::pair<std::string, std::string> > vec(begin, end);
this->Configure(vec);
}
/*!
* \brief evaluate a specific metric
* \param preds prediction
@@ -68,7 +57,7 @@ class Metric {
* and the name will be matched in the registry.
* \return the created metric.
*/
static Metric* Create(const std::string& name, LearnerTrainParam const* tparam);
static Metric* Create(const std::string& name, GenericParameter const* tparam);
};
/*!

View File

@@ -24,19 +24,11 @@ namespace xgboost {
/*! \brief interface of objective function */
class ObjFunction {
protected:
LearnerTrainParam const* tparam_;
GenericParameter const* tparam_;
public:
/*! \brief virtual destructor */
virtual ~ObjFunction() = default;
/*!
* \brief set configuration from pair iterators.
* \param begin The beginning iterator.
* \param end The end iterator.
* \tparam PairIter iterator<std::pair<std::string, std::string> >
*/
template<typename PairIter>
inline void Configure(PairIter begin, PairIter end);
/*!
* \brief Configure the objective with the specified parameters.
* \param args arguments to the objective function.
@@ -85,16 +77,9 @@ class ObjFunction {
* \param tparam Generic parameters.
* \param name Name of the objective.
*/
static ObjFunction* Create(const std::string& name, LearnerTrainParam const* tparam);
static ObjFunction* Create(const std::string& name, GenericParameter const* tparam);
};
// implementing configure.
template<typename PairIter>
inline void ObjFunction::Configure(PairIter begin, PairIter end) {
std::vector<std::pair<std::string, std::string> > vec(begin, end);
this->Configure(vec);
}
/*!
* \brief Registry entry for objective factory functions.
*/

View File

@@ -40,7 +40,7 @@ namespace xgboost {
class Predictor {
protected:
LearnerTrainParam const* learner_param_;
GenericParameter const* learner_param_;
public:
virtual ~Predictor() = default;
@@ -55,8 +55,8 @@ class Predictor {
* \param cache Vector of DMatrix's to be used in prediction.
*/
virtual void Init(const std::vector<std::pair<std::string, std::string>>& cfg,
const std::vector<std::shared_ptr<DMatrix>>& cache);
virtual void Configure(const std::vector<std::pair<std::string, std::string>>& cfg,
const std::vector<std::shared_ptr<DMatrix>>& cache);
/**
* \brief Generate batch predictions for a given feature matrix. May use
@@ -174,7 +174,7 @@ class Predictor {
*
*/
static Predictor* Create(std::string const& name, LearnerTrainParam const*);
static Predictor* Create(std::string const& name, GenericParameter const*);
protected:
/**
@@ -191,7 +191,6 @@ class Predictor {
* \brief Map of matrices and associated cached predictions to facilitate
* storing and looking up predictions.
*/
std::unordered_map<DMatrix*, PredictionCacheEntry> cache_;
};

View File

@@ -27,7 +27,7 @@ namespace xgboost {
*/
class TreeUpdater {
protected:
LearnerTrainParam const* tparam_;
GenericParameter const* tparam_;
public:
/*! \brief virtual destructor */
@@ -36,7 +36,7 @@ class TreeUpdater {
* \brief Initialize the updater with given arguments.
* \param args arguments to the objective function.
*/
virtual void Init(const std::vector<std::pair<std::string, std::string> >& args) = 0;
virtual void Configure(const Args& args) = 0;
/*!
* \brief perform update to the tree models
* \param gpair the gradient pair statistics of the data
@@ -65,11 +65,13 @@ class TreeUpdater {
return false;
}
virtual char const* Name() const = 0;
/*!
* \brief Create a tree updater given name
* \param name Name of the tree updater.
*/
static TreeUpdater* Create(const std::string& name, LearnerTrainParam const* tparam);
static TreeUpdater* Create(const std::string& name, GenericParameter const* tparam);
};
/*!