everything is ready, except for propose

This commit is contained in:
tqchen 2014-11-02 21:52:59 -08:00
parent 96c5196647
commit ca96468745
2 changed files with 105 additions and 24 deletions

View File

@ -68,7 +68,7 @@ class TreeModel {
} }
}; };
/*! \brief tree node */ /*! \brief tree node */
class Node{ class Node {
public: public:
/*! \brief index of left child */ /*! \brief index of left child */
inline int cleft(void) const { inline int cleft(void) const {

View File

@ -29,7 +29,7 @@ class HistMaker: public IUpdater {
param.learning_rate = lr / trees.size(); param.learning_rate = lr / trees.size();
// build tree // build tree
for (size_t i = 0; i < trees.size(); ++i) { for (size_t i = 0; i < trees.size(); ++i) {
// TODO this->Update(gpair, p_fmat, info, trees[i]);
} }
param.learning_rate = lr; param.learning_rate = lr;
} }
@ -80,25 +80,16 @@ class HistMaker: public IUpdater {
// per thread histset // per thread histset
std::vector<HistSet> hset; std::vector<HistSet> hset;
// initialize the hist set // initialize the hist set
inline void Init(const TrainParam &param) { inline void Init(const TrainParam &param, int nthread) {
int nthread;
#pragma omp parallel
{
nthread = omp_get_num_threads();
}
hset.resize(nthread); hset.resize(nthread);
// cleanup statistics // cleanup statistics
#pragma omp parallel for (int tid = 0; tid < nthread; ++tid) {
{
int tid = omp_get_thread_num();
for (size_t i = 0; i < hset[tid].data.size(); ++i) { for (size_t i = 0; i < hset[tid].data.size(); ++i) {
hset[tid].data[i].Clear(); hset[tid].data[i].Clear();
} }
} hset[tid].rptr = BeginPtr(rptr);
for (int i = 0; i < nthread; ++i) { hset[tid].cut = BeginPtr(cut);
hset[i].rptr = BeginPtr(rptr); hset[tid].data.resize(cut.size(), TStats(param));
hset[i].cut = BeginPtr(cut);
hset[i].data.resize(cut.size(), TStats(param));
} }
} }
// aggregate all statistics to hset[0] // aggregate all statistics to hset[0]
@ -119,7 +110,7 @@ class HistMaker: public IUpdater {
inline size_t Size(void) const { inline size_t Size(void) const {
return rptr.size() - 1; return rptr.size() - 1;
} }
}; };
// training parameter // training parameter
TrainParam param; TrainParam param;
// workspace of thread // workspace of thread
@ -132,30 +123,116 @@ class HistMaker: public IUpdater {
std::vector<int> node2workindex; std::vector<int> node2workindex;
// reducer for histogram // reducer for histogram
sync::Reducer<TStats> histred; sync::Reducer<TStats> histred;
// helper function to get to next level of the tree
// must work on non-leaf node
inline static int NextLevel(const SparseBatch::Inst &inst, const RegTree &tree, int nid) {
const RegTree::Node &n = tree[nid];
bst_uint findex = n.split_index();
for (unsigned i = 0; i < inst.length; ++i) {
if (findex == inst[i].index) {
if (inst[i].fvalue < n.split_cond()) {
return n.cleft();
} else {
return n.cright();
}
}
}
return n.cdefault();
}
private: private:
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->InitNewNode(qexpand_, gpair, *p_fmat, info, *p_tree); this->UpdateNode2WorkIndex(*p_tree);
for (int depth = 0; depth < param.max_depth; ++depth) { for (int depth = 0; depth < param.max_depth; ++depth) {
this->FindSplit(depth, gpair, p_fmat, info, p_tree); this->FindSplit(depth, gpair, p_fmat, info, p_tree);
//this->ResetPosition(qexpand_, p_fmat, *p_tree); this->UpdateQueueExpand(*p_tree);
//this->UpdateQueueExpand(*p_tree, &qexpand_); this->UpdateNode2WorkIndex(*p_tree);
//this->InitNewNode(qexpand_, gpair, *p_fmat, info, *p_tree);
// if nothing left to be expand, break // if nothing left to be expand, break
if (qexpand.size() == 0) break; if (qexpand.size() == 0) break;
} }
} }
// initialize temp data structure
inline void InitData(const std::vector<bst_gpair> &gpair,
const IFMatrix &fmat,
const std::vector<unsigned> &root_index, const RegTree &tree) {
utils::Assert(tree.param.num_nodes == tree.param.num_roots, "HistMaker: can only grow new tree");
{// setup position
position.resize(gpair.size());
if (root_index.size() == 0) {
std::fill(position.begin(), position.end(), 0);
} else {
for (size_t i = 0; i < position.size(); ++i) {
position[i] = root_index[i];
utils::Assert(root_index[i] < (unsigned)tree.param.num_roots,
"root index exceed setting");
}
}
// mark delete for the deleted datas
for (size_t i = 0; i < position.size(); ++i) {
if (gpair[i].hess < 0.0f) position[i] = ~position[i];
}
// mark subsample
if (param.subsample < 1.0f) {
for (size_t i = 0; i < position.size(); ++i) {
if (gpair[i].hess < 0.0f) continue;
if (random::SampleBinary(param.subsample) == 0) position[i] = ~position[i];
}
}
}
{// expand query
qexpand.reserve(256); qexpand.clear();
for (int i = 0; i < tree.param.num_roots; ++i) {
qexpand.push_back(i);
}
}
}
/*! \brief update queue expand add in new leaves */
inline void UpdateQueueExpand(const RegTree &tree) {
std::vector<int> newnodes;
for (size_t i = 0; i < qexpand.size(); ++i) {
const int nid = qexpand[i];
if (!tree[nid].is_leaf()) {
newnodes.push_back(tree[nid].cleft());
newnodes.push_back(tree[nid].cright());
}
}
// use new nodes for qexpand
qexpand = newnodes;
}
inline void UpdateNode2WorkIndex(const RegTree &tree) {
// update the node2workindex
std::fill(node2workindex.begin(), node2workindex.end(), -1);
node2workindex.resize(tree.param.num_nodes);
for (size_t i = 0; i < qexpand.size(); ++i) {
node2workindex[qexpand[i]] = static_cast<int>(i);
}
}
// this function does two jobs
// (1) reset the position in array position, to be the latest leaf id
// (2) propose a set of candidate cuts and set wspace.rptr wspace.cut correctly
virtual void ResetPosAndPropose(IFMatrix *p_fmat,
const BoosterInfo &info,
const RegTree &tree) {
}
// create histogram for a setup histset // create histogram for a setup histset
inline void CreateHist(const std::vector<bst_gpair> &gpair, inline void CreateHist(const std::vector<bst_gpair> &gpair,
IFMatrix *p_fmat, IFMatrix *p_fmat,
const BoosterInfo &info, const BoosterInfo &info,
const RegTree &tree) { const RegTree &tree) {
bst_uint num_feature = tree.param.num_feature; bst_uint num_feature = tree.param.num_feature;
int nthread;
#pragma omp parallel
{
nthread = omp_get_num_threads();
}
// intialize work space // intialize work space
wspace.Init(param); wspace.Init(param, nthread);
// start accumulating statistics // start accumulating statistics
utils::IIterator<RowBatch> *iter = p_fmat->RowIterator(); utils::IIterator<RowBatch> *iter = p_fmat->RowIterator();
iter->BeforeFirst(); iter->BeforeFirst();
@ -225,6 +302,8 @@ class HistMaker: public IUpdater {
const BoosterInfo &info, const BoosterInfo &info,
RegTree *p_tree) { RegTree *p_tree) {
const bst_uint num_feature = p_tree->param.num_feature; const bst_uint num_feature = p_tree->param.num_feature;
// reset and propose candidate split
this->ResetPosAndPropose(p_fmat, info, *p_tree);
// create histogram // create histogram
this->CreateHist(gpair, p_fmat, info, *p_tree); this->CreateHist(gpair, p_fmat, info, *p_tree);
// get the best split condition for each node // get the best split condition for each node
@ -265,6 +344,8 @@ class HistMaker: public IUpdater {
} }
} }
}; };
} // namespace tree } // namespace tree
} // namespace xgboost } // namespace xgboost
#endif // XGBOOST_TREE_UPDATER_HISTMAKER_INL_HPP_ #endif // XGBOOST_TREE_UPDATER_HISTMAKER_INL_HPP_