chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
/*!
|
||||
* Copyright (c) 2021-2026 Microsoft Corporation. All rights reserved.
|
||||
* Copyright (c) 2021-2026 The LightGBM developers. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE file in the project root for license information.
|
||||
*/
|
||||
|
||||
#ifdef USE_CUDA
|
||||
|
||||
#include <LightGBM/cuda/cuda_tree.hpp>
|
||||
|
||||
namespace LightGBM {
|
||||
|
||||
CUDATree::CUDATree(int max_leaves, bool track_branch_features, bool is_linear,
|
||||
const int gpu_device_id, const bool has_categorical_feature):
|
||||
Tree(max_leaves, track_branch_features, is_linear),
|
||||
num_threads_per_block_add_prediction_to_score_(1024) {
|
||||
is_cuda_tree_ = true;
|
||||
if (gpu_device_id >= 0) {
|
||||
SetCUDADevice(gpu_device_id, __FILE__, __LINE__);
|
||||
} else {
|
||||
SetCUDADevice(0, __FILE__, __LINE__);
|
||||
}
|
||||
if (has_categorical_feature) {
|
||||
cuda_cat_boundaries_.Resize(max_leaves);
|
||||
cuda_cat_boundaries_inner_.Resize(max_leaves);
|
||||
}
|
||||
InitCUDAMemory();
|
||||
}
|
||||
|
||||
CUDATree::CUDATree(const Tree* host_tree):
|
||||
Tree(*host_tree),
|
||||
num_threads_per_block_add_prediction_to_score_(1024) {
|
||||
is_cuda_tree_ = true;
|
||||
InitCUDA();
|
||||
}
|
||||
|
||||
CUDATree::~CUDATree() {
|
||||
gpuAssert(cudaStreamDestroy(cuda_stream_), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void CUDATree::InitCUDAMemory() {
|
||||
cuda_left_child_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_right_child_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_split_feature_inner_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_split_feature_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_leaf_depth_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_leaf_parent_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_threshold_in_bin_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_threshold_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_decision_type_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_leaf_value_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_internal_weight_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_internal_value_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_leaf_weight_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_leaf_count_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_internal_count_.Resize(static_cast<size_t>(max_leaves_));
|
||||
cuda_split_gain_.Resize(static_cast<size_t>(max_leaves_));
|
||||
SetCUDAMemory<double>(cuda_leaf_value_.RawData(), 0.0f, 1, __FILE__, __LINE__);
|
||||
SetCUDAMemory<double>(cuda_leaf_weight_.RawData(), 0.0f, 1, __FILE__, __LINE__);
|
||||
SetCUDAMemory<int>(cuda_leaf_parent_.RawData(), -1, 1, __FILE__, __LINE__);
|
||||
CUDASUCCESS_OR_FATAL(cudaStreamCreate(&cuda_stream_));
|
||||
SynchronizeCUDADevice(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void CUDATree::InitCUDA() {
|
||||
cuda_left_child_.InitFromHostVector(left_child_);
|
||||
cuda_right_child_.InitFromHostVector(right_child_);
|
||||
cuda_split_feature_inner_.InitFromHostVector(split_feature_inner_);
|
||||
cuda_split_feature_.InitFromHostVector(split_feature_);
|
||||
cuda_threshold_in_bin_.InitFromHostVector(threshold_in_bin_);
|
||||
cuda_threshold_.InitFromHostVector(threshold_);
|
||||
cuda_leaf_depth_.InitFromHostVector(leaf_depth_);
|
||||
cuda_decision_type_.InitFromHostVector(decision_type_);
|
||||
cuda_internal_weight_.InitFromHostVector(internal_weight_);
|
||||
cuda_internal_value_.InitFromHostVector(internal_value_);
|
||||
cuda_internal_count_.InitFromHostVector(internal_count_);
|
||||
cuda_leaf_count_.InitFromHostVector(leaf_count_);
|
||||
cuda_split_gain_.InitFromHostVector(split_gain_);
|
||||
cuda_leaf_value_.InitFromHostVector(leaf_value_);
|
||||
cuda_leaf_weight_.InitFromHostVector(leaf_weight_);
|
||||
cuda_leaf_parent_.InitFromHostVector(leaf_parent_);
|
||||
CUDASUCCESS_OR_FATAL(cudaStreamCreate(&cuda_stream_));
|
||||
SynchronizeCUDADevice(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
int CUDATree::Split(const int leaf_index,
|
||||
const int real_feature_index,
|
||||
const double real_threshold,
|
||||
const MissingType missing_type,
|
||||
const CUDASplitInfo* cuda_split_info) {
|
||||
LaunchSplitKernel(leaf_index, real_feature_index, real_threshold, missing_type, cuda_split_info);
|
||||
RecordBranchFeatures(leaf_index, num_leaves_, real_feature_index);
|
||||
++num_leaves_;
|
||||
return num_leaves_ - 1;
|
||||
}
|
||||
|
||||
int CUDATree::SplitCategorical(const int leaf_index,
|
||||
const int real_feature_index,
|
||||
const MissingType missing_type,
|
||||
const CUDASplitInfo* cuda_split_info,
|
||||
uint32_t* cuda_bitset,
|
||||
size_t cuda_bitset_len,
|
||||
uint32_t* cuda_bitset_inner,
|
||||
size_t cuda_bitset_inner_len) {
|
||||
LaunchSplitCategoricalKernel(leaf_index, real_feature_index,
|
||||
missing_type, cuda_split_info,
|
||||
cuda_bitset_len, cuda_bitset_inner_len);
|
||||
cuda_bitset_.PushBack(cuda_bitset, cuda_bitset_len);
|
||||
cuda_bitset_inner_.PushBack(cuda_bitset_inner, cuda_bitset_inner_len);
|
||||
++num_leaves_;
|
||||
++num_cat_;
|
||||
RecordBranchFeatures(leaf_index, num_leaves_, real_feature_index);
|
||||
return num_leaves_ - 1;
|
||||
}
|
||||
|
||||
void CUDATree::RecordBranchFeatures(const int left_leaf_index,
|
||||
const int right_leaf_index,
|
||||
const int real_feature_index) {
|
||||
if (track_branch_features_) {
|
||||
branch_features_[right_leaf_index] = branch_features_[left_leaf_index];
|
||||
branch_features_[right_leaf_index].push_back(real_feature_index);
|
||||
branch_features_[left_leaf_index].push_back(real_feature_index);
|
||||
}
|
||||
}
|
||||
|
||||
void CUDATree::AddPredictionToScore(const Dataset* data,
|
||||
data_size_t num_data,
|
||||
double* score) const {
|
||||
LaunchAddPredictionToScoreKernel(data, nullptr, num_data, score);
|
||||
SynchronizeCUDADevice(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void CUDATree::AddPredictionToScore(const Dataset* data,
|
||||
const data_size_t* used_data_indices,
|
||||
data_size_t num_data, double* score) const {
|
||||
LaunchAddPredictionToScoreKernel(data, used_data_indices, num_data, score);
|
||||
SynchronizeCUDADevice(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
inline void CUDATree::Shrinkage(double rate) {
|
||||
Tree::Shrinkage(rate);
|
||||
LaunchShrinkageKernel(rate);
|
||||
}
|
||||
|
||||
inline void CUDATree::AddBias(double val) {
|
||||
Tree::AddBias(val);
|
||||
LaunchAddBiasKernel(val);
|
||||
}
|
||||
|
||||
void CUDATree::ToHost() {
|
||||
left_child_.resize(max_leaves_ - 1);
|
||||
right_child_.resize(max_leaves_ - 1);
|
||||
split_feature_inner_.resize(max_leaves_ - 1);
|
||||
split_feature_.resize(max_leaves_ - 1);
|
||||
threshold_in_bin_.resize(max_leaves_ - 1);
|
||||
threshold_.resize(max_leaves_ - 1);
|
||||
decision_type_.resize(max_leaves_ - 1, 0);
|
||||
split_gain_.resize(max_leaves_ - 1);
|
||||
leaf_parent_.resize(max_leaves_);
|
||||
leaf_value_.resize(max_leaves_);
|
||||
leaf_weight_.resize(max_leaves_);
|
||||
leaf_count_.resize(max_leaves_);
|
||||
internal_value_.resize(max_leaves_ - 1);
|
||||
internal_weight_.resize(max_leaves_ - 1);
|
||||
internal_count_.resize(max_leaves_ - 1);
|
||||
leaf_depth_.resize(max_leaves_);
|
||||
|
||||
const size_t num_leaves_size = static_cast<size_t>(num_leaves_);
|
||||
CopyFromCUDADeviceToHost<int>(left_child_.data(), cuda_left_child_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<int>(right_child_.data(), cuda_right_child_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<int>(split_feature_inner_.data(), cuda_split_feature_inner_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<int>(split_feature_.data(), cuda_split_feature_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<uint32_t>(threshold_in_bin_.data(), cuda_threshold_in_bin_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<double>(threshold_.data(), cuda_threshold_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<int8_t>(decision_type_.data(), cuda_decision_type_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<float>(split_gain_.data(), cuda_split_gain_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<int>(leaf_parent_.data(), cuda_leaf_parent_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<double>(leaf_value_.data(), cuda_leaf_value_.RawData(), num_leaves_size, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<double>(leaf_weight_.data(), cuda_leaf_weight_.RawData(), num_leaves_size, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<data_size_t>(leaf_count_.data(), cuda_leaf_count_.RawData(), num_leaves_size, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<double>(internal_value_.data(), cuda_internal_value_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<double>(internal_weight_.data(), cuda_internal_weight_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<data_size_t>(internal_count_.data(), cuda_internal_count_.RawData(), num_leaves_size - 1, __FILE__, __LINE__);
|
||||
CopyFromCUDADeviceToHost<int>(leaf_depth_.data(), cuda_leaf_depth_.RawData(), num_leaves_size, __FILE__, __LINE__);
|
||||
|
||||
if (num_cat_ > 0) {
|
||||
cuda_cat_boundaries_inner_.Resize(num_cat_ + 1);
|
||||
cuda_cat_boundaries_.Resize(num_cat_ + 1);
|
||||
cat_boundaries_ = cuda_cat_boundaries_.ToHost();
|
||||
cat_boundaries_inner_ = cuda_cat_boundaries_inner_.ToHost();
|
||||
cat_threshold_ = cuda_bitset_.ToHost();
|
||||
cat_threshold_inner_ = cuda_bitset_inner_.ToHost();
|
||||
}
|
||||
|
||||
SynchronizeCUDADevice(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void CUDATree::SyncLeafOutputFromHostToCUDA() {
|
||||
CopyFromHostToCUDADevice<double>(cuda_leaf_value_.RawData(), leaf_value_.data(), leaf_value_.size(), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void CUDATree::SyncLeafOutputFromCUDAToHost() {
|
||||
CopyFromCUDADeviceToHost<double>(leaf_value_.data(), cuda_leaf_value_.RawData(), leaf_value_.size(), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void CUDATree::AsConstantTree(double val, int count) {
|
||||
Tree::AsConstantTree(val, count);
|
||||
CopyFromHostToCUDADevice<double>(cuda_leaf_value_.RawData(), &val, 1, __FILE__, __LINE__);
|
||||
CopyFromHostToCUDADevice<int>(cuda_leaf_count_.RawData(), &count, 1, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
} // namespace LightGBM
|
||||
|
||||
#endif // USE_CUDA
|
||||
Reference in New Issue
Block a user