sync Jun 1
This commit is contained in:
@@ -497,6 +497,77 @@ TEST(HistUtil, AdapterDeviceSketchBatches) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
auto MakeData(Context const* ctx, std::size_t n_samples, bst_feature_t n_features) {
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
dh::safe_cuda(cudaSetDevice(ctx->gpu_id));
|
||||
#elif defined(XGBOOST_USE_HIP)
|
||||
dh::safe_cuda(hipSetDevice(ctx->gpu_id));
|
||||
#endif
|
||||
auto n = n_samples * n_features;
|
||||
std::vector<float> x;
|
||||
x.resize(n);
|
||||
|
||||
std::iota(x.begin(), x.end(), 0);
|
||||
std::int32_t c{0};
|
||||
float missing = n_samples * n_features;
|
||||
for (std::size_t i = 0; i < x.size(); ++i) {
|
||||
if (i % 5 == 0) {
|
||||
x[i] = missing;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
thrust::device_vector<float> d_x;
|
||||
d_x = x;
|
||||
|
||||
auto n_invalids = n / 10 * 2 + 1;
|
||||
auto is_valid = data::IsValidFunctor{missing};
|
||||
return std::tuple{x, d_x, n_invalids, is_valid};
|
||||
}
|
||||
|
||||
void TestGetColumnSize(std::size_t n_samples) {
|
||||
auto ctx = MakeCUDACtx(0);
|
||||
bst_feature_t n_features = 12;
|
||||
[[maybe_unused]] auto [x, d_x, n_invalids, is_valid] = MakeData(&ctx, n_samples, n_features);
|
||||
|
||||
auto adapter = AdapterFromData(d_x, n_samples, n_features);
|
||||
auto batch = adapter.Value();
|
||||
|
||||
auto batch_iter = dh::MakeTransformIterator<data::COOTuple>(
|
||||
thrust::make_counting_iterator(0llu),
|
||||
[=] __device__(std::size_t idx) { return batch.GetElement(idx); });
|
||||
|
||||
dh::caching_device_vector<std::size_t> column_sizes_scan;
|
||||
column_sizes_scan.resize(n_features + 1);
|
||||
std::vector<std::size_t> h_column_size(column_sizes_scan.size());
|
||||
std::vector<std::size_t> h_column_size_1(column_sizes_scan.size());
|
||||
|
||||
detail::LaunchGetColumnSizeKernel<decltype(batch_iter), true, true>(
|
||||
ctx.gpu_id, IterSpan{batch_iter, batch.Size()}, is_valid, dh::ToSpan(column_sizes_scan));
|
||||
thrust::copy(column_sizes_scan.begin(), column_sizes_scan.end(), h_column_size.begin());
|
||||
|
||||
detail::LaunchGetColumnSizeKernel<decltype(batch_iter), true, false>(
|
||||
ctx.gpu_id, IterSpan{batch_iter, batch.Size()}, is_valid, dh::ToSpan(column_sizes_scan));
|
||||
thrust::copy(column_sizes_scan.begin(), column_sizes_scan.end(), h_column_size_1.begin());
|
||||
ASSERT_EQ(h_column_size, h_column_size_1);
|
||||
|
||||
detail::LaunchGetColumnSizeKernel<decltype(batch_iter), false, true>(
|
||||
ctx.gpu_id, IterSpan{batch_iter, batch.Size()}, is_valid, dh::ToSpan(column_sizes_scan));
|
||||
thrust::copy(column_sizes_scan.begin(), column_sizes_scan.end(), h_column_size_1.begin());
|
||||
ASSERT_EQ(h_column_size, h_column_size_1);
|
||||
|
||||
detail::LaunchGetColumnSizeKernel<decltype(batch_iter), false, false>(
|
||||
ctx.gpu_id, IterSpan{batch_iter, batch.Size()}, is_valid, dh::ToSpan(column_sizes_scan));
|
||||
thrust::copy(column_sizes_scan.begin(), column_sizes_scan.end(), h_column_size_1.begin());
|
||||
ASSERT_EQ(h_column_size, h_column_size_1);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(HistUtil, GetColumnSize) {
|
||||
bst_row_t n_samples = 4096;
|
||||
TestGetColumnSize(n_samples);
|
||||
}
|
||||
|
||||
// Check sketching from adapter or DMatrix results in the same answer
|
||||
// Consistency here is useful for testing and user experience
|
||||
TEST(HistUtil, SketchingEquivalent) {
|
||||
|
||||
@@ -56,7 +56,7 @@ void TestSketchUnique(float sparsity) {
|
||||
thrust::make_counting_iterator(0llu),
|
||||
[=] __device__(size_t idx) { return batch.GetElement(idx); });
|
||||
auto end = kCols * kRows;
|
||||
detail::GetColumnSizesScan(0, kCols, n_cuts, batch_iter, is_valid, 0, end,
|
||||
detail::GetColumnSizesScan(0, kCols, n_cuts, IterSpan{batch_iter, end}, is_valid,
|
||||
&cut_sizes_scan, &column_sizes_scan);
|
||||
auto const& cut_sizes = cut_sizes_scan.HostVector();
|
||||
ASSERT_LE(sketch.Data().size(), cut_sizes.back());
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
/*!
|
||||
* Copyright 2018 XGBoost contributors
|
||||
/**
|
||||
* Copyright 2018-2023, XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <vector>
|
||||
|
||||
#include <xgboost/span.h>
|
||||
#include "test_span.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace common {
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/span.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../../../src/common/transform_iterator.h" // for MakeIndexTransformIter
|
||||
|
||||
namespace xgboost::common {
|
||||
TEST(Span, TestStatus) {
|
||||
int status = 1;
|
||||
TestTestStatus {&status}();
|
||||
@@ -526,5 +527,17 @@ TEST(SpanDeathTest, Empty) {
|
||||
Span<float> s{data.data(), static_cast<Span<float>::index_type>(0)};
|
||||
EXPECT_DEATH(s[0], ""); // not ok to use it.
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace xgboost
|
||||
|
||||
TEST(IterSpan, Basic) {
|
||||
auto iter = common::MakeIndexTransformIter([](std::size_t i) { return i; });
|
||||
std::size_t n = 13;
|
||||
auto span = IterSpan{iter, n};
|
||||
ASSERT_EQ(span.size(), n);
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
ASSERT_EQ(span[i], i);
|
||||
}
|
||||
ASSERT_EQ(span.subspan(1).size(), n - 1);
|
||||
ASSERT_EQ(span.subspan(1)[0], 1);
|
||||
ASSERT_EQ(span.subspan(1, 2)[1], 2);
|
||||
}
|
||||
} // namespace xgboost::common
|
||||
|
||||
@@ -62,3 +62,22 @@ void TestCudfAdapter()
|
||||
TEST(DeviceAdapter, CudfAdapter) {
|
||||
TestCudfAdapter();
|
||||
}
|
||||
|
||||
namespace xgboost::data {
|
||||
TEST(DeviceAdapter, GetRowCounts) {
|
||||
auto ctx = MakeCUDACtx(0);
|
||||
|
||||
for (bst_feature_t n_features : {1, 2, 4, 64, 128, 256}) {
|
||||
HostDeviceVector<float> storage;
|
||||
auto str_arr = RandomDataGenerator{8192, n_features, 0.0}
|
||||
.Device(ctx.gpu_id)
|
||||
.GenerateArrayInterface(&storage);
|
||||
auto adapter = CupyAdapter{str_arr};
|
||||
HostDeviceVector<bst_row_t> offset(adapter.NumRows() + 1, 0);
|
||||
offset.SetDevice(ctx.gpu_id);
|
||||
auto rstride = GetRowCounts(adapter.Value(), offset.DeviceSpan(), ctx.gpu_id,
|
||||
std::numeric_limits<float>::quiet_NaN());
|
||||
ASSERT_EQ(rstride, n_features);
|
||||
}
|
||||
}
|
||||
} // namespace xgboost::data
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "../../src/collective/communicator-inl.h"
|
||||
#include "../../src/common/common.h"
|
||||
#include "../../src/common/threading_utils.h"
|
||||
#include "../../src/data/array_interface.h"
|
||||
#include "filesystem.h" // dmlc::TemporaryDirectory
|
||||
#include "xgboost/linalg.h"
|
||||
@@ -388,6 +389,23 @@ inline Context CreateEmptyGenericParam(int gpu_id) {
|
||||
return tparam;
|
||||
}
|
||||
|
||||
inline std::unique_ptr<HostDeviceVector<GradientPair>> GenerateGradients(
|
||||
std::size_t rows, bst_target_t n_targets = 1) {
|
||||
auto p_gradients = std::make_unique<HostDeviceVector<GradientPair>>(rows * n_targets);
|
||||
auto& h_gradients = p_gradients->HostVector();
|
||||
|
||||
xgboost::SimpleLCG gen;
|
||||
xgboost::SimpleRealUniformDistribution<bst_float> dist(0.0f, 1.0f);
|
||||
|
||||
for (std::size_t i = 0; i < rows * n_targets; ++i) {
|
||||
auto grad = dist(&gen);
|
||||
auto hess = dist(&gen);
|
||||
h_gradients[i] = GradientPair{grad, hess};
|
||||
}
|
||||
|
||||
return p_gradients;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Make a context that uses CUDA.
|
||||
*/
|
||||
@@ -509,11 +527,7 @@ void RunWithInMemoryCommunicator(int32_t world_size, Function&& function, Args&&
|
||||
xgboost::collective::Finalize();
|
||||
};
|
||||
#if defined(_OPENMP)
|
||||
#pragma omp parallel num_threads(world_size)
|
||||
{
|
||||
auto rank = omp_get_thread_num();
|
||||
run(rank);
|
||||
}
|
||||
common::ParallelFor(world_size, world_size, run);
|
||||
#else
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < world_size; rank++) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "../../../plugin/federated/federated_server.h"
|
||||
#include "../../../src/collective/communicator-inl.h"
|
||||
#include "../../../src/common/threading_utils.h"
|
||||
|
||||
namespace xgboost {
|
||||
|
||||
@@ -75,11 +76,7 @@ void RunWithFederatedCommunicator(int32_t world_size, std::string const& server_
|
||||
xgboost::collective::Finalize();
|
||||
};
|
||||
#if defined(_OPENMP)
|
||||
#pragma omp parallel num_threads(world_size)
|
||||
{
|
||||
auto rank = omp_get_thread_num();
|
||||
run(rank);
|
||||
}
|
||||
common::ParallelFor(world_size, world_size, run);
|
||||
#else
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < world_size; rank++) {
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
namespace xgboost {
|
||||
namespace {
|
||||
auto MakeModel(std::string objective, std::shared_ptr<DMatrix> dmat) {
|
||||
auto MakeModel(std::string tree_method, std::string objective, std::shared_ptr<DMatrix> dmat) {
|
||||
std::unique_ptr<Learner> learner{Learner::Create({dmat})};
|
||||
learner->SetParam("tree_method", "approx");
|
||||
learner->SetParam("tree_method", tree_method);
|
||||
learner->SetParam("objective", objective);
|
||||
if (objective.find("quantile") != std::string::npos) {
|
||||
learner->SetParam("quantile_alpha", "0.5");
|
||||
@@ -35,7 +35,7 @@ auto MakeModel(std::string objective, std::shared_ptr<DMatrix> dmat) {
|
||||
}
|
||||
|
||||
void VerifyObjective(size_t rows, size_t cols, float expected_base_score, Json expected_model,
|
||||
std::string objective) {
|
||||
std::string tree_method, std::string objective) {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
std::shared_ptr<DMatrix> dmat{RandomDataGenerator{rows, cols, 0}.GenerateDMatrix(rank == 0)};
|
||||
@@ -61,7 +61,7 @@ void VerifyObjective(size_t rows, size_t cols, float expected_base_score, Json e
|
||||
}
|
||||
std::shared_ptr<DMatrix> sliced{dmat->SliceCol(world_size, rank)};
|
||||
|
||||
auto model = MakeModel(objective, sliced);
|
||||
auto model = MakeModel(tree_method, objective, sliced);
|
||||
auto base_score = GetBaseScore(model);
|
||||
ASSERT_EQ(base_score, expected_base_score);
|
||||
ASSERT_EQ(model, expected_model);
|
||||
@@ -76,7 +76,7 @@ class FederatedLearnerTest : public ::testing::TestWithParam<std::string> {
|
||||
void SetUp() override { server_ = std::make_unique<ServerForTest>(kWorldSize); }
|
||||
void TearDown() override { server_.reset(nullptr); }
|
||||
|
||||
void Run(std::string objective) {
|
||||
void Run(std::string tree_method, std::string objective) {
|
||||
static auto constexpr kRows{16};
|
||||
static auto constexpr kCols{16};
|
||||
|
||||
@@ -99,17 +99,22 @@ class FederatedLearnerTest : public ::testing::TestWithParam<std::string> {
|
||||
}
|
||||
}
|
||||
|
||||
auto model = MakeModel(objective, dmat);
|
||||
auto model = MakeModel(tree_method, objective, dmat);
|
||||
auto score = GetBaseScore(model);
|
||||
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyObjective, kRows, kCols,
|
||||
score, model, objective);
|
||||
score, model, tree_method, objective);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(FederatedLearnerTest, Objective) {
|
||||
TEST_P(FederatedLearnerTest, Approx) {
|
||||
std::string objective = GetParam();
|
||||
this->Run(objective);
|
||||
this->Run("approx", objective);
|
||||
}
|
||||
|
||||
TEST_P(FederatedLearnerTest, Hist) {
|
||||
std::string objective = GetParam();
|
||||
this->Run("hist", objective);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(FederatedLearnerObjective, FederatedLearnerTest,
|
||||
|
||||
@@ -33,7 +33,7 @@ void TestEvaluateSplits(bool force_read_by_column) {
|
||||
|
||||
auto dmat = RandomDataGenerator(kRows, kCols, 0).Seed(3).GenerateDMatrix();
|
||||
|
||||
auto evaluator = HistEvaluator<CPUExpandEntry>{&ctx, ¶m, dmat->Info(), sampler};
|
||||
auto evaluator = HistEvaluator{&ctx, ¶m, dmat->Info(), sampler};
|
||||
common::HistCollection hist;
|
||||
std::vector<GradientPair> row_gpairs = {
|
||||
{1.23f, 0.24f}, {0.24f, 0.25f}, {0.26f, 0.27f}, {2.27f, 0.28f},
|
||||
@@ -167,7 +167,7 @@ TEST(HistEvaluator, Apply) {
|
||||
param.UpdateAllowUnknown(Args{{"min_child_weight", "0"}, {"reg_lambda", "0.0"}});
|
||||
auto dmat = RandomDataGenerator(kNRows, kNCols, 0).Seed(3).GenerateDMatrix();
|
||||
auto sampler = std::make_shared<common::ColumnSampler>();
|
||||
auto evaluator_ = HistEvaluator<CPUExpandEntry>{&ctx, ¶m, dmat->Info(), sampler};
|
||||
auto evaluator_ = HistEvaluator{&ctx, ¶m, dmat->Info(), sampler};
|
||||
|
||||
CPUExpandEntry entry{0, 0};
|
||||
entry.split.loss_chg = 10.0f;
|
||||
@@ -195,7 +195,7 @@ TEST_F(TestPartitionBasedSplit, CPUHist) {
|
||||
// check the evaluator is returning the optimal split
|
||||
std::vector<FeatureType> ft{FeatureType::kCategorical};
|
||||
auto sampler = std::make_shared<common::ColumnSampler>();
|
||||
HistEvaluator<CPUExpandEntry> evaluator{&ctx, ¶m_, info_, sampler};
|
||||
HistEvaluator evaluator{&ctx, ¶m_, info_, sampler};
|
||||
evaluator.InitRoot(GradStats{total_gpair_});
|
||||
RegTree tree;
|
||||
std::vector<CPUExpandEntry> entries(1);
|
||||
@@ -225,7 +225,7 @@ auto CompareOneHotAndPartition(bool onehot) {
|
||||
RandomDataGenerator(kRows, kCols, 0).Seed(3).Type(ft).MaxCategory(n_cats).GenerateDMatrix();
|
||||
|
||||
auto sampler = std::make_shared<common::ColumnSampler>();
|
||||
auto evaluator = HistEvaluator<CPUExpandEntry>{&ctx, ¶m, dmat->Info(), sampler};
|
||||
auto evaluator = HistEvaluator{&ctx, ¶m, dmat->Info(), sampler};
|
||||
std::vector<CPUExpandEntry> entries(1);
|
||||
|
||||
for (auto const &gmat : dmat->GetBatches<GHistIndexMatrix>(&ctx, {32, param.sparse_threshold})) {
|
||||
@@ -276,7 +276,7 @@ TEST_F(TestCategoricalSplitWithMissing, HistEvaluator) {
|
||||
info.num_col_ = 1;
|
||||
info.feature_types = {FeatureType::kCategorical};
|
||||
Context ctx;
|
||||
auto evaluator = HistEvaluator<CPUExpandEntry>{&ctx, ¶m_, info, sampler};
|
||||
auto evaluator = HistEvaluator{&ctx, ¶m_, info, sampler};
|
||||
evaluator.InitRoot(GradStats{parent_sum_});
|
||||
|
||||
std::vector<CPUExpandEntry> entries(1);
|
||||
|
||||
@@ -79,7 +79,7 @@ TEST(CPUMonoConstraint, Basic) {
|
||||
auto Xy = RandomDataGenerator{kRows, kCols, 0.0}.GenerateDMatrix(true);
|
||||
auto sampler = std::make_shared<common::ColumnSampler>();
|
||||
|
||||
HistEvaluator<CPUExpandEntry> evalutor{&ctx, ¶m, Xy->Info(), sampler};
|
||||
HistEvaluator evalutor{&ctx, ¶m, Xy->Info(), sampler};
|
||||
evalutor.InitRoot(GradStats{2.0, 2.0});
|
||||
|
||||
SplitEntry split;
|
||||
|
||||
@@ -9,28 +9,20 @@
|
||||
#include "../helpers.h"
|
||||
|
||||
namespace xgboost::tree {
|
||||
std::shared_ptr<DMatrix> GenerateDMatrix(std::size_t rows, std::size_t cols){
|
||||
return RandomDataGenerator{rows, cols, 0.6f}.Seed(3).GenerateDMatrix();
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDeviceVector<GradientPair>> GenerateGradients(std::size_t rows) {
|
||||
auto p_gradients = std::make_unique<HostDeviceVector<GradientPair>>(rows);
|
||||
auto& h_gradients = p_gradients->HostVector();
|
||||
|
||||
xgboost::SimpleLCG gen;
|
||||
xgboost::SimpleRealUniformDistribution<bst_float> dist(0.0f, 1.0f);
|
||||
|
||||
for (std::size_t i = 0; i < rows; ++i) {
|
||||
auto grad = dist(&gen);
|
||||
auto hess = dist(&gen);
|
||||
h_gradients[i] = GradientPair{grad, hess};
|
||||
std::shared_ptr<DMatrix> GenerateDMatrix(std::size_t rows, std::size_t cols,
|
||||
bool categorical = false) {
|
||||
if (categorical) {
|
||||
std::vector<FeatureType> ft(cols);
|
||||
for (size_t i = 0; i < ft.size(); ++i) {
|
||||
ft[i] = (i % 3 == 0) ? FeatureType::kNumerical : FeatureType::kCategorical;
|
||||
}
|
||||
return RandomDataGenerator(rows, cols, 0.6f).Seed(3).Type(ft).MaxCategory(17).GenerateDMatrix();
|
||||
} else {
|
||||
return RandomDataGenerator{rows, cols, 0.6f}.Seed(3).GenerateDMatrix();
|
||||
}
|
||||
|
||||
return p_gradients;
|
||||
}
|
||||
|
||||
TEST(GrowHistMaker, InteractionConstraint)
|
||||
{
|
||||
TEST(GrowHistMaker, InteractionConstraint) {
|
||||
auto constexpr kRows = 32;
|
||||
auto constexpr kCols = 16;
|
||||
auto p_dmat = GenerateDMatrix(kRows, kCols);
|
||||
@@ -74,8 +66,9 @@ TEST(GrowHistMaker, InteractionConstraint)
|
||||
}
|
||||
|
||||
namespace {
|
||||
void TestColumnSplit(int32_t rows, bst_feature_t cols, RegTree const& expected_tree) {
|
||||
auto p_dmat = GenerateDMatrix(rows, cols);
|
||||
void VerifyColumnSplit(int32_t rows, bst_feature_t cols, bool categorical,
|
||||
RegTree const& expected_tree) {
|
||||
auto p_dmat = GenerateDMatrix(rows, cols, categorical);
|
||||
auto p_gradients = GenerateGradients(rows);
|
||||
Context ctx;
|
||||
ObjInfo task{ObjInfo::kRegression};
|
||||
@@ -90,27 +83,21 @@ void TestColumnSplit(int32_t rows, bst_feature_t cols, RegTree const& expected_t
|
||||
param.Init(Args{});
|
||||
updater->Update(¶m, p_gradients.get(), sliced.get(), position, {&tree});
|
||||
|
||||
ASSERT_EQ(tree.NumExtraNodes(), 10);
|
||||
ASSERT_EQ(tree[0].SplitIndex(), 1);
|
||||
|
||||
ASSERT_NE(tree[tree[0].LeftChild()].SplitIndex(), 0);
|
||||
ASSERT_NE(tree[tree[0].RightChild()].SplitIndex(), 0);
|
||||
|
||||
FeatureMap fmap;
|
||||
auto json = tree.DumpModel(fmap, false, "json");
|
||||
auto expected_json = expected_tree.DumpModel(fmap, false, "json");
|
||||
Json json{Object{}};
|
||||
tree.SaveModel(&json);
|
||||
Json expected_json{Object{}};
|
||||
expected_tree.SaveModel(&expected_json);
|
||||
ASSERT_EQ(json, expected_json);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(GrowHistMaker, ColumnSplit) {
|
||||
void TestColumnSplit(bool categorical) {
|
||||
auto constexpr kRows = 32;
|
||||
auto constexpr kCols = 16;
|
||||
|
||||
RegTree expected_tree{1u, kCols};
|
||||
ObjInfo task{ObjInfo::kRegression};
|
||||
{
|
||||
auto p_dmat = GenerateDMatrix(kRows, kCols);
|
||||
auto p_dmat = GenerateDMatrix(kRows, kCols, categorical);
|
||||
auto p_gradients = GenerateGradients(kRows);
|
||||
Context ctx;
|
||||
std::unique_ptr<TreeUpdater> updater{TreeUpdater::Create("grow_histmaker", &ctx, &task)};
|
||||
@@ -121,6 +108,12 @@ TEST(GrowHistMaker, ColumnSplit) {
|
||||
}
|
||||
|
||||
auto constexpr kWorldSize = 2;
|
||||
RunWithInMemoryCommunicator(kWorldSize, TestColumnSplit, kRows, kCols, std::cref(expected_tree));
|
||||
RunWithInMemoryCommunicator(kWorldSize, VerifyColumnSplit, kRows, kCols, categorical,
|
||||
std::cref(expected_tree));
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(GrowHistMaker, ColumnSplitNumerical) { TestColumnSplit(false); }
|
||||
|
||||
TEST(GrowHistMaker, ColumnSplitCategorical) { TestColumnSplit(true); }
|
||||
} // namespace xgboost::tree
|
||||
|
||||
@@ -113,7 +113,6 @@ void VerifyColumnSplitPartitioner(bst_target_t n_targets, size_t n_samples,
|
||||
|
||||
for (auto const& page : Xy->GetBatches<SparsePage>()) {
|
||||
GHistIndexMatrix gmat(page, {}, cuts, 64, true, 0.5, ctx.Threads());
|
||||
bst_feature_t const split_ind = 0;
|
||||
common::ColumnMatrix column_indices;
|
||||
column_indices.InitFromSparse(page, gmat, 0.5, ctx.Threads());
|
||||
{
|
||||
@@ -194,11 +193,65 @@ void TestColumnSplitPartitioner(bst_target_t n_targets) {
|
||||
|
||||
auto constexpr kWorkers = 4;
|
||||
RunWithInMemoryCommunicator(kWorkers, VerifyColumnSplitPartitioner<ExpandEntry>, n_targets,
|
||||
n_samples, n_features, base_rowid, Xy, min_value, mid_value, mid_partitioner);
|
||||
n_samples, n_features, base_rowid, Xy, min_value, mid_value,
|
||||
mid_partitioner);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(QuantileHist, PartitionerColSplit) { TestColumnSplitPartitioner<CPUExpandEntry>(1); }
|
||||
|
||||
TEST(QuantileHist, MultiPartitionerColSplit) { TestColumnSplitPartitioner<MultiExpandEntry>(3); }
|
||||
|
||||
namespace {
|
||||
void VerifyColumnSplit(bst_row_t rows, bst_feature_t cols, bst_target_t n_targets,
|
||||
RegTree const& expected_tree) {
|
||||
auto Xy = RandomDataGenerator{rows, cols, 0}.GenerateDMatrix(true);
|
||||
auto p_gradients = GenerateGradients(rows, n_targets);
|
||||
Context ctx;
|
||||
ObjInfo task{ObjInfo::kRegression};
|
||||
std::unique_ptr<TreeUpdater> updater{TreeUpdater::Create("grow_quantile_histmaker", &ctx, &task)};
|
||||
std::vector<HostDeviceVector<bst_node_t>> position(1);
|
||||
|
||||
std::unique_ptr<DMatrix> sliced{Xy->SliceCol(collective::GetWorldSize(), collective::GetRank())};
|
||||
|
||||
RegTree tree{n_targets, cols};
|
||||
TrainParam param;
|
||||
param.Init(Args{});
|
||||
updater->Update(¶m, p_gradients.get(), sliced.get(), position, {&tree});
|
||||
|
||||
Json json{Object{}};
|
||||
tree.SaveModel(&json);
|
||||
Json expected_json{Object{}};
|
||||
expected_tree.SaveModel(&expected_json);
|
||||
ASSERT_EQ(json, expected_json);
|
||||
}
|
||||
|
||||
void TestColumnSplit(bst_target_t n_targets) {
|
||||
auto constexpr kRows = 32;
|
||||
auto constexpr kCols = 16;
|
||||
|
||||
RegTree expected_tree{n_targets, kCols};
|
||||
ObjInfo task{ObjInfo::kRegression};
|
||||
{
|
||||
auto Xy = RandomDataGenerator{kRows, kCols, 0}.GenerateDMatrix(true);
|
||||
auto p_gradients = GenerateGradients(kRows, n_targets);
|
||||
Context ctx;
|
||||
std::unique_ptr<TreeUpdater> updater{
|
||||
TreeUpdater::Create("grow_quantile_histmaker", &ctx, &task)};
|
||||
std::vector<HostDeviceVector<bst_node_t>> position(1);
|
||||
TrainParam param;
|
||||
param.Init(Args{});
|
||||
updater->Update(¶m, p_gradients.get(), Xy.get(), position, {&expected_tree});
|
||||
}
|
||||
|
||||
auto constexpr kWorldSize = 2;
|
||||
RunWithInMemoryCommunicator(kWorldSize, VerifyColumnSplit, kRows, kCols, n_targets,
|
||||
std::cref(expected_tree));
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(QuantileHist, ColumnSplit) { TestColumnSplit(1); }
|
||||
|
||||
TEST(QuantileHist, ColumnSplitMultiTarget) { TestColumnSplit(3); }
|
||||
|
||||
} // namespace xgboost::tree
|
||||
|
||||
Reference in New Issue
Block a user