Quick fix for memory leak in CPU Hist. (#5153)

Closes https://github.com/dmlc/xgboost/issues/3579 .

* Don't use map.
This commit is contained in:
Jiaming Yuan 2019-12-31 14:05:53 +08:00 committed by GitHub
parent 018df6004e
commit 04db125699
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 23 additions and 18 deletions

View File

@ -41,7 +41,6 @@ void QuantileHistMaker::Configure(const Args& args) {
} }
pruner_->Configure(args); pruner_->Configure(args);
param_.UpdateAllowUnknown(args); param_.UpdateAllowUnknown(args);
is_gmat_initialized_ = false;
// initialise the split evaluator // initialise the split evaluator
if (!spliteval_) { if (!spliteval_) {
@ -54,12 +53,14 @@ void QuantileHistMaker::Configure(const Args& args) {
void QuantileHistMaker::Update(HostDeviceVector<GradientPair> *gpair, void QuantileHistMaker::Update(HostDeviceVector<GradientPair> *gpair,
DMatrix *dmat, DMatrix *dmat,
const std::vector<RegTree *> &trees) { const std::vector<RegTree *> &trees) {
if (is_gmat_initialized_ == false) { if (dmat != p_last_dmat_ || is_gmat_initialized_ == false) {
gmat_.Init(dmat, static_cast<uint32_t>(param_.max_bin)); gmat_.Init(dmat, static_cast<uint32_t>(param_.max_bin));
column_matrix_.Init(gmat_, param_.sparse_threshold); column_matrix_.Init(gmat_, param_.sparse_threshold);
if (param_.enable_feature_grouping > 0) { if (param_.enable_feature_grouping > 0) {
gmatb_.Init(gmat_, column_matrix_, param_); gmatb_.Init(gmat_, column_matrix_, param_);
} }
// A proper solution is puting cut matrix in DMatrix, see:
// https://github.com/dmlc/xgboost/issues/5143
is_gmat_initialized_ = true; is_gmat_initialized_ = true;
} }
// rescale learning rate according to size of trees // rescale learning rate according to size of trees
@ -72,12 +73,14 @@ void QuantileHistMaker::Update(HostDeviceVector<GradientPair> *gpair,
param_, param_,
std::move(pruner_), std::move(pruner_),
std::unique_ptr<SplitEvaluator>(spliteval_->GetHostClone()), std::unique_ptr<SplitEvaluator>(spliteval_->GetHostClone()),
int_constraint_)); int_constraint_, dmat));
} }
for (auto tree : trees) { for (auto tree : trees) {
builder_->Update(gmat_, gmatb_, column_matrix_, gpair, dmat, tree); builder_->Update(gmat_, gmatb_, column_matrix_, gpair, dmat, tree);
} }
param_.learning_rate = lr; param_.learning_rate = lr;
p_last_dmat_ = dmat;
} }
bool QuantileHistMaker::UpdatePredictionCache( bool QuantileHistMaker::UpdatePredictionCache(
@ -508,12 +511,8 @@ void QuantileHistMaker::Builder::InitData(const GHistIndexMatrix& gmat,
data_layout_ = kSparseData; data_layout_ = kSparseData;
} }
} }
{ // store a pointer to the tree
// store a pointer to the tree p_last_tree_ = &tree;
p_last_tree_ = &tree;
// store a pointer to training data
p_last_fmat_ = &fmat;
}
if (data_layout_ == kDenseDataOneBased) { if (data_layout_ == kDenseDataOneBased) {
column_sampler_.Init(info.num_col_, param_.colsample_bynode, param_.colsample_bylevel, column_sampler_.Init(info.num_col_, param_.colsample_bynode, param_.colsample_bylevel,
param_.colsample_bytree, true); param_.colsample_bytree, true);

View File

@ -19,6 +19,7 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include "xgboost/data.h"
#include "xgboost/json.h" #include "xgboost/json.h"
#include "constraints.h" #include "constraints.h"
#include "./param.h" #include "./param.h"
@ -80,7 +81,7 @@ using xgboost::common::Column;
/*! \brief construct a tree using quantized feature values */ /*! \brief construct a tree using quantized feature values */
class QuantileHistMaker: public TreeUpdater { class QuantileHistMaker: public TreeUpdater {
public: public:
QuantileHistMaker() : is_gmat_initialized_{ false } {} QuantileHistMaker() {}
void Configure(const Args& args) override; void Configure(const Args& args) override;
void Update(HostDeviceVector<GradientPair>* gpair, void Update(HostDeviceVector<GradientPair>* gpair,
@ -112,7 +113,8 @@ class QuantileHistMaker: public TreeUpdater {
GHistIndexBlockMatrix gmatb_; GHistIndexBlockMatrix gmatb_;
// column accessor // column accessor
ColumnMatrix column_matrix_; ColumnMatrix column_matrix_;
bool is_gmat_initialized_; DMatrix const* p_last_dmat_ {nullptr};
bool is_gmat_initialized_ {false};
// data structure // data structure
struct NodeEntry { struct NodeEntry {
@ -136,10 +138,11 @@ class QuantileHistMaker: public TreeUpdater {
explicit Builder(const TrainParam& param, explicit Builder(const TrainParam& param,
std::unique_ptr<TreeUpdater> pruner, std::unique_ptr<TreeUpdater> pruner,
std::unique_ptr<SplitEvaluator> spliteval, std::unique_ptr<SplitEvaluator> spliteval,
FeatureInteractionConstraintHost int_constraints_) FeatureInteractionConstraintHost int_constraints_,
DMatrix const* fmat)
: param_(param), pruner_(std::move(pruner)), : param_(param), pruner_(std::move(pruner)),
spliteval_(std::move(spliteval)), interaction_constraints_{int_constraints_}, spliteval_(std::move(spliteval)), interaction_constraints_{int_constraints_},
p_last_tree_(nullptr), p_last_fmat_(nullptr) { p_last_tree_(nullptr), p_last_fmat_(fmat) {
builder_monitor_.Init("Quantile::Builder"); builder_monitor_.Init("Quantile::Builder");
} }
// update one tree, growing // update one tree, growing
@ -313,7 +316,7 @@ class QuantileHistMaker: public TreeUpdater {
// back pointers to tree and data matrix // back pointers to tree and data matrix
const RegTree* p_last_tree_; const RegTree* p_last_tree_;
const DMatrix* p_last_fmat_; DMatrix const* const p_last_fmat_;
using ExpandQueue = using ExpandQueue =
std::priority_queue<ExpandEntry, std::vector<ExpandEntry>, std::priority_queue<ExpandEntry, std::vector<ExpandEntry>,

View File

@ -13,6 +13,7 @@
#include "../../../src/tree/param.h" #include "../../../src/tree/param.h"
#include "../../../src/tree/updater_quantile_hist.h" #include "../../../src/tree/updater_quantile_hist.h"
#include "../../../src/tree/split_evaluator.h" #include "../../../src/tree/split_evaluator.h"
#include "xgboost/data.h"
namespace xgboost { namespace xgboost {
namespace tree { namespace tree {
@ -26,8 +27,9 @@ class QuantileHistMock : public QuantileHistMaker {
BuilderMock(const TrainParam& param, BuilderMock(const TrainParam& param,
std::unique_ptr<TreeUpdater> pruner, std::unique_ptr<TreeUpdater> pruner,
std::unique_ptr<SplitEvaluator> spliteval, std::unique_ptr<SplitEvaluator> spliteval,
FeatureInteractionConstraintHost int_constraint) FeatureInteractionConstraintHost int_constraint,
: RealImpl(param, std::move(pruner), std::move(spliteval), std::move(int_constraint)) {} DMatrix const* fmat)
: RealImpl(param, std::move(pruner), std::move(spliteval), std::move(int_constraint), fmat) {}
public: public:
void TestInitData(const GHistIndexMatrix& gmat, void TestInitData(const GHistIndexMatrix& gmat,
@ -236,13 +238,14 @@ class QuantileHistMock : public QuantileHistMaker {
cfg_{args} { cfg_{args} {
QuantileHistMaker::Configure(args); QuantileHistMaker::Configure(args);
spliteval_->Init(&param_); spliteval_->Init(&param_);
dmat_ = CreateDMatrix(kNRows, kNCols, 0.8, 3);
builder_.reset( builder_.reset(
new BuilderMock( new BuilderMock(
param_, param_,
std::move(pruner_), std::move(pruner_),
std::unique_ptr<SplitEvaluator>(spliteval_->GetHostClone()), std::unique_ptr<SplitEvaluator>(spliteval_->GetHostClone()),
int_constraint_)); int_constraint_,
dmat_ = CreateDMatrix(kNRows, kNCols, 0.8, 3); dmat_->get()));
} }
~QuantileHistMock() override { delete dmat_; } ~QuantileHistMock() override { delete dmat_; }