From 4b4b36d047367f7417f4c9a543d9c0b18d2e4cf0 Mon Sep 17 00:00:00 2001 From: tqchen Date: Sun, 3 Jan 2016 05:31:00 -0800 Subject: [PATCH] [GBM] remove need to explicit InitModel, rename save/load --- include/xgboost/gbm.h | 9 +---- include/xgboost/tree_model.h | 4 +- src/gbm/gblinear.cc | 20 +++++----- src/gbm/gbtree.cc | 72 +++++++++++++++++------------------- src/tree/updater_sync.cc | 4 +- 5 files changed, 50 insertions(+), 59 deletions(-) diff --git a/include/xgboost/gbm.h b/include/xgboost/gbm.h index 852906ef7..e1fef71ca 100644 --- a/include/xgboost/gbm.h +++ b/include/xgboost/gbm.h @@ -32,21 +32,16 @@ class GradientBooster { * \param cfg configurations on both training and model parameters. */ virtual void Configure(const std::vector >& cfg) = 0; - /*! - * \brief Initialize the model. - * User need to call Configure before calling InitModel. - */ - virtual void InitModel() = 0; /*! * \brief load model from stream * \param fi input stream. */ - virtual void LoadModel(dmlc::Stream* fi) = 0; + virtual void Load(dmlc::Stream* fi) = 0; /*! * \brief save model to stream. * \param fo output stream */ - virtual void SaveModel(dmlc::Stream* fo) const = 0; + virtual void Save(dmlc::Stream* fo) const = 0; /*! * \brief reset the predict buffer size. * This will invalidate all the previous cached results diff --git a/include/xgboost/tree_model.h b/include/xgboost/tree_model.h index ed22d7caf..923cfaa7e 100644 --- a/include/xgboost/tree_model.h +++ b/include/xgboost/tree_model.h @@ -304,7 +304,7 @@ class TreeModel { * \brief load model from stream * \param fi input stream */ - inline void LoadModel(dmlc::Stream* fi) { + inline void Load(dmlc::Stream* fi) { CHECK_EQ(fi->Read(¶m, sizeof(TreeParam)), sizeof(TreeParam)); nodes.resize(param.num_nodes); stats.resize(param.num_nodes); @@ -327,7 +327,7 @@ class TreeModel { * \brief save model to stream * \param fo output stream */ - inline void SaveModel(dmlc::Stream* fo) const { + inline void Save(dmlc::Stream* fo) const { CHECK_EQ(param.num_nodes, static_cast(nodes.size())); CHECK_EQ(param.num_nodes, static_cast(stats.size())); fo->Write(¶m, sizeof(TreeParam)); diff --git a/src/gbm/gblinear.cc b/src/gbm/gblinear.cc index d78756516..010655047 100644 --- a/src/gbm/gblinear.cc +++ b/src/gbm/gblinear.cc @@ -90,18 +90,20 @@ class GBLinear : public GradientBooster { } param.InitAllowUnknown(cfg); } - void LoadModel(dmlc::Stream* fi) override { - model.LoadModel(fi); + void Load(dmlc::Stream* fi) override { + model.Load(fi); } - void SaveModel(dmlc::Stream* fo) const override { - model.SaveModel(fo); - } - void InitModel() override { - model.InitModel(); + void Save(dmlc::Stream* fo) const override { + model.Save(fo); } virtual void DoBoost(DMatrix *p_fmat, int64_t buffer_offset, std::vector *in_gpair) { + // lazily initialize the model when not ready. + if (model.weight.size() == 0) { + model.InitModel(); + } + std::vector &gpair = *in_gpair; const int ngroup = model.param.num_output_group; const std::vector &rowset = p_fmat->buffered_rowset(); @@ -248,12 +250,12 @@ class GBLinear : public GradientBooster { std::fill(weight.begin(), weight.end(), 0.0f); } // save the model to file - inline void SaveModel(dmlc::Stream* fo) const { + inline void Save(dmlc::Stream* fo) const { fo->Write(¶m, sizeof(param)); fo->Write(weight); } // load model from file - inline void LoadModel(dmlc::Stream* fi) { + inline void Load(dmlc::Stream* fi) { CHECK_EQ(fi->Read(¶m, sizeof(param)), sizeof(param)); fi->Read(&weight); } diff --git a/src/gbm/gbtree.cc b/src/gbm/gbtree.cc index ef75e5de8..0b2a9c6fd 100644 --- a/src/gbm/gbtree.cc +++ b/src/gbm/gbtree.cc @@ -52,8 +52,8 @@ struct GBTreeModelParam : public dmlc::Parameter { int num_feature; /*! \brief pad this space, for backward compatiblity reason.*/ int pad_32bit; - /*! \brief size of prediction buffer allocated used for buffering */ - int64_t num_pbuffer; + /*! \brief deprecated padding space. */ + int64_t num_pbuffer_deprecated; /*! * \brief how many output group a single instance can produce * this affects the behavior of number of output we have: @@ -82,24 +82,13 @@ struct GBTreeModelParam : public dmlc::Parameter { DMLC_DECLARE_FIELD(size_leaf_vector).set_lower_bound(0).set_default(0) .describe("Reserved option for vector tree."); } - /*! \return size of prediction buffer actually needed */ - inline size_t PredBufferSize() const { - return num_output_group * num_pbuffer * (size_leaf_vector + 1); - } - /*! - * \brief get the buffer offset given a buffer index and group id - * \return calculated buffer offset - */ - inline int64_t BufferOffset(int64_t buffer_index, int bst_group) const { - if (buffer_index < 0) return -1; - CHECK_LT(buffer_index, num_pbuffer); - return (buffer_index + num_pbuffer * bst_group) * (size_leaf_vector + 1); - } }; // gradient boosted trees class GBTree : public GradientBooster { public: + GBTree() : num_pbuffer(0) {} + void Configure(const std::vector >& cfg) override { this->cfg = cfg; // initialize model parameters if not yet been initialized. @@ -118,13 +107,13 @@ class GBTree : public GradientBooster { } } - void LoadModel(dmlc::Stream* fi) override { + void Load(dmlc::Stream* fi) override { CHECK_EQ(fi->Read(&mparam, sizeof(mparam)), sizeof(mparam)) << "GBTree: invalid model file"; trees.clear(); for (int i = 0; i < mparam.num_trees; ++i) { std::unique_ptr ptr(new RegTree()); - ptr->LoadModel(fi); + ptr->Load(fi); trees.push_back(std::move(ptr)); } tree_info.resize(mparam.num_trees); @@ -132,38 +121,27 @@ class GBTree : public GradientBooster { CHECK_EQ(fi->Read(dmlc::BeginPtr(tree_info), sizeof(int) * mparam.num_trees), sizeof(int) * mparam.num_trees); } - this->ResetPredBuffer(0); + // clear the predict buffer. + this->ResetPredBuffer(num_pbuffer); } - void SaveModel(dmlc::Stream* fo) const override { + void Save(dmlc::Stream* fo) const override { CHECK_EQ(mparam.num_trees, static_cast(trees.size())); - // not save predict buffer. - GBTreeModelParam p = mparam; - p.num_pbuffer = 0; - fo->Write(&p, sizeof(p)); + fo->Write(&mparam, sizeof(mparam)); for (size_t i = 0; i < trees.size(); ++i) { - trees[i]->SaveModel(fo); + trees[i]->Save(fo); } if (tree_info.size() != 0) { fo->Write(dmlc::BeginPtr(tree_info), sizeof(int) * tree_info.size()); } } - void InitModel() override { - CHECK(mparam.num_trees == 0 && trees.size() == 0) - << "Model has already been initialized."; - pred_buffer.clear(); - pred_counter.clear(); - pred_buffer.resize(mparam.PredBufferSize(), 0.0f); - pred_counter.resize(mparam.PredBufferSize(), 0); - } - void ResetPredBuffer(size_t num_pbuffer) override { - mparam.num_pbuffer = static_cast(num_pbuffer); + this->num_pbuffer = num_pbuffer; pred_buffer.clear(); pred_counter.clear(); - pred_buffer.resize(mparam.PredBufferSize(), 0.0f); - pred_counter.resize(mparam.PredBufferSize(), 0); + pred_buffer.resize(this->PredBufferSize(), 0.0f); + pred_counter.resize(this->PredBufferSize(), 0); } bool AllowLazyCheckPoint() const override { @@ -348,7 +326,7 @@ class GBTree : public GradientBooster { #pragma omp parallel for schedule(static) for (bst_omp_uint i = 0; i < ndata; ++i) { const bst_uint ridx = rowset[i]; - const int64_t bid = mparam.BufferOffset(buffer_offset + ridx, bst_group); + const int64_t bid = this->BufferOffset(buffer_offset + ridx, bst_group); const int tid = leaf_position[ridx]; CHECK_EQ(pred_counter[bid], trees.size()); CHECK_GE(tid, 0); @@ -372,7 +350,7 @@ class GBTree : public GradientBooster { float psum = 0.0f; // sum of leaf vector std::vector vec_psum(mparam.size_leaf_vector, 0.0f); - const int64_t bid = mparam.BufferOffset(buffer_index, bst_group); + const int64_t bid = this->BufferOffset(buffer_index, bst_group); // number of valid trees unsigned treeleft = ntree_limit == 0 ? std::numeric_limits::max() : ntree_limit; // load buffered results if any @@ -452,6 +430,20 @@ class GBTree : public GradientBooster { } } } + /*! \return size of prediction buffer actually needed */ + inline size_t PredBufferSize() const { + return mparam.num_output_group * num_pbuffer * (mparam.size_leaf_vector + 1); + } + /*! + * \brief get the buffer offset given a buffer index and group id + * \return calculated buffer offset + */ + inline int64_t BufferOffset(int64_t buffer_index, int bst_group) const { + if (buffer_index < 0) return -1; + size_t bidx = static_cast(buffer_index); + CHECK_LT(bidx, num_pbuffer); + return (bidx + num_pbuffer * bst_group) * (mparam.size_leaf_vector + 1); + } // --- data structure --- // training parameter @@ -462,8 +454,10 @@ class GBTree : public GradientBooster { std::vector > trees; /*! \brief some information indicator of the tree, reserved */ std::vector tree_info; + /*! \brief predict buffer size */ + size_t num_pbuffer; /*! \brief prediction buffer */ - std::vector pred_buffer; + std::vector pred_buffer; /*! \brief prediction buffer counter, remember the prediction */ std::vector pred_counter; // ----training fields---- diff --git a/src/tree/updater_sync.cc b/src/tree/updater_sync.cc index 00a0b95bb..0869a232f 100644 --- a/src/tree/updater_sync.cc +++ b/src/tree/updater_sync.cc @@ -29,13 +29,13 @@ class TreeSyncher: public TreeUpdater { int rank = rabit::GetRank(); if (rank == 0) { for (size_t i = 0; i < trees.size(); ++i) { - trees[i]->SaveModel(&fs); + trees[i]->Save(&fs); } } fs.Seek(0); rabit::Broadcast(&s_model, 0); for (size_t i = 0; i < trees.size(); ++i) { - trees[i]->LoadModel(&fs); + trees[i]->Load(&fs); } } };