check pipe, commit optimization for hist
This commit is contained in:
parent
6b674b491f
commit
974202eb55
@ -15,4 +15,4 @@ Notes
|
|||||||
* The code is multi-threaded, so you want to run one xgboost-mpi per node
|
* The code is multi-threaded, so you want to run one xgboost-mpi per node
|
||||||
* Row-based solver split data by row, each node work on subset of rows, it uses an approximate histogram count algorithm,
|
* Row-based solver split data by row, each node work on subset of rows, it uses an approximate histogram count algorithm,
|
||||||
and will only examine subset of potential split points as opposed to all split points.
|
and will only examine subset of potential split points as opposed to all split points.
|
||||||
* ```colsample_bytree``` is not enabled in row split mode so far
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ gamma = 1.0
|
|||||||
min_child_weight = 1
|
min_child_weight = 1
|
||||||
# maximum depth of a tree
|
# maximum depth of a tree
|
||||||
max_depth = 3
|
max_depth = 3
|
||||||
|
|
||||||
# Task parameters
|
# Task parameters
|
||||||
# the number of round to do boosting
|
# the number of round to do boosting
|
||||||
num_round = 2
|
num_round = 2
|
||||||
|
|||||||
@ -12,7 +12,7 @@ k=$1
|
|||||||
python splitrows.py ../../demo/data/agaricus.txt.train train $k
|
python splitrows.py ../../demo/data/agaricus.txt.train train $k
|
||||||
|
|
||||||
# run xgboost mpi
|
# run xgboost mpi
|
||||||
mpirun -n $k ../../xgboost-mpi mushroom-row.conf dsplit=row nthread=1
|
mpirun -n $k ../../xgboost-mpi mushroom-row.conf dsplit=row nthread=1
|
||||||
|
|
||||||
# the model can be directly loaded by single machine xgboost solver, as usuall
|
# the model can be directly loaded by single machine xgboost solver, as usuall
|
||||||
../../xgboost mushroom-row.conf task=dump model_in=0002.model fmap=../../demo/data/featmap.txt name_dump=dump.nice.$k.txt
|
../../xgboost mushroom-row.conf task=dump model_in=0002.model fmap=../../demo/data/featmap.txt name_dump=dump.nice.$k.txt
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
#include "../utils/random.h"
|
#include "../utils/random.h"
|
||||||
#include "../utils/quantile.h"
|
#include "../utils/quantile.h"
|
||||||
|
|
||||||
@ -24,8 +25,73 @@ class BaseMaker: public IUpdater {
|
|||||||
virtual void SetParam(const char *name, const char *val) {
|
virtual void SetParam(const char *name, const char *val) {
|
||||||
param.SetParam(name, val);
|
param.SetParam(name, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// helper to collect and query feature meta information
|
||||||
|
struct FMetaHelper {
|
||||||
|
public:
|
||||||
|
/*! \brief find type of each feature, use column format */
|
||||||
|
inline void InitByCol(IFMatrix *p_fmat,
|
||||||
|
const RegTree &tree) {
|
||||||
|
fminmax.resize(tree.param.num_feature * 2);
|
||||||
|
std::fill(fminmax.begin(), fminmax.end(),
|
||||||
|
-std::numeric_limits<bst_float>::max());
|
||||||
|
// start accumulating statistics
|
||||||
|
utils::IIterator<ColBatch> *iter = p_fmat->ColIterator();
|
||||||
|
iter->BeforeFirst();
|
||||||
|
while (iter->Next()) {
|
||||||
|
const ColBatch &batch = iter->Value();
|
||||||
|
for (bst_uint i = 0; i < batch.size; ++i) {
|
||||||
|
const bst_uint fid = batch.col_index[i];
|
||||||
|
const ColBatch::Inst &c = batch[i];
|
||||||
|
if (c.length != 0) {
|
||||||
|
fminmax[fid * 2 + 0] = std::max(-c[0].fvalue, fminmax[fid * 2 + 0]);
|
||||||
|
fminmax[fid * 2 + 1] = std::max(c[c.length - 1].fvalue, fminmax[fid * 2 + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sync::AllReduce(BeginPtr(fminmax), fminmax.size(), sync::kMax);
|
||||||
|
}
|
||||||
|
// get feature type, 0:empty 1:binary 2:real
|
||||||
|
inline int Type(bst_uint fid) const {
|
||||||
|
utils::Assert(fid * 2 + 1 < fminmax.size(),
|
||||||
|
"FeatHelper fid exceed query bound ");
|
||||||
|
bst_float a = fminmax[fid * 2];
|
||||||
|
bst_float b = fminmax[fid * 2 + 1];
|
||||||
|
if (a == -std::numeric_limits<bst_float>::max()) return 0;
|
||||||
|
if (-a == b) return 1;
|
||||||
|
else return 2;
|
||||||
|
}
|
||||||
|
inline bst_float MaxValue(bst_uint fid) const {
|
||||||
|
return fminmax[fid *2 + 1];
|
||||||
|
}
|
||||||
|
inline void SampleCol(float p, std::vector<bst_uint> *p_findex) const {
|
||||||
|
std::vector<bst_uint> &findex = *p_findex;
|
||||||
|
findex.clear();
|
||||||
|
for (size_t i = 0; i < fminmax.size(); i += 2) {
|
||||||
|
if (this->Type(i / 2) != 0) findex.push_back(i / 2);
|
||||||
|
}
|
||||||
|
unsigned n = static_cast<unsigned>(p * findex.size());
|
||||||
|
random::Shuffle(findex);
|
||||||
|
findex.resize(n);
|
||||||
|
if (n != findex.size()) {
|
||||||
|
// sync the findex if it is subsample
|
||||||
|
std::string s_cache;
|
||||||
|
utils::MemoryBufferStream fc(&s_cache);
|
||||||
|
utils::IStream &fs = fc;
|
||||||
|
if (sync::GetRank() == 0) {
|
||||||
|
fs.Write(findex);
|
||||||
|
sync::Bcast(&s_cache, 0);
|
||||||
|
} else {
|
||||||
|
sync::Bcast(&s_cache, 0);
|
||||||
|
fs.Read(&findex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<bst_float> fminmax;
|
||||||
|
};
|
||||||
// ------static helper functions ------
|
// ------static helper functions ------
|
||||||
// helper function to get to next level of the tree
|
// helper function to get to next level of the tree
|
||||||
/*! \brief this is helper function for row based data*/
|
/*! \brief this is helper function for row based data*/
|
||||||
|
|||||||
@ -118,19 +118,22 @@ class HistMaker: public BaseMaker {
|
|||||||
ThreadWSpace wspace;
|
ThreadWSpace wspace;
|
||||||
// reducer for histogram
|
// reducer for histogram
|
||||||
sync::Reducer<TStats> histred;
|
sync::Reducer<TStats> histred;
|
||||||
|
// set of working features
|
||||||
|
std::vector<bst_uint> fwork_set;
|
||||||
// update function implementation
|
// update function implementation
|
||||||
virtual void Update(const std::vector<bst_gpair> &gpair,
|
virtual void Update(const std::vector<bst_gpair> &gpair,
|
||||||
IFMatrix *p_fmat,
|
IFMatrix *p_fmat,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
RegTree *p_tree) {
|
RegTree *p_tree) {
|
||||||
this->InitData(gpair, *p_fmat, info.root_index, *p_tree);
|
this->InitData(gpair, *p_fmat, info.root_index, *p_tree);
|
||||||
|
this->InitWorkSet(p_fmat, *p_tree, &fwork_set);
|
||||||
for (int depth = 0; depth < param.max_depth; ++depth) {
|
for (int depth = 0; depth < param.max_depth; ++depth) {
|
||||||
// reset and propose candidate split
|
// reset and propose candidate split
|
||||||
this->ResetPosAndPropose(gpair, p_fmat, info, *p_tree);
|
this->ResetPosAndPropose(gpair, p_fmat, info, fwork_set, *p_tree);
|
||||||
// create histogram
|
// create histogram
|
||||||
this->CreateHist(gpair, p_fmat, info, *p_tree);
|
this->CreateHist(gpair, p_fmat, info, fwork_set, *p_tree);
|
||||||
// find split based on histogram statistics
|
// find split based on histogram statistics
|
||||||
this->FindSplit(depth, gpair, p_fmat, info, p_tree);
|
this->FindSplit(depth, gpair, p_fmat, info, fwork_set, p_tree);
|
||||||
// reset position after split
|
// reset position after split
|
||||||
this->ResetPositionAfterSplit(p_fmat, *p_tree);
|
this->ResetPositionAfterSplit(p_fmat, *p_tree);
|
||||||
this->UpdateQueueExpand(*p_tree);
|
this->UpdateQueueExpand(*p_tree);
|
||||||
@ -148,7 +151,17 @@ class HistMaker: public BaseMaker {
|
|||||||
virtual void ResetPosAndPropose(const std::vector<bst_gpair> &gpair,
|
virtual void ResetPosAndPropose(const std::vector<bst_gpair> &gpair,
|
||||||
IFMatrix *p_fmat,
|
IFMatrix *p_fmat,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
const RegTree &tree) = 0;
|
const std::vector <bst_uint> &fset,
|
||||||
|
const RegTree &tree) = 0;
|
||||||
|
// initialize the current working set of features in this round
|
||||||
|
virtual void InitWorkSet(IFMatrix *p_fmat,
|
||||||
|
const RegTree &tree,
|
||||||
|
std::vector<bst_uint> *p_fset) {
|
||||||
|
p_fset->resize(tree.param.num_feature);
|
||||||
|
for (size_t i = 0; i < p_fset->size(); ++i) {
|
||||||
|
(*p_fset)[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
// reset position after split, this is not a must, depending on implementation
|
// reset position after split, this is not a must, depending on implementation
|
||||||
virtual void ResetPositionAfterSplit(IFMatrix *p_fmat,
|
virtual void ResetPositionAfterSplit(IFMatrix *p_fmat,
|
||||||
const RegTree &tree) {
|
const RegTree &tree) {
|
||||||
@ -156,45 +169,8 @@ class HistMaker: public BaseMaker {
|
|||||||
virtual void CreateHist(const std::vector<bst_gpair> &gpair,
|
virtual void CreateHist(const std::vector<bst_gpair> &gpair,
|
||||||
IFMatrix *p_fmat,
|
IFMatrix *p_fmat,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
const RegTree &tree) {
|
const std::vector <bst_uint> &fset,
|
||||||
bst_uint num_feature = tree.param.num_feature;
|
const RegTree &tree) = 0;
|
||||||
// intialize work space
|
|
||||||
wspace.Init(param, this->get_nthread());
|
|
||||||
// start accumulating statistics
|
|
||||||
utils::IIterator<RowBatch> *iter = p_fmat->RowIterator();
|
|
||||||
iter->BeforeFirst();
|
|
||||||
while (iter->Next()) {
|
|
||||||
const RowBatch &batch = iter->Value();
|
|
||||||
utils::Check(batch.size < std::numeric_limits<unsigned>::max(),
|
|
||||||
"too large batch size ");
|
|
||||||
const bst_omp_uint nbatch = static_cast<bst_omp_uint>(batch.size);
|
|
||||||
#pragma omp parallel for schedule(static)
|
|
||||||
for (bst_omp_uint i = 0; i < nbatch; ++i) {
|
|
||||||
RowBatch::Inst inst = batch[i];
|
|
||||||
const int tid = omp_get_thread_num();
|
|
||||||
HistSet &hset = wspace.hset[tid];
|
|
||||||
const bst_uint ridx = static_cast<bst_uint>(batch.base_rowid + i);
|
|
||||||
int nid = position[ridx];
|
|
||||||
if (nid >= 0) {
|
|
||||||
const int wid = this->node2workindex[nid];
|
|
||||||
for (bst_uint i = 0; i < inst.length; ++i) {
|
|
||||||
utils::Assert(inst[i].index < num_feature, "feature index exceed bound");
|
|
||||||
// feature histogram
|
|
||||||
hset[inst[i].index + wid * (num_feature+1)]
|
|
||||||
.Add(inst[i].fvalue, gpair, info, ridx);
|
|
||||||
}
|
|
||||||
// node histogram, use num_feature to borrow space
|
|
||||||
hset[num_feature + wid * (num_feature + 1)]
|
|
||||||
.data[0].Add(gpair, info, ridx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// accumulating statistics together
|
|
||||||
wspace.Aggregate();
|
|
||||||
// sync the histogram
|
|
||||||
histred.AllReduce(BeginPtr(wspace.hset[0].data), wspace.hset[0].data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void EnumerateSplit(const HistUnit &hist,
|
inline void EnumerateSplit(const HistUnit &hist,
|
||||||
const TStats &node_sum,
|
const TStats &node_sum,
|
||||||
@ -235,8 +211,9 @@ class HistMaker: public BaseMaker {
|
|||||||
const std::vector<bst_gpair> &gpair,
|
const std::vector<bst_gpair> &gpair,
|
||||||
IFMatrix *p_fmat,
|
IFMatrix *p_fmat,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
|
const std::vector <bst_uint> &fset,
|
||||||
RegTree *p_tree) {
|
RegTree *p_tree) {
|
||||||
const bst_uint num_feature = p_tree->param.num_feature;
|
const size_t num_feature = fset.size();
|
||||||
// get the best split condition for each node
|
// get the best split condition for each node
|
||||||
std::vector<SplitEntry> sol(qexpand.size());
|
std::vector<SplitEntry> sol(qexpand.size());
|
||||||
std::vector<TStats> left_sum(qexpand.size());
|
std::vector<TStats> left_sum(qexpand.size());
|
||||||
@ -248,9 +225,9 @@ class HistMaker: public BaseMaker {
|
|||||||
"node2workindex inconsistent");
|
"node2workindex inconsistent");
|
||||||
SplitEntry &best = sol[wid];
|
SplitEntry &best = sol[wid];
|
||||||
TStats &node_sum = wspace.hset[0][num_feature + wid * (num_feature + 1)].data[0];
|
TStats &node_sum = wspace.hset[0][num_feature + wid * (num_feature + 1)].data[0];
|
||||||
for (bst_uint fid = 0; fid < num_feature; ++ fid) {
|
for (size_t i = 0; i < fset.size(); ++ i) {
|
||||||
EnumerateSplit(this->wspace.hset[0][fid + wid * (num_feature+1)],
|
EnumerateSplit(this->wspace.hset[0][i + wid * (num_feature+1)],
|
||||||
node_sum, fid, &best, &left_sum[wid]);
|
node_sum, fset[i], &best, &left_sum[wid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get the best result, we can synchronize the solution
|
// get the best result, we can synchronize the solution
|
||||||
@ -306,15 +283,32 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
hist.data[istart].Add(gpair, info, ridx);
|
hist.data[istart].Add(gpair, info, ridx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// sketch type used for this
|
||||||
typedef utils::WXQuantileSketch<bst_float, bst_float> WXQSketch;
|
typedef utils::WXQuantileSketch<bst_float, bst_float> WXQSketch;
|
||||||
|
// initialize the work set of tree
|
||||||
|
virtual void InitWorkSet(IFMatrix *p_fmat,
|
||||||
|
const RegTree &tree,
|
||||||
|
std::vector<bst_uint> *p_fset) {
|
||||||
|
feat_helper.InitByCol(p_fmat, tree);
|
||||||
|
feat_helper.SampleCol(this->param.colsample_bytree, p_fset);
|
||||||
|
}
|
||||||
|
// code to create histogram
|
||||||
virtual void CreateHist(const std::vector<bst_gpair> &gpair,
|
virtual void CreateHist(const std::vector<bst_gpair> &gpair,
|
||||||
IFMatrix *p_fmat,
|
IFMatrix *p_fmat,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
|
const std::vector<bst_uint> &fset,
|
||||||
const RegTree &tree) {
|
const RegTree &tree) {
|
||||||
|
// fill in reverse map
|
||||||
|
feat2workindex.resize(tree.param.num_feature);
|
||||||
|
std::fill(feat2workindex.begin(), feat2workindex.end(), -1);
|
||||||
|
for (size_t i = 0; i < fset.size(); ++i) {
|
||||||
|
feat2workindex[fset[i]] = static_cast<int>(i);
|
||||||
|
}
|
||||||
|
// start to work
|
||||||
this->wspace.Init(this->param, 1);
|
this->wspace.Init(this->param, 1);
|
||||||
thread_hist.resize(this->get_nthread());
|
thread_hist.resize(this->get_nthread());
|
||||||
// start accumulating statistics
|
// start accumulating statistics
|
||||||
utils::IIterator<ColBatch> *iter = p_fmat->ColIterator();
|
utils::IIterator<ColBatch> *iter = p_fmat->ColIterator(fset);
|
||||||
iter->BeforeFirst();
|
iter->BeforeFirst();
|
||||||
while (iter->Next()) {
|
while (iter->Next()) {
|
||||||
const ColBatch &batch = iter->Value();
|
const ColBatch &batch = iter->Value();
|
||||||
@ -322,15 +316,18 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
const bst_omp_uint nsize = static_cast<bst_omp_uint>(batch.size);
|
const bst_omp_uint nsize = static_cast<bst_omp_uint>(batch.size);
|
||||||
#pragma omp parallel for schedule(dynamic, 1)
|
#pragma omp parallel for schedule(dynamic, 1)
|
||||||
for (bst_omp_uint i = 0; i < nsize; ++i) {
|
for (bst_omp_uint i = 0; i < nsize; ++i) {
|
||||||
this->UpdateHistCol(gpair, batch[i], info, tree,
|
int offset = feat2workindex[batch.col_index[i]];
|
||||||
batch.col_index[i],
|
if (offset >= 0) {
|
||||||
&thread_hist[omp_get_thread_num()]);
|
this->UpdateHistCol(gpair, batch[i], info, tree,
|
||||||
|
fset, offset,
|
||||||
|
&thread_hist[omp_get_thread_num()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < this->qexpand.size(); ++i) {
|
for (size_t i = 0; i < this->qexpand.size(); ++i) {
|
||||||
const int nid = this->qexpand[i];
|
const int nid = this->qexpand[i];
|
||||||
const int wid = this->node2workindex[nid];
|
const int wid = this->node2workindex[nid];
|
||||||
this->wspace.hset[0][tree.param.num_feature + wid * (tree.param.num_feature+1)]
|
this->wspace.hset[0][fset.size() + wid * (fset.size()+1)]
|
||||||
.data[0] = node_stats[nid];
|
.data[0] = node_stats[nid];
|
||||||
}
|
}
|
||||||
// sync the histogram
|
// sync the histogram
|
||||||
@ -343,10 +340,24 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
virtual void ResetPosAndPropose(const std::vector<bst_gpair> &gpair,
|
virtual void ResetPosAndPropose(const std::vector<bst_gpair> &gpair,
|
||||||
IFMatrix *p_fmat,
|
IFMatrix *p_fmat,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
|
const std::vector<bst_uint> &fset,
|
||||||
const RegTree &tree) {
|
const RegTree &tree) {
|
||||||
|
// fill in reverse map
|
||||||
|
feat2workindex.resize(tree.param.num_feature);
|
||||||
|
std::fill(feat2workindex.begin(), feat2workindex.end(), -1);
|
||||||
|
freal_set.clear();
|
||||||
|
for (size_t i = 0; i < fset.size(); ++i) {
|
||||||
|
if (feat_helper.Type(fset[i]) == 2) {
|
||||||
|
feat2workindex[fset[i]] = static_cast<int>(freal_set.size());
|
||||||
|
freal_set.push_back(fset[i]);
|
||||||
|
} else {
|
||||||
|
feat2workindex[fset[i]] = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->GetNodeStats(gpair, *p_fmat, tree, info,
|
this->GetNodeStats(gpair, *p_fmat, tree, info,
|
||||||
&thread_stats, &node_stats);
|
&thread_stats, &node_stats);
|
||||||
sketchs.resize(this->qexpand.size() * tree.param.num_feature);
|
sketchs.resize(this->qexpand.size() * freal_set.size());
|
||||||
for (size_t i = 0; i < sketchs.size(); ++i) {
|
for (size_t i = 0; i < sketchs.size(); ++i) {
|
||||||
sketchs[i].Init(info.num_row, this->param.sketch_eps);
|
sketchs[i].Init(info.num_row, this->param.sketch_eps);
|
||||||
}
|
}
|
||||||
@ -354,7 +365,7 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
// number of rows in
|
// number of rows in
|
||||||
const size_t nrows = p_fmat->buffered_rowset().size();
|
const size_t nrows = p_fmat->buffered_rowset().size();
|
||||||
// start accumulating statistics
|
// start accumulating statistics
|
||||||
utils::IIterator<ColBatch> *iter = p_fmat->ColIterator();
|
utils::IIterator<ColBatch> *iter = p_fmat->ColIterator(freal_set);
|
||||||
iter->BeforeFirst();
|
iter->BeforeFirst();
|
||||||
while (iter->Next()) {
|
while (iter->Next()) {
|
||||||
const ColBatch &batch = iter->Value();
|
const ColBatch &batch = iter->Value();
|
||||||
@ -362,11 +373,14 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
const bst_omp_uint nsize = static_cast<bst_omp_uint>(batch.size);
|
const bst_omp_uint nsize = static_cast<bst_omp_uint>(batch.size);
|
||||||
#pragma omp parallel for schedule(dynamic, 1)
|
#pragma omp parallel for schedule(dynamic, 1)
|
||||||
for (bst_omp_uint i = 0; i < nsize; ++i) {
|
for (bst_omp_uint i = 0; i < nsize; ++i) {
|
||||||
this->UpdateSketchCol(gpair, batch[i], tree,
|
int offset = feat2workindex[batch.col_index[i]];
|
||||||
node_stats,
|
if (offset >= 0) {
|
||||||
batch.col_index[i],
|
this->UpdateSketchCol(gpair, batch[i], tree,
|
||||||
batch[i].length == nrows,
|
node_stats,
|
||||||
&thread_sketch[omp_get_thread_num()]);
|
freal_set, offset,
|
||||||
|
batch[i].length == nrows,
|
||||||
|
&thread_sketch[omp_get_thread_num()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// setup maximum size
|
// setup maximum size
|
||||||
@ -379,36 +393,46 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
summary_array[i].Reserve(max_size);
|
summary_array[i].Reserve(max_size);
|
||||||
summary_array[i].SetPrune(out, max_size);
|
summary_array[i].SetPrune(out, max_size);
|
||||||
}
|
}
|
||||||
size_t n4bytes = (WXQSketch::SummaryContainer::CalcMemCost(max_size) + 3) / 4;
|
if (summary_array.size() != 0) {
|
||||||
sreducer.AllReduce(BeginPtr(summary_array), n4bytes, summary_array.size());
|
size_t n4bytes = (WXQSketch::SummaryContainer::CalcMemCost(max_size) + 3) / 4;
|
||||||
|
sreducer.AllReduce(BeginPtr(summary_array), n4bytes, summary_array.size());
|
||||||
|
}
|
||||||
// now we get the final result of sketch, setup the cut
|
// now we get the final result of sketch, setup the cut
|
||||||
this->wspace.cut.clear();
|
this->wspace.cut.clear();
|
||||||
this->wspace.rptr.clear();
|
this->wspace.rptr.clear();
|
||||||
this->wspace.rptr.push_back(0);
|
this->wspace.rptr.push_back(0);
|
||||||
for (size_t wid = 0; wid < this->qexpand.size(); ++wid) {
|
for (size_t wid = 0; wid < this->qexpand.size(); ++wid) {
|
||||||
for (int fid = 0; fid < tree.param.num_feature; ++fid) {
|
for (size_t i = 0; i < fset.size(); ++i) {
|
||||||
const WXQSketch::Summary &a = summary_array[wid * tree.param.num_feature + fid];
|
int offset = feat2workindex[fset[i]];
|
||||||
for (size_t i = 1; i < a.size; ++i) {
|
if (offset >= 0) {
|
||||||
bst_float cpt = a.data[i].value - rt_eps;
|
const WXQSketch::Summary &a = summary_array[wid * freal_set.size() + offset];
|
||||||
if (i == 1 || cpt > this->wspace.cut.back()) {
|
for (size_t i = 1; i < a.size; ++i) {
|
||||||
this->wspace.cut.push_back(cpt);
|
bst_float cpt = a.data[i].value - rt_eps;
|
||||||
|
if (i == 1 || cpt > this->wspace.cut.back()) {
|
||||||
|
this->wspace.cut.push_back(cpt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// push a value that is greater than anything
|
||||||
|
if (a.size != 0) {
|
||||||
|
bst_float cpt = a.data[a.size - 1].value;
|
||||||
|
// this must be bigger than last value in a scale
|
||||||
|
bst_float last = cpt + fabs(cpt) + rt_eps;
|
||||||
|
this->wspace.cut.push_back(last);
|
||||||
|
}
|
||||||
|
this->wspace.rptr.push_back(this->wspace.cut.size());
|
||||||
|
} else {
|
||||||
|
utils::Assert(offset == -2, "BUG in mark");
|
||||||
|
bst_float cpt = feat_helper.MaxValue(fset[i]);
|
||||||
|
this->wspace.cut.push_back(cpt + fabs(cpt) + rt_eps);
|
||||||
|
this->wspace.rptr.push_back(this->wspace.cut.size());
|
||||||
}
|
}
|
||||||
// push a value that is greater than anything
|
|
||||||
if (a.size != 0) {
|
|
||||||
bst_float cpt = a.data[a.size - 1].value;
|
|
||||||
// this must be bigger than last value in a scale
|
|
||||||
bst_float last = cpt + fabs(cpt) + rt_eps;
|
|
||||||
this->wspace.cut.push_back(last);
|
|
||||||
}
|
|
||||||
this->wspace.rptr.push_back(this->wspace.cut.size());
|
|
||||||
}
|
}
|
||||||
// reserve last value for global statistics
|
// reserve last value for global statistics
|
||||||
this->wspace.cut.push_back(0.0f);
|
this->wspace.cut.push_back(0.0f);
|
||||||
this->wspace.rptr.push_back(this->wspace.cut.size());
|
this->wspace.rptr.push_back(this->wspace.cut.size());
|
||||||
}
|
}
|
||||||
utils::Assert(this->wspace.rptr.size() ==
|
utils::Assert(this->wspace.rptr.size() ==
|
||||||
(tree.param.num_feature + 1) * this->qexpand.size() + 1,
|
(fset.size() + 1) * this->qexpand.size() + 1,
|
||||||
"cut space inconsistent");
|
"cut space inconsistent");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +441,8 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
const ColBatch::Inst &c,
|
const ColBatch::Inst &c,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
const RegTree &tree,
|
const RegTree &tree,
|
||||||
bst_uint fid,
|
const std::vector<bst_uint> &fset,
|
||||||
|
bst_uint fid_offset,
|
||||||
std::vector<HistEntry> *p_temp) {
|
std::vector<HistEntry> *p_temp) {
|
||||||
if (c.length == 0) return;
|
if (c.length == 0) return;
|
||||||
// initialize sbuilder for use
|
// initialize sbuilder for use
|
||||||
@ -427,7 +452,7 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
const unsigned nid = this->qexpand[i];
|
const unsigned nid = this->qexpand[i];
|
||||||
const unsigned wid = this->node2workindex[nid];
|
const unsigned wid = this->node2workindex[nid];
|
||||||
hbuilder[nid].istart = 0;
|
hbuilder[nid].istart = 0;
|
||||||
hbuilder[nid].hist = this->wspace.hset[0][fid + wid * (tree.param.num_feature+1)];
|
hbuilder[nid].hist = this->wspace.hset[0][fid_offset + wid * (fset.size()+1)];
|
||||||
}
|
}
|
||||||
for (bst_uint j = 0; j < c.length; ++j) {
|
for (bst_uint j = 0; j < c.length; ++j) {
|
||||||
const bst_uint ridx = c[j].index;
|
const bst_uint ridx = c[j].index;
|
||||||
@ -441,7 +466,8 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
const ColBatch::Inst &c,
|
const ColBatch::Inst &c,
|
||||||
const RegTree &tree,
|
const RegTree &tree,
|
||||||
const std::vector<TStats> &nstats,
|
const std::vector<TStats> &nstats,
|
||||||
bst_uint fid,
|
const std::vector<bst_uint> &frealset,
|
||||||
|
bst_uint offset,
|
||||||
bool col_full,
|
bool col_full,
|
||||||
std::vector<BaseMaker::SketchEntry> *p_temp) {
|
std::vector<BaseMaker::SketchEntry> *p_temp) {
|
||||||
if (c.length == 0) return;
|
if (c.length == 0) return;
|
||||||
@ -452,7 +478,7 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
const unsigned nid = this->qexpand[i];
|
const unsigned nid = this->qexpand[i];
|
||||||
const unsigned wid = this->node2workindex[nid];
|
const unsigned wid = this->node2workindex[nid];
|
||||||
sbuilder[nid].sum_total = 0.0f;
|
sbuilder[nid].sum_total = 0.0f;
|
||||||
sbuilder[nid].sketch = &sketchs[wid * tree.param.num_feature + fid];
|
sbuilder[nid].sketch = &sketchs[wid * frealset.size() + offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!col_full) {
|
if (!col_full) {
|
||||||
@ -497,7 +523,12 @@ class CQHistMaker: public HistMaker<TStats> {
|
|||||||
sbuilder[nid].Finalize(max_size);
|
sbuilder[nid].Finalize(max_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// feature helper
|
||||||
|
BaseMaker::FMetaHelper feat_helper;
|
||||||
|
// temp space to map feature id to working index
|
||||||
|
std::vector<int> feat2workindex;
|
||||||
|
// set of index from fset that are real
|
||||||
|
std::vector<bst_uint> freal_set;
|
||||||
// thread temp data
|
// thread temp data
|
||||||
std::vector< std::vector<BaseMaker::SketchEntry> > thread_sketch;
|
std::vector< std::vector<BaseMaker::SketchEntry> > thread_sketch;
|
||||||
// used to hold statistics
|
// used to hold statistics
|
||||||
@ -521,6 +552,7 @@ class QuantileHistMaker: public HistMaker<TStats> {
|
|||||||
virtual void ResetPosAndPropose(const std::vector<bst_gpair> &gpair,
|
virtual void ResetPosAndPropose(const std::vector<bst_gpair> &gpair,
|
||||||
IFMatrix *p_fmat,
|
IFMatrix *p_fmat,
|
||||||
const BoosterInfo &info,
|
const BoosterInfo &info,
|
||||||
|
const std::vector <bst_uint> &fset,
|
||||||
const RegTree &tree) {
|
const RegTree &tree) {
|
||||||
// initialize the data structure
|
// initialize the data structure
|
||||||
int nthread = BaseMaker::get_nthread();
|
int nthread = BaseMaker::get_nthread();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user