|
1 | 1 | /**
|
2 |
| - * Copyright 2019-2024 XGBoost contributors |
| 2 | + * Copyright 2019-2025, XGBoost contributors |
3 | 3 | */
|
4 | 4 | #include <gtest/gtest.h>
|
5 | 5 | #include <xgboost/c_api.h>
|
|
8 | 8 | #include <xgboost/learner.h>
|
9 | 9 | #include <xgboost/version_config.h>
|
10 | 10 |
|
| 11 | +#include <algorithm> // for copy_n |
11 | 12 | #include <array> // for array
|
12 | 13 | #include <cstddef> // std::size_t
|
13 | 14 | #include <filesystem> // std::filesystem
|
|
22 | 23 | #include "../../../src/data/batch_utils.h" // for MatchingPageBytes
|
23 | 24 | #include "../../../src/data/gradient_index.h" // for GHistIndexMatrix
|
24 | 25 | #include "../../../src/data/iterative_dmatrix.h" // for IterativeDMatrix
|
| 26 | +#include "../../../src/data/proxy_dmatrix.h" // for DMatrixProxy |
25 | 27 | #include "../../../src/data/sparse_page_dmatrix.h" // for SparsePageDMatrix
|
26 | 28 | #include "../helpers.h"
|
27 | 29 |
|
@@ -599,4 +601,112 @@ TEST(CAPI, GPUXGDMatrixGetQuantileCut) {
|
599 | 601 | TestXGDMatrixGetQuantileCut(&ctx);
|
600 | 602 | }
|
601 | 603 | #endif // defined(XGBOOST_USE_CUDA)
|
| 604 | + |
| 605 | +TEST(CAPI, PredictReuseProxy) { |
| 606 | + // Configuration for creating DMatrix |
| 607 | + Json fmat_cfg{Object{}}; |
| 608 | + fmat_cfg["missing"] = std::numeric_limits<float>::quiet_NaN(); |
| 609 | + auto sfmat_cfg = Json::Dump(fmat_cfg); |
| 610 | + |
| 611 | + // Configuration for prediction |
| 612 | + Json config{Object{}}; |
| 613 | + config["type"] = Integer{0}; |
| 614 | + config["iteration_begin"] = config["iteration_end"] = Integer{0}; |
| 615 | + config["missing"] = Number{std::numeric_limits<float>::quiet_NaN()}; |
| 616 | + config["strict_shape"] = Boolean{true}; |
| 617 | + config["training"] = Boolean{false}; |
| 618 | + auto scfg = Json::Dump(config); |
| 619 | + |
| 620 | + HostDeviceVector<float> storage; |
| 621 | + bst_idx_t n_samples = 1024; |
| 622 | + auto inf = RandomDataGenerator{n_samples, 256, 0.0}.GenerateArrayInterface(&storage); |
| 623 | + HostDeviceVector<float> storage_y; |
| 624 | + auto y_inf = RandomDataGenerator{n_samples, 1, 0.0}.GenerateArrayInterface(&storage_y); |
| 625 | + |
| 626 | + // Create a DMatrix for training |
| 627 | + DMatrixHandle fmat_hdl{nullptr}; |
| 628 | + ASSERT_EQ(XGDMatrixCreateFromDense(inf.c_str(), sfmat_cfg.c_str(), &fmat_hdl), 0); |
| 629 | + ASSERT_EQ(XGDMatrixSetInfoFromInterface(fmat_hdl, "label", y_inf.c_str()), 0); |
| 630 | + |
| 631 | + // Create booster and train. |
| 632 | + std::array<DMatrixHandle, 1> mats{fmat_hdl}; |
| 633 | + BoosterHandle booster_hdl; |
| 634 | + ASSERT_EQ(XGBoosterCreate(mats.data(), 1, &booster_hdl), 0); |
| 635 | + |
| 636 | + for (std::int32_t i = 0; i < 3; ++i) { |
| 637 | + ASSERT_EQ(XGBoosterUpdateOneIter(booster_hdl, i, fmat_hdl), 0); |
| 638 | + } |
| 639 | + |
| 640 | + // Create a proxy that can be reused. |
| 641 | + DMatrixHandle proxy_hdl{nullptr}; |
| 642 | + ASSERT_EQ(XGProxyDMatrixCreate(&proxy_hdl), 0); |
| 643 | + |
| 644 | + bst_ulong const *outshape{nullptr}; |
| 645 | + bst_ulong outdim{0}; |
| 646 | + float const *result{nullptr}; |
| 647 | + |
| 648 | + { |
| 649 | + // Prediction with DMatrix |
| 650 | + ASSERT_EQ(XGBoosterPredictFromDMatrix(booster_hdl, fmat_hdl, scfg.c_str(), &outshape, &outdim, |
| 651 | + &result), |
| 652 | + 0); |
| 653 | + bst_ulong n_samples_ret = 0; |
| 654 | + ASSERT_EQ(XGDMatrixNumRow(fmat_hdl, &n_samples_ret), 0); |
| 655 | + std::vector<float> vec_0(n_samples_ret); |
| 656 | + ASSERT_EQ(vec_0.size(), n_samples); |
| 657 | + ASSERT_EQ(outdim, 2); |
| 658 | + std::copy_n(result, vec_0.size(), vec_0.begin()); |
| 659 | + |
| 660 | + // In-place predict |
| 661 | + ASSERT_EQ(XGBoosterPredictFromDense(booster_hdl, inf.c_str(), scfg.c_str(), proxy_hdl, |
| 662 | + &outshape, &outdim, &result), |
| 663 | + 0); |
| 664 | + ASSERT_EQ(XGDMatrixNumRow(proxy_hdl, &n_samples_ret), 0); |
| 665 | + std::vector<float> vec_1(n_samples_ret); |
| 666 | + ASSERT_EQ(vec_1.size(), n_samples); |
| 667 | + ASSERT_EQ(outdim, 2); |
| 668 | + std::copy_n(result, vec_1.size(), vec_1.begin()); |
| 669 | + |
| 670 | + // Same result |
| 671 | + ASSERT_EQ(vec_0, vec_1); |
| 672 | + } |
| 673 | + |
| 674 | + { |
| 675 | + bst_idx_t n_samples = 512; |
| 676 | + |
| 677 | + // Prediction with DMatrix |
| 678 | + auto inf = RandomDataGenerator{n_samples, 256, 0.0}.GenerateArrayInterface(&storage); |
| 679 | + DMatrixHandle fmat_hdl{nullptr}; |
| 680 | + ASSERT_EQ(XGDMatrixCreateFromDense(inf.c_str(), sfmat_cfg.c_str(), &fmat_hdl), 0); |
| 681 | + |
| 682 | + ASSERT_EQ(XGBoosterPredictFromDMatrix(booster_hdl, fmat_hdl, scfg.c_str(), &outshape, &outdim, |
| 683 | + &result), |
| 684 | + 0); |
| 685 | + bst_ulong n_samples_ret = 0; |
| 686 | + ASSERT_EQ(XGDMatrixNumRow(fmat_hdl, &n_samples_ret), 0); |
| 687 | + std::vector<float> vec_0(n_samples_ret); |
| 688 | + ASSERT_EQ(vec_0.size(), n_samples); |
| 689 | + ASSERT_EQ(outdim, 2); |
| 690 | + std::copy_n(result, vec_0.size(), vec_0.begin()); |
| 691 | + |
| 692 | + // In-place predict, same proxy as before |
| 693 | + ASSERT_EQ(XGBoosterPredictFromDense(booster_hdl, inf.c_str(), scfg.c_str(), proxy_hdl, |
| 694 | + &outshape, &outdim, &result), |
| 695 | + 0); |
| 696 | + ASSERT_EQ(XGDMatrixNumRow(proxy_hdl, &n_samples_ret), 0); |
| 697 | + std::vector<float> vec_1(n_samples_ret); |
| 698 | + ASSERT_EQ(vec_1.size(), n_samples); |
| 699 | + ASSERT_EQ(outdim, 2); |
| 700 | + std::copy_n(result, vec_1.size(), vec_1.begin()); |
| 701 | + |
| 702 | + // Same result |
| 703 | + ASSERT_EQ(vec_0, vec_1); |
| 704 | + |
| 705 | + ASSERT_EQ(XGDMatrixFree(fmat_hdl), 0); |
| 706 | + } |
| 707 | + |
| 708 | + ASSERT_EQ(XGDMatrixFree(fmat_hdl), 0); |
| 709 | + ASSERT_EQ(XGBoosterFree(booster_hdl), 0); |
| 710 | + ASSERT_EQ(XGDMatrixFree(proxy_hdl), 0); |
| 711 | +} |
602 | 712 | } // namespace xgboost
|
0 commit comments