feature_parallel_tree_learner.cpp 2.58 KB
Newer Older
Guolin Ke's avatar
Guolin Ke committed
1
2
3
4
5
6
7
8
#include "parallel_tree_learner.h"

#include <cstring>

#include <vector>

namespace LightGBM {

Guolin Ke's avatar
Guolin Ke committed
9
FeatureParallelTreeLearner::FeatureParallelTreeLearner(const TreeConfig* tree_config)
Guolin Ke's avatar
Guolin Ke committed
10
  :SerialTreeLearner(tree_config) {
Guolin Ke's avatar
Guolin Ke committed
11
12
13
}

FeatureParallelTreeLearner::~FeatureParallelTreeLearner() {
Guolin Ke's avatar
Guolin Ke committed
14

Guolin Ke's avatar
Guolin Ke committed
15
16
17
18
19
}
void FeatureParallelTreeLearner::Init(const Dataset* train_data) {
  SerialTreeLearner::Init(train_data);
  rank_ = Network::rank();
  num_machines_ = Network::num_machines();
Guolin Ke's avatar
Guolin Ke committed
20
21
  input_buffer_.resize(sizeof(SplitInfo) * 2);
  output_buffer_.resize(sizeof(SplitInfo) * 2);
Guolin Ke's avatar
Guolin Ke committed
22
23
24
25
26
27
28
29
30
}



void FeatureParallelTreeLearner::BeforeTrain() {
  SerialTreeLearner::BeforeTrain();
  // get feature partition
  std::vector<std::vector<int>> feature_distribution(num_machines_, std::vector<int>());
  std::vector<int> num_bins_distributed(num_machines_, 0);
Guolin Ke's avatar
Guolin Ke committed
31
32
33
34
  for (int i = 0; i < train_data_->num_total_features(); ++i) {
    int inner_feature_index = train_data_->InnerFeatureIndex(i);
    if (inner_feature_index == -1) { continue; }
    if (is_feature_used_[inner_feature_index]) {
Guolin Ke's avatar
Guolin Ke committed
35
      int cur_min_machine = static_cast<int>(ArrayArgs<int>::ArgMin(num_bins_distributed));
Guolin Ke's avatar
Guolin Ke committed
36
37
38
      feature_distribution[cur_min_machine].push_back(inner_feature_index);
      num_bins_distributed[cur_min_machine] += train_data_->FeatureNumBin(inner_feature_index);
      is_feature_used_[inner_feature_index] = false;
Guolin Ke's avatar
Guolin Ke committed
39
40
41
42
43
44
45
46
47
48
49
    }
  }
  // get local used features
  for (auto fid : feature_distribution[rank_]) {
    is_feature_used_[fid] = true;
  }
}

void FeatureParallelTreeLearner::FindBestSplitsForLeaves() {
  SplitInfo smaller_best, larger_best;
  // get best split at smaller leaf
Guolin Ke's avatar
Guolin Ke committed
50
51
  smaller_best = best_split_per_leaf_[smaller_leaf_splits_->LeafIndex()];
  // find local best split for larger leaf
Guolin Ke's avatar
Guolin Ke committed
52
  if (larger_leaf_splits_->LeafIndex() >= 0) {
Guolin Ke's avatar
Guolin Ke committed
53
    larger_best = best_split_per_leaf_[larger_leaf_splits_->LeafIndex()];
Guolin Ke's avatar
Guolin Ke committed
54
55
  }
  // sync global best info
Guolin Ke's avatar
Guolin Ke committed
56
57
  std::memcpy(input_buffer_.data(), &smaller_best, sizeof(SplitInfo));
  std::memcpy(input_buffer_.data() + sizeof(SplitInfo), &larger_best, sizeof(SplitInfo));
Guolin Ke's avatar
Guolin Ke committed
58

Guolin Ke's avatar
Guolin Ke committed
59
60
  Network::Allreduce(input_buffer_.data(), sizeof(SplitInfo) * 2, sizeof(SplitInfo),
                     output_buffer_.data(), &SplitInfo::MaxReducer);
Guolin Ke's avatar
Guolin Ke committed
61
  // copy back
Guolin Ke's avatar
Guolin Ke committed
62
63
  std::memcpy(&smaller_best, output_buffer_.data(), sizeof(SplitInfo));
  std::memcpy(&larger_best, output_buffer_.data() + sizeof(SplitInfo), sizeof(SplitInfo));
Guolin Ke's avatar
Guolin Ke committed
64
65
66
67
68
69
70
71
  // update best split
  best_split_per_leaf_[smaller_leaf_splits_->LeafIndex()] = smaller_best;
  if (larger_leaf_splits_->LeafIndex() >= 0) {
    best_split_per_leaf_[larger_leaf_splits_->LeafIndex()] = larger_best;
  }
}

}  // namespace LightGBM