Revamp the rabit implementation. (#10112)
This PR replaces the original RABIT implementation with a new one, which has already been partially merged into XGBoost. The new one features: - Federated learning for both CPU and GPU. - NCCL. - More data types. - A unified interface for all the underlying implementations. - Improved timeout handling for both tracker and workers. - Exhausted tests with metrics (fixed a couple of bugs along the way). - A reusable tracker for Python and JVM packages.
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Copyright 2022-2023, XGBoost Contributors
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/collective/socket.h>
|
||||
|
||||
#include <fstream> // ifstream
|
||||
|
||||
#include "../helpers.h" // for FileExists
|
||||
|
||||
namespace xgboost::collective {
|
||||
class SocketTest : public ::testing::Test {
|
||||
protected:
|
||||
std::string skip_msg_{"Skipping IPv6 test"};
|
||||
|
||||
bool SkipTest() {
|
||||
std::string path{"/sys/module/ipv6/parameters/disable"};
|
||||
if (FileExists(path)) {
|
||||
std::ifstream fin(path);
|
||||
if (!fin) {
|
||||
return true;
|
||||
}
|
||||
std::string s_value;
|
||||
fin >> s_value;
|
||||
auto value = std::stoi(s_value);
|
||||
if (value != 0) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp() override { system::SocketStartup(); }
|
||||
void TearDown() override { system::SocketFinalize(); }
|
||||
};
|
||||
} // namespace xgboost::collective
|
||||
@@ -175,4 +175,35 @@ TEST_F(AllgatherTest, VAlgo) {
|
||||
worker.TestVAlgo();
|
||||
});
|
||||
}
|
||||
|
||||
TEST(VectorAllgatherV, Basic) {
|
||||
std::int32_t n_workers{3};
|
||||
TestDistributedGlobal(n_workers, []() {
|
||||
auto n_workers = collective::GetWorldSize();
|
||||
ASSERT_EQ(n_workers, 3);
|
||||
auto rank = collective::GetRank();
|
||||
// Construct input that has different length for each worker.
|
||||
std::vector<std::vector<char>> inputs;
|
||||
for (std::int32_t i = 0; i < rank + 1; ++i) {
|
||||
std::vector<char> in;
|
||||
for (std::int32_t j = 0; j < rank + 1; ++j) {
|
||||
in.push_back(static_cast<char>(j));
|
||||
}
|
||||
inputs.emplace_back(std::move(in));
|
||||
}
|
||||
|
||||
Context ctx;
|
||||
auto outputs = VectorAllgatherV(&ctx, inputs);
|
||||
|
||||
ASSERT_EQ(outputs.size(), (1 + n_workers) * n_workers / 2);
|
||||
auto const& res = outputs;
|
||||
|
||||
for (std::int32_t i = 0; i < n_workers; ++i) {
|
||||
std::int32_t k = 0;
|
||||
for (auto v : res[i]) {
|
||||
ASSERT_EQ(v, k++);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} // namespace xgboost::collective
|
||||
|
||||
@@ -39,6 +39,22 @@ class AllreduceWorker : public WorkerForTest {
|
||||
}
|
||||
}
|
||||
|
||||
void Restricted() {
|
||||
this->LimitSockBuf(4096);
|
||||
|
||||
std::size_t n = 4096 * 4;
|
||||
std::vector<std::int32_t> data(comm_.World() * n, 1);
|
||||
auto rc = Allreduce(comm_, common::Span{data.data(), data.size()}, [](auto lhs, auto rhs) {
|
||||
for (std::size_t i = 0; i < rhs.size(); ++i) {
|
||||
rhs[i] += lhs[i];
|
||||
}
|
||||
});
|
||||
ASSERT_TRUE(rc.OK());
|
||||
for (auto v : data) {
|
||||
ASSERT_EQ(v, comm_.World());
|
||||
}
|
||||
}
|
||||
|
||||
void Acc() {
|
||||
std::vector<double> data(314, 1.5);
|
||||
auto rc = Allreduce(comm_, common::Span{data.data(), data.size()}, [](auto lhs, auto rhs) {
|
||||
@@ -95,4 +111,45 @@ TEST_F(AllreduceTest, BitOr) {
|
||||
worker.BitOr();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(AllreduceTest, Restricted) {
|
||||
std::int32_t n_workers = std::min(3u, std::thread::hardware_concurrency());
|
||||
TestDistributed(n_workers, [=](std::string host, std::int32_t port, std::chrono::seconds timeout,
|
||||
std::int32_t r) {
|
||||
AllreduceWorker worker{host, port, timeout, n_workers, r};
|
||||
worker.Restricted();
|
||||
});
|
||||
}
|
||||
|
||||
TEST(AllreduceGlobal, Basic) {
|
||||
auto n_workers = 3;
|
||||
TestDistributedGlobal(n_workers, [&]() {
|
||||
std::vector<float> values(n_workers * 2, 0);
|
||||
auto rank = GetRank();
|
||||
auto s_values = common::Span{values.data(), values.size()};
|
||||
auto self = s_values.subspan(rank * 2, 2);
|
||||
for (auto& v : self) {
|
||||
v = 1.0f;
|
||||
}
|
||||
Context ctx;
|
||||
auto rc =
|
||||
Allreduce(&ctx, linalg::MakeVec(s_values.data(), s_values.size()), collective::Op::kSum);
|
||||
SafeColl(rc);
|
||||
for (auto v : s_values) {
|
||||
ASSERT_EQ(v, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TEST(AllreduceGlobal, Small) {
|
||||
// Test when the data is not large enougth to be divided by the number of workers
|
||||
auto n_workers = 8;
|
||||
TestDistributedGlobal(n_workers, [&]() {
|
||||
std::uint64_t value{1};
|
||||
Context ctx;
|
||||
auto rc = Allreduce(&ctx, linalg::MakeVec(&value, 1), collective::Op::kSum);
|
||||
SafeColl(rc);
|
||||
ASSERT_EQ(value, n_workers);
|
||||
});
|
||||
}
|
||||
} // namespace xgboost::collective
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2022 XGBoost contributors
|
||||
*/
|
||||
#include <dmlc/parameter.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../../../src/collective/communicator.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace collective {
|
||||
|
||||
TEST(CommunicatorFactory, TypeFromEnv) {
|
||||
EXPECT_EQ(CommunicatorType::kUnknown, Communicator::GetTypeFromEnv());
|
||||
|
||||
dmlc::SetEnv<std::string>("XGBOOST_COMMUNICATOR", "foo");
|
||||
EXPECT_THROW(Communicator::GetTypeFromEnv(), dmlc::Error);
|
||||
|
||||
dmlc::SetEnv<std::string>("XGBOOST_COMMUNICATOR", "rabit");
|
||||
EXPECT_EQ(CommunicatorType::kRabit, Communicator::GetTypeFromEnv());
|
||||
|
||||
dmlc::SetEnv<std::string>("XGBOOST_COMMUNICATOR", "Federated");
|
||||
EXPECT_EQ(CommunicatorType::kFederated, Communicator::GetTypeFromEnv());
|
||||
|
||||
dmlc::SetEnv<std::string>("XGBOOST_COMMUNICATOR", "In-Memory");
|
||||
EXPECT_EQ(CommunicatorType::kInMemory, Communicator::GetTypeFromEnv());
|
||||
}
|
||||
|
||||
TEST(CommunicatorFactory, TypeFromArgs) {
|
||||
Json config{JsonObject()};
|
||||
EXPECT_EQ(CommunicatorType::kUnknown, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["xgboost_communicator"] = String("rabit");
|
||||
EXPECT_EQ(CommunicatorType::kRabit, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["xgboost_communicator"] = String("federated");
|
||||
EXPECT_EQ(CommunicatorType::kFederated, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["xgboost_communicator"] = String("in-memory");
|
||||
EXPECT_EQ(CommunicatorType::kInMemory, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["xgboost_communicator"] = String("foo");
|
||||
EXPECT_THROW(Communicator::GetTypeFromConfig(config), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(CommunicatorFactory, TypeFromArgsUpperCase) {
|
||||
Json config{JsonObject()};
|
||||
EXPECT_EQ(CommunicatorType::kUnknown, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["XGBOOST_COMMUNICATOR"] = String("rabit");
|
||||
EXPECT_EQ(CommunicatorType::kRabit, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["XGBOOST_COMMUNICATOR"] = String("federated");
|
||||
EXPECT_EQ(CommunicatorType::kFederated, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["XGBOOST_COMMUNICATOR"] = String("in-memory");
|
||||
EXPECT_EQ(CommunicatorType::kInMemory, Communicator::GetTypeFromConfig(config));
|
||||
|
||||
config["XGBOOST_COMMUNICATOR"] = String("foo");
|
||||
EXPECT_THROW(Communicator::GetTypeFromConfig(config), dmlc::Error);
|
||||
}
|
||||
|
||||
} // namespace collective
|
||||
} // namespace xgboost
|
||||
@@ -1,237 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2022 XGBoost contributors
|
||||
*/
|
||||
#include <dmlc/parameter.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <bitset>
|
||||
#include <thread>
|
||||
|
||||
#include "../../../src/collective/in_memory_communicator.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace collective {
|
||||
|
||||
class InMemoryCommunicatorTest : public ::testing::Test {
|
||||
public:
|
||||
static void Verify(void (*function)(int)) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(function, rank);
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
static void Allgather(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllgather(comm, rank);
|
||||
}
|
||||
|
||||
static void AllgatherV(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllgatherV(comm, rank);
|
||||
}
|
||||
|
||||
static void AllreduceMax(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllreduceMax(comm, rank);
|
||||
}
|
||||
|
||||
static void AllreduceMin(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllreduceMin(comm, rank);
|
||||
}
|
||||
|
||||
static void AllreduceSum(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllreduceSum(comm);
|
||||
}
|
||||
|
||||
static void AllreduceBitwiseAND(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllreduceBitwiseAND(comm, rank);
|
||||
}
|
||||
|
||||
static void AllreduceBitwiseOR(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllreduceBitwiseOR(comm, rank);
|
||||
}
|
||||
|
||||
static void AllreduceBitwiseXOR(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyAllreduceBitwiseXOR(comm, rank);
|
||||
}
|
||||
|
||||
static void Broadcast(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
VerifyBroadcast(comm, rank);
|
||||
}
|
||||
|
||||
static void Mixture(int rank) {
|
||||
InMemoryCommunicator comm{kWorldSize, rank};
|
||||
for (auto i = 0; i < 5; i++) {
|
||||
VerifyAllgather(comm, rank);
|
||||
VerifyAllreduceMax(comm, rank);
|
||||
VerifyAllreduceMin(comm, rank);
|
||||
VerifyAllreduceSum(comm);
|
||||
VerifyAllreduceBitwiseAND(comm, rank);
|
||||
VerifyAllreduceBitwiseOR(comm, rank);
|
||||
VerifyAllreduceBitwiseXOR(comm, rank);
|
||||
VerifyBroadcast(comm, rank);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
static void VerifyAllgather(InMemoryCommunicator &comm, int rank) {
|
||||
std::string input{static_cast<char>('0' + rank)};
|
||||
auto output = comm.AllGather(input);
|
||||
for (auto i = 0; i < kWorldSize; i++) {
|
||||
EXPECT_EQ(output[i], static_cast<char>('0' + i));
|
||||
}
|
||||
}
|
||||
|
||||
static void VerifyAllgatherV(InMemoryCommunicator &comm, int rank) {
|
||||
std::vector<std::string_view> inputs{"a", "bb", "ccc"};
|
||||
auto output = comm.AllGatherV(inputs[rank]);
|
||||
EXPECT_EQ(output, "abbccc");
|
||||
}
|
||||
|
||||
static void VerifyAllreduceMax(InMemoryCommunicator &comm, int rank) {
|
||||
int buffer[] = {1 + rank, 2 + rank, 3 + rank, 4 + rank, 5 + rank};
|
||||
comm.AllReduce(buffer, sizeof(buffer) / sizeof(buffer[0]), DataType::kInt32, Operation::kMax);
|
||||
int expected[] = {3, 4, 5, 6, 7};
|
||||
for (auto i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(buffer[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void VerifyAllreduceMin(InMemoryCommunicator &comm, int rank) {
|
||||
int buffer[] = {1 + rank, 2 + rank, 3 + rank, 4 + rank, 5 + rank};
|
||||
comm.AllReduce(buffer, sizeof(buffer) / sizeof(buffer[0]), DataType::kInt32, Operation::kMin);
|
||||
int expected[] = {1, 2, 3, 4, 5};
|
||||
for (auto i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(buffer[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void VerifyAllreduceSum(InMemoryCommunicator &comm) {
|
||||
int buffer[] = {1, 2, 3, 4, 5};
|
||||
comm.AllReduce(buffer, sizeof(buffer) / sizeof(buffer[0]), DataType::kInt32, Operation::kSum);
|
||||
int expected[] = {3, 6, 9, 12, 15};
|
||||
for (auto i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(buffer[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void VerifyAllreduceBitwiseAND(InMemoryCommunicator &comm, int rank) {
|
||||
std::bitset<2> original(rank);
|
||||
auto buffer = original.to_ulong();
|
||||
comm.AllReduce(&buffer, 1, DataType::kUInt32, Operation::kBitwiseAND);
|
||||
EXPECT_EQ(buffer, 0UL);
|
||||
}
|
||||
|
||||
static void VerifyAllreduceBitwiseOR(InMemoryCommunicator &comm, int rank) {
|
||||
std::bitset<2> original(rank);
|
||||
auto buffer = original.to_ulong();
|
||||
comm.AllReduce(&buffer, 1, DataType::kUInt32, Operation::kBitwiseOR);
|
||||
std::bitset<2> actual(buffer);
|
||||
std::bitset<2> expected{0b11};
|
||||
EXPECT_EQ(actual, expected);
|
||||
}
|
||||
|
||||
static void VerifyAllreduceBitwiseXOR(InMemoryCommunicator &comm, int rank) {
|
||||
std::bitset<3> original(rank * 2);
|
||||
auto buffer = original.to_ulong();
|
||||
comm.AllReduce(&buffer, 1, DataType::kUInt32, Operation::kBitwiseXOR);
|
||||
std::bitset<3> actual(buffer);
|
||||
std::bitset<3> expected{0b110};
|
||||
EXPECT_EQ(actual, expected);
|
||||
}
|
||||
|
||||
static void VerifyBroadcast(InMemoryCommunicator &comm, int rank) {
|
||||
if (rank == 0) {
|
||||
std::string buffer{"hello"};
|
||||
comm.Broadcast(&buffer[0], buffer.size(), 0);
|
||||
EXPECT_EQ(buffer, "hello");
|
||||
} else {
|
||||
std::string buffer{" "};
|
||||
comm.Broadcast(&buffer[0], buffer.size(), 0);
|
||||
EXPECT_EQ(buffer, "hello");
|
||||
}
|
||||
}
|
||||
|
||||
static int const kWorldSize{3};
|
||||
};
|
||||
|
||||
TEST(InMemoryCommunicatorSimpleTest, ThrowOnWorldSizeTooSmall) {
|
||||
auto construct = []() { InMemoryCommunicator comm{0, 0}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(InMemoryCommunicatorSimpleTest, ThrowOnRankTooSmall) {
|
||||
auto construct = []() { InMemoryCommunicator comm{1, -1}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(InMemoryCommunicatorSimpleTest, ThrowOnRankTooBig) {
|
||||
auto construct = []() { InMemoryCommunicator comm{1, 1}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(InMemoryCommunicatorSimpleTest, ThrowOnWorldSizeNotInteger) {
|
||||
auto construct = []() {
|
||||
Json config{JsonObject()};
|
||||
config["in_memory_world_size"] = std::string("1");
|
||||
config["in_memory_rank"] = Integer(0);
|
||||
auto *comm = InMemoryCommunicator::Create(config);
|
||||
delete comm;
|
||||
};
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(InMemoryCommunicatorSimpleTest, ThrowOnRankNotInteger) {
|
||||
auto construct = []() {
|
||||
Json config{JsonObject()};
|
||||
config["in_memory_world_size"] = 1;
|
||||
config["in_memory_rank"] = std::string("0");
|
||||
auto *comm = InMemoryCommunicator::Create(config);
|
||||
delete comm;
|
||||
};
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(InMemoryCommunicatorSimpleTest, GetWorldSizeAndRank) {
|
||||
InMemoryCommunicator comm{1, 0};
|
||||
EXPECT_EQ(comm.GetWorldSize(), 1);
|
||||
EXPECT_EQ(comm.GetRank(), 0);
|
||||
}
|
||||
|
||||
TEST(InMemoryCommunicatorSimpleTest, IsDistributed) {
|
||||
InMemoryCommunicator comm{1, 0};
|
||||
EXPECT_TRUE(comm.IsDistributed());
|
||||
}
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, Allgather) { Verify(&Allgather); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, AllgatherV) { Verify(&AllgatherV); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, AllreduceMax) { Verify(&AllreduceMax); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, AllreduceMin) { Verify(&AllreduceMin); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, AllreduceSum) { Verify(&AllreduceSum); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, AllreduceBitwiseAND) { Verify(&AllreduceBitwiseAND); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, AllreduceBitwiseOR) { Verify(&AllreduceBitwiseOR); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, AllreduceBitwiseXOR) { Verify(&AllreduceBitwiseXOR); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, Broadcast) { Verify(&Broadcast); }
|
||||
|
||||
TEST_F(InMemoryCommunicatorTest, Mixture) { Verify(&Mixture); }
|
||||
|
||||
} // namespace collective
|
||||
} // namespace xgboost
|
||||
@@ -59,7 +59,7 @@ class LoopTest : public ::testing::Test {
|
||||
TEST_F(LoopTest, Timeout) {
|
||||
std::vector<std::int8_t> data(1);
|
||||
Loop::Op op{Loop::Op::kRead, 0, data.data(), data.size(), &pair_.second, 0};
|
||||
loop_->Submit(op);
|
||||
loop_->Submit(std::move(op));
|
||||
auto rc = loop_->Block();
|
||||
ASSERT_FALSE(rc.OK());
|
||||
ASSERT_EQ(rc.Code(), std::make_error_code(std::errc::timed_out)) << rc.Report();
|
||||
@@ -75,8 +75,8 @@ TEST_F(LoopTest, Op) {
|
||||
Loop::Op wop{Loop::Op::kWrite, 0, wbuf.data(), wbuf.size(), &send, 0};
|
||||
Loop::Op rop{Loop::Op::kRead, 0, rbuf.data(), rbuf.size(), &recv, 0};
|
||||
|
||||
loop_->Submit(wop);
|
||||
loop_->Submit(rop);
|
||||
loop_->Submit(std::move(wop));
|
||||
loop_->Submit(std::move(rop));
|
||||
|
||||
auto rc = loop_->Block();
|
||||
SafeColl(rc);
|
||||
@@ -90,7 +90,7 @@ TEST_F(LoopTest, Block) {
|
||||
|
||||
common::Timer t;
|
||||
t.Start();
|
||||
loop_->Submit(op);
|
||||
loop_->Submit(std::move(op));
|
||||
t.Stop();
|
||||
// submit is non-blocking
|
||||
ASSERT_LT(t.ElapsedSeconds(), 1);
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* Copyright 2022-2023, XGBoost contributors
|
||||
*/
|
||||
#ifdef XGBOOST_USE_NCCL
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <bitset>
|
||||
#include <string> // for string
|
||||
|
||||
#include "../../../src/collective/comm.cuh"
|
||||
#include "../../../src/collective/communicator-inl.cuh"
|
||||
#include "../../../src/collective/nccl_device_communicator.cuh"
|
||||
#include "../helpers.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace collective {
|
||||
|
||||
TEST(NcclDeviceCommunicatorSimpleTest, ThrowOnInvalidDeviceOrdinal) {
|
||||
auto construct = []() { NcclDeviceCommunicator comm{-1, false, DefaultNcclName()}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(NcclDeviceCommunicatorSimpleTest, SystemError) {
|
||||
auto stub = std::make_shared<NcclStub>(DefaultNcclName());
|
||||
auto rc = stub->GetNcclResult(ncclSystemError);
|
||||
auto msg = rc.Report();
|
||||
ASSERT_TRUE(msg.find("environment variables") != std::string::npos);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void VerifyAllReduceBitwiseAND() {
|
||||
auto const rank = collective::GetRank();
|
||||
std::bitset<64> original{};
|
||||
original[rank] = true;
|
||||
HostDeviceVector<uint64_t> buffer({original.to_ullong()}, DeviceOrd::CUDA(rank));
|
||||
collective::AllReduce<collective::Operation::kBitwiseAND>(rank, buffer.DevicePointer(), 1);
|
||||
collective::Synchronize(rank);
|
||||
EXPECT_EQ(buffer.HostVector()[0], 0ULL);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(NcclDeviceCommunicator, MGPUAllReduceBitwiseAND) {
|
||||
auto const n_gpus = common::AllVisibleGPUs();
|
||||
if (n_gpus <= 1) {
|
||||
GTEST_SKIP() << "Skipping MGPUAllReduceBitwiseAND test with # GPUs = " << n_gpus;
|
||||
}
|
||||
auto constexpr kUseNccl = true;
|
||||
RunWithInMemoryCommunicator<kUseNccl>(n_gpus, VerifyAllReduceBitwiseAND);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void VerifyAllReduceBitwiseOR() {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
std::bitset<64> original{};
|
||||
original[rank] = true;
|
||||
HostDeviceVector<uint64_t> buffer({original.to_ullong()}, DeviceOrd::CUDA(rank));
|
||||
collective::AllReduce<collective::Operation::kBitwiseOR>(rank, buffer.DevicePointer(), 1);
|
||||
collective::Synchronize(rank);
|
||||
EXPECT_EQ(buffer.HostVector()[0], (1ULL << world_size) - 1);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(NcclDeviceCommunicator, MGPUAllReduceBitwiseOR) {
|
||||
auto const n_gpus = common::AllVisibleGPUs();
|
||||
if (n_gpus <= 1) {
|
||||
GTEST_SKIP() << "Skipping MGPUAllReduceBitwiseOR test with # GPUs = " << n_gpus;
|
||||
}
|
||||
auto constexpr kUseNccl = true;
|
||||
RunWithInMemoryCommunicator<kUseNccl>(n_gpus, VerifyAllReduceBitwiseOR);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void VerifyAllReduceBitwiseXOR() {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
std::bitset<64> original{~0ULL};
|
||||
original[rank] = false;
|
||||
HostDeviceVector<uint64_t> buffer({original.to_ullong()}, DeviceOrd::CUDA(rank));
|
||||
collective::AllReduce<collective::Operation::kBitwiseXOR>(rank, buffer.DevicePointer(), 1);
|
||||
collective::Synchronize(rank);
|
||||
EXPECT_EQ(buffer.HostVector()[0], (1ULL << world_size) - 1);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(NcclDeviceCommunicator, MGPUAllReduceBitwiseXOR) {
|
||||
auto const n_gpus = common::AllVisibleGPUs();
|
||||
if (n_gpus <= 1) {
|
||||
GTEST_SKIP() << "Skipping MGPUAllReduceBitwiseXOR test with # GPUs = " << n_gpus;
|
||||
}
|
||||
auto constexpr kUseNccl = true;
|
||||
RunWithInMemoryCommunicator<kUseNccl>(n_gpus, VerifyAllReduceBitwiseXOR);
|
||||
}
|
||||
|
||||
} // namespace collective
|
||||
} // namespace xgboost
|
||||
|
||||
#endif // XGBOOST_USE_NCCL
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* Copyright 2022-2024, XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../../../src/collective/rabit_communicator.h"
|
||||
#include "../helpers.h"
|
||||
|
||||
namespace xgboost::collective {
|
||||
TEST(RabitCommunicatorSimpleTest, ThrowOnWorldSizeTooSmall) {
|
||||
auto construct = []() { RabitCommunicator comm{0, 0}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(RabitCommunicatorSimpleTest, ThrowOnRankTooSmall) {
|
||||
auto construct = []() { RabitCommunicator comm{1, -1}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(RabitCommunicatorSimpleTest, ThrowOnRankTooBig) {
|
||||
auto construct = []() { RabitCommunicator comm{1, 1}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(RabitCommunicatorSimpleTest, GetWorldSizeAndRank) {
|
||||
RabitCommunicator comm{6, 3};
|
||||
EXPECT_EQ(comm.GetWorldSize(), 6);
|
||||
EXPECT_EQ(comm.GetRank(), 3);
|
||||
}
|
||||
|
||||
TEST(RabitCommunicatorSimpleTest, IsNotDistributed) {
|
||||
RabitCommunicator comm{2, 1};
|
||||
// Rabit is only distributed with a tracker.
|
||||
EXPECT_FALSE(comm.IsDistributed());
|
||||
}
|
||||
|
||||
namespace {
|
||||
void VerifyVectorAllgatherV() {
|
||||
auto n_workers = collective::GetWorldSize();
|
||||
ASSERT_EQ(n_workers, 3);
|
||||
auto rank = collective::GetRank();
|
||||
// Construct input that has different length for each worker.
|
||||
std::vector<std::vector<char>> inputs;
|
||||
for (std::int32_t i = 0; i < rank + 1; ++i) {
|
||||
std::vector<char> in;
|
||||
for (std::int32_t j = 0; j < rank + 1; ++j) {
|
||||
in.push_back(static_cast<char>(j));
|
||||
}
|
||||
inputs.emplace_back(std::move(in));
|
||||
}
|
||||
|
||||
auto outputs = VectorAllgatherV(inputs);
|
||||
|
||||
ASSERT_EQ(outputs.size(), (1 + n_workers) * n_workers / 2);
|
||||
auto const& res = outputs;
|
||||
|
||||
for (std::int32_t i = 0; i < n_workers; ++i) {
|
||||
std::int32_t k = 0;
|
||||
for (auto v : res[i]) {
|
||||
ASSERT_EQ(v, k++);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(VectorAllgatherV, Basic) {
|
||||
std::int32_t n_workers{3};
|
||||
RunWithInMemoryCommunicator(n_workers, VerifyVectorAllgatherV);
|
||||
}
|
||||
} // namespace xgboost::collective
|
||||
@@ -29,6 +29,7 @@ class PrintWorker : public WorkerForTest {
|
||||
|
||||
TEST_F(TrackerTest, Bootstrap) {
|
||||
RabitTracker tracker{MakeTrackerConfig(host, n_workers, timeout)};
|
||||
ASSERT_TRUE(HasTimeout(tracker.Timeout()));
|
||||
ASSERT_FALSE(tracker.Ready());
|
||||
auto fut = tracker.Run();
|
||||
|
||||
@@ -47,6 +48,9 @@ TEST_F(TrackerTest, Bootstrap) {
|
||||
w.join();
|
||||
}
|
||||
SafeColl(fut.get());
|
||||
|
||||
ASSERT_FALSE(HasTimeout(std::chrono::seconds{-1}));
|
||||
ASSERT_FALSE(HasTimeout(std::chrono::seconds{0}));
|
||||
}
|
||||
|
||||
TEST_F(TrackerTest, Print) {
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#include "../../../src/collective/tracker.h" // for GetHostAddress
|
||||
#include "../helpers.h" // for FileExists
|
||||
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
#include "../plugin/federated/test_worker.h"
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
|
||||
namespace xgboost::collective {
|
||||
class WorkerForTest {
|
||||
std::string tracker_host_;
|
||||
@@ -45,6 +49,7 @@ class WorkerForTest {
|
||||
if (i != comm_.Rank()) {
|
||||
ASSERT_TRUE(comm_.Chan(i)->Socket()->NonBlocking());
|
||||
ASSERT_TRUE(comm_.Chan(i)->Socket()->SetBufSize(n_bytes).OK());
|
||||
ASSERT_TRUE(comm_.Chan(i)->Socket()->SetNoDelay().OK());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,15 +131,80 @@ void TestDistributed(std::int32_t n_workers, WorkerFn worker_fn) {
|
||||
|
||||
ASSERT_TRUE(fut.get().OK());
|
||||
}
|
||||
|
||||
inline auto MakeDistributedTestConfig(std::string host, std::int32_t port,
|
||||
std::chrono::seconds timeout, std::int32_t r) {
|
||||
Json config{Object{}};
|
||||
config["dmlc_communicator"] = std::string{"rabit"};
|
||||
config["dmlc_tracker_uri"] = host;
|
||||
config["dmlc_tracker_port"] = port;
|
||||
config["dmlc_timeout_sec"] = static_cast<std::int64_t>(timeout.count());
|
||||
config["dmlc_timeout"] = static_cast<std::int64_t>(timeout.count());
|
||||
config["dmlc_task_id"] = std::to_string(r);
|
||||
config["dmlc_retry"] = 2;
|
||||
return config;
|
||||
}
|
||||
|
||||
template <typename WorkerFn>
|
||||
void TestDistributedGlobal(std::int32_t n_workers, WorkerFn worker_fn, bool need_finalize = true) {
|
||||
system::SocketStartup();
|
||||
std::chrono::seconds timeout{1};
|
||||
|
||||
std::string host;
|
||||
auto rc = GetHostAddress(&host);
|
||||
SafeColl(rc);
|
||||
|
||||
RabitTracker tracker{MakeTrackerConfig(host, n_workers, timeout)};
|
||||
auto fut = tracker.Run();
|
||||
|
||||
std::vector<std::thread> workers;
|
||||
std::int32_t port = tracker.Port();
|
||||
|
||||
for (std::int32_t i = 0; i < n_workers; ++i) {
|
||||
workers.emplace_back([=] {
|
||||
auto config = MakeDistributedTestConfig(host, port, timeout, i);
|
||||
Init(config);
|
||||
worker_fn();
|
||||
if (need_finalize) {
|
||||
Finalize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& t : workers) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(fut.get().OK());
|
||||
system::SocketFinalize();
|
||||
}
|
||||
|
||||
class BaseMGPUTest : public ::testing::Test {
|
||||
public:
|
||||
/**
|
||||
* @param emulate_if_single Emulate multi-GPU for federated test if there's only one GPU
|
||||
* available.
|
||||
*/
|
||||
template <typename Fn>
|
||||
auto DoTest(Fn&& fn, bool is_federated, bool emulate_if_single = false) const {
|
||||
auto n_gpus = common::AllVisibleGPUs();
|
||||
if (is_federated) {
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
if (n_gpus == 1 && emulate_if_single) {
|
||||
// Emulate multiple GPUs.
|
||||
// We don't use nccl and can have multiple communicators running on the same device.
|
||||
n_gpus = 3;
|
||||
}
|
||||
TestFederatedGlobal(n_gpus, fn);
|
||||
#else
|
||||
GTEST_SKIP_("Not compiled with federated learning.");
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
} else {
|
||||
#if defined(XGBOOST_USE_NCCL)
|
||||
TestDistributedGlobal(n_gpus, fn);
|
||||
#else
|
||||
GTEST_SKIP_("Not compiled with NCCL.");
|
||||
#endif // defined(XGBOOST_USE_NCCL)
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace xgboost::collective
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace xgboost::common {
|
||||
TEST(MemoryFixSizeBuffer, Seek) {
|
||||
size_t constexpr kSize { 64 };
|
||||
std::vector<int32_t> memory( kSize );
|
||||
rabit::utils::MemoryFixSizeBuffer buf(memory.data(), memory.size());
|
||||
buf.Seek(rabit::utils::MemoryFixSizeBuffer::kSeekEnd);
|
||||
MemoryFixSizeBuffer buf(memory.data(), memory.size());
|
||||
buf.Seek(MemoryFixSizeBuffer::kSeekEnd);
|
||||
size_t end = buf.Tell();
|
||||
ASSERT_EQ(end, kSize);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
/**
|
||||
* Copyright 2020-2023 by XGBoost Contributors
|
||||
* Copyright 2020-2024, XGBoost Contributors
|
||||
*/
|
||||
#include "test_quantile.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint> // for int64_t
|
||||
|
||||
#include "../../../src/collective/allreduce.h"
|
||||
#include "../../../src/common/hist_util.h"
|
||||
#include "../../../src/data/adapter.h"
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "xgboost/context.h"
|
||||
|
||||
namespace xgboost::common {
|
||||
@@ -90,6 +94,7 @@ void DoTestDistributedQuantile(size_t rows, size_t cols) {
|
||||
|
||||
// Generate cuts for single node environment
|
||||
collective::Finalize();
|
||||
|
||||
CHECK_EQ(collective::GetWorldSize(), 1);
|
||||
std::for_each(column_size.begin(), column_size.end(), [=](auto& size) { size *= world; });
|
||||
m->Info().num_row_ = world * rows;
|
||||
@@ -145,7 +150,8 @@ void DoTestDistributedQuantile(size_t rows, size_t cols) {
|
||||
template <bool use_column>
|
||||
void TestDistributedQuantile(size_t const rows, size_t const cols) {
|
||||
auto constexpr kWorkers = 4;
|
||||
RunWithInMemoryCommunicator(kWorkers, DoTestDistributedQuantile<use_column>, rows, cols);
|
||||
collective::TestDistributedGlobal(
|
||||
kWorkers, [=] { DoTestDistributedQuantile<use_column>(rows, cols); }, false);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
@@ -272,7 +278,8 @@ void DoTestColSplitQuantile(size_t rows, size_t cols) {
|
||||
template <bool use_column>
|
||||
void TestColSplitQuantile(size_t rows, size_t cols) {
|
||||
auto constexpr kWorkers = 4;
|
||||
RunWithInMemoryCommunicator(kWorkers, DoTestColSplitQuantile<use_column>, rows, cols);
|
||||
collective::TestDistributedGlobal(kWorkers,
|
||||
[=] { DoTestColSplitQuantile<use_column>(rows, cols); });
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
@@ -324,43 +331,56 @@ void TestSameOnAllWorkers() {
|
||||
cut_ptrs(cuts.Ptrs().size() * world, 0);
|
||||
std::vector<float> cut_min_values(cuts.MinValues().size() * world, 0);
|
||||
|
||||
size_t value_size = cuts.Values().size();
|
||||
collective::Allreduce<collective::Operation::kMax>(&value_size, 1);
|
||||
size_t ptr_size = cuts.Ptrs().size();
|
||||
collective::Allreduce<collective::Operation::kMax>(&ptr_size, 1);
|
||||
CHECK_EQ(ptr_size, kCols + 1);
|
||||
size_t min_value_size = cuts.MinValues().size();
|
||||
collective::Allreduce<collective::Operation::kMax>(&min_value_size, 1);
|
||||
CHECK_EQ(min_value_size, kCols);
|
||||
std::int64_t value_size = cuts.Values().size();
|
||||
std::int64_t ptr_size = cuts.Ptrs().size();
|
||||
std::int64_t min_value_size = cuts.MinValues().size();
|
||||
|
||||
size_t value_offset = value_size * rank;
|
||||
std::copy(cuts.Values().begin(), cuts.Values().end(),
|
||||
cut_values.begin() + value_offset);
|
||||
size_t ptr_offset = ptr_size * rank;
|
||||
std::copy(cuts.Ptrs().cbegin(), cuts.Ptrs().cend(),
|
||||
cut_ptrs.begin() + ptr_offset);
|
||||
size_t min_values_offset = min_value_size * rank;
|
||||
auto rc = collective::Success() << [&] {
|
||||
return collective::Allreduce(&ctx, &value_size, collective::Op::kMax);
|
||||
} << [&] {
|
||||
return collective::Allreduce(&ctx, &ptr_size, collective::Op::kMax);
|
||||
} << [&] {
|
||||
return collective::Allreduce(&ctx, &min_value_size, collective::Op::kMax);
|
||||
};
|
||||
collective::SafeColl(rc);
|
||||
ASSERT_EQ(ptr_size, kCols + 1);
|
||||
ASSERT_EQ(min_value_size, kCols);
|
||||
|
||||
std::size_t value_offset = value_size * rank;
|
||||
std::copy(cuts.Values().begin(), cuts.Values().end(), cut_values.begin() + value_offset);
|
||||
std::size_t ptr_offset = ptr_size * rank;
|
||||
std::copy(cuts.Ptrs().cbegin(), cuts.Ptrs().cend(), cut_ptrs.begin() + ptr_offset);
|
||||
std::size_t min_values_offset = min_value_size * rank;
|
||||
std::copy(cuts.MinValues().cbegin(), cuts.MinValues().cend(),
|
||||
cut_min_values.begin() + min_values_offset);
|
||||
|
||||
collective::Allreduce<collective::Operation::kSum>(cut_values.data(), cut_values.size());
|
||||
collective::Allreduce<collective::Operation::kSum>(cut_ptrs.data(), cut_ptrs.size());
|
||||
collective::Allreduce<collective::Operation::kSum>(cut_min_values.data(), cut_min_values.size());
|
||||
rc = std::move(rc) << [&] {
|
||||
return collective::Allreduce(&ctx, linalg::MakeVec(cut_values.data(), cut_values.size()),
|
||||
collective::Op::kSum);
|
||||
} << [&] {
|
||||
return collective::Allreduce(&ctx, linalg::MakeVec(cut_ptrs.data(), cut_ptrs.size()),
|
||||
collective::Op::kSum);
|
||||
} << [&] {
|
||||
return collective::Allreduce(
|
||||
&ctx, linalg::MakeVec(cut_min_values.data(), cut_min_values.size()),
|
||||
collective::Op::kSum);
|
||||
};
|
||||
collective::SafeColl(rc);
|
||||
|
||||
for (int32_t i = 0; i < world; i++) {
|
||||
for (size_t j = 0; j < value_size; ++j) {
|
||||
for (std::int32_t i = 0; i < world; i++) {
|
||||
for (std::int64_t j = 0; j < value_size; ++j) {
|
||||
size_t idx = i * value_size + j;
|
||||
EXPECT_NEAR(cuts.Values().at(j), cut_values.at(idx), kRtEps);
|
||||
ASSERT_NEAR(cuts.Values().at(j), cut_values.at(idx), kRtEps);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < ptr_size; ++j) {
|
||||
for (std::int64_t j = 0; j < ptr_size; ++j) {
|
||||
size_t idx = i * ptr_size + j;
|
||||
EXPECT_EQ(cuts.Ptrs().at(j), cut_ptrs.at(idx));
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < min_value_size; ++j) {
|
||||
for (std::int64_t j = 0; j < min_value_size; ++j) {
|
||||
size_t idx = i * min_value_size + j;
|
||||
EXPECT_EQ(cuts.MinValues().at(j), cut_min_values.at(idx));
|
||||
ASSERT_EQ(cuts.MinValues().at(j), cut_min_values.at(idx));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -369,6 +389,6 @@ void TestSameOnAllWorkers() {
|
||||
|
||||
TEST(Quantile, SameOnAllWorkers) {
|
||||
auto constexpr kWorkers = 4;
|
||||
RunWithInMemoryCommunicator(kWorkers, TestSameOnAllWorkers);
|
||||
collective::TestDistributedGlobal(kWorkers, [] { TestSameOnAllWorkers(); });
|
||||
}
|
||||
} // namespace xgboost::common
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* Copyright 2020-2023, XGBoost contributors
|
||||
* Copyright 2020-2024, XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../../../src/collective/communicator-inl.cuh"
|
||||
#include "../../../src/collective/allreduce.h"
|
||||
#include "../../../src/common/hist_util.cuh"
|
||||
#include "../../../src/common/quantile.cuh"
|
||||
#include "../../../src/data/device_adapter.cuh" // CupyAdapter
|
||||
#include "../collective/test_worker.h" // for BaseMGPUTest
|
||||
#include "../helpers.h"
|
||||
#include "test_quantile.h"
|
||||
|
||||
@@ -18,9 +19,9 @@ struct IsSorted {
|
||||
}
|
||||
};
|
||||
}
|
||||
namespace common {
|
||||
|
||||
class MGPUQuantileTest : public BaseMGPUTest {};
|
||||
namespace common {
|
||||
class MGPUQuantileTest : public collective::BaseMGPUTest {};
|
||||
|
||||
TEST(GPUQuantile, Basic) {
|
||||
constexpr size_t kRows = 1000, kCols = 100, kBins = 256;
|
||||
@@ -36,7 +37,8 @@ TEST(GPUQuantile, Basic) {
|
||||
|
||||
void TestSketchUnique(float sparsity) {
|
||||
constexpr size_t kRows = 1000, kCols = 100;
|
||||
RunWithSeedsAndBins(kRows, [kRows, kCols, sparsity](int32_t seed, size_t n_bins, MetaInfo const& info) {
|
||||
RunWithSeedsAndBins(kRows, [kRows, kCols, sparsity](std::int32_t seed, bst_bin_t n_bins,
|
||||
MetaInfo const& info) {
|
||||
HostDeviceVector<FeatureType> ft;
|
||||
SketchContainer sketch(ft, n_bins, kCols, kRows, FstCU());
|
||||
|
||||
@@ -121,7 +123,7 @@ void TestQuantileElemRank(DeviceOrd device, Span<SketchEntry const> in,
|
||||
|
||||
TEST(GPUQuantile, Prune) {
|
||||
constexpr size_t kRows = 1000, kCols = 100;
|
||||
RunWithSeedsAndBins(kRows, [=](int32_t seed, size_t n_bins, MetaInfo const& info) {
|
||||
RunWithSeedsAndBins(kRows, [=](std::int32_t seed, bst_bin_t n_bins, MetaInfo const& info) {
|
||||
HostDeviceVector<FeatureType> ft;
|
||||
SketchContainer sketch(ft, n_bins, kCols, kRows, FstCU());
|
||||
|
||||
@@ -190,7 +192,7 @@ TEST(GPUQuantile, MergeEmpty) {
|
||||
|
||||
TEST(GPUQuantile, MergeBasic) {
|
||||
constexpr size_t kRows = 1000, kCols = 100;
|
||||
RunWithSeedsAndBins(kRows, [=](int32_t seed, size_t n_bins, MetaInfo const &info) {
|
||||
RunWithSeedsAndBins(kRows, [=](std::int32_t seed, bst_bin_t n_bins, MetaInfo const& info) {
|
||||
HostDeviceVector<FeatureType> ft;
|
||||
SketchContainer sketch_0(ft, n_bins, kCols, kRows, FstCU());
|
||||
HostDeviceVector<float> storage_0;
|
||||
@@ -260,9 +262,9 @@ void TestMergeDuplicated(int32_t n_bins, size_t cols, size_t rows, float frac) {
|
||||
using Tuple = thrust::tuple<size_t, float>;
|
||||
auto it = thrust::make_zip_iterator(tuple_it);
|
||||
thrust::transform(thrust::device, it, it + data_1.size(), data_1.data(),
|
||||
[=] __device__(Tuple const &tuple) {
|
||||
[=] XGBOOST_DEVICE(Tuple const& tuple) {
|
||||
auto i = thrust::get<0>(tuple);
|
||||
if (thrust::get<0>(tuple) % 2 == 0) {
|
||||
if (i % 2 == 0) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return thrust::get<1>(tuple);
|
||||
@@ -306,7 +308,7 @@ TEST(GPUQuantile, MergeDuplicated) {
|
||||
TEST(GPUQuantile, MultiMerge) {
|
||||
constexpr size_t kRows = 20, kCols = 1;
|
||||
int32_t world = 2;
|
||||
RunWithSeedsAndBins(kRows, [=](int32_t seed, size_t n_bins, MetaInfo const& info) {
|
||||
RunWithSeedsAndBins(kRows, [=](std::int32_t seed, bst_bin_t n_bins, MetaInfo const& info) {
|
||||
// Set up single node version
|
||||
HostDeviceVector<FeatureType> ft;
|
||||
SketchContainer sketch_on_single_node(ft, n_bins, kCols, kRows, FstCU());
|
||||
@@ -368,16 +370,18 @@ namespace {
|
||||
void TestAllReduceBasic() {
|
||||
auto const world = collective::GetWorldSize();
|
||||
constexpr size_t kRows = 1000, kCols = 100;
|
||||
RunWithSeedsAndBins(kRows, [=](int32_t seed, size_t n_bins, MetaInfo const& info) {
|
||||
RunWithSeedsAndBins(kRows, [=](std::int32_t seed, bst_bin_t n_bins, MetaInfo const& info) {
|
||||
auto const device = DeviceOrd::CUDA(GPUIDX);
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
|
||||
// Set up single node version;
|
||||
/**
|
||||
* Set up single node version.
|
||||
*/
|
||||
HostDeviceVector<FeatureType> ft({}, device);
|
||||
SketchContainer sketch_on_single_node(ft, n_bins, kCols, kRows, device);
|
||||
|
||||
size_t intermediate_num_cuts = std::min(
|
||||
kRows * world, static_cast<size_t>(n_bins * WQSketch::kFactor));
|
||||
size_t intermediate_num_cuts =
|
||||
std::min(kRows * world, static_cast<size_t>(n_bins * WQSketch::kFactor));
|
||||
std::vector<SketchContainer> containers;
|
||||
for (auto rank = 0; rank < world; ++rank) {
|
||||
HostDeviceVector<float> storage({}, device);
|
||||
@@ -388,21 +392,22 @@ void TestAllReduceBasic() {
|
||||
data::CupyAdapter adapter(interface_str);
|
||||
HostDeviceVector<FeatureType> ft({}, device);
|
||||
containers.emplace_back(ft, n_bins, kCols, kRows, device);
|
||||
AdapterDeviceSketch(adapter.Value(), n_bins, info,
|
||||
std::numeric_limits<float>::quiet_NaN(),
|
||||
AdapterDeviceSketch(adapter.Value(), n_bins, info, std::numeric_limits<float>::quiet_NaN(),
|
||||
&containers.back());
|
||||
}
|
||||
for (auto &sketch : containers) {
|
||||
for (auto& sketch : containers) {
|
||||
sketch.Prune(intermediate_num_cuts);
|
||||
sketch_on_single_node.Merge(sketch.ColumnsPtr(), sketch.Data());
|
||||
sketch_on_single_node.FixError();
|
||||
}
|
||||
sketch_on_single_node.Unique();
|
||||
TestQuantileElemRank(device, sketch_on_single_node.Data(),
|
||||
sketch_on_single_node.ColumnsPtr(), true);
|
||||
TestQuantileElemRank(device, sketch_on_single_node.Data(), sketch_on_single_node.ColumnsPtr(),
|
||||
true);
|
||||
|
||||
// Set up distributed version. We rely on using rank as seed to generate
|
||||
// the exact same copy of data.
|
||||
/**
|
||||
* Set up distributed version. We rely on using rank as seed to generate
|
||||
* the exact same copy of data.
|
||||
*/
|
||||
auto rank = collective::GetRank();
|
||||
SketchContainer sketch_distributed(ft, n_bins, kCols, kRows, device);
|
||||
HostDeviceVector<float> storage({}, device);
|
||||
@@ -411,22 +416,23 @@ void TestAllReduceBasic() {
|
||||
.Seed(rank + seed)
|
||||
.GenerateArrayInterface(&storage);
|
||||
data::CupyAdapter adapter(interface_str);
|
||||
AdapterDeviceSketch(adapter.Value(), n_bins, info,
|
||||
std::numeric_limits<float>::quiet_NaN(),
|
||||
AdapterDeviceSketch(adapter.Value(), n_bins, info, std::numeric_limits<float>::quiet_NaN(),
|
||||
&sketch_distributed);
|
||||
if (world == 1) {
|
||||
auto n_samples_global = kRows * world;
|
||||
intermediate_num_cuts =
|
||||
std::min(n_samples_global, static_cast<size_t>(n_bins * SketchContainer::kFactor));
|
||||
sketch_distributed.Prune(intermediate_num_cuts);
|
||||
}
|
||||
sketch_distributed.AllReduce(&ctx, false);
|
||||
sketch_distributed.Unique();
|
||||
|
||||
ASSERT_EQ(sketch_distributed.ColumnsPtr().size(),
|
||||
sketch_on_single_node.ColumnsPtr().size());
|
||||
ASSERT_EQ(sketch_distributed.Data().size(),
|
||||
sketch_on_single_node.Data().size());
|
||||
ASSERT_EQ(sketch_distributed.ColumnsPtr().size(), sketch_on_single_node.ColumnsPtr().size());
|
||||
ASSERT_EQ(sketch_distributed.Data().size(), sketch_on_single_node.Data().size());
|
||||
|
||||
TestQuantileElemRank(device, sketch_distributed.Data(),
|
||||
sketch_distributed.ColumnsPtr(), true);
|
||||
TestQuantileElemRank(device, sketch_distributed.Data(), sketch_distributed.ColumnsPtr(), true);
|
||||
|
||||
std::vector<SketchEntry> single_node_data(
|
||||
sketch_on_single_node.Data().size());
|
||||
std::vector<SketchEntry> single_node_data(sketch_on_single_node.Data().size());
|
||||
dh::CopyDeviceSpanToVector(&single_node_data, sketch_on_single_node.Data());
|
||||
|
||||
std::vector<SketchEntry> distributed_data(sketch_distributed.Data().size());
|
||||
@@ -444,7 +450,8 @@ void TestAllReduceBasic() {
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_F(MGPUQuantileTest, AllReduceBasic) {
|
||||
DoTest(TestAllReduceBasic);
|
||||
this->DoTest([] { TestAllReduceBasic(); }, true);
|
||||
this->DoTest([] { TestAllReduceBasic(); }, false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -490,7 +497,8 @@ void TestColumnSplit(DMatrix* dmat) {
|
||||
TEST_F(MGPUQuantileTest, ColumnSplitBasic) {
|
||||
std::size_t constexpr kRows = 1000, kCols = 100;
|
||||
auto dmat = RandomDataGenerator{kRows, kCols, 0}.GenerateDMatrix();
|
||||
DoTest(TestColumnSplit, dmat.get());
|
||||
this->DoTest([&] { TestColumnSplit(dmat.get()); }, true);
|
||||
this->DoTest([&] { TestColumnSplit(dmat.get()); }, false);
|
||||
}
|
||||
|
||||
TEST_F(MGPUQuantileTest, ColumnSplitCategorical) {
|
||||
@@ -507,15 +515,15 @@ TEST_F(MGPUQuantileTest, ColumnSplitCategorical) {
|
||||
.Type(ft)
|
||||
.MaxCategory(13)
|
||||
.GenerateDMatrix();
|
||||
DoTest(TestColumnSplit, dmat.get());
|
||||
this->DoTest([&] { TestColumnSplit(dmat.get()); }, true);
|
||||
this->DoTest([&] { TestColumnSplit(dmat.get()); }, false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void TestSameOnAllWorkers() {
|
||||
auto world = collective::GetWorldSize();
|
||||
constexpr size_t kRows = 1000, kCols = 100;
|
||||
RunWithSeedsAndBins(kRows, [=](int32_t seed, size_t n_bins,
|
||||
MetaInfo const &info) {
|
||||
RunWithSeedsAndBins(kRows, [=](std::int32_t seed, bst_bin_t n_bins, MetaInfo const& info) {
|
||||
auto const rank = collective::GetRank();
|
||||
auto const device = DeviceOrd::CUDA(GPUIDX);
|
||||
Context ctx = MakeCUDACtx(device.ordinal);
|
||||
@@ -536,7 +544,8 @@ void TestSameOnAllWorkers() {
|
||||
|
||||
// Test for all workers having the same sketch.
|
||||
size_t n_data = sketch_distributed.Data().size();
|
||||
collective::Allreduce<collective::Operation::kMax>(&n_data, 1);
|
||||
auto rc = collective::Allreduce(&ctx, linalg::MakeVec(&n_data, 1), collective::Op::kMax);
|
||||
SafeColl(rc);
|
||||
ASSERT_EQ(n_data, sketch_distributed.Data().size());
|
||||
size_t size_as_float =
|
||||
sketch_distributed.Data().size_bytes() / sizeof(float);
|
||||
@@ -549,9 +558,10 @@ void TestSameOnAllWorkers() {
|
||||
thrust::copy(thrust::device, local_data.data(),
|
||||
local_data.data() + local_data.size(),
|
||||
all_workers.begin() + local_data.size() * rank);
|
||||
collective::AllReduce<collective::Operation::kSum>(device.ordinal, all_workers.data().get(),
|
||||
all_workers.size());
|
||||
collective::Synchronize(device.ordinal);
|
||||
rc = collective::Allreduce(
|
||||
&ctx, linalg::MakeVec(all_workers.data().get(), all_workers.size(), ctx.Device()),
|
||||
collective::Op::kSum);
|
||||
SafeColl(rc);
|
||||
|
||||
auto base_line = dh::ToSpan(all_workers).subspan(0, size_as_float);
|
||||
std::vector<float> h_base_line(base_line.size());
|
||||
@@ -573,7 +583,8 @@ void TestSameOnAllWorkers() {
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_F(MGPUQuantileTest, SameOnAllWorkers) {
|
||||
DoTest(TestSameOnAllWorkers);
|
||||
this->DoTest([] { TestSameOnAllWorkers(); }, true);
|
||||
this->DoTest([] { TestSameOnAllWorkers(); }, false);
|
||||
}
|
||||
|
||||
TEST(GPUQuantile, Push) {
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
/**
|
||||
* Copyright 2020-2024, XGBoost Contributors
|
||||
*/
|
||||
#ifndef XGBOOST_TESTS_CPP_COMMON_TEST_QUANTILE_H_
|
||||
#define XGBOOST_TESTS_CPP_COMMON_TEST_QUANTILE_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../helpers.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace common {
|
||||
namespace xgboost::common {
|
||||
template <typename Fn> void RunWithSeedsAndBins(size_t rows, Fn fn) {
|
||||
std::vector<int32_t> seeds(2);
|
||||
SimpleLCG lcg;
|
||||
SimpleRealUniformDistribution<float> dist(3, 1000);
|
||||
std::generate(seeds.begin(), seeds.end(), [&](){ return dist(&lcg); });
|
||||
|
||||
std::vector<size_t> bins(2);
|
||||
std::vector<bst_bin_t> bins(2);
|
||||
for (size_t i = 0; i < bins.size() - 1; ++i) {
|
||||
bins[i] = i * 35 + 2;
|
||||
}
|
||||
@@ -36,7 +37,6 @@ template <typename Fn> void RunWithSeedsAndBins(size_t rows, Fn fn) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace xgboost
|
||||
} // namespace xgboost::common
|
||||
|
||||
#endif // XGBOOST_TESTS_CPP_COMMON_TEST_QUANTILE_H_
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
*/
|
||||
#include "test_metainfo.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <dmlc/io.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <xgboost/data.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "../filesystem.h" // dmlc::TemporaryDirectory
|
||||
#include "../helpers.h" // for GMockTHrow
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../filesystem.h" // dmlc::TemporaryDirectory
|
||||
#include "../helpers.h" // for GMockTHrow
|
||||
#include "xgboost/base.h"
|
||||
|
||||
namespace xgboost {
|
||||
@@ -118,8 +119,8 @@ void VerifyGetSetFeatureColumnSplit() {
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(MetaInfo, GetSetFeatureColumnSplit) {
|
||||
auto constexpr kWorldSize{3};
|
||||
RunWithInMemoryCommunicator(kWorldSize, VerifyGetSetFeatureColumnSplit);
|
||||
auto constexpr kWorkers{3};
|
||||
collective::TestDistributedGlobal(kWorkers, VerifyGetSetFeatureColumnSplit);
|
||||
}
|
||||
|
||||
TEST(MetaInfo, SaveLoadBinary) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "../../../src/data/adapter.h" // ArrayAdapter
|
||||
#include "../../../src/data/simple_dmatrix.h" // SimpleDMatrix
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../filesystem.h" // dmlc::TemporaryDirectory
|
||||
#include "../helpers.h" // RandomDataGenerator,CreateSimpleTestData
|
||||
#include "xgboost/base.h"
|
||||
@@ -444,5 +445,5 @@ void VerifyColumnSplit() {
|
||||
|
||||
TEST(SimpleDMatrix, ColumnSplit) {
|
||||
auto constexpr kWorldSize{3};
|
||||
RunWithInMemoryCommunicator(kWorldSize, VerifyColumnSplit);
|
||||
collective::TestDistributedGlobal(kWorldSize, VerifyColumnSplit);
|
||||
}
|
||||
|
||||
@@ -520,67 +520,6 @@ inline LearnerModelParam MakeMP(bst_feature_t n_features, float base_score, uint
|
||||
|
||||
inline std::int32_t AllThreadsForTest() { return Context{}.Threads(); }
|
||||
|
||||
template <bool use_nccl = false, typename Function, typename... Args>
|
||||
void RunWithInMemoryCommunicator(int32_t world_size, Function&& function, Args&&... args) {
|
||||
auto run = [&](auto rank) {
|
||||
Json config{JsonObject()};
|
||||
if constexpr (use_nccl) {
|
||||
config["xgboost_communicator"] = String("in-memory-nccl");
|
||||
} else {
|
||||
config["xgboost_communicator"] = String("in-memory");
|
||||
}
|
||||
config["in_memory_world_size"] = world_size;
|
||||
config["in_memory_rank"] = rank;
|
||||
xgboost::collective::Init(config);
|
||||
|
||||
std::forward<Function>(function)(std::forward<Args>(args)...);
|
||||
|
||||
xgboost::collective::Finalize();
|
||||
};
|
||||
#if defined(_OPENMP)
|
||||
common::ParallelFor(world_size, world_size, run);
|
||||
#else
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < world_size; rank++) {
|
||||
threads.emplace_back(run, rank);
|
||||
}
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class BaseMGPUTest : public ::testing::Test {
|
||||
protected:
|
||||
int world_size_;
|
||||
bool use_nccl_{false};
|
||||
|
||||
void SetUp() override {
|
||||
auto const n_gpus = common::AllVisibleGPUs();
|
||||
if (n_gpus <= 1) {
|
||||
// Use a single GPU to simulate distributed environment.
|
||||
world_size_ = 3;
|
||||
// NCCL doesn't like sharing a single GPU, so we use the adapter instead.
|
||||
use_nccl_ = false;
|
||||
} else {
|
||||
// Use multiple GPUs for real.
|
||||
world_size_ = n_gpus;
|
||||
use_nccl_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Function, typename... Args>
|
||||
void DoTest(Function&& function, Args&&... args) {
|
||||
if (use_nccl_) {
|
||||
RunWithInMemoryCommunicator<true>(world_size_, function, args...);
|
||||
} else {
|
||||
RunWithInMemoryCommunicator<false>(world_size_, function, args...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DeclareUnifiedDistributedTest(MetricTest) : public BaseMGPUTest{};
|
||||
|
||||
inline DeviceOrd FstCU() { return DeviceOrd::CUDA(0); }
|
||||
|
||||
inline auto GMockThrow(StringView msg) {
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#include "test_auc.h"
|
||||
|
||||
#include <xgboost/metric.h>
|
||||
|
||||
namespace xgboost {
|
||||
namespace metric {
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(BinaryAUC)) { VerifyBinaryAUC(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MultiClassAUC)) { VerifyMultiClassAUC(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(RankingAUC)) { VerifyRankingAUC(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(PRAUC)) { VerifyPRAUC(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MultiClassPRAUC)) { VerifyMultiClassPRAUC(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(RankingPRAUC)) { VerifyRankingPRAUC(); }
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), BinaryAUCRowSplit) {
|
||||
DoTest(VerifyBinaryAUC, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), BinaryAUCColumnSplit) {
|
||||
DoTest(VerifyBinaryAUC, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassAUCRowSplit) {
|
||||
DoTest(VerifyMultiClassAUC, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassAUCColumnSplit) {
|
||||
DoTest(VerifyMultiClassAUC, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RankingAUCRowSplit) {
|
||||
DoTest(VerifyRankingAUC, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RankingAUCColumnSplit) {
|
||||
DoTest(VerifyRankingAUC, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), PRAUCRowSplit) {
|
||||
DoTest(VerifyPRAUC, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), PRAUCColumnSplit) {
|
||||
DoTest(VerifyPRAUC, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassPRAUCRowSplit) {
|
||||
DoTest(VerifyMultiClassPRAUC, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassPRAUCColumnSplit) {
|
||||
DoTest(VerifyMultiClassPRAUC, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RankingPRAUCRowSplit) {
|
||||
DoTest(VerifyRankingPRAUC, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RankingPRAUCColumnSplit) {
|
||||
DoTest(VerifyRankingPRAUC, DataSplitMode::kCol);
|
||||
}
|
||||
} // namespace metric
|
||||
} // namespace xgboost
|
||||
@@ -1,5 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2021 XGBoost contributors
|
||||
*/
|
||||
// Dummy file to keep the CUDA conditional compile trick.
|
||||
#include "test_auc.cc"
|
||||
@@ -7,11 +7,9 @@
|
||||
|
||||
#include "../helpers.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace metric {
|
||||
|
||||
inline void VerifyBinaryAUC(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
namespace xgboost::metric {
|
||||
inline void VerifyBinaryAUC(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
std::unique_ptr<Metric> uni_ptr{Metric::Create("auc", &ctx)};
|
||||
Metric* metric = uni_ptr.get();
|
||||
ASSERT_STREQ(metric->Name(), "auc");
|
||||
@@ -53,8 +51,8 @@ inline void VerifyBinaryAUC(DataSplitMode data_split_mode = DataSplitMode::kRow)
|
||||
0.5, 1e-10);
|
||||
}
|
||||
|
||||
inline void VerifyMultiClassAUC(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyMultiClassAUC(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
std::unique_ptr<Metric> uni_ptr{Metric::Create("auc", &ctx)};
|
||||
auto metric = uni_ptr.get();
|
||||
|
||||
@@ -114,8 +112,8 @@ inline void VerifyMultiClassAUC(DataSplitMode data_split_mode = DataSplitMode::k
|
||||
ASSERT_GT(auc, 0.714);
|
||||
}
|
||||
|
||||
inline void VerifyRankingAUC(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyRankingAUC(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
std::unique_ptr<Metric> metric{Metric::Create("auc", &ctx)};
|
||||
|
||||
// single group
|
||||
@@ -148,8 +146,8 @@ inline void VerifyRankingAUC(DataSplitMode data_split_mode = DataSplitMode::kRow
|
||||
0.769841f, 1e-6);
|
||||
}
|
||||
|
||||
inline void VerifyPRAUC(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyPRAUC(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
|
||||
xgboost::Metric* metric = xgboost::Metric::Create("aucpr", &ctx);
|
||||
ASSERT_STREQ(metric->Name(), "aucpr");
|
||||
@@ -185,8 +183,8 @@ inline void VerifyPRAUC(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
delete metric;
|
||||
}
|
||||
|
||||
inline void VerifyMultiClassPRAUC(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyMultiClassPRAUC(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
|
||||
std::unique_ptr<Metric> metric{Metric::Create("aucpr", &ctx)};
|
||||
|
||||
@@ -209,8 +207,8 @@ inline void VerifyMultiClassPRAUC(DataSplitMode data_split_mode = DataSplitMode:
|
||||
ASSERT_GT(auc, 0.699);
|
||||
}
|
||||
|
||||
inline void VerifyRankingPRAUC(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyRankingPRAUC(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
|
||||
std::unique_ptr<Metric> metric{Metric::Create("aucpr", &ctx)};
|
||||
|
||||
@@ -245,5 +243,4 @@ inline void VerifyRankingPRAUC(DataSplitMode data_split_mode = DataSplitMode::kR
|
||||
data_split_mode),
|
||||
0.556021f, 0.001f);
|
||||
}
|
||||
} // namespace metric
|
||||
} // namespace xgboost
|
||||
} // namespace xgboost::metric
|
||||
|
||||
192
tests/cpp/metric/test_distributed_metric.cc
Normal file
192
tests/cpp/metric/test_distributed_metric.cc
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Copyright 2023, XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/context.h> // for DeviceOrd
|
||||
#include <xgboost/data.h> // for DataSplitMode
|
||||
|
||||
#include <algorithm> // for min
|
||||
#include <cstdint> // for int32_t
|
||||
#include <functional> // for function
|
||||
#include <string> // for string
|
||||
#include <thread> // for thread
|
||||
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "test_auc.h"
|
||||
#include "test_elementwise_metric.h"
|
||||
#include "test_multiclass_metric.h"
|
||||
#include "test_rank_metric.h"
|
||||
#include "test_survival_metric.h"
|
||||
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
|
||||
#include "../plugin/federated/test_worker.h" // for TestFederatedGlobal
|
||||
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
|
||||
namespace xgboost::metric {
|
||||
namespace {
|
||||
using Verifier = std::function<void(DataSplitMode, DeviceOrd)>;
|
||||
struct Param {
|
||||
bool is_dist; // is distributed
|
||||
bool is_fed; // is federated learning
|
||||
DataSplitMode split; // how to split data
|
||||
Verifier v; // test function
|
||||
std::string name; // metric name
|
||||
DeviceOrd device; // device to run
|
||||
};
|
||||
|
||||
class TestDistributedMetric : public ::testing::TestWithParam<Param> {
|
||||
protected:
|
||||
template <typename Fn>
|
||||
void Run(bool is_dist, bool is_fed, DataSplitMode split_mode, Fn fn, DeviceOrd device) {
|
||||
if (!is_dist) {
|
||||
fn(split_mode, device);
|
||||
return;
|
||||
}
|
||||
|
||||
std::int32_t n_workers{0};
|
||||
if (device.IsCUDA()) {
|
||||
n_workers = common::AllVisibleGPUs();
|
||||
} else {
|
||||
n_workers = std::min(static_cast<std::int32_t>(std::thread::hardware_concurrency()), 3);
|
||||
}
|
||||
auto fn1 = [&]() {
|
||||
auto r = collective::GetRank();
|
||||
if (device.IsCPU()) {
|
||||
fn(split_mode, DeviceOrd::CPU());
|
||||
} else {
|
||||
fn(split_mode, DeviceOrd::CUDA(r));
|
||||
}
|
||||
};
|
||||
if (is_fed) {
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
collective::TestFederatedGlobal(n_workers, fn1);
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
} else {
|
||||
collective::TestDistributedGlobal(n_workers, fn1);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_P(TestDistributedMetric, BinaryAUCRowSplit) {
|
||||
auto p = GetParam();
|
||||
this->Run(p.is_dist, p.is_fed, p.split, p.v, p.device);
|
||||
}
|
||||
|
||||
constexpr bool UseNCCL() {
|
||||
#if defined(XGBOOST_USE_NCCL)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif // defined(XGBOOST_USE_NCCL)
|
||||
}
|
||||
|
||||
constexpr bool UseCUDA() {
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif // defined(XGBOOST_USE_CUDA)
|
||||
}
|
||||
|
||||
constexpr bool UseFederated() {
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto MakeParamsForTest() {
|
||||
std::vector<Param> cases;
|
||||
|
||||
auto push = [&](std::string name, auto fn) {
|
||||
for (bool is_federated : {false, true}) {
|
||||
for (DataSplitMode m : {DataSplitMode::kCol, DataSplitMode::kRow}) {
|
||||
for (auto d : {DeviceOrd::CPU(), DeviceOrd::CUDA(0)}) {
|
||||
if (!is_federated && !UseNCCL() && d.IsCUDA()) {
|
||||
// Federated doesn't use nccl.
|
||||
continue;
|
||||
}
|
||||
if (!UseCUDA() && d.IsCUDA()) {
|
||||
// skip CUDA tests
|
||||
continue;
|
||||
}
|
||||
if (!UseFederated() && is_federated) {
|
||||
// skip GRPC tests
|
||||
continue;
|
||||
}
|
||||
|
||||
auto p = Param{true, is_federated, m, fn, name, d};
|
||||
cases.push_back(p);
|
||||
if (!is_federated) {
|
||||
// Add a local test.
|
||||
p.is_dist = false;
|
||||
cases.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define REFLECT_NAME(name) push(#name, Verify##name)
|
||||
// AUC
|
||||
REFLECT_NAME(BinaryAUC);
|
||||
REFLECT_NAME(MultiClassAUC);
|
||||
REFLECT_NAME(RankingAUC);
|
||||
REFLECT_NAME(PRAUC);
|
||||
REFLECT_NAME(MultiClassPRAUC);
|
||||
REFLECT_NAME(RankingPRAUC);
|
||||
// Elementwise
|
||||
REFLECT_NAME(RMSE);
|
||||
REFLECT_NAME(RMSLE);
|
||||
REFLECT_NAME(MAE);
|
||||
REFLECT_NAME(MAPE);
|
||||
REFLECT_NAME(MPHE);
|
||||
REFLECT_NAME(LogLoss);
|
||||
REFLECT_NAME(Error);
|
||||
REFLECT_NAME(PoissonNegLogLik);
|
||||
REFLECT_NAME(MultiRMSE);
|
||||
REFLECT_NAME(Quantile);
|
||||
// Multi-Class
|
||||
REFLECT_NAME(MultiClassError);
|
||||
REFLECT_NAME(MultiClassLogLoss);
|
||||
// Ranking
|
||||
REFLECT_NAME(Precision);
|
||||
REFLECT_NAME(NDCG);
|
||||
REFLECT_NAME(MAP);
|
||||
REFLECT_NAME(NDCGExpGain);
|
||||
// AFT
|
||||
using namespace xgboost::common; // NOLINT
|
||||
REFLECT_NAME(AFTNegLogLik);
|
||||
REFLECT_NAME(IntervalRegressionAccuracy);
|
||||
|
||||
#undef REFLECT_NAME
|
||||
|
||||
return cases;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DistributedMetric, TestDistributedMetric, ::testing::ValuesIn(MakeParamsForTest()),
|
||||
[](const ::testing::TestParamInfo<TestDistributedMetric::ParamType>& info) {
|
||||
std::string result;
|
||||
if (info.param.is_dist) {
|
||||
result += "Dist_";
|
||||
}
|
||||
if (info.param.is_fed) {
|
||||
result += "Federated_";
|
||||
}
|
||||
if (info.param.split == DataSplitMode::kRow) {
|
||||
result += "RowSplit";
|
||||
} else {
|
||||
result += "ColSplit";
|
||||
}
|
||||
result += "_";
|
||||
result += info.param.device.IsCPU() ? "CPU" : "CUDA";
|
||||
result += "_";
|
||||
result += info.param.name;
|
||||
return result;
|
||||
});
|
||||
} // namespace xgboost::metric
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* Copyright 2018-2023 by XGBoost contributors
|
||||
*/
|
||||
#include "test_elementwise_metric.h"
|
||||
|
||||
namespace xgboost::metric {
|
||||
TEST(Metric, DeclareUnifiedTest(RMSE)) { VerifyRMSE(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(RMSLE)) { VerifyRMSLE(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MAE)) { VerifyMAE(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MAPE)) { VerifyMAPE(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MPHE)) { VerifyMPHE(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(LogLoss)) { VerifyLogLoss(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(Error)) { VerifyError(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(PoissonNegLogLik)) { VerifyPoissonNegLogLik(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MultiRMSE)) { VerifyMultiRMSE(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(Quantile)) { VerifyQuantile(); }
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RMSERowSplit) {
|
||||
DoTest(VerifyRMSE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RMSEColumnSplit) {
|
||||
DoTest(VerifyRMSE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RMSLERowSplit) {
|
||||
DoTest(VerifyRMSLE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), RMSLEColumnSplit) {
|
||||
DoTest(VerifyRMSLE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MAERowSplit) {
|
||||
DoTest(VerifyMAE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MAEColumnSplit) {
|
||||
DoTest(VerifyMAE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MAPERowSplit) {
|
||||
DoTest(VerifyMAPE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MAPEColumnSplit) {
|
||||
DoTest(VerifyMAPE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MPHERowSplit) {
|
||||
DoTest(VerifyMPHE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MPHEColumnSplit) {
|
||||
DoTest(VerifyMPHE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), LogLossRowSplit) {
|
||||
DoTest(VerifyLogLoss, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), LogLossColumnSplit) {
|
||||
DoTest(VerifyLogLoss, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), ErrorRowSplit) {
|
||||
DoTest(VerifyError, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), ErrorColumnSplit) {
|
||||
DoTest(VerifyError, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), PoissonNegLogLikRowSplit) {
|
||||
DoTest(VerifyPoissonNegLogLik, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), PoissonNegLogLikColumnSplit) {
|
||||
DoTest(VerifyPoissonNegLogLik, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiRMSERowSplit) {
|
||||
DoTest(VerifyMultiRMSE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiRMSEColumnSplit) {
|
||||
DoTest(VerifyMultiRMSE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), QuantileRowSplit) {
|
||||
DoTest(VerifyQuantile, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), QuantileColumnSplit) {
|
||||
DoTest(VerifyQuantile, DataSplitMode::kCol);
|
||||
}
|
||||
} // namespace xgboost::metric
|
||||
@@ -1,5 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2018 XGBoost contributors
|
||||
*/
|
||||
// Dummy file to keep the CUDA conditional compile trick.
|
||||
#include "test_elementwise_metric.cc"
|
||||
@@ -42,8 +42,8 @@ inline void CheckDeterministicMetricElementWise(StringView name, int32_t device)
|
||||
}
|
||||
}
|
||||
|
||||
inline void VerifyRMSE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyRMSE(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("rmse", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "rmse");
|
||||
@@ -68,11 +68,11 @@ inline void VerifyRMSE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
0.6708f, 0.001f);
|
||||
delete metric;
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"rmse"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"rmse"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void VerifyRMSLE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyRMSLE(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("rmsle", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "rmsle");
|
||||
@@ -97,11 +97,11 @@ inline void VerifyRMSLE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
0.2415f, 1e-4);
|
||||
delete metric;
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"rmsle"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"rmsle"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void VerifyMAE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyMAE(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("mae", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "mae");
|
||||
@@ -126,11 +126,11 @@ inline void VerifyMAE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
0.54f, 0.001f);
|
||||
delete metric;
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"mae"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"mae"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void VerifyMAPE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyMAPE(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("mape", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "mape");
|
||||
@@ -155,11 +155,11 @@ inline void VerifyMAPE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
1.3250f, 0.001f);
|
||||
delete metric;
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"mape"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"mape"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void VerifyMPHE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyMPHE(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
std::unique_ptr<xgboost::Metric> metric{xgboost::Metric::Create("mphe", &ctx)};
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "mphe");
|
||||
@@ -183,7 +183,7 @@ inline void VerifyMPHE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
{ 1, 2, 9, 8}, {}, data_split_mode),
|
||||
0.1922f, 1e-4);
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"mphe"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"mphe"}, device.ordinal);
|
||||
|
||||
metric->Configure({{"huber_slope", "0.1"}});
|
||||
EXPECT_NEAR(GetMetricEval(metric.get(),
|
||||
@@ -193,8 +193,8 @@ inline void VerifyMPHE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
0.0461686f, 1e-4);
|
||||
}
|
||||
|
||||
inline void VerifyLogLoss(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyLogLoss(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("logloss", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "logloss");
|
||||
@@ -223,11 +223,11 @@ inline void VerifyLogLoss(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
1.3138f, 0.001f);
|
||||
delete metric;
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"logloss"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"logloss"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void VerifyError(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyError(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("error", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "error");
|
||||
@@ -285,11 +285,11 @@ inline void VerifyError(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
0.45f, 0.001f);
|
||||
delete metric;
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"error@0.5"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"error@0.5"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void VerifyPoissonNegLogLik(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyPoissonNegLogLik(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("poisson-nloglik", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "poisson-nloglik");
|
||||
@@ -318,11 +318,11 @@ inline void VerifyPoissonNegLogLik(DataSplitMode data_split_mode = DataSplitMode
|
||||
1.5783f, 0.001f);
|
||||
delete metric;
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"poisson-nloglik"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"poisson-nloglik"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void VerifyMultiRMSE(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyMultiRMSE(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
size_t n_samples = 32, n_targets = 8;
|
||||
linalg::Tensor<float, 2> y{{n_samples, n_targets}, ctx.Device()};
|
||||
auto &h_y = y.Data()->HostVector();
|
||||
@@ -343,8 +343,8 @@ inline void VerifyMultiRMSE(DataSplitMode data_split_mode = DataSplitMode::kRow)
|
||||
ASSERT_FLOAT_EQ(ret, loss_w);
|
||||
}
|
||||
|
||||
inline void VerifyQuantile(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyQuantile(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
std::unique_ptr<Metric> metric{Metric::Create("quantile", &ctx)};
|
||||
|
||||
HostDeviceVector<float> predts{0.1f, 0.9f, 0.1f, 0.9f};
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright by Contributors
|
||||
#include "test_multiclass_metric.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace xgboost {
|
||||
namespace metric {
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MultiClassError)) { VerifyMultiClassError(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MultiClassLogLoss)) { VerifyMultiClassLogLoss(); }
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassErrorRowSplit) {
|
||||
DoTest(VerifyMultiClassError, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassErrorColumnSplit) {
|
||||
DoTest(VerifyMultiClassError, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassLogLossRowSplit) {
|
||||
DoTest(VerifyMultiClassLogLoss, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MultiClassLogLossColumnSplit) {
|
||||
DoTest(VerifyMultiClassLogLoss, DataSplitMode::kCol);
|
||||
}
|
||||
} // namespace metric
|
||||
} // namespace xgboost
|
||||
@@ -1,5 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2019 XGBoost contributors
|
||||
*/
|
||||
// Dummy file to keep the CUDA conditional compile trick.
|
||||
#include "test_multiclass_metric.cc"
|
||||
@@ -44,8 +44,8 @@ inline void CheckDeterministicMetricMultiClass(StringView name, int32_t device)
|
||||
}
|
||||
}
|
||||
|
||||
inline void TestMultiClassError(int device, DataSplitMode data_split_mode) {
|
||||
auto ctx = MakeCUDACtx(device);
|
||||
inline void TestMultiClassError(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("merror", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "merror");
|
||||
@@ -59,13 +59,13 @@ inline void TestMultiClassError(int device, DataSplitMode data_split_mode) {
|
||||
delete metric;
|
||||
}
|
||||
|
||||
inline void VerifyMultiClassError(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
TestMultiClassError(GPUIDX, data_split_mode);
|
||||
CheckDeterministicMetricMultiClass(StringView{"merror"}, GPUIDX);
|
||||
inline void VerifyMultiClassError(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
TestMultiClassError(data_split_mode, device);
|
||||
CheckDeterministicMetricMultiClass(StringView{"merror"}, device.ordinal);
|
||||
}
|
||||
|
||||
inline void TestMultiClassLogLoss(int device, DataSplitMode data_split_mode) {
|
||||
auto ctx = MakeCUDACtx(device);
|
||||
inline void TestMultiClassLogLoss(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
xgboost::Metric * metric = xgboost::Metric::Create("mlogloss", &ctx);
|
||||
metric->Configure({});
|
||||
ASSERT_STREQ(metric->Name(), "mlogloss");
|
||||
@@ -80,9 +80,9 @@ inline void TestMultiClassLogLoss(int device, DataSplitMode data_split_mode) {
|
||||
delete metric;
|
||||
}
|
||||
|
||||
inline void VerifyMultiClassLogLoss(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
TestMultiClassLogLoss(GPUIDX, data_split_mode);
|
||||
CheckDeterministicMetricMultiClass(StringView{"mlogloss"}, GPUIDX);
|
||||
inline void VerifyMultiClassLogLoss(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
TestMultiClassLogLoss(data_split_mode, device);
|
||||
CheckDeterministicMetricMultiClass(StringView{"mlogloss"}, device.ordinal);
|
||||
}
|
||||
|
||||
} // namespace metric
|
||||
|
||||
@@ -1,84 +1,29 @@
|
||||
/**
|
||||
* Copyright 2016-2023 by XGBoost Contributors
|
||||
* Copyright 2016-2023, XGBoost Contributors
|
||||
*/
|
||||
#include <gtest/gtest.h> // for Test, EXPECT_NEAR, ASSERT_STREQ
|
||||
#include <xgboost/context.h> // for Context
|
||||
#include <xgboost/data.h> // for MetaInfo, DMatrix
|
||||
#include <xgboost/linalg.h> // for Matrix
|
||||
#include <xgboost/metric.h> // for Metric
|
||||
|
||||
#include <algorithm> // for max
|
||||
#include <memory> // for unique_ptr
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "test_rank_metric.h"
|
||||
#include "../helpers.h" // for GetMetricEval, CreateEmptyGe...
|
||||
#include "xgboost/base.h" // for bst_float, kRtEps
|
||||
#include "xgboost/host_device_vector.h" // for HostDeviceVector
|
||||
#include "xgboost/json.h" // for Json, String, Object
|
||||
|
||||
namespace xgboost {
|
||||
namespace metric {
|
||||
#include <gtest/gtest.h> // for Test, EXPECT_NEAR, ASSERT_STREQ
|
||||
#include <xgboost/context.h> // for Context
|
||||
#include <xgboost/metric.h> // for Metric
|
||||
|
||||
#if !defined(__CUDACC__)
|
||||
#include <memory> // for unique_ptr
|
||||
|
||||
#include "../helpers.h" // for GetMetricEval, CreateEmptyGe...
|
||||
#include "xgboost/base.h" // for bst_float, kRtEps
|
||||
|
||||
namespace xgboost::metric {
|
||||
TEST(Metric, AMS) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
EXPECT_ANY_THROW(Metric::Create("ams", &ctx));
|
||||
Metric* metric = Metric::Create("ams@0.5f", &ctx);
|
||||
std::unique_ptr<Metric> metric{Metric::Create("ams@0.5f", &ctx)};
|
||||
ASSERT_STREQ(metric->Name(), "ams@0.5");
|
||||
EXPECT_NEAR(GetMetricEval(metric, {0, 1}, {0, 1}), 0.311f, 0.001f);
|
||||
EXPECT_NEAR(GetMetricEval(metric,
|
||||
{0.1f, 0.9f, 0.1f, 0.9f},
|
||||
{ 0, 0, 1, 1}),
|
||||
0.29710f, 0.001f);
|
||||
EXPECT_NEAR(GetMetricEval(metric.get(), {0, 1}, {0, 1}), 0.311f, 0.001f);
|
||||
EXPECT_NEAR(GetMetricEval(metric.get(), {0.1f, 0.9f, 0.1f, 0.9f}, {0, 0, 1, 1}), 0.29710f,
|
||||
0.001f);
|
||||
|
||||
delete metric;
|
||||
metric = Metric::Create("ams@0", &ctx);
|
||||
metric.reset(Metric::Create("ams@0", &ctx));
|
||||
ASSERT_STREQ(metric->Name(), "ams@0");
|
||||
EXPECT_NEAR(GetMetricEval(metric, {0, 1}, {0, 1}), 0.311f, 0.001f);
|
||||
|
||||
delete metric;
|
||||
EXPECT_NEAR(GetMetricEval(metric.get(), {0, 1}, {0, 1}), 0.311f, 0.001f);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(Precision)) { VerifyPrecision(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(NDCG)) { VerifyNDCG(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(MAP)) { VerifyMAP(); }
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(NDCGExpGain)) { VerifyNDCGExpGain(); }
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), PrecisionRowSplit) {
|
||||
DoTest(VerifyPrecision, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), PrecisionColumnSplit) {
|
||||
DoTest(VerifyPrecision, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), NDCGRowSplit) {
|
||||
DoTest(VerifyNDCG, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), NDCGColumnSplit) {
|
||||
DoTest(VerifyNDCG, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MAPRowSplit) {
|
||||
DoTest(VerifyMAP, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), MAPColumnSplit) {
|
||||
DoTest(VerifyMAP, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), NDCGExpGainRowSplit) {
|
||||
DoTest(VerifyNDCGExpGain, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), NDCGExpGainColumnSplit) {
|
||||
DoTest(VerifyNDCGExpGain, DataSplitMode::kCol);
|
||||
}
|
||||
} // namespace metric
|
||||
} // namespace xgboost
|
||||
} // namespace xgboost::metric
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2019 XGBoost contributors
|
||||
*/
|
||||
// Dummy file to keep the CUDA conditional compile trick.
|
||||
#include "test_rank_metric.cc"
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
namespace xgboost::metric {
|
||||
|
||||
inline void VerifyPrecision(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyPrecision(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
std::unique_ptr<xgboost::Metric> metric{Metric::Create("pre", &ctx)};
|
||||
ASSERT_STREQ(metric->Name(), "pre");
|
||||
EXPECT_NEAR(GetMetricEval(metric.get(), {0, 1}, {0, 1}, {}, {}, data_split_mode), 0.5, 1e-7);
|
||||
@@ -43,8 +43,8 @@ inline void VerifyPrecision(DataSplitMode data_split_mode = DataSplitMode::kRow)
|
||||
0.5f, 1e-7);
|
||||
}
|
||||
|
||||
inline void VerifyNDCG(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyNDCG(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
Metric * metric = xgboost::Metric::Create("ndcg", &ctx);
|
||||
ASSERT_STREQ(metric->Name(), "ndcg");
|
||||
EXPECT_ANY_THROW(GetMetricEval(metric, {0, 1}, {}, {}, {}, data_split_mode));
|
||||
@@ -101,8 +101,8 @@ inline void VerifyNDCG(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
delete metric;
|
||||
}
|
||||
|
||||
inline void VerifyMAP(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyMAP(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
Metric * metric = xgboost::Metric::Create("map", &ctx);
|
||||
ASSERT_STREQ(metric->Name(), "map");
|
||||
EXPECT_NEAR(GetMetricEval(metric, {0, 1}, {0, 1}, {}, {}, data_split_mode), 1, kRtEps);
|
||||
@@ -149,8 +149,8 @@ inline void VerifyMAP(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
delete metric;
|
||||
}
|
||||
|
||||
inline void VerifyNDCGExpGain(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
Context ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyNDCGExpGain(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
Context ctx = MakeCUDACtx(device.ordinal);
|
||||
|
||||
auto p_fmat = xgboost::RandomDataGenerator{0, 0, 0}.GenerateDMatrix();
|
||||
MetaInfo& info = p_fmat->Info();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (c) by Contributors 2020
|
||||
/**
|
||||
* Copyright 2020-2023, XGBoost Contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
@@ -16,8 +16,7 @@
|
||||
// CUDA conditional compile trick.
|
||||
#include "test_survival_metric.cu"
|
||||
|
||||
namespace xgboost {
|
||||
namespace common {
|
||||
namespace xgboost::common {
|
||||
|
||||
/** Tests for Survival metrics that should run only on CPU **/
|
||||
|
||||
@@ -113,6 +112,4 @@ TEST(AFTLoss, IntervalCensored) {
|
||||
{ 8.0000, 4.8004, 2.8805, 1.7284, 1.0372, 0.6231, 0.3872, 0.3031, 0.3740, 0.5839, 0.8995,
|
||||
1.2878, 1.7231, 2.1878, 2.6707, 3.1647, 3.6653, 4.1699, 4.6770, 5.1856 });
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
} // namespace xgboost
|
||||
} // namespace xgboost::common
|
||||
|
||||
@@ -7,28 +7,7 @@
|
||||
|
||||
/** Tests for Survival metrics that should run both on CPU and GPU **/
|
||||
|
||||
namespace xgboost {
|
||||
namespace common {
|
||||
TEST(Metric, DeclareUnifiedTest(AFTNegLogLik)) { VerifyAFTNegLogLik(); }
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), AFTNegLogLikRowSplit) {
|
||||
DoTest(VerifyAFTNegLogLik, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), AFTNegLogLikColumnSplit) {
|
||||
DoTest(VerifyAFTNegLogLik, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST(Metric, DeclareUnifiedTest(IntervalRegressionAccuracy)) { VerifyIntervalRegressionAccuracy(); }
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), IntervalRegressionAccuracyRowSplit) {
|
||||
DoTest(VerifyIntervalRegressionAccuracy, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(DeclareUnifiedDistributedTest(MetricTest), IntervalRegressionAccuracyColumnSplit) {
|
||||
DoTest(VerifyIntervalRegressionAccuracy, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
namespace xgboost::common {
|
||||
// Test configuration of AFT metric
|
||||
TEST(AFTNegLogLikMetric, DeclareUnifiedTest(Configuration)) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
@@ -44,5 +23,4 @@ TEST(AFTNegLogLikMetric, DeclareUnifiedTest(Configuration)) {
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"aft-nloglik"}, GPUIDX);
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace xgboost
|
||||
} // namespace xgboost::common
|
||||
|
||||
@@ -47,8 +47,8 @@ inline void CheckDeterministicMetricElementWise(StringView name, int32_t device)
|
||||
}
|
||||
}
|
||||
|
||||
inline void VerifyAFTNegLogLik(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyAFTNegLogLik(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
|
||||
/**
|
||||
* Test aggregate output from the AFT metric over a small test data set.
|
||||
@@ -78,8 +78,8 @@ inline void VerifyAFTNegLogLik(DataSplitMode data_split_mode = DataSplitMode::kR
|
||||
}
|
||||
}
|
||||
|
||||
inline void VerifyIntervalRegressionAccuracy(DataSplitMode data_split_mode = DataSplitMode::kRow) {
|
||||
auto ctx = MakeCUDACtx(GPUIDX);
|
||||
inline void VerifyIntervalRegressionAccuracy(DataSplitMode data_split_mode, DeviceOrd device) {
|
||||
auto ctx = MakeCUDACtx(device.ordinal);
|
||||
|
||||
auto p_fmat = EmptyDMatrix();
|
||||
MetaInfo& info = p_fmat->Info();
|
||||
@@ -101,7 +101,7 @@ inline void VerifyIntervalRegressionAccuracy(DataSplitMode data_split_mode = Dat
|
||||
info.labels_lower_bound_.HostVector()[0] = 70.0f;
|
||||
EXPECT_FLOAT_EQ(metric->Evaluate(preds, p_fmat), 0.25f);
|
||||
|
||||
CheckDeterministicMetricElementWise(StringView{"interval-regression-accuracy"}, GPUIDX);
|
||||
CheckDeterministicMetricElementWise(StringView{"interval-regression-accuracy"}, device.ordinal);
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace xgboost
|
||||
|
||||
@@ -50,7 +50,7 @@ class TestDefaultObjConfig : public ::testing::TestWithParam<std::string> {
|
||||
|
||||
public:
|
||||
void Run(std::string objective) {
|
||||
auto Xy = MakeFmatForObjTest(objective);
|
||||
auto Xy = MakeFmatForObjTest(objective, 10, 10);
|
||||
std::unique_ptr<Learner> learner{Learner::Create({Xy})};
|
||||
std::unique_ptr<ObjFunction> objfn{ObjFunction::Create(objective, &ctx_)};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023, XGBoost contributors
|
||||
* Copyright 2023-2024, XGBoost contributors
|
||||
*/
|
||||
#include "objective_helpers.h"
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
#include "helpers.h" // for RandomDataGenerator
|
||||
|
||||
namespace xgboost {
|
||||
std::shared_ptr<DMatrix> MakeFmatForObjTest(std::string const& obj) {
|
||||
auto constexpr kRows = 10, kCols = 10;
|
||||
auto p_fmat = RandomDataGenerator{kRows, kCols, 0}.GenerateDMatrix(true);
|
||||
|
||||
void MakeLabelForObjTest(std::shared_ptr<DMatrix> p_fmat, std::string const& obj) {
|
||||
auto& h_upper = p_fmat->Info().labels_upper_bound_.HostVector();
|
||||
auto& h_lower = p_fmat->Info().labels_lower_bound_.HostVector();
|
||||
h_lower.resize(kRows);
|
||||
h_upper.resize(kRows);
|
||||
for (size_t i = 0; i < kRows; ++i) {
|
||||
h_lower.resize(p_fmat->Info().num_row_);
|
||||
h_upper.resize(p_fmat->Info().num_row_);
|
||||
for (size_t i = 0; i < p_fmat->Info().num_row_; ++i) {
|
||||
h_lower[i] = 1;
|
||||
h_upper[i] = 10;
|
||||
}
|
||||
|
||||
if (obj.find("rank:") != std::string::npos) {
|
||||
auto h_label = p_fmat->Info().labels.HostView();
|
||||
std::size_t k = 0;
|
||||
@@ -26,6 +26,12 @@ std::shared_ptr<DMatrix> MakeFmatForObjTest(std::string const& obj) {
|
||||
++k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<DMatrix> MakeFmatForObjTest(std::string const& obj, bst_idx_t n_samples,
|
||||
bst_feature_t n_features) {
|
||||
auto p_fmat = RandomDataGenerator{n_samples, n_features, 0}.GenerateDMatrix(true);
|
||||
MakeLabelForObjTest(p_fmat, obj);
|
||||
return p_fmat;
|
||||
};
|
||||
} // namespace xgboost
|
||||
|
||||
@@ -32,5 +32,11 @@ inline std::string ObjTestNameGenerator(const ::testing::TestParamInfo<ParamType
|
||||
return name;
|
||||
};
|
||||
|
||||
std::shared_ptr<DMatrix> MakeFmatForObjTest(std::string const& obj);
|
||||
/**
|
||||
* @brief Construct random label for testing.
|
||||
*/
|
||||
void MakeLabelForObjTest(std::shared_ptr<DMatrix> p_fmat, std::string const& obj);
|
||||
|
||||
std::shared_ptr<DMatrix> MakeFmatForObjTest(std::string const& obj, bst_idx_t n_samples,
|
||||
bst_feature_t n_features);
|
||||
} // namespace xgboost
|
||||
|
||||
@@ -108,6 +108,32 @@ TEST_F(FederatedCollTestGPU, Allreduce) {
|
||||
});
|
||||
}
|
||||
|
||||
TEST(FederatedCollGPUGlobal, Allreduce) {
|
||||
std::int32_t n_workers = common::AllVisibleGPUs();
|
||||
TestFederatedGlobal(n_workers, [&] {
|
||||
auto r = collective::GetRank();
|
||||
auto world = collective::GetWorldSize();
|
||||
CHECK_EQ(n_workers, world);
|
||||
|
||||
dh::device_vector<std::uint32_t> values(3, r);
|
||||
auto ctx = MakeCUDACtx(r);
|
||||
auto rc = collective::Allreduce(
|
||||
&ctx, linalg::MakeVec(values.data().get(), values.size(), DeviceOrd::CUDA(r)),
|
||||
Op::kBitwiseOR);
|
||||
SafeColl(rc);
|
||||
|
||||
std::vector<std::uint32_t> expected(values.size(), 0);
|
||||
for (std::int32_t rank = 0; rank < world; ++rank) {
|
||||
for (std::size_t i = 0; i < expected.size(); ++i) {
|
||||
expected[i] |= rank;
|
||||
}
|
||||
}
|
||||
for (std::size_t i = 0; i < expected.size(); ++i) {
|
||||
CHECK_EQ(expected[i], values[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(FederatedCollTestGPU, Broadcast) {
|
||||
std::int32_t n_workers = common::AllVisibleGPUs();
|
||||
TestFederated(n_workers, [=](std::shared_ptr<FederatedComm> comm, std::int32_t rank) {
|
||||
|
||||
@@ -11,12 +11,24 @@
|
||||
|
||||
#include "../../../../plugin/federated/federated_tracker.h"
|
||||
#include "../../../../src/collective/comm_group.h"
|
||||
#include "../../../../src/collective/communicator-inl.h"
|
||||
#include "federated_comm.h" // for FederatedComm
|
||||
#include "xgboost/json.h" // for Json
|
||||
|
||||
namespace xgboost::collective {
|
||||
inline Json FederatedTestConfig(std::int32_t n_workers, std::int32_t port, std::int32_t i) {
|
||||
Json config{Object{}};
|
||||
config["dmlc_communicator"] = std::string{"federated"};
|
||||
config["dmlc_task_id"] = std::to_string(i);
|
||||
config["dmlc_retry"] = 2;
|
||||
config["federated_world_size"] = n_workers;
|
||||
config["federated_rank"] = i;
|
||||
config["federated_server_address"] = "0.0.0.0:" + std::to_string(port);
|
||||
return config;
|
||||
}
|
||||
|
||||
template <typename WorkerFn>
|
||||
void TestFederated(std::int32_t n_workers, WorkerFn&& fn) {
|
||||
void TestFederatedImpl(std::int32_t n_workers, WorkerFn&& fn) {
|
||||
Json config{Object()};
|
||||
config["federated_secure"] = Boolean{false};
|
||||
config["n_workers"] = Integer{n_workers};
|
||||
@@ -30,16 +42,7 @@ void TestFederated(std::int32_t n_workers, WorkerFn&& fn) {
|
||||
std::int32_t port = tracker.Port();
|
||||
|
||||
for (std::int32_t i = 0; i < n_workers; ++i) {
|
||||
workers.emplace_back([=] {
|
||||
Json config{Object{}};
|
||||
config["federated_world_size"] = n_workers;
|
||||
config["federated_rank"] = i;
|
||||
config["federated_server_address"] = "0.0.0.0:" + std::to_string(port);
|
||||
auto comm = std::make_shared<FederatedComm>(
|
||||
DefaultRetry(), std::chrono::seconds{DefaultTimeoutSec()}, std::to_string(i), config);
|
||||
|
||||
fn(comm, i);
|
||||
});
|
||||
workers.emplace_back([=] { fn(port, i); });
|
||||
}
|
||||
|
||||
for (auto& t : workers) {
|
||||
@@ -51,39 +54,33 @@ void TestFederated(std::int32_t n_workers, WorkerFn&& fn) {
|
||||
ASSERT_TRUE(fut.get().OK());
|
||||
}
|
||||
|
||||
template <typename WorkerFn>
|
||||
void TestFederated(std::int32_t n_workers, WorkerFn&& fn) {
|
||||
TestFederatedImpl(n_workers, [&](std::int32_t port, std::int32_t i) {
|
||||
auto config = FederatedTestConfig(n_workers, port, i);
|
||||
auto comm = std::make_shared<FederatedComm>(
|
||||
DefaultRetry(), std::chrono::seconds{DefaultTimeoutSec()}, std::to_string(i), config);
|
||||
|
||||
fn(comm, i);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename WorkerFn>
|
||||
void TestFederatedGroup(std::int32_t n_workers, WorkerFn&& fn) {
|
||||
Json config{Object()};
|
||||
config["federated_secure"] = Boolean{false};
|
||||
config["n_workers"] = Integer{n_workers};
|
||||
FederatedTracker tracker{config};
|
||||
auto fut = tracker.Run();
|
||||
TestFederatedImpl(n_workers, [&](std::int32_t port, std::int32_t i) {
|
||||
auto config = FederatedTestConfig(n_workers, port, i);
|
||||
std::shared_ptr<CommGroup> comm_group{CommGroup::Create(config)};
|
||||
fn(comm_group, i);
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<std::thread> workers;
|
||||
auto rc = tracker.WaitUntilReady();
|
||||
ASSERT_TRUE(rc.OK()) << rc.Report();
|
||||
std::int32_t port = tracker.Port();
|
||||
|
||||
for (std::int32_t i = 0; i < n_workers; ++i) {
|
||||
workers.emplace_back([=] {
|
||||
Json config{Object{}};
|
||||
config["dmlc_communicator"] = std::string{"federated"};
|
||||
config["dmlc_task_id"] = std::to_string(i);
|
||||
config["dmlc_retry"] = 2;
|
||||
config["federated_world_size"] = n_workers;
|
||||
config["federated_rank"] = i;
|
||||
config["federated_server_address"] = "0.0.0.0:" + std::to_string(port);
|
||||
std::shared_ptr<CommGroup> comm_group{CommGroup::Create(config)};
|
||||
fn(comm_group, i);
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& t : workers) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
rc = tracker.Shutdown();
|
||||
ASSERT_TRUE(rc.OK()) << rc.Report();
|
||||
ASSERT_TRUE(fut.get().OK());
|
||||
template <typename WorkerFn>
|
||||
void TestFederatedGlobal(std::int32_t n_workers, WorkerFn&& fn) {
|
||||
TestFederatedImpl(n_workers, [&](std::int32_t port, std::int32_t i) {
|
||||
auto config = FederatedTestConfig(n_workers, port, i);
|
||||
collective::Init(config);
|
||||
fn();
|
||||
collective::Finalize();
|
||||
});
|
||||
}
|
||||
} // namespace xgboost::collective
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* Copyright 2022-2023, XGBoost contributors
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <dmlc/omp.h>
|
||||
#include <grpcpp/server_builder.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/json.h>
|
||||
|
||||
#include <random>
|
||||
#include <thread> // for thread, sleep_for
|
||||
|
||||
#include "../../../plugin/federated/federated_server.h"
|
||||
#include "../../../src/collective/communicator-inl.h"
|
||||
#include "../../../src/common/threading_utils.h"
|
||||
|
||||
namespace xgboost {
|
||||
|
||||
class ServerForTest {
|
||||
std::string server_address_;
|
||||
std::unique_ptr<std::thread> server_thread_;
|
||||
std::unique_ptr<grpc::Server> server_;
|
||||
|
||||
public:
|
||||
explicit ServerForTest(std::size_t world_size) {
|
||||
server_thread_.reset(new std::thread([this, world_size] {
|
||||
grpc::ServerBuilder builder;
|
||||
xgboost::federated::FederatedService service{static_cast<std::int32_t>(world_size)};
|
||||
int selected_port;
|
||||
builder.AddListeningPort("localhost:0", grpc::InsecureServerCredentials(), &selected_port);
|
||||
builder.RegisterService(&service);
|
||||
server_ = builder.BuildAndStart();
|
||||
server_address_ = std::string("localhost:") + std::to_string(selected_port);
|
||||
server_->Wait();
|
||||
}));
|
||||
}
|
||||
|
||||
~ServerForTest() {
|
||||
using namespace std::chrono_literals;
|
||||
while (!server_) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
server_->Shutdown();
|
||||
while (!server_thread_) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
server_thread_->join();
|
||||
}
|
||||
|
||||
auto Address() const {
|
||||
using namespace std::chrono_literals;
|
||||
while (server_address_.empty()) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
return server_address_;
|
||||
}
|
||||
};
|
||||
|
||||
class BaseFederatedTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override { server_ = std::make_unique<ServerForTest>(kWorldSize); }
|
||||
|
||||
void TearDown() override { server_.reset(nullptr); }
|
||||
|
||||
static int constexpr kWorldSize{2};
|
||||
std::unique_ptr<ServerForTest> server_;
|
||||
};
|
||||
|
||||
template <typename Function, typename... Args>
|
||||
void RunWithFederatedCommunicator(int32_t world_size, std::string const& server_address,
|
||||
Function&& function, Args&&... args) {
|
||||
auto run = [&](auto rank) {
|
||||
Json config{JsonObject()};
|
||||
config["xgboost_communicator"] = String("federated");
|
||||
config["federated_secure"] = false;
|
||||
config["federated_server_address"] = String(server_address);
|
||||
config["federated_world_size"] = world_size;
|
||||
config["federated_rank"] = rank;
|
||||
xgboost::collective::Init(config);
|
||||
|
||||
std::forward<Function>(function)(std::forward<Args>(args)...);
|
||||
|
||||
xgboost::collective::Finalize();
|
||||
};
|
||||
#if defined(_OPENMP)
|
||||
common::ParallelFor(world_size, world_size, run);
|
||||
#else
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < world_size; rank++) {
|
||||
threads.emplace_back(run, rank);
|
||||
}
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace xgboost
|
||||
@@ -1,97 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2022 XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <thrust/host_vector.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "../../../plugin/federated/federated_communicator.h"
|
||||
#include "../../../src/collective/communicator-inl.cuh"
|
||||
#include "../../../src/collective/device_communicator_adapter.cuh"
|
||||
#include "../helpers.h"
|
||||
#include "./helpers.h"
|
||||
|
||||
namespace xgboost::collective {
|
||||
|
||||
class FederatedAdapterTest : public BaseFederatedTest {};
|
||||
|
||||
TEST(FederatedAdapterSimpleTest, ThrowOnInvalidDeviceOrdinal) {
|
||||
auto construct = []() { DeviceCommunicatorAdapter adapter{-1}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void VerifyAllReduceSum() {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const device = GPUIDX;
|
||||
int count = 3;
|
||||
common::SetDevice(device);
|
||||
thrust::device_vector<double> buffer(count, 0);
|
||||
thrust::sequence(buffer.begin(), buffer.end());
|
||||
collective::AllReduce<collective::Operation::kSum>(device, buffer.data().get(), count);
|
||||
thrust::host_vector<double> host_buffer = buffer;
|
||||
EXPECT_EQ(host_buffer.size(), count);
|
||||
for (auto i = 0; i < count; i++) {
|
||||
EXPECT_EQ(host_buffer[i], i * world_size);
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_F(FederatedAdapterTest, MGPUAllReduceSum) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyAllReduceSum);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void VerifyAllGather() {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
auto const device = GPUIDX;
|
||||
common::SetDevice(device);
|
||||
thrust::device_vector<double> send_buffer(1, rank);
|
||||
thrust::device_vector<double> receive_buffer(world_size, 0);
|
||||
collective::AllGather(device, send_buffer.data().get(), receive_buffer.data().get(),
|
||||
sizeof(double));
|
||||
thrust::host_vector<double> host_buffer = receive_buffer;
|
||||
EXPECT_EQ(host_buffer.size(), world_size);
|
||||
for (auto i = 0; i < world_size; i++) {
|
||||
EXPECT_EQ(host_buffer[i], i);
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_F(FederatedAdapterTest, MGPUAllGather) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyAllGather);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void VerifyAllGatherV() {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
auto const device = GPUIDX;
|
||||
int const count = rank + 2;
|
||||
common::SetDevice(device);
|
||||
thrust::device_vector<char> buffer(count, 0);
|
||||
thrust::sequence(buffer.begin(), buffer.end());
|
||||
std::vector<std::size_t> segments(world_size);
|
||||
dh::caching_device_vector<char> receive_buffer{};
|
||||
|
||||
collective::AllGatherV(device, buffer.data().get(), count, &segments, &receive_buffer);
|
||||
|
||||
EXPECT_EQ(segments[0], 2);
|
||||
EXPECT_EQ(segments[1], 3);
|
||||
thrust::host_vector<char> host_buffer = receive_buffer;
|
||||
EXPECT_EQ(host_buffer.size(), 5);
|
||||
int expected[] = {0, 1, 0, 1, 2};
|
||||
for (auto i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(host_buffer[i], expected[i]);
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_F(FederatedAdapterTest, MGPUAllGatherV) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyAllGatherV);
|
||||
}
|
||||
} // namespace xgboost::collective
|
||||
@@ -1,161 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2022 XGBoost contributors
|
||||
*/
|
||||
#include <dmlc/parameter.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "../../../plugin/federated/federated_communicator.h"
|
||||
#include "helpers.h"
|
||||
|
||||
namespace xgboost::collective {
|
||||
|
||||
class FederatedCommunicatorTest : public BaseFederatedTest {
|
||||
public:
|
||||
static void VerifyAllgather(int rank, const std::string &server_address) {
|
||||
FederatedCommunicator comm{kWorldSize, rank, server_address};
|
||||
CheckAllgather(comm, rank);
|
||||
}
|
||||
|
||||
static void VerifyAllgatherV(int rank, const std::string &server_address) {
|
||||
FederatedCommunicator comm{kWorldSize, rank, server_address};
|
||||
CheckAllgatherV(comm, rank);
|
||||
}
|
||||
|
||||
static void VerifyAllreduce(int rank, const std::string &server_address) {
|
||||
FederatedCommunicator comm{kWorldSize, rank, server_address};
|
||||
CheckAllreduce(comm);
|
||||
}
|
||||
|
||||
static void VerifyBroadcast(int rank, const std::string &server_address) {
|
||||
FederatedCommunicator comm{kWorldSize, rank, server_address};
|
||||
CheckBroadcast(comm, rank);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void CheckAllgather(FederatedCommunicator &comm, int rank) {
|
||||
std::string input{static_cast<char>('0' + rank)};
|
||||
auto output = comm.AllGather(input);
|
||||
for (auto i = 0; i < kWorldSize; i++) {
|
||||
EXPECT_EQ(output[i], static_cast<char>('0' + i));
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckAllgatherV(FederatedCommunicator &comm, int rank) {
|
||||
std::vector<std::string_view> inputs{"Federated", " Learning!!!"};
|
||||
auto output = comm.AllGatherV(inputs[rank]);
|
||||
EXPECT_EQ(output, "Federated Learning!!!");
|
||||
}
|
||||
|
||||
static void CheckAllreduce(FederatedCommunicator &comm) {
|
||||
int buffer[] = {1, 2, 3, 4, 5};
|
||||
comm.AllReduce(buffer, sizeof(buffer) / sizeof(buffer[0]), DataType::kInt32, Operation::kSum);
|
||||
int expected[] = {2, 4, 6, 8, 10};
|
||||
for (auto i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(buffer[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckBroadcast(FederatedCommunicator &comm, int rank) {
|
||||
if (rank == 0) {
|
||||
std::string buffer{"hello"};
|
||||
comm.Broadcast(&buffer[0], buffer.size(), 0);
|
||||
EXPECT_EQ(buffer, "hello");
|
||||
} else {
|
||||
std::string buffer{" "};
|
||||
comm.Broadcast(&buffer[0], buffer.size(), 0);
|
||||
EXPECT_EQ(buffer, "hello");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST(FederatedCommunicatorSimpleTest, ThrowOnWorldSizeTooSmall) {
|
||||
auto construct = [] { FederatedCommunicator comm{0, 0, "localhost:0", "", "", ""}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(FederatedCommunicatorSimpleTest, ThrowOnRankTooSmall) {
|
||||
auto construct = [] { FederatedCommunicator comm{1, -1, "localhost:0", "", "", ""}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(FederatedCommunicatorSimpleTest, ThrowOnRankTooBig) {
|
||||
auto construct = [] { FederatedCommunicator comm{1, 1, "localhost:0", "", "", ""}; };
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(FederatedCommunicatorSimpleTest, ThrowOnWorldSizeNotInteger) {
|
||||
auto construct = [] {
|
||||
Json config{JsonObject()};
|
||||
config["federated_server_address"] = std::string("localhost:0");
|
||||
config["federated_world_size"] = std::string("1");
|
||||
config["federated_rank"] = Integer(0);
|
||||
FederatedCommunicator::Create(config);
|
||||
};
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(FederatedCommunicatorSimpleTest, ThrowOnRankNotInteger) {
|
||||
auto construct = [] {
|
||||
Json config{JsonObject()};
|
||||
config["federated_server_address"] = std::string("localhost:0");
|
||||
config["federated_world_size"] = 1;
|
||||
config["federated_rank"] = std::string("0");
|
||||
FederatedCommunicator::Create(config);
|
||||
};
|
||||
EXPECT_THROW(construct(), dmlc::Error);
|
||||
}
|
||||
|
||||
TEST(FederatedCommunicatorSimpleTest, GetWorldSizeAndRank) {
|
||||
FederatedCommunicator comm{6, 3, "localhost:0"};
|
||||
EXPECT_EQ(comm.GetWorldSize(), 6);
|
||||
EXPECT_EQ(comm.GetRank(), 3);
|
||||
}
|
||||
|
||||
TEST(FederatedCommunicatorSimpleTest, IsDistributed) {
|
||||
FederatedCommunicator comm{2, 1, "localhost:0"};
|
||||
EXPECT_TRUE(comm.IsDistributed());
|
||||
}
|
||||
|
||||
TEST_F(FederatedCommunicatorTest, Allgather) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedCommunicatorTest::VerifyAllgather, rank, server_->Address());
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedCommunicatorTest, AllgatherV) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedCommunicatorTest::VerifyAllgatherV, rank, server_->Address());
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedCommunicatorTest, Allreduce) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedCommunicatorTest::VerifyAllreduce, rank, server_->Address());
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedCommunicatorTest, Broadcast) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedCommunicatorTest::VerifyBroadcast, rank, server_->Address());
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
} // namespace xgboost::collective
|
||||
@@ -6,16 +6,13 @@
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "../../../plugin/federated/federated_server.h"
|
||||
#include "../../../src/collective/communicator-inl.h"
|
||||
#include "../filesystem.h"
|
||||
#include "../helpers.h"
|
||||
#include "helpers.h"
|
||||
#include "federated/test_worker.h"
|
||||
|
||||
namespace xgboost {
|
||||
|
||||
class FederatedDataTest : public BaseFederatedTest {};
|
||||
|
||||
void VerifyLoadUri() {
|
||||
auto const rank = collective::GetRank();
|
||||
|
||||
@@ -47,7 +44,8 @@ void VerifyLoadUri() {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedDataTest, LoadUri) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyLoadUri);
|
||||
TEST(FederatedDataTest, LoadUri) {
|
||||
static int constexpr kWorldSize{2};
|
||||
collective::TestFederatedGlobal(kWorldSize, [] { VerifyLoadUri(); });
|
||||
}
|
||||
} // namespace xgboost
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
/*!
|
||||
* Copyright 2023 XGBoost contributors
|
||||
/**
|
||||
* Copyright 2023-2024, XGBoost contributors
|
||||
*
|
||||
* Some other tests for federated learning are in the main test suite (test_learner.cc),
|
||||
* gaurded by the `XGBOOST_USE_FEDERATED`.
|
||||
*/
|
||||
#include <dmlc/parameter.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/data.h>
|
||||
#include <xgboost/objective.h>
|
||||
|
||||
#include "../../../plugin/federated/federated_server.h"
|
||||
#include "../../../src/collective/communicator-inl.h"
|
||||
#include "../../../src/common/linalg_op.h"
|
||||
#include "../../../src/common/linalg_op.h" // for begin, end
|
||||
#include "../helpers.h"
|
||||
#include "../objective_helpers.h" // for MakeObjNamesForTest, ObjTestNameGenerator
|
||||
#include "helpers.h"
|
||||
#include "federated/test_worker.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace {
|
||||
@@ -36,32 +38,16 @@ auto MakeModel(std::string tree_method, std::string device, std::string objectiv
|
||||
return model;
|
||||
}
|
||||
|
||||
void VerifyObjective(size_t rows, size_t cols, float expected_base_score, Json expected_model,
|
||||
std::string tree_method, std::string device, std::string objective) {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
void VerifyObjective(std::size_t rows, std::size_t cols, float expected_base_score,
|
||||
Json expected_model, std::string const &tree_method, std::string device,
|
||||
std::string const &objective) {
|
||||
auto rank = collective::GetRank();
|
||||
std::shared_ptr<DMatrix> dmat{RandomDataGenerator{rows, cols, 0}.GenerateDMatrix(rank == 0)};
|
||||
|
||||
if (rank == 0) {
|
||||
auto &h_upper = dmat->Info().labels_upper_bound_.HostVector();
|
||||
auto &h_lower = dmat->Info().labels_lower_bound_.HostVector();
|
||||
h_lower.resize(rows);
|
||||
h_upper.resize(rows);
|
||||
for (size_t i = 0; i < rows; ++i) {
|
||||
h_lower[i] = 1;
|
||||
h_upper[i] = 10;
|
||||
}
|
||||
|
||||
if (objective.find("rank:") != std::string::npos) {
|
||||
auto h_label = dmat->Info().labels.HostView();
|
||||
std::size_t k = 0;
|
||||
for (auto &v : h_label) {
|
||||
v = k % 2 == 0;
|
||||
++k;
|
||||
}
|
||||
}
|
||||
MakeLabelForObjTest(dmat, objective);
|
||||
}
|
||||
std::shared_ptr<DMatrix> sliced{dmat->SliceCol(world_size, rank)};
|
||||
std::shared_ptr<DMatrix> sliced{dmat->SliceCol(collective::GetWorldSize(), rank)};
|
||||
|
||||
auto model = MakeModel(tree_method, device, objective, sliced);
|
||||
auto base_score = GetBaseScore(model);
|
||||
@@ -71,18 +57,15 @@ void VerifyObjective(size_t rows, size_t cols, float expected_base_score, Json e
|
||||
} // namespace
|
||||
|
||||
class VerticalFederatedLearnerTest : public ::testing::TestWithParam<std::string> {
|
||||
std::unique_ptr<ServerForTest> server_;
|
||||
static int constexpr kWorldSize{3};
|
||||
|
||||
protected:
|
||||
void SetUp() override { server_ = std::make_unique<ServerForTest>(kWorldSize); }
|
||||
void TearDown() override { server_.reset(nullptr); }
|
||||
|
||||
void Run(std::string tree_method, std::string device, std::string objective) {
|
||||
static auto constexpr kRows{16};
|
||||
static auto constexpr kCols{16};
|
||||
|
||||
std::shared_ptr<DMatrix> dmat{RandomDataGenerator{kRows, kCols, 0}.GenerateDMatrix(true)};
|
||||
MakeLabelForObjTest(dmat, objective);
|
||||
|
||||
auto &h_upper = dmat->Info().labels_upper_bound_.HostVector();
|
||||
auto &h_lower = dmat->Info().labels_lower_bound_.HostVector();
|
||||
@@ -103,9 +86,9 @@ class VerticalFederatedLearnerTest : public ::testing::TestWithParam<std::string
|
||||
|
||||
auto model = MakeModel(tree_method, device, objective, dmat);
|
||||
auto score = GetBaseScore(model);
|
||||
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyObjective, kRows, kCols,
|
||||
score, model, tree_method, device, objective);
|
||||
collective::TestFederatedGlobal(kWorldSize, [&]() {
|
||||
VerifyObjective(kRows, kCols, score, model, tree_method, device, objective);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2023 XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../metric/test_auc.h"
|
||||
#include "../metric/test_elementwise_metric.h"
|
||||
#include "../metric/test_multiclass_metric.h"
|
||||
#include "../metric/test_rank_metric.h"
|
||||
#include "../metric/test_survival_metric.h"
|
||||
#include "helpers.h"
|
||||
|
||||
namespace {
|
||||
class FederatedMetricTest : public xgboost::BaseFederatedTest {};
|
||||
} // anonymous namespace
|
||||
|
||||
namespace xgboost {
|
||||
namespace metric {
|
||||
TEST_F(FederatedMetricTest, BinaryAUCRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyBinaryAUC,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, BinaryAUCColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyBinaryAUC,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassAUCRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassAUC,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassAUCColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassAUC,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RankingAUCRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRankingAUC,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RankingAUCColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRankingAUC,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, PRAUCRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyPRAUC, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, PRAUCColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyPRAUC, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassPRAUCRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassPRAUC,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassPRAUCColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassPRAUC,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RankingPRAUCRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRankingPRAUC,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RankingPRAUCColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRankingPRAUC,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RMSERowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRMSE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RMSEColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRMSE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RMSLERowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRMSLE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, RMSLEColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyRMSLE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MAERowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMAE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MAEColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMAE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MAPERowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMAPE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MAPEColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMAPE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MPHERowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMPHE, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MPHEColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMPHE, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, LogLossRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyLogLoss, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, LogLossColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyLogLoss, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, ErrorRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyError, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, ErrorColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyError, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, PoissonNegLogLikRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyPoissonNegLogLik,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, PoissonNegLogLikColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyPoissonNegLogLik,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiRMSERowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiRMSE,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiRMSEColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiRMSE,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, QuantileRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyQuantile,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, QuantileColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyQuantile,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassErrorRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassError,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassErrorColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassError,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassLogLossRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassLogLoss,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MultiClassLogLossColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMultiClassLogLoss,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, PrecisionRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyPrecision,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, PrecisionColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyPrecision,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, NDCGRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyNDCG, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, NDCGColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyNDCG, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MAPRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMAP, DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, MAPColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyMAP, DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, NDCGExpGainRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyNDCGExpGain,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, NDCGExpGainColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyNDCGExpGain,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
} // namespace metric
|
||||
} // namespace xgboost
|
||||
|
||||
namespace xgboost {
|
||||
namespace common {
|
||||
TEST_F(FederatedMetricTest, AFTNegLogLikRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyAFTNegLogLik,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, AFTNegLogLikColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyAFTNegLogLik,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, IntervalRegressionAccuracyRowSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyIntervalRegressionAccuracy,
|
||||
DataSplitMode::kRow);
|
||||
}
|
||||
|
||||
TEST_F(FederatedMetricTest, IntervalRegressionAccuracyColumnSplit) {
|
||||
RunWithFederatedCommunicator(kWorldSize, server_->Address(), &VerifyIntervalRegressionAccuracy,
|
||||
DataSplitMode::kCol);
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace xgboost
|
||||
@@ -1,133 +0,0 @@
|
||||
/*!
|
||||
* Copyright 2017-2020 XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "federated_client.h"
|
||||
#include "helpers.h"
|
||||
|
||||
namespace xgboost {
|
||||
|
||||
class FederatedServerTest : public BaseFederatedTest {
|
||||
public:
|
||||
static void VerifyAllgather(int rank, const std::string& server_address) {
|
||||
federated::FederatedClient client{server_address, rank};
|
||||
CheckAllgather(client, rank);
|
||||
}
|
||||
|
||||
static void VerifyAllgatherV(int rank, const std::string& server_address) {
|
||||
federated::FederatedClient client{server_address, rank};
|
||||
CheckAllgatherV(client, rank);
|
||||
}
|
||||
|
||||
static void VerifyAllreduce(int rank, const std::string& server_address) {
|
||||
federated::FederatedClient client{server_address, rank};
|
||||
CheckAllreduce(client);
|
||||
}
|
||||
|
||||
static void VerifyBroadcast(int rank, const std::string& server_address) {
|
||||
federated::FederatedClient client{server_address, rank};
|
||||
CheckBroadcast(client, rank);
|
||||
}
|
||||
|
||||
static void VerifyMixture(int rank, const std::string& server_address) {
|
||||
federated::FederatedClient client{server_address, rank};
|
||||
for (auto i = 0; i < 10; i++) {
|
||||
CheckAllgather(client, rank);
|
||||
CheckAllreduce(client);
|
||||
CheckBroadcast(client, rank);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
static void CheckAllgather(federated::FederatedClient& client, int rank) {
|
||||
int data[] = {rank};
|
||||
std::string send_buffer(reinterpret_cast<char const*>(data), sizeof(data));
|
||||
auto reply = client.Allgather(send_buffer);
|
||||
auto const* result = reinterpret_cast<int const*>(reply.data());
|
||||
for (auto i = 0; i < kWorldSize; i++) {
|
||||
EXPECT_EQ(result[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckAllgatherV(federated::FederatedClient& client, int rank) {
|
||||
std::vector<std::string_view> inputs{"Hello,", " World!"};
|
||||
auto reply = client.AllgatherV(inputs[rank]);
|
||||
EXPECT_EQ(reply, "Hello, World!");
|
||||
}
|
||||
|
||||
static void CheckAllreduce(federated::FederatedClient& client) {
|
||||
int data[] = {1, 2, 3, 4, 5};
|
||||
std::string send_buffer(reinterpret_cast<char const*>(data), sizeof(data));
|
||||
auto reply = client.Allreduce(send_buffer, federated::INT32, federated::SUM);
|
||||
auto const* result = reinterpret_cast<int const*>(reply.data());
|
||||
int expected[] = {2, 4, 6, 8, 10};
|
||||
for (auto i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(result[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckBroadcast(federated::FederatedClient& client, int rank) {
|
||||
std::string send_buffer{};
|
||||
if (rank == 0) {
|
||||
send_buffer = "hello broadcast";
|
||||
}
|
||||
auto reply = client.Broadcast(send_buffer, 0);
|
||||
EXPECT_EQ(reply, "hello broadcast") << "rank " << rank;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FederatedServerTest, Allgather) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedServerTest::VerifyAllgather, rank, server_->Address());
|
||||
}
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedServerTest, AllgatherV) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedServerTest::VerifyAllgatherV, rank, server_->Address());
|
||||
}
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedServerTest, Allreduce) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedServerTest::VerifyAllreduce, rank, server_->Address());
|
||||
}
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedServerTest, Broadcast) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedServerTest::VerifyBroadcast, rank, server_->Address());
|
||||
}
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FederatedServerTest, Mixture) {
|
||||
std::vector<std::thread> threads;
|
||||
for (auto rank = 0; rank < kWorldSize; rank++) {
|
||||
threads.emplace_back(&FederatedServerTest::VerifyMixture, rank, server_->Address());
|
||||
}
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xgboost
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "../../../src/data/proxy_dmatrix.h"
|
||||
#include "../../../src/gbm/gbtree.h"
|
||||
#include "../../../src/gbm/gbtree_model.h"
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../filesystem.h" // dmlc::TemporaryDirectory
|
||||
#include "../helpers.h"
|
||||
#include "test_predictor.h"
|
||||
@@ -43,7 +44,7 @@ void TestColumnSplit() {
|
||||
|
||||
TEST(CpuPredictor, BasicColumnSplit) {
|
||||
auto constexpr kWorldSize = 2;
|
||||
RunWithInMemoryCommunicator(kWorldSize, TestColumnSplit);
|
||||
collective::TestDistributedGlobal(kWorldSize, TestColumnSplit);
|
||||
}
|
||||
|
||||
TEST(CpuPredictor, IterationRange) {
|
||||
@@ -157,7 +158,7 @@ TEST(CPUPredictor, CategoricalPrediction) {
|
||||
|
||||
TEST(CPUPredictor, CategoricalPredictionColumnSplit) {
|
||||
auto constexpr kWorldSize = 2;
|
||||
RunWithInMemoryCommunicator(kWorldSize, TestCategoricalPrediction, false, true);
|
||||
collective::TestDistributedGlobal(kWorldSize, [] { TestCategoricalPrediction(false, true); });
|
||||
}
|
||||
|
||||
TEST(CPUPredictor, CategoricalPredictLeaf) {
|
||||
@@ -168,7 +169,7 @@ TEST(CPUPredictor, CategoricalPredictLeaf) {
|
||||
TEST(CPUPredictor, CategoricalPredictLeafColumnSplit) {
|
||||
auto constexpr kWorldSize = 2;
|
||||
Context ctx;
|
||||
RunWithInMemoryCommunicator(kWorldSize, TestCategoricalPredictLeaf, &ctx, true);
|
||||
collective::TestDistributedGlobal(kWorldSize, [&] { TestCategoricalPredictLeaf(&ctx, true); });
|
||||
}
|
||||
|
||||
TEST(CpuPredictor, UpdatePredictionCache) {
|
||||
@@ -183,7 +184,8 @@ TEST(CpuPredictor, LesserFeatures) {
|
||||
|
||||
TEST(CpuPredictor, LesserFeaturesColumnSplit) {
|
||||
auto constexpr kWorldSize = 2;
|
||||
RunWithInMemoryCommunicator(kWorldSize, TestPredictionWithLesserFeaturesColumnSplit, false);
|
||||
collective::TestDistributedGlobal(kWorldSize,
|
||||
[] { TestPredictionWithLesserFeaturesColumnSplit(false); });
|
||||
}
|
||||
|
||||
TEST(CpuPredictor, Sparse) {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "../../../src/data/device_adapter.cuh"
|
||||
#include "../../../src/data/proxy_dmatrix.h"
|
||||
#include "../../../src/gbm/gbtree_model.h"
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal, BaseMGPUTest
|
||||
#include "../helpers.h"
|
||||
#include "test_predictor.h"
|
||||
|
||||
@@ -85,7 +86,7 @@ void VerifyBasicColumnSplit(std::array<std::vector<float>, 32> const& expected_r
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
class MGPUPredictorTest : public BaseMGPUTest {};
|
||||
class MGPUPredictorTest : public collective::BaseMGPUTest {};
|
||||
|
||||
TEST_F(MGPUPredictorTest, BasicColumnSplit) {
|
||||
auto ctx = MakeCUDACtx(0);
|
||||
@@ -111,7 +112,8 @@ TEST_F(MGPUPredictorTest, BasicColumnSplit) {
|
||||
result[i - 1] = out_predictions_h;
|
||||
}
|
||||
|
||||
DoTest(VerifyBasicColumnSplit, result);
|
||||
this->DoTest([&] { VerifyBasicColumnSplit(result); }, true);
|
||||
this->DoTest([&] { VerifyBasicColumnSplit(result); }, false);
|
||||
}
|
||||
|
||||
TEST(GPUPredictor, EllpackBasic) {
|
||||
@@ -209,7 +211,8 @@ TEST(GpuPredictor, LesserFeatures) {
|
||||
}
|
||||
|
||||
TEST_F(MGPUPredictorTest, LesserFeaturesColumnSplit) {
|
||||
RunWithInMemoryCommunicator(world_size_, TestPredictionWithLesserFeaturesColumnSplit, true);
|
||||
this->DoTest([] { TestPredictionWithLesserFeaturesColumnSplit(true); }, true);
|
||||
this->DoTest([] { TestPredictionWithLesserFeaturesColumnSplit(true); }, false);
|
||||
}
|
||||
|
||||
// Very basic test of empty model
|
||||
@@ -277,7 +280,7 @@ TEST(GPUPredictor, IterationRange) {
|
||||
}
|
||||
|
||||
TEST_F(MGPUPredictorTest, IterationRangeColumnSplit) {
|
||||
TestIterationRangeColumnSplit(world_size_, true);
|
||||
TestIterationRangeColumnSplit(common::AllVisibleGPUs(), true);
|
||||
}
|
||||
|
||||
TEST(GPUPredictor, CategoricalPrediction) {
|
||||
@@ -285,7 +288,8 @@ TEST(GPUPredictor, CategoricalPrediction) {
|
||||
}
|
||||
|
||||
TEST_F(MGPUPredictorTest, CategoricalPredictionColumnSplit) {
|
||||
RunWithInMemoryCommunicator(world_size_, TestCategoricalPrediction, true, true);
|
||||
this->DoTest([] { TestCategoricalPrediction(true, true); }, true);
|
||||
this->DoTest([] { TestCategoricalPrediction(true, true); }, false);
|
||||
}
|
||||
|
||||
TEST(GPUPredictor, CategoricalPredictLeaf) {
|
||||
@@ -294,8 +298,18 @@ TEST(GPUPredictor, CategoricalPredictLeaf) {
|
||||
}
|
||||
|
||||
TEST_F(MGPUPredictorTest, CategoricalPredictionLeafColumnSplit) {
|
||||
auto ctx = MakeCUDACtx(common::AllVisibleGPUs() == 1 ? 0 : collective::GetRank());
|
||||
RunWithInMemoryCommunicator(world_size_, TestCategoricalPredictLeaf, &ctx, true);
|
||||
this->DoTest(
|
||||
[&] {
|
||||
auto ctx = MakeCUDACtx(collective::GetRank());
|
||||
TestCategoricalPredictLeaf(&ctx, true);
|
||||
},
|
||||
true);
|
||||
this->DoTest(
|
||||
[&] {
|
||||
auto ctx = MakeCUDACtx(collective::GetRank());
|
||||
TestCategoricalPredictLeaf(&ctx, true);
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(GPUPredictor, PredictLeafBasic) {
|
||||
@@ -325,7 +339,7 @@ TEST(GPUPredictor, Sparse) {
|
||||
}
|
||||
|
||||
TEST_F(MGPUPredictorTest, SparseColumnSplit) {
|
||||
TestSparsePredictionColumnSplit(world_size_, true, 0.2);
|
||||
TestSparsePredictionColumnSplit(world_size_, true, 0.8);
|
||||
TestSparsePredictionColumnSplit(common::AllVisibleGPUs(), true, 0.2);
|
||||
TestSparsePredictionColumnSplit(common::AllVisibleGPUs(), true, 0.8);
|
||||
}
|
||||
} // namespace xgboost::predictor
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2020-2023 by XGBoost Contributors
|
||||
* Copyright 2020-2024, XGBoost Contributors
|
||||
*/
|
||||
#include "test_predictor.h"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <xgboost/predictor.h> // for PredictionCacheEntry, Predictor, Predic...
|
||||
#include <xgboost/string_view.h> // for StringView
|
||||
|
||||
#include <algorithm> // for max
|
||||
#include <limits> // for numeric_limits
|
||||
#include <memory> // for shared_ptr
|
||||
#include <unordered_map> // for unordered_map
|
||||
@@ -18,6 +17,7 @@
|
||||
#include "../../../src/common/bitfield.h" // for LBitField32
|
||||
#include "../../../src/data/iterative_dmatrix.h" // for IterativeDMatrix
|
||||
#include "../../../src/data/proxy_dmatrix.h" // for DMatrixProxy
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../helpers.h" // for GetDMatrixFromData, RandomDataGenerator
|
||||
#include "xgboost/json.h" // for Json, Object, get, String
|
||||
#include "xgboost/linalg.h" // for MakeVec, Tensor, TensorView, Vector
|
||||
@@ -593,9 +593,23 @@ void TestIterationRangeColumnSplit(int world_size, bool use_gpu) {
|
||||
Json sliced_model{Object{}};
|
||||
sliced->SaveModel(&sliced_model);
|
||||
|
||||
RunWithInMemoryCommunicator(world_size, VerifyIterationRangeColumnSplit, use_gpu, ranged_model,
|
||||
sliced_model, kRows, kCols, kClasses, margin_ranged, margin_sliced,
|
||||
leaf_ranged, leaf_sliced);
|
||||
#if !defined(XGBOOST_USE_NCCL)
|
||||
if (use_gpu) {
|
||||
GTEST_SKIP_("Not compiled with NCCL");
|
||||
return;
|
||||
}
|
||||
#endif // defined(XGBOOST_USE_NCCL)
|
||||
collective::TestDistributedGlobal(world_size, [&] {
|
||||
VerifyIterationRangeColumnSplit(use_gpu, ranged_model, sliced_model, kRows, kCols, kClasses,
|
||||
margin_ranged, margin_sliced, leaf_ranged, leaf_sliced);
|
||||
});
|
||||
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
collective::TestFederatedGlobal(world_size, [&] {
|
||||
VerifyIterationRangeColumnSplit(use_gpu, ranged_model, sliced_model, kRows, kCols, kClasses,
|
||||
margin_ranged, margin_sliced, leaf_ranged, leaf_sliced);
|
||||
});
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
}
|
||||
|
||||
void TestSparsePrediction(Context const *ctx, float sparsity) {
|
||||
@@ -701,8 +715,23 @@ void TestSparsePredictionColumnSplit(int world_size, bool use_gpu, float sparsit
|
||||
learner->SetParam("device", ctx.DeviceName());
|
||||
learner->Predict(Xy, false, &sparse_predt, 0, 0);
|
||||
|
||||
RunWithInMemoryCommunicator(world_size, VerifySparsePredictionColumnSplit, use_gpu, model,
|
||||
kRows, kCols, sparsity, sparse_predt.HostVector());
|
||||
#if !defined(XGBOOST_USE_NCCL)
|
||||
if (use_gpu) {
|
||||
GTEST_SKIP_("Not compiled with NCCL.");
|
||||
return;
|
||||
}
|
||||
#endif // defined(XGBOOST_USE_CUDA)
|
||||
collective::TestDistributedGlobal(world_size, [&] {
|
||||
VerifySparsePredictionColumnSplit(use_gpu, model, kRows, kCols, sparsity,
|
||||
sparse_predt.HostVector());
|
||||
});
|
||||
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
collective::TestFederatedGlobal(world_size, [&] {
|
||||
VerifySparsePredictionColumnSplit(use_gpu, model, kRows, kCols, sparsity,
|
||||
sparse_predt.HostVector());
|
||||
});
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
}
|
||||
|
||||
void TestVectorLeafPrediction(Context const *ctx) {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#define RABIT_CXXTESTDEFS_H
|
||||
#if !defined(_WIN32)
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "../../../rabit/src/allreduce_base.h"
|
||||
|
||||
TEST(AllreduceBase, InitTask)
|
||||
{
|
||||
rabit::engine::AllreduceBase base;
|
||||
|
||||
std::string rabit_task_id = "rabit_task_id=1";
|
||||
char cmd[rabit_task_id.size()+1];
|
||||
std::copy(rabit_task_id.begin(), rabit_task_id.end(), cmd);
|
||||
cmd[rabit_task_id.size()] = '\0';
|
||||
|
||||
char* argv[] = {cmd};
|
||||
base.Init(1, argv);
|
||||
EXPECT_EQ(base.task_id, "1");
|
||||
}
|
||||
|
||||
TEST(AllreduceBase, InitWithRingReduce)
|
||||
{
|
||||
rabit::engine::AllreduceBase base;
|
||||
|
||||
std::string rabit_task_id = "rabit_task_id=1";
|
||||
char cmd[rabit_task_id.size()+1];
|
||||
std::copy(rabit_task_id.begin(), rabit_task_id.end(), cmd);
|
||||
cmd[rabit_task_id.size()] = '\0';
|
||||
|
||||
std::string rabit_reduce_ring_mincount = "rabit_reduce_ring_mincount=1";
|
||||
char cmd2[rabit_reduce_ring_mincount.size()+1];
|
||||
std::copy(rabit_reduce_ring_mincount.begin(), rabit_reduce_ring_mincount.end(), cmd2);
|
||||
cmd2[rabit_reduce_ring_mincount.size()] = '\0';
|
||||
|
||||
char* argv[] = {cmd, cmd2};
|
||||
base.Init(2, argv);
|
||||
EXPECT_EQ(base.task_id, "1");
|
||||
EXPECT_EQ(base.reduce_ring_mincount, 1ul);
|
||||
}
|
||||
#endif // !defined(_WIN32)
|
||||
@@ -1,6 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <rabit/internal/utils.h>
|
||||
|
||||
TEST(Utils, Assert) {
|
||||
EXPECT_THROW({rabit::utils::Assert(false, "foo");}, dmlc::Error);
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
/**
|
||||
* Copyright 2017-2024, XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <xgboost/learner.h> // for Learner
|
||||
#include <xgboost/logging.h> // for LogCheck_NE, CHECK_NE, LogCheck_EQ
|
||||
#include <xgboost/objective.h> // for ObjFunction
|
||||
#include <xgboost/version_config.h> // for XGBOOST_VER_MAJOR, XGBOOST_VER_MINOR
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/learner.h> // for Learner
|
||||
#include <xgboost/logging.h> // for LogCheck_NE, CHECK_NE, LogCheck_EQ
|
||||
#include <xgboost/objective.h> // for ObjFunction
|
||||
#include <xgboost/version_config.h> // for XGBOOST_VER_MAJOR, XGBOOST_VER_MINOR
|
||||
|
||||
#include <algorithm> // for equal, transform
|
||||
#include <cinttypes> // for int32_t, int64_t, uint32_t
|
||||
#include <cstddef> // for size_t
|
||||
#include <iosfwd> // for ofstream
|
||||
#include <limits> // for numeric_limits
|
||||
@@ -27,6 +26,7 @@
|
||||
#include "../../src/common/io.h" // for LoadSequentialFile
|
||||
#include "../../src/common/linalg_op.h" // for ElementWiseTransformHost, begin, end
|
||||
#include "../../src/common/random.h" // for GlobalRandom
|
||||
#include "./collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "dmlc/io.h" // for Stream
|
||||
#include "dmlc/omp.h" // for omp_get_max_threads
|
||||
#include "filesystem.h" // for TemporaryDirectory
|
||||
@@ -658,7 +658,7 @@ class TestColumnSplit : public ::testing::TestWithParam<std::string> {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
|
||||
auto p_fmat = MakeFmatForObjTest(objective);
|
||||
auto p_fmat = MakeFmatForObjTest(objective, 10, 10);
|
||||
std::shared_ptr<DMatrix> sliced{p_fmat->SliceCol(world_size, rank)};
|
||||
std::unique_ptr<Learner> learner{Learner::Create({sliced})};
|
||||
learner->SetParam("tree_method", "approx");
|
||||
@@ -682,7 +682,7 @@ class TestColumnSplit : public ::testing::TestWithParam<std::string> {
|
||||
|
||||
public:
|
||||
void Run(std::string objective) {
|
||||
auto p_fmat = MakeFmatForObjTest(objective);
|
||||
auto p_fmat = MakeFmatForObjTest(objective, 10, 10);
|
||||
std::unique_ptr<Learner> learner{Learner::Create({p_fmat})};
|
||||
learner->SetParam("tree_method", "approx");
|
||||
learner->SetParam("objective", objective);
|
||||
@@ -703,7 +703,9 @@ class TestColumnSplit : public ::testing::TestWithParam<std::string> {
|
||||
auto constexpr kWorldSize{3};
|
||||
auto call = [this, &objective](auto&... args) { TestBaseScore(objective, args...); };
|
||||
auto score = GetBaseScore(config);
|
||||
RunWithInMemoryCommunicator(kWorldSize, call, score, model);
|
||||
collective::TestDistributedGlobal(kWorldSize, [&] {
|
||||
call(score, model);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -736,7 +738,7 @@ void VerifyColumnSplitWithArgs(std::string const& tree_method, bool use_gpu, Arg
|
||||
Json const& expected_model) {
|
||||
auto const world_size = collective::GetWorldSize();
|
||||
auto const rank = collective::GetRank();
|
||||
auto p_fmat = MakeFmatForObjTest("");
|
||||
auto p_fmat = MakeFmatForObjTest("", 10, 10);
|
||||
std::shared_ptr<DMatrix> sliced{p_fmat->SliceCol(world_size, rank)};
|
||||
std::string device = "cpu";
|
||||
if (use_gpu) {
|
||||
@@ -747,82 +749,99 @@ void VerifyColumnSplitWithArgs(std::string const& tree_method, bool use_gpu, Arg
|
||||
ASSERT_EQ(model, expected_model);
|
||||
}
|
||||
|
||||
void TestColumnSplitWithArgs(std::string const& tree_method, bool use_gpu, Args const& args) {
|
||||
auto p_fmat = MakeFmatForObjTest("");
|
||||
void TestColumnSplitWithArgs(std::string const& tree_method, bool use_gpu, Args const& args,
|
||||
bool federated) {
|
||||
auto p_fmat = MakeFmatForObjTest("", 10, 10);
|
||||
std::string device = use_gpu ? "cuda:0" : "cpu";
|
||||
auto model = GetModelWithArgs(p_fmat, tree_method, device, args);
|
||||
|
||||
auto world_size{3};
|
||||
if (use_gpu) {
|
||||
world_size = common::AllVisibleGPUs();
|
||||
// Simulate MPU on a single GPU.
|
||||
if (world_size == 1) {
|
||||
// Simulate MPU on a single GPU. Federated doesn't use nccl, can run multiple
|
||||
// instances on the same GPU.
|
||||
if (world_size == 1 && federated) {
|
||||
world_size = 3;
|
||||
}
|
||||
}
|
||||
RunWithInMemoryCommunicator(world_size, VerifyColumnSplitWithArgs, tree_method, use_gpu, args,
|
||||
model);
|
||||
if (federated) {
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
collective::TestFederatedGlobal(
|
||||
world_size, [&] { VerifyColumnSplitWithArgs(tree_method, use_gpu, args, model); });
|
||||
#else
|
||||
GTEST_SKIP_("Not compiled with federated learning.");
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
} else {
|
||||
#if !defined(XGBOOST_USE_NCCL)
|
||||
if (use_gpu) {
|
||||
GTEST_SKIP_("Not compiled with NCCL.");
|
||||
return;
|
||||
}
|
||||
#endif // defined(XGBOOST_USE_NCCL)
|
||||
collective::TestDistributedGlobal(
|
||||
world_size, [&] { VerifyColumnSplitWithArgs(tree_method, use_gpu, args, model); });
|
||||
}
|
||||
}
|
||||
|
||||
void TestColumnSplitColumnSampler(std::string const& tree_method, bool use_gpu) {
|
||||
Args args{{"colsample_bytree", "0.5"}, {"colsample_bylevel", "0.6"}, {"colsample_bynode", "0.7"}};
|
||||
TestColumnSplitWithArgs(tree_method, use_gpu, args);
|
||||
}
|
||||
class ColumnSplitTrainingTest
|
||||
: public ::testing::TestWithParam<std::tuple<std::string, bool, bool>> {
|
||||
public:
|
||||
static void TestColumnSplitColumnSampler(std::string const& tree_method, bool use_gpu,
|
||||
bool federated) {
|
||||
Args args{
|
||||
{"colsample_bytree", "0.5"}, {"colsample_bylevel", "0.6"}, {"colsample_bynode", "0.7"}};
|
||||
TestColumnSplitWithArgs(tree_method, use_gpu, args, federated);
|
||||
}
|
||||
static void TestColumnSplitInteractionConstraints(std::string const& tree_method, bool use_gpu,
|
||||
bool federated) {
|
||||
Args args{{"interaction_constraints", "[[0, 5, 7], [2, 8, 9], [1, 3, 6]]"}};
|
||||
TestColumnSplitWithArgs(tree_method, use_gpu, args, federated);
|
||||
}
|
||||
static void TestColumnSplitMonotoneConstraints(std::string const& tree_method, bool use_gpu,
|
||||
bool federated) {
|
||||
Args args{{"monotone_constraints", "(1,-1,0,1,1,-1,-1,0,0,1)"}};
|
||||
TestColumnSplitWithArgs(tree_method, use_gpu, args, federated);
|
||||
}
|
||||
};
|
||||
|
||||
void TestColumnSplitInteractionConstraints(std::string const& tree_method, bool use_gpu) {
|
||||
Args args{{"interaction_constraints", "[[0, 5, 7], [2, 8, 9], [1, 3, 6]]"}};
|
||||
TestColumnSplitWithArgs(tree_method, use_gpu, args);
|
||||
}
|
||||
|
||||
void TestColumnSplitMonotoneConstraints(std::string const& tree_method, bool use_gpu) {
|
||||
Args args{{"monotone_constraints", "(1,-1,0,1,1,-1,-1,0,0,1)"}};
|
||||
TestColumnSplitWithArgs(tree_method, use_gpu, args);
|
||||
auto MakeParamsForTest() {
|
||||
std::vector<std::tuple<std::string, bool, bool>> configs;
|
||||
for (auto tm : {"hist", "approx"}) {
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
std::array<bool, 2> use_gpu{true, false};
|
||||
#else
|
||||
std::array<bool, 1> use_gpu{false};
|
||||
#endif
|
||||
for (auto i : use_gpu) {
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
std::array<bool, 2> fed{true, false};
|
||||
#else
|
||||
std::array<bool, 1> fed{false};
|
||||
#endif
|
||||
for (auto j : fed) {
|
||||
configs.emplace_back(tm, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(ColumnSplitColumnSampler, Approx) { TestColumnSplitColumnSampler("approx", false); }
|
||||
|
||||
TEST(ColumnSplitColumnSampler, Hist) { TestColumnSplitColumnSampler("hist", false); }
|
||||
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
TEST(MGPUColumnSplitColumnSampler, GPUApprox) { TestColumnSplitColumnSampler("approx", true); }
|
||||
|
||||
TEST(MGPUColumnSplitColumnSampler, GPUHist) { TestColumnSplitColumnSampler("hist", true); }
|
||||
#endif // defined(XGBOOST_USE_CUDA)
|
||||
|
||||
TEST(ColumnSplitInteractionConstraints, Approx) {
|
||||
TestColumnSplitInteractionConstraints("approx", false);
|
||||
TEST_P(ColumnSplitTrainingTest, ColumnSampler) {
|
||||
auto param = GetParam();
|
||||
std::apply(TestColumnSplitColumnSampler, param);
|
||||
}
|
||||
|
||||
TEST(ColumnSplitInteractionConstraints, Hist) {
|
||||
TestColumnSplitInteractionConstraints("hist", false);
|
||||
TEST_P(ColumnSplitTrainingTest, InteractionConstraints) {
|
||||
auto param = GetParam();
|
||||
std::apply(TestColumnSplitInteractionConstraints, param);
|
||||
}
|
||||
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
TEST(MGPUColumnSplitInteractionConstraints, GPUApprox) {
|
||||
TestColumnSplitInteractionConstraints("approx", true);
|
||||
TEST_P(ColumnSplitTrainingTest, MonotoneConstraints) {
|
||||
auto param = GetParam();
|
||||
std::apply(TestColumnSplitMonotoneConstraints, param);
|
||||
}
|
||||
|
||||
TEST(MGPUColumnSplitInteractionConstraints, GPUHist) {
|
||||
TestColumnSplitInteractionConstraints("hist", true);
|
||||
}
|
||||
#endif // defined(XGBOOST_USE_CUDA)
|
||||
|
||||
TEST(ColumnSplitMonotoneConstraints, Approx) {
|
||||
TestColumnSplitMonotoneConstraints("approx", false);
|
||||
}
|
||||
|
||||
TEST(ColumnSplitMonotoneConstraints, Hist) {
|
||||
TestColumnSplitMonotoneConstraints("hist", false);
|
||||
}
|
||||
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
TEST(MGPUColumnSplitMonotoneConstraints, GPUApprox) {
|
||||
TestColumnSplitMonotoneConstraints("approx", true);
|
||||
}
|
||||
|
||||
TEST(MGPUColumnSplitMonotoneConstraints, GPUHist) {
|
||||
TestColumnSplitMonotoneConstraints("hist", true);
|
||||
}
|
||||
#endif // defined(XGBOOST_USE_CUDA)
|
||||
INSTANTIATE_TEST_SUITE_P(ColumnSplit, ColumnSplitTrainingTest,
|
||||
::testing::ValuesIn(MakeParamsForTest()));
|
||||
} // namespace xgboost
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
// Copyright by Contributors
|
||||
/**
|
||||
* Copyright 2016-2024, XGBoost Contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/base.h>
|
||||
#include <xgboost/logging.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
xgboost::Args args {{"verbosity", "2"}};
|
||||
int main(int argc, char** argv) {
|
||||
xgboost::Args args{{"verbosity", "2"}};
|
||||
xgboost::ConsoleLogger::Configure(args);
|
||||
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Copyright 2020-2023, XGBoost contributors
|
||||
* Copyright 2020-2024, XGBoost contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <thrust/host_vector.h>
|
||||
|
||||
#include "../../../../src/tree/gpu_hist/evaluate_splits.cuh"
|
||||
#include "../../collective/test_worker.h" // for BaseMGPUTest
|
||||
#include "../../helpers.h"
|
||||
#include "../../histogram_helpers.h"
|
||||
#include "../test_evaluate_splits.h" // TestPartitionBasedSplit
|
||||
|
||||
namespace xgboost::tree {
|
||||
@@ -17,13 +17,13 @@ auto ZeroParam() {
|
||||
tparam.UpdateAllowUnknown(args);
|
||||
return tparam;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
inline GradientQuantiser DummyRoundingFactor(Context const* ctx) {
|
||||
GradientQuantiser DummyRoundingFactor(Context const* ctx) {
|
||||
thrust::device_vector<GradientPair> gpair(1);
|
||||
gpair[0] = {1000.f, 1000.f}; // Tests should not exceed sum of 1000
|
||||
return {ctx, dh::ToSpan(gpair), MetaInfo()};
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
thrust::device_vector<GradientPairInt64> ConvertToInteger(Context const* ctx,
|
||||
std::vector<GradientPairPrecise> x) {
|
||||
@@ -546,7 +546,7 @@ TEST_F(TestPartitionBasedSplit, GpuHist) {
|
||||
ASSERT_NEAR(split.loss_chg, best_score_, 1e-2);
|
||||
}
|
||||
|
||||
class MGPUHistTest : public BaseMGPUTest {};
|
||||
class MGPUHistTest : public collective::BaseMGPUTest {};
|
||||
|
||||
namespace {
|
||||
void VerifyColumnSplitEvaluateSingleSplit(bool is_categorical) {
|
||||
@@ -589,21 +589,29 @@ void VerifyColumnSplitEvaluateSingleSplit(bool is_categorical) {
|
||||
evaluator.Reset(cuts, dh::ToSpan(feature_types), feature_set.size(), tparam, true, ctx.Device());
|
||||
DeviceSplitCandidate result = evaluator.EvaluateSingleSplit(&ctx, input, shared_inputs).split;
|
||||
|
||||
EXPECT_EQ(result.findex, 1) << "rank: " << rank;
|
||||
EXPECT_EQ(result.findex, 1);
|
||||
if (is_categorical) {
|
||||
ASSERT_TRUE(std::isnan(result.fvalue));
|
||||
} else {
|
||||
EXPECT_EQ(result.fvalue, 11.0) << "rank: " << rank;
|
||||
EXPECT_EQ(result.fvalue, 11.0);
|
||||
}
|
||||
EXPECT_EQ(result.left_sum + result.right_sum, parent_sum) << "rank: " << rank;
|
||||
EXPECT_EQ(result.left_sum + result.right_sum, parent_sum);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_F(MGPUHistTest, ColumnSplitEvaluateSingleSplit) {
|
||||
DoTest(VerifyColumnSplitEvaluateSingleSplit, false);
|
||||
if (common::AllVisibleGPUs() > 1) {
|
||||
// We can't emulate multiple GPUs with NCCL.
|
||||
this->DoTest([] { VerifyColumnSplitEvaluateSingleSplit(false); }, false, true);
|
||||
}
|
||||
this->DoTest([] { VerifyColumnSplitEvaluateSingleSplit(false); }, true, true);
|
||||
}
|
||||
|
||||
TEST_F(MGPUHistTest, ColumnSplitEvaluateSingleCategoricalSplit) {
|
||||
DoTest(VerifyColumnSplitEvaluateSingleSplit, true);
|
||||
if (common::AllVisibleGPUs() > 1) {
|
||||
// We can't emulate multiple GPUs with NCCL.
|
||||
this->DoTest([] { VerifyColumnSplitEvaluateSingleSplit(true); }, false, true);
|
||||
}
|
||||
this->DoTest([] { VerifyColumnSplitEvaluateSingleSplit(true); }, true, true);
|
||||
}
|
||||
} // namespace xgboost::tree
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "../../../../src/tree/hist/histogram.h" // for HistogramBuilder
|
||||
#include "../../../../src/tree/hist/param.h" // for HistMakerTrainParam
|
||||
#include "../../categorical_helpers.h" // for OneHotEncodeFeature
|
||||
#include "../../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../../helpers.h" // for RandomDataGenerator, GenerateRa...
|
||||
|
||||
namespace xgboost::tree {
|
||||
@@ -300,8 +301,8 @@ TEST(CPUHistogram, BuildHist) {
|
||||
|
||||
TEST(CPUHistogram, BuildHistColSplit) {
|
||||
auto constexpr kWorkers = 4;
|
||||
RunWithInMemoryCommunicator(kWorkers, TestBuildHistogram, true, true, true);
|
||||
RunWithInMemoryCommunicator(kWorkers, TestBuildHistogram, true, false, true);
|
||||
collective::TestDistributedGlobal(kWorkers, [] { TestBuildHistogram(true, true, true); });
|
||||
collective::TestDistributedGlobal(kWorkers, [] { TestBuildHistogram(true, false, true); });
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/**
|
||||
* Copyright 2021-2023 by XGBoost contributors.
|
||||
* Copyright 2021-2024, XGBoost contributors.
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../../../src/common/numeric.h"
|
||||
#include "../../../src/tree/common_row_partitioner.h"
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../helpers.h"
|
||||
#include "test_partitioner.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace tree {
|
||||
namespace xgboost::tree {
|
||||
namespace {
|
||||
std::vector<float> GenerateHess(size_t n_samples) {
|
||||
auto grad = GenerateRandomGradients(n_samples);
|
||||
@@ -145,8 +145,9 @@ TEST(Approx, PartitionerColSplit) {
|
||||
}
|
||||
|
||||
auto constexpr kWorkers = 4;
|
||||
RunWithInMemoryCommunicator(kWorkers, TestColumnSplitPartitioner, n_samples, base_rowid, Xy,
|
||||
&hess, min_value, mid_value, mid_partitioner);
|
||||
collective::TestDistributedGlobal(kWorkers, [&] {
|
||||
TestColumnSplitPartitioner(n_samples, base_rowid, Xy, &hess, min_value, mid_value,
|
||||
mid_partitioner);
|
||||
});
|
||||
}
|
||||
} // namespace tree
|
||||
} // namespace xgboost
|
||||
} // namespace xgboost::tree
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2022-2023 by XGBoost Contributors
|
||||
* Copyright 2022-2024, XGBoost Contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/base.h> // for GradientPairInternal, GradientPairPrecise
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <limits> // for numeric_limits
|
||||
#include <numeric> // for iota
|
||||
#include <tuple> // for make_tuple, tie, tuple
|
||||
#include <utility> // for pair
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "../../../src/common/hist_util.h" // for HistogramCuts, HistCollection, GHistRow
|
||||
@@ -23,7 +22,6 @@
|
||||
#include "../../../src/tree/param.h" // for TrainParam, GradStats
|
||||
#include "../../../src/tree/split_evaluator.h" // for TreeEvaluator
|
||||
#include "../helpers.h" // for SimpleLCG, SimpleRealUniformDistribution
|
||||
#include "gtest/gtest_pred_impl.h" // for AssertionResult, ASSERT_EQ, ASSERT_TRUE
|
||||
|
||||
namespace xgboost::tree {
|
||||
/**
|
||||
@@ -96,13 +94,11 @@ class TestPartitionBasedSplit : public ::testing::Test {
|
||||
|
||||
// enumerate all possible partitions to find the optimal split
|
||||
do {
|
||||
int32_t thresh;
|
||||
float score;
|
||||
std::vector<GradientPairPrecise> sorted_hist(node_hist.size());
|
||||
for (size_t i = 0; i < sorted_hist.size(); ++i) {
|
||||
sorted_hist[i] = node_hist[sorted_idx_[i]];
|
||||
}
|
||||
std::tie(thresh, score) = enumerate({sorted_hist}, total_gpair_);
|
||||
auto [thresh, score] = enumerate({sorted_hist}, total_gpair_);
|
||||
if (score > best_score_) {
|
||||
best_score_ = score;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* Copyright 2022-2023, XGBoost Contributors
|
||||
* Copyright 2022-2024, XGBoost Contributors
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <xgboost/linalg.h>
|
||||
|
||||
#include "../../src/common/linalg_op.h"
|
||||
#include "../../src/tree/fit_stump.h"
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../helpers.h"
|
||||
|
||||
namespace xgboost::tree {
|
||||
@@ -43,7 +44,7 @@ TEST(InitEstimation, FitStump) {
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
TEST(InitEstimation, GPUFitStump) {
|
||||
Context ctx;
|
||||
ctx.UpdateAllowUnknown(Args{{"gpu_id", "0"}});
|
||||
ctx.UpdateAllowUnknown(Args{{"device", "cuda"}});
|
||||
TestFitStump(&ctx);
|
||||
}
|
||||
#endif // defined(XGBOOST_USE_CUDA)
|
||||
@@ -51,6 +52,6 @@ TEST(InitEstimation, GPUFitStump) {
|
||||
TEST(InitEstimation, FitStumpColumnSplit) {
|
||||
Context ctx;
|
||||
auto constexpr kWorldSize{3};
|
||||
RunWithInMemoryCommunicator(kWorldSize, &TestFitStump, &ctx, DataSplitMode::kCol);
|
||||
collective::TestDistributedGlobal(kWorldSize, [&] { TestFitStump(&ctx, DataSplitMode::kCol); });
|
||||
}
|
||||
} // namespace xgboost::tree
|
||||
|
||||
@@ -13,14 +13,19 @@
|
||||
#include "../../../src/common/common.h"
|
||||
#include "../../../src/data/ellpack_page.cuh" // for EllpackPageImpl
|
||||
#include "../../../src/data/ellpack_page.h" // for EllpackPage
|
||||
#include "../../../src/tree/param.h" // for TrainParam
|
||||
#include "../../../src/tree/param.h" // for TrainParam
|
||||
#include "../../../src/tree/updater_gpu_hist.cu"
|
||||
#include "../filesystem.h" // dmlc::TemporaryDirectory
|
||||
#include "../collective/test_worker.h" // for BaseMGPUTest
|
||||
#include "../filesystem.h" // dmlc::TemporaryDirectory
|
||||
#include "../helpers.h"
|
||||
#include "../histogram_helpers.h"
|
||||
#include "xgboost/context.h"
|
||||
#include "xgboost/json.h"
|
||||
|
||||
#if defined(XGBOOST_USE_FEDERATED)
|
||||
#include "../plugin/federated/test_worker.h" // for TestFederatedGlobal
|
||||
#endif // defined(XGBOOST_USE_FEDERATED)
|
||||
|
||||
namespace xgboost::tree {
|
||||
TEST(GpuHist, DeviceHistogram) {
|
||||
// Ensures that node allocates correctly after reaching `kStopGrowingSize`.
|
||||
@@ -458,9 +463,9 @@ void VerifyHistColumnSplit(bst_idx_t rows, bst_feature_t cols, RegTree const& ex
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
class MGPUHistTest : public BaseMGPUTest {};
|
||||
class MGPUHistTest : public collective::BaseMGPUTest {};
|
||||
|
||||
TEST_F(MGPUHistTest, GPUHistColumnSplit) {
|
||||
TEST_F(MGPUHistTest, HistColumnSplit) {
|
||||
auto constexpr kRows = 32;
|
||||
auto constexpr kCols = 16;
|
||||
|
||||
@@ -468,7 +473,8 @@ TEST_F(MGPUHistTest, GPUHistColumnSplit) {
|
||||
auto dmat = RandomDataGenerator{kRows, kCols, 0}.GenerateDMatrix(true);
|
||||
RegTree expected_tree = GetHistTree(&ctx, dmat.get());
|
||||
|
||||
DoTest(VerifyHistColumnSplit, kRows, kCols, expected_tree);
|
||||
this->DoTest([&] { VerifyHistColumnSplit(kRows, kCols, expected_tree); }, true);
|
||||
this->DoTest([&] { VerifyHistColumnSplit(kRows, kCols, expected_tree); }, false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -508,7 +514,7 @@ void VerifyApproxColumnSplit(bst_idx_t rows, bst_feature_t cols, RegTree const&
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
class MGPUApproxTest : public BaseMGPUTest {};
|
||||
class MGPUApproxTest : public collective::BaseMGPUTest {};
|
||||
|
||||
TEST_F(MGPUApproxTest, GPUApproxColumnSplit) {
|
||||
auto constexpr kRows = 32;
|
||||
@@ -518,6 +524,7 @@ TEST_F(MGPUApproxTest, GPUApproxColumnSplit) {
|
||||
auto dmat = RandomDataGenerator{kRows, kCols, 0}.GenerateDMatrix(true);
|
||||
RegTree expected_tree = GetApproxTree(&ctx, dmat.get());
|
||||
|
||||
DoTest(VerifyApproxColumnSplit, kRows, kCols, expected_tree);
|
||||
this->DoTest([&] { VerifyApproxColumnSplit(kRows, kCols, expected_tree); }, true);
|
||||
this->DoTest([&] { VerifyApproxColumnSplit(kRows, kCols, expected_tree); }, false);
|
||||
}
|
||||
} // namespace xgboost::tree
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#include <xgboost/tree_model.h>
|
||||
#include <xgboost/tree_updater.h>
|
||||
|
||||
#include "../../../src/tree/param.h" // for TrainParam
|
||||
#include "../../../src/tree/param.h" // for TrainParam
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../helpers.h"
|
||||
|
||||
namespace xgboost::tree {
|
||||
@@ -118,8 +119,8 @@ void TestColumnSplit(bool categorical) {
|
||||
}
|
||||
|
||||
auto constexpr kWorldSize = 2;
|
||||
RunWithInMemoryCommunicator(kWorldSize, VerifyColumnSplit, kRows, kCols, categorical,
|
||||
std::cref(expected_tree));
|
||||
collective::TestDistributedGlobal(
|
||||
kWorldSize, [&] { VerifyColumnSplit(kRows, kCols, categorical, expected_tree); });
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
@@ -11,26 +11,26 @@ namespace {
|
||||
auto MakeTreeForTest() {
|
||||
bst_target_t n_targets{3};
|
||||
bst_feature_t n_features{4};
|
||||
RegTree tree{n_targets, n_features};
|
||||
CHECK(tree.IsMultiTarget());
|
||||
std::unique_ptr<RegTree> tree{std::make_unique<RegTree>(n_targets, n_features)};
|
||||
CHECK(tree->IsMultiTarget());
|
||||
linalg::Vector<float> base_weight{{1.0f, 2.0f, 3.0f}, {3ul}, DeviceOrd::CPU()};
|
||||
linalg::Vector<float> left_weight{{2.0f, 3.0f, 4.0f}, {3ul}, DeviceOrd::CPU()};
|
||||
linalg::Vector<float> right_weight{{3.0f, 4.0f, 5.0f}, {3ul}, DeviceOrd::CPU()};
|
||||
tree.ExpandNode(RegTree::kRoot, /*split_idx=*/1, 0.5f, true, base_weight.HostView(),
|
||||
left_weight.HostView(), right_weight.HostView());
|
||||
tree->ExpandNode(RegTree::kRoot, /*split_idx=*/1, 0.5f, true, base_weight.HostView(),
|
||||
left_weight.HostView(), right_weight.HostView());
|
||||
return tree;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(MultiTargetTree, JsonIO) {
|
||||
auto tree = MakeTreeForTest();
|
||||
ASSERT_EQ(tree.NumNodes(), 3);
|
||||
ASSERT_EQ(tree.NumTargets(), 3);
|
||||
ASSERT_EQ(tree.GetMultiTargetTree()->Size(), 3);
|
||||
ASSERT_EQ(tree.Size(), 3);
|
||||
ASSERT_EQ(tree->NumNodes(), 3);
|
||||
ASSERT_EQ(tree->NumTargets(), 3);
|
||||
ASSERT_EQ(tree->GetMultiTargetTree()->Size(), 3);
|
||||
ASSERT_EQ(tree->Size(), 3);
|
||||
|
||||
Json jtree{Object{}};
|
||||
tree.SaveModel(&jtree);
|
||||
tree->SaveModel(&jtree);
|
||||
|
||||
auto check_jtree = [](Json jtree, RegTree const& tree) {
|
||||
ASSERT_EQ(get<String const>(jtree["tree_param"]["num_nodes"]), std::to_string(tree.NumNodes()));
|
||||
@@ -40,7 +40,7 @@ TEST(MultiTargetTree, JsonIO) {
|
||||
ASSERT_EQ(get<I32Array const>(jtree["left_children"]).size(), tree.NumNodes());
|
||||
ASSERT_EQ(get<I32Array const>(jtree["right_children"]).size(), tree.NumNodes());
|
||||
};
|
||||
check_jtree(jtree, tree);
|
||||
check_jtree(jtree, *tree);
|
||||
|
||||
RegTree loaded;
|
||||
loaded.LoadModel(jtree);
|
||||
@@ -49,18 +49,18 @@ TEST(MultiTargetTree, JsonIO) {
|
||||
|
||||
Json jtree1{Object{}};
|
||||
loaded.SaveModel(&jtree1);
|
||||
check_jtree(jtree1, tree);
|
||||
check_jtree(jtree1, *tree);
|
||||
}
|
||||
|
||||
TEST(MultiTargetTree, DumpDot) {
|
||||
auto tree = MakeTreeForTest();
|
||||
auto n_features = tree.NumFeatures();
|
||||
auto n_features = tree->NumFeatures();
|
||||
FeatureMap fmap;
|
||||
for (bst_feature_t f = 0; f < n_features; ++f) {
|
||||
auto name = "feat_" + std::to_string(f);
|
||||
fmap.PushBack(f, name.c_str(), "q");
|
||||
}
|
||||
auto str = tree.DumpModel(fmap, true, "dot");
|
||||
auto str = tree->DumpModel(fmap, true, "dot");
|
||||
ASSERT_NE(str.find("leaf=[2, 3, 4]"), std::string::npos);
|
||||
ASSERT_NE(str.find("leaf=[3, 4, 5]"), std::string::npos);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "../../../src/tree/common_row_partitioner.h"
|
||||
#include "../../../src/tree/hist/expand_entry.h" // for MultiExpandEntry, CPUExpandEntry
|
||||
#include "../../../src/tree/param.h"
|
||||
#include "../collective/test_worker.h" // for TestDistributedGlobal
|
||||
#include "../helpers.h"
|
||||
#include "test_partitioner.h"
|
||||
#include "xgboost/data.h"
|
||||
@@ -190,9 +191,10 @@ 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);
|
||||
collective::TestDistributedGlobal(kWorkers, [&] {
|
||||
VerifyColumnSplitPartitioner<ExpandEntry>(n_targets, n_samples, n_features, base_rowid, Xy,
|
||||
min_value, mid_value, mid_partitioner);
|
||||
});
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
@@ -245,8 +247,9 @@ void TestColumnSplit(bst_target_t n_targets) {
|
||||
}
|
||||
|
||||
auto constexpr kWorldSize = 2;
|
||||
RunWithInMemoryCommunicator(kWorldSize, VerifyColumnSplit, &ctx, kRows, kCols, n_targets,
|
||||
std::cref(expected_tree));
|
||||
collective::TestDistributedGlobal(kWorldSize, [&] {
|
||||
VerifyColumnSplit(&ctx, kRows, kCols, n_targets, std::cref(expected_tree));
|
||||
});
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user