Compare commits
18 Commits
release_1.
...
v1.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
742c19f3ec | ||
|
|
2245a6e9ac | ||
|
|
ed8ba2150b | ||
|
|
87ddcf308e | ||
|
|
35dac8af1d | ||
|
|
1311a20f49 | ||
|
|
328d1e18db | ||
|
|
3e2d7519a6 | ||
|
|
afb9dfd421 | ||
|
|
eb69c6110a | ||
|
|
0f9ffcdc16 | ||
|
|
9bbd00a49f | ||
|
|
7e239f229c | ||
|
|
a013942649 | ||
|
|
4d2ea0d4ef | ||
|
|
d1052b5cfe | ||
|
|
14c56f05da | ||
|
|
11f8b5cfcd |
73
.github/workflows/python_tests.yml
vendored
73
.github/workflows/python_tests.yml
vendored
@@ -45,13 +45,59 @@ jobs:
|
|||||||
cd ..
|
cd ..
|
||||||
python -c 'import xgboost'
|
python -c 'import xgboost'
|
||||||
|
|
||||||
python-tests:
|
python-tests-on-win:
|
||||||
name: Test XGBoost Python package on ${{ matrix.config.os }}
|
name: Test XGBoost Python package on ${{ matrix.config.os }}
|
||||||
runs-on: ${{ matrix.config.os }}
|
runs-on: ${{ matrix.config.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
config:
|
config:
|
||||||
- {os: windows-2016, python-version: '3.8'}
|
- {os: windows-2016, python-version: '3.8'}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
|
- uses: conda-incubator/setup-miniconda@v2
|
||||||
|
with:
|
||||||
|
auto-update-conda: true
|
||||||
|
python-version: ${{ matrix.config.python-version }}
|
||||||
|
activate-environment: win64_env
|
||||||
|
environment-file: tests/ci_build/conda_env/win64_cpu_test.yml
|
||||||
|
|
||||||
|
- name: Display Conda env
|
||||||
|
shell: bash -l {0}
|
||||||
|
run: |
|
||||||
|
conda info
|
||||||
|
conda list
|
||||||
|
|
||||||
|
- name: Build XGBoost on Windows
|
||||||
|
shell: bash -l {0}
|
||||||
|
run: |
|
||||||
|
mkdir build_msvc
|
||||||
|
cd build_msvc
|
||||||
|
cmake .. -G"Visual Studio 15 2017" -DCMAKE_CONFIGURATION_TYPES="Release" -A x64 -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON
|
||||||
|
cmake --build . --config Release --parallel $(nproc)
|
||||||
|
|
||||||
|
- name: Install Python package
|
||||||
|
shell: bash -l {0}
|
||||||
|
run: |
|
||||||
|
cd python-package
|
||||||
|
python --version
|
||||||
|
python setup.py bdist_wheel --universal
|
||||||
|
pip install ./dist/*.whl
|
||||||
|
|
||||||
|
- name: Test Python package
|
||||||
|
shell: bash -l {0}
|
||||||
|
run: |
|
||||||
|
pytest -s -v ./tests/python
|
||||||
|
|
||||||
|
python-tests-on-macos:
|
||||||
|
name: Test XGBoost Python package on ${{ matrix.config.os }}
|
||||||
|
runs-on: ${{ matrix.config.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
- {os: macos-10.15, python-version "3.8" }
|
- {os: macos-10.15, python-version "3.8" }
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -63,8 +109,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
auto-update-conda: true
|
auto-update-conda: true
|
||||||
python-version: ${{ matrix.config.python-version }}
|
python-version: ${{ matrix.config.python-version }}
|
||||||
activate-environment: win64_test
|
activate-environment: macos_test
|
||||||
environment-file: tests/ci_build/conda_env/win64_cpu_test.yml
|
environment-file: tests/ci_build/conda_env/macos_cpu_test.yml
|
||||||
|
|
||||||
- name: Display Conda env
|
- name: Display Conda env
|
||||||
shell: bash -l {0}
|
shell: bash -l {0}
|
||||||
@@ -72,17 +118,7 @@ jobs:
|
|||||||
conda info
|
conda info
|
||||||
conda list
|
conda list
|
||||||
|
|
||||||
- name: Build XGBoost on Windows
|
|
||||||
shell: bash -l {0}
|
|
||||||
if: matrix.config.os == 'windows-2016'
|
|
||||||
run: |
|
|
||||||
mkdir build_msvc
|
|
||||||
cd build_msvc
|
|
||||||
cmake .. -G"Visual Studio 15 2017" -DCMAKE_CONFIGURATION_TYPES="Release" -A x64 -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON
|
|
||||||
cmake --build . --config Release --parallel $(nproc)
|
|
||||||
|
|
||||||
- name: Build XGBoost on macos
|
- name: Build XGBoost on macos
|
||||||
if: matrix.config.os == 'macos-10.15'
|
|
||||||
run: |
|
run: |
|
||||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -O $(find $(brew --repository) -name libomp.rb)
|
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -O $(find $(brew --repository) -name libomp.rb)
|
||||||
brew install ninja libomp
|
brew install ninja libomp
|
||||||
@@ -108,16 +144,19 @@ jobs:
|
|||||||
|
|
||||||
- name: Rename Python wheel
|
- name: Rename Python wheel
|
||||||
shell: bash -l {0}
|
shell: bash -l {0}
|
||||||
if: matrix.config.os == 'macos-10.15'
|
|
||||||
run: |
|
run: |
|
||||||
TAG=macosx_10_15_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64
|
TAG=macosx_10_15_x86_64.macosx_11_0_x86_64.macosx_12_0_x86_64
|
||||||
python tests/ci_build/rename_whl.py python-package/dist/*.whl ${{ github.sha }} ${TAG}
|
python tests/ci_build/rename_whl.py python-package/dist/*.whl ${{ github.sha }} ${TAG}
|
||||||
|
|
||||||
|
- name: Extract branch name
|
||||||
|
shell: bash
|
||||||
|
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
|
||||||
|
id: extract_branch
|
||||||
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
||||||
|
|
||||||
- name: Upload Python wheel
|
- name: Upload Python wheel
|
||||||
shell: bash -l {0}
|
shell: bash -l {0}
|
||||||
if: |
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
||||||
(github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')) &&
|
|
||||||
matrix.os == 'macos-latest'
|
|
||||||
run: |
|
run: |
|
||||||
python -m awscli s3 cp python-package/dist/*.whl s3://xgboost-nightly-builds/${{ steps.extract_branch.outputs.branch }}/ --acl public-read
|
python -m awscli s3 cp python-package/dist/*.whl s3://xgboost-nightly-builds/${{ steps.extract_branch.outputs.branch }}/ --acl public-read
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||||
project(xgboost LANGUAGES CXX C VERSION 1.5.0)
|
project(xgboost LANGUAGES CXX C VERSION 1.5.2)
|
||||||
include(cmake/Utils.cmake)
|
include(cmake/Utils.cmake)
|
||||||
list(APPEND CMAKE_MODULE_PATH "${xgboost_SOURCE_DIR}/cmake/modules")
|
list(APPEND CMAKE_MODULE_PATH "${xgboost_SOURCE_DIR}/cmake/modules")
|
||||||
cmake_policy(SET CMP0022 NEW)
|
cmake_policy(SET CMP0022 NEW)
|
||||||
@@ -135,6 +135,10 @@ if (USE_CUDA)
|
|||||||
set(GEN_CODE "")
|
set(GEN_CODE "")
|
||||||
format_gencode_flags("${GPU_COMPUTE_VER}" GEN_CODE)
|
format_gencode_flags("${GPU_COMPUTE_VER}" GEN_CODE)
|
||||||
add_subdirectory(${PROJECT_SOURCE_DIR}/gputreeshap)
|
add_subdirectory(${PROJECT_SOURCE_DIR}/gputreeshap)
|
||||||
|
|
||||||
|
if ((${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 11.4) AND (NOT BUILD_WITH_CUDA_CUB))
|
||||||
|
message(SEND_ERROR "`BUILD_WITH_CUDA_CUB` should be set to `ON` for CUDA >= 11.4")
|
||||||
|
endif ()
|
||||||
endif (USE_CUDA)
|
endif (USE_CUDA)
|
||||||
|
|
||||||
if (FORCE_COLORED_OUTPUT AND (CMAKE_GENERATOR STREQUAL "Ninja") AND
|
if (FORCE_COLORED_OUTPUT AND (CMAKE_GENERATOR STREQUAL "Ninja") AND
|
||||||
|
|||||||
@@ -4,4 +4,3 @@
|
|||||||
^.*\.Rproj$
|
^.*\.Rproj$
|
||||||
^\.Rproj\.user$
|
^\.Rproj\.user$
|
||||||
README.md
|
README.md
|
||||||
CMakeLists.txt
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
Package: xgboost
|
Package: xgboost
|
||||||
Type: Package
|
Type: Package
|
||||||
Title: Extreme Gradient Boosting
|
Title: Extreme Gradient Boosting
|
||||||
Version: 1.5.0.2
|
Version: 1.5.2.1
|
||||||
Date: 2021-11-19
|
Date: 2022-1-17
|
||||||
Authors@R: c(
|
Authors@R: c(
|
||||||
person("Tianqi", "Chen", role = c("aut"),
|
person("Tianqi", "Chen", role = c("aut"),
|
||||||
email = "tianqi.tchen@gmail.com"),
|
email = "tianqi.tchen@gmail.com"),
|
||||||
|
|||||||
@@ -435,7 +435,8 @@ predict.xgb.Booster <- function(object, newdata, missing = NA, outputmargin = FA
|
|||||||
lapply(seq_len(n_groups), function(g) arr[g, , ])
|
lapply(seq_len(n_groups), function(g) arr[g, , ])
|
||||||
} else {
|
} else {
|
||||||
## remove the first axis (group)
|
## remove the first axis (group)
|
||||||
as.matrix(arr[1, , ])
|
dn <- dimnames(arr)
|
||||||
|
matrix(arr[1, , ], nrow = dim(arr)[2], ncol = dim(arr)[3], dimnames = c(dn[2], dn[3]))
|
||||||
}
|
}
|
||||||
} else if (predinteraction) {
|
} else if (predinteraction) {
|
||||||
## Predict interaction
|
## Predict interaction
|
||||||
@@ -447,7 +448,8 @@ predict.xgb.Booster <- function(object, newdata, missing = NA, outputmargin = FA
|
|||||||
lapply(seq_len(n_groups), function(g) arr[g, , , ])
|
lapply(seq_len(n_groups), function(g) arr[g, , , ])
|
||||||
} else {
|
} else {
|
||||||
## remove the first axis (group)
|
## remove the first axis (group)
|
||||||
arr[1, , , ]
|
arr <- arr[1, , , , drop = FALSE]
|
||||||
|
array(arr, dim = dim(arr)[2:4], dimnames(arr)[2:4])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
## Normal prediction
|
## Normal prediction
|
||||||
|
|||||||
@@ -46,3 +46,31 @@ test_that("gblinear works", {
|
|||||||
expect_equal(dim(h), c(n, ncol(dtrain) + 1))
|
expect_equal(dim(h), c(n, ncol(dtrain) + 1))
|
||||||
expect_s4_class(h, "dgCMatrix")
|
expect_s4_class(h, "dgCMatrix")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test_that("gblinear early stopping works", {
|
||||||
|
data(agaricus.train, package = 'xgboost')
|
||||||
|
data(agaricus.test, package = 'xgboost')
|
||||||
|
dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||||
|
dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||||
|
|
||||||
|
param <- list(
|
||||||
|
objective = "binary:logistic", eval_metric = "error", booster = "gblinear",
|
||||||
|
nthread = 2, eta = 0.8, alpha = 0.0001, lambda = 0.0001,
|
||||||
|
updater = "coord_descent"
|
||||||
|
)
|
||||||
|
|
||||||
|
es_round <- 1
|
||||||
|
n <- 10
|
||||||
|
booster <- xgb.train(
|
||||||
|
param, dtrain, n, list(eval = dtest, train = dtrain), early_stopping_rounds = es_round
|
||||||
|
)
|
||||||
|
expect_equal(booster$best_iteration, 5)
|
||||||
|
predt_es <- predict(booster, dtrain)
|
||||||
|
|
||||||
|
n <- booster$best_iteration + es_round
|
||||||
|
booster <- xgb.train(
|
||||||
|
param, dtrain, n, list(eval = dtest, train = dtrain), early_stopping_rounds = es_round
|
||||||
|
)
|
||||||
|
predt <- predict(booster, dtrain)
|
||||||
|
expect_equal(predt_es, predt)
|
||||||
|
})
|
||||||
|
|||||||
@@ -157,3 +157,28 @@ test_that("multiclass feature interactions work", {
|
|||||||
# sums WRT columns must be close to feature contributions
|
# sums WRT columns must be close to feature contributions
|
||||||
expect_lt(max(abs(apply(intr, c(1, 2, 3), sum) - aperm(cont, c(3, 1, 2)))), 0.00001)
|
expect_lt(max(abs(apply(intr, c(1, 2, 3), sum) - aperm(cont, c(3, 1, 2)))), 0.00001)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test_that("SHAP single sample works", {
|
||||||
|
train <- agaricus.train
|
||||||
|
test <- agaricus.test
|
||||||
|
booster <- xgboost(
|
||||||
|
data = train$data,
|
||||||
|
label = train$label,
|
||||||
|
max_depth = 2,
|
||||||
|
nrounds = 4,
|
||||||
|
objective = "binary:logistic",
|
||||||
|
)
|
||||||
|
|
||||||
|
predt <- predict(
|
||||||
|
booster,
|
||||||
|
newdata = train$data[1, , drop = FALSE], predcontrib = TRUE
|
||||||
|
)
|
||||||
|
expect_equal(dim(predt), c(1, dim(train$data)[2] + 1))
|
||||||
|
|
||||||
|
predt <- predict(
|
||||||
|
booster,
|
||||||
|
newdata = train$data[1, , drop = FALSE], predinteraction = TRUE
|
||||||
|
)
|
||||||
|
expect_equal(dim(predt), c(1, dim(train$data)[2] + 1, dim(train$data)[2] + 1))
|
||||||
|
})
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ From the command line on Linux starting from the XGBoost directory:
|
|||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. -DUSE_CUDA=ON
|
# For CUDA toolkit >= 11.4, `BUILD_WITH_CUDA_CUB` is required.
|
||||||
|
cmake .. -DUSE_CUDA=ON -DBUILD_WITH_CUDA_CUB=ON
|
||||||
make -j4
|
make -j4
|
||||||
|
|
||||||
.. note:: Specifying compute capability
|
.. note:: Specifying compute capability
|
||||||
|
|||||||
@@ -95,13 +95,13 @@ XGBoost makes use of `GPUTreeShap <https://github.com/rapidsai/gputreeshap>`_ as
|
|||||||
shap_interaction_values = model.predict(dtrain, pred_interactions=True)
|
shap_interaction_values = model.predict(dtrain, pred_interactions=True)
|
||||||
|
|
||||||
See examples `here
|
See examples `here
|
||||||
<https://github.com/dmlc/xgboost/tree/master/demo/gpu_acceleration>`_.
|
<https://github.com/dmlc/xgboost/tree/master/demo/gpu_acceleration>`__.
|
||||||
|
|
||||||
Multi-node Multi-GPU Training
|
Multi-node Multi-GPU Training
|
||||||
=============================
|
=============================
|
||||||
XGBoost supports fully distributed GPU training using `Dask <https://dask.org/>`_. For
|
XGBoost supports fully distributed GPU training using `Dask <https://dask.org/>`_. For
|
||||||
getting started see our tutorial :doc:`/tutorials/dask` and worked examples `here
|
getting started see our tutorial :doc:`/tutorials/dask` and worked examples `here
|
||||||
<https://github.com/dmlc/xgboost/tree/master/demo/dask>`_, also Python documentation
|
<https://github.com/dmlc/xgboost/tree/master/demo/dask>`__, also Python documentation
|
||||||
:ref:`dask_api` for complete reference.
|
:ref:`dask_api` for complete reference.
|
||||||
|
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ Working memory is allocated inside the algorithm proportional to the number of r
|
|||||||
|
|
||||||
The quantile finding algorithm also uses some amount of working device memory. It is able to operate in batches, but is not currently well optimised for sparse data.
|
The quantile finding algorithm also uses some amount of working device memory. It is able to operate in batches, but is not currently well optimised for sparse data.
|
||||||
|
|
||||||
If you are getting out-of-memory errors on a big dataset, try the `external memory version <../tutorials/external_memory.html>`_.
|
If you are getting out-of-memory errors on a big dataset, try the :doc:`external memory version </tutorials/external_memory>`.
|
||||||
|
|
||||||
Developer notes
|
Developer notes
|
||||||
===============
|
===============
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ The first thing in data transformation is to load the dataset as Spark's structu
|
|||||||
StructField("class", StringType, true)))
|
StructField("class", StringType, true)))
|
||||||
val rawInput = spark.read.schema(schema).csv("input_path")
|
val rawInput = spark.read.schema(schema).csv("input_path")
|
||||||
|
|
||||||
At the first line, we create a instance of `SparkSession <http://spark.apache.org/docs/latest/sql-programming-guide.html#starting-point-sparksession>`_ which is the entry of any Spark program working with DataFrame. The ``schema`` variable defines the schema of DataFrame wrapping Iris data. With this explicitly set schema, we can define the columns' name as well as their types; otherwise the column name would be the default ones derived by Spark, such as ``_col0``, etc. Finally, we can use Spark's built-in csv reader to load Iris csv file as a DataFrame named ``rawInput``.
|
At the first line, we create a instance of `SparkSession <https://spark.apache.org/docs/latest/sql-getting-started.html#starting-point-sparksession>`_ which is the entry of any Spark program working with DataFrame. The ``schema`` variable defines the schema of DataFrame wrapping Iris data. With this explicitly set schema, we can define the columns' name as well as their types; otherwise the column name would be the default ones derived by Spark, such as ``_col0``, etc. Finally, we can use Spark's built-in csv reader to load Iris csv file as a DataFrame named ``rawInput``.
|
||||||
|
|
||||||
Spark also contains many built-in readers for other format. The latest version of Spark supports CSV, JSON, Parquet, and LIBSVM.
|
Spark also contains many built-in readers for other format. The latest version of Spark supports CSV, JSON, Parquet, and LIBSVM.
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ labels. A DataFrame like this (containing vector-represented features and numeri
|
|||||||
Dealing with missing values
|
Dealing with missing values
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
XGBoost supports missing values by default (`as desribed here <https://xgboost.readthedocs.io/en/latest/faq.html#how-to-deal-with-missing-value>`_).
|
XGBoost supports missing values by default (`as desribed here <https://xgboost.readthedocs.io/en/latest/faq.html#how-to-deal-with-missing-values>`_).
|
||||||
If given a SparseVector, XGBoost will treat any values absent from the SparseVector as missing. You are also able to
|
If given a SparseVector, XGBoost will treat any values absent from the SparseVector as missing. You are also able to
|
||||||
specify to XGBoost to treat a specific value in your Dataset as if it was a missing value. By default XGBoost will treat NaN as the value representing missing.
|
specify to XGBoost to treat a specific value in your Dataset as if it was a missing value. By default XGBoost will treat NaN as the value representing missing.
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ Then we can load this model with single node Python XGBoost:
|
|||||||
|
|
||||||
When interacting with other language bindings, XGBoost also supports saving-models-to and loading-models-from file systems other than the local one. You can use HDFS and S3 by prefixing the path with ``hdfs://`` and ``s3://`` respectively. However, for this capability, you must do **one** of the following:
|
When interacting with other language bindings, XGBoost also supports saving-models-to and loading-models-from file systems other than the local one. You can use HDFS and S3 by prefixing the path with ``hdfs://`` and ``s3://`` respectively. However, for this capability, you must do **one** of the following:
|
||||||
|
|
||||||
1. Build XGBoost4J-Spark with the steps described in `here <https://xgboost.readthedocs.io/en/latest/jvm/index.html#installation-from-source>`_, but turning `USE_HDFS <https://github.com/dmlc/xgboost/blob/e939192978a0c152ad7b49b744630e99d54cffa8/jvm-packages/create_jni.py#L18>`_ (or USE_S3, etc. in the same place) switch on. With this approach, you can reuse the above code example by replacing "nativeModelPath" with a HDFS path.
|
1. Build XGBoost4J-Spark with the steps described in :ref:`here <install_jvm_packages>`, but turning `USE_HDFS <https://github.com/dmlc/xgboost/blob/e939192978a0c152ad7b49b744630e99d54cffa8/jvm-packages/create_jni.py#L18>`_ (or USE_S3, etc. in the same place) switch on. With this approach, you can reuse the above code example by replacing "nativeModelPath" with a HDFS path.
|
||||||
|
|
||||||
- However, if you build with USE_HDFS, etc. you have to ensure that the involved shared object file, e.g. libhdfs.so, is put in the LIBRARY_PATH of your cluster. To avoid the complicated cluster environment configuration, choose the other option.
|
- However, if you build with USE_HDFS, etc. you have to ensure that the involved shared object file, e.g. libhdfs.so, is put in the LIBRARY_PATH of your cluster. To avoid the complicated cluster environment configuration, choose the other option.
|
||||||
|
|
||||||
|
|||||||
@@ -366,8 +366,8 @@ Specify the learning task and the corresponding learning objective. The objectiv
|
|||||||
- ``rank:pairwise``: Use LambdaMART to perform pairwise ranking where the pairwise loss is minimized
|
- ``rank:pairwise``: Use LambdaMART to perform pairwise ranking where the pairwise loss is minimized
|
||||||
- ``rank:ndcg``: Use LambdaMART to perform list-wise ranking where `Normalized Discounted Cumulative Gain (NDCG) <http://en.wikipedia.org/wiki/NDCG>`_ is maximized
|
- ``rank:ndcg``: Use LambdaMART to perform list-wise ranking where `Normalized Discounted Cumulative Gain (NDCG) <http://en.wikipedia.org/wiki/NDCG>`_ is maximized
|
||||||
- ``rank:map``: Use LambdaMART to perform list-wise ranking where `Mean Average Precision (MAP) <http://en.wikipedia.org/wiki/Mean_average_precision#Mean_average_precision>`_ is maximized
|
- ``rank:map``: Use LambdaMART to perform list-wise ranking where `Mean Average Precision (MAP) <http://en.wikipedia.org/wiki/Mean_average_precision#Mean_average_precision>`_ is maximized
|
||||||
- ``reg:gamma``: gamma regression with log-link. Output is a mean of gamma distribution. It might be useful, e.g., for modeling insurance claims severity, or for any outcome that might be `gamma-distributed <https://en.wikipedia.org/wiki/Gamma_distribution#Applications>`_.
|
- ``reg:gamma``: gamma regression with log-link. Output is a mean of gamma distribution. It might be useful, e.g., for modeling insurance claims severity, or for any outcome that might be `gamma-distributed <https://en.wikipedia.org/wiki/Gamma_distribution#Occurrence_and_applications>`_.
|
||||||
- ``reg:tweedie``: Tweedie regression with log-link. It might be useful, e.g., for modeling total loss in insurance, or for any outcome that might be `Tweedie-distributed <https://en.wikipedia.org/wiki/Tweedie_distribution#Applications>`_.
|
- ``reg:tweedie``: Tweedie regression with log-link. It might be useful, e.g., for modeling total loss in insurance, or for any outcome that might be `Tweedie-distributed <https://en.wikipedia.org/wiki/Tweedie_distribution#Occurrence_and_applications>`_.
|
||||||
|
|
||||||
* ``base_score`` [default=0.5]
|
* ``base_score`` [default=0.5]
|
||||||
|
|
||||||
@@ -390,7 +390,7 @@ Specify the learning task and the corresponding learning objective. The objectiv
|
|||||||
- ``error@t``: a different than 0.5 binary classification threshold value could be specified by providing a numerical value through 't'.
|
- ``error@t``: a different than 0.5 binary classification threshold value could be specified by providing a numerical value through 't'.
|
||||||
- ``merror``: Multiclass classification error rate. It is calculated as ``#(wrong cases)/#(all cases)``.
|
- ``merror``: Multiclass classification error rate. It is calculated as ``#(wrong cases)/#(all cases)``.
|
||||||
- ``mlogloss``: `Multiclass logloss <http://scikit-learn.org/stable/modules/generated/sklearn.metrics.log_loss.html>`_.
|
- ``mlogloss``: `Multiclass logloss <http://scikit-learn.org/stable/modules/generated/sklearn.metrics.log_loss.html>`_.
|
||||||
- ``auc``: `Receiver Operating Characteristic Area under the Curve <http://en.wikipedia.org/wiki/Receiver_operating_characteristic#Area_under_curve>`_.
|
- ``auc``: `Receiver Operating Characteristic Area under the Curve <https://en.wikipedia.org/wiki/Receiver_operating_characteristic#Area_under_the_curve>`_.
|
||||||
Available for classification and learning-to-rank tasks.
|
Available for classification and learning-to-rank tasks.
|
||||||
|
|
||||||
- When used with binary classification, the objective should be ``binary:logistic`` or similar functions that work on probability.
|
- When used with binary classification, the objective should be ``binary:logistic`` or similar functions that work on probability.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ In order to run a XGBoost job in a Kubernetes cluster, perform the following ste
|
|||||||
|
|
||||||
1. Install XGBoost Operator on the Kubernetes cluster.
|
1. Install XGBoost Operator on the Kubernetes cluster.
|
||||||
|
|
||||||
a. XGBoost Operator is designed to manage the scheduling and monitoring of XGBoost jobs. Follow `this installation guide <https://github.com/kubeflow/xgboost-operator#installing-xgboost-operator>`_ to install XGBoost Operator.
|
a. XGBoost Operator is designed to manage the scheduling and monitoring of XGBoost jobs. Follow `this installation guide <https://github.com/kubeflow/xgboost-operator#install-xgboost-operator>`_ to install XGBoost Operator.
|
||||||
|
|
||||||
2. Write application code that will be executed by the XGBoost Operator.
|
2. Write application code that will be executed by the XGBoost Operator.
|
||||||
|
|
||||||
|
|||||||
@@ -227,15 +227,15 @@ XGBoost has a function called ``dump_model`` in Booster object, which lets you t
|
|||||||
the model in a readable format like ``text``, ``json`` or ``dot`` (graphviz). The primary
|
the model in a readable format like ``text``, ``json`` or ``dot`` (graphviz). The primary
|
||||||
use case for it is for model interpretation or visualization, and is not supposed to be
|
use case for it is for model interpretation or visualization, and is not supposed to be
|
||||||
loaded back to XGBoost. The JSON version has a `schema
|
loaded back to XGBoost. The JSON version has a `schema
|
||||||
<https://github.com/dmlc/xgboost/blob/master/doc/dump.schema>`_. See next section for
|
<https://github.com/dmlc/xgboost/blob/master/doc/dump.schema>`__. See next section for
|
||||||
more info.
|
more info.
|
||||||
|
|
||||||
***********
|
***********
|
||||||
JSON Schema
|
JSON Schema
|
||||||
***********
|
***********
|
||||||
|
|
||||||
Another important feature of JSON format is a documented `Schema
|
Another important feature of JSON format is a documented `schema
|
||||||
<https://json-schema.org/>`_, based on which one can easily reuse the output model from
|
<https://json-schema.org/>`__, based on which one can easily reuse the output model from
|
||||||
XGBoost. Here is the initial draft of JSON schema for the output model (not
|
XGBoost. Here is the initial draft of JSON schema for the output model (not
|
||||||
serialization, which will not be stable as noted above). It's subject to change due to
|
serialization, which will not be stable as noted above). It's subject to change due to
|
||||||
the beta status. For an example of parsing XGBoost tree model, see ``/demo/json-model``.
|
the beta status. For an example of parsing XGBoost tree model, see ``/demo/json-model``.
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
|
|
||||||
#define XGBOOST_VER_MAJOR 1
|
#define XGBOOST_VER_MAJOR 1
|
||||||
#define XGBOOST_VER_MINOR 5
|
#define XGBOOST_VER_MINOR 5
|
||||||
#define XGBOOST_VER_PATCH 0
|
#define XGBOOST_VER_PATCH 2
|
||||||
|
|
||||||
#endif // XGBOOST_VERSION_CONFIG_H_
|
#endif // XGBOOST_VERSION_CONFIG_H_
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm_2.12</artifactId>
|
<artifactId>xgboost-jvm_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>XGBoost JVM Package</name>
|
<name>XGBoost JVM Package</name>
|
||||||
<description>JVM Package for XGBoost</description>
|
<description>JVM Package for XGBoost</description>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm_2.12</artifactId>
|
<artifactId>xgboost-jvm_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-example_2.12</artifactId>
|
<artifactId>xgboost4j-example_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j-spark_${scala.binary.version}</artifactId>
|
<artifactId>xgboost4j-spark_${scala.binary.version}</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.spark</groupId>
|
<groupId>org.apache.spark</groupId>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j-flink_${scala.binary.version}</artifactId>
|
<artifactId>xgboost4j-flink_${scala.binary.version}</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm_2.12</artifactId>
|
<artifactId>xgboost-jvm_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-flink_2.12</artifactId>
|
<artifactId>xgboost4j-flink_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j_${scala.binary.version}</artifactId>
|
<artifactId>xgboost4j_${scala.binary.version}</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm_2.12</artifactId>
|
<artifactId>xgboost-jvm_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-gpu_2.12</artifactId>
|
<artifactId>xgboost4j-gpu_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm_2.12</artifactId>
|
<artifactId>xgboost-jvm_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-spark-gpu_2.12</artifactId>
|
<artifactId>xgboost4j-spark-gpu_2.12</artifactId>
|
||||||
<build>
|
<build>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j-gpu_${scala.binary.version}</artifactId>
|
<artifactId>xgboost4j-gpu_${scala.binary.version}</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.spark</groupId>
|
<groupId>org.apache.spark</groupId>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm_2.12</artifactId>
|
<artifactId>xgboost-jvm_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j-spark_2.12</artifactId>
|
<artifactId>xgboost4j-spark_2.12</artifactId>
|
||||||
<build>
|
<build>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost4j_${scala.binary.version}</artifactId>
|
<artifactId>xgboost4j_${scala.binary.version}</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.spark</groupId>
|
<groupId>org.apache.spark</groupId>
|
||||||
|
|||||||
@@ -17,11 +17,13 @@
|
|||||||
package ml.dmlc.xgboost4j.scala.spark.params
|
package ml.dmlc.xgboost4j.scala.spark.params
|
||||||
|
|
||||||
import org.apache.hadoop.fs.Path
|
import org.apache.hadoop.fs.Path
|
||||||
|
|
||||||
import org.apache.spark.SparkContext
|
import org.apache.spark.SparkContext
|
||||||
import org.apache.spark.ml.param.{ParamPair, Params}
|
import org.apache.spark.ml.param.{ParamPair, Params}
|
||||||
import org.json4s.JsonDSL._
|
|
||||||
import org.json4s.jackson.JsonMethods._
|
import org.json4s.jackson.JsonMethods._
|
||||||
import org.json4s.{JObject, _}
|
import org.json4s.{JArray, JBool, JDouble, JField, JInt, JNothing, JObject, JString, JValue}
|
||||||
|
|
||||||
|
import JsonDSLXGBoost._
|
||||||
|
|
||||||
// This originates from apache-spark DefaultPramsWriter copy paste
|
// This originates from apache-spark DefaultPramsWriter copy paste
|
||||||
private[spark] object DefaultXGBoostParamsWriter {
|
private[spark] object DefaultXGBoostParamsWriter {
|
||||||
@@ -87,3 +89,62 @@ private[spark] object DefaultXGBoostParamsWriter {
|
|||||||
metadataJson
|
metadataJson
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix json4s bin-incompatible issue.
|
||||||
|
// This originates from org.json4s.JsonDSL of 3.6.6
|
||||||
|
object JsonDSLXGBoost {
|
||||||
|
|
||||||
|
implicit def seq2jvalue[A](s: Iterable[A])(implicit ev: A => JValue): JArray =
|
||||||
|
JArray(s.toList.map(ev))
|
||||||
|
|
||||||
|
implicit def map2jvalue[A](m: Map[String, A])(implicit ev: A => JValue): JObject =
|
||||||
|
JObject(m.toList.map { case (k, v) => JField(k, ev(v)) })
|
||||||
|
|
||||||
|
implicit def option2jvalue[A](opt: Option[A])(implicit ev: A => JValue): JValue = opt match {
|
||||||
|
case Some(x) => ev(x)
|
||||||
|
case None => JNothing
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit def short2jvalue(x: Short): JValue = JInt(x)
|
||||||
|
implicit def byte2jvalue(x: Byte): JValue = JInt(x)
|
||||||
|
implicit def char2jvalue(x: Char): JValue = JInt(x)
|
||||||
|
implicit def int2jvalue(x: Int): JValue = JInt(x)
|
||||||
|
implicit def long2jvalue(x: Long): JValue = JInt(x)
|
||||||
|
implicit def bigint2jvalue(x: BigInt): JValue = JInt(x)
|
||||||
|
implicit def double2jvalue(x: Double): JValue = JDouble(x)
|
||||||
|
implicit def float2jvalue(x: Float): JValue = JDouble(x.toDouble)
|
||||||
|
implicit def bigdecimal2jvalue(x: BigDecimal): JValue = JDouble(x.doubleValue)
|
||||||
|
implicit def boolean2jvalue(x: Boolean): JValue = JBool(x)
|
||||||
|
implicit def string2jvalue(x: String): JValue = JString(x)
|
||||||
|
|
||||||
|
implicit def symbol2jvalue(x: Symbol): JString = JString(x.name)
|
||||||
|
implicit def pair2jvalue[A](t: (String, A))(implicit ev: A => JValue): JObject =
|
||||||
|
JObject(List(JField(t._1, ev(t._2))))
|
||||||
|
implicit def list2jvalue(l: List[JField]): JObject = JObject(l)
|
||||||
|
implicit def jobject2assoc(o: JObject): JsonListAssoc = new JsonListAssoc(o.obj)
|
||||||
|
implicit def pair2Assoc[A](t: (String, A))(implicit ev: A => JValue): JsonAssoc[A] =
|
||||||
|
new JsonAssoc(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class JsonAssoc[A](private val left: (String, A)) extends AnyVal {
|
||||||
|
def ~[B](right: (String, B))(implicit ev1: A => JValue, ev2: B => JValue): JObject = {
|
||||||
|
val l: JValue = ev1(left._2)
|
||||||
|
val r: JValue = ev2(right._2)
|
||||||
|
JObject(JField(left._1, l) :: JField(right._1, r) :: Nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
def ~(right: JObject)(implicit ev: A => JValue): JObject = {
|
||||||
|
val l: JValue = ev(left._2)
|
||||||
|
JObject(JField(left._1, l) :: right.obj)
|
||||||
|
}
|
||||||
|
def ~~[B](right: (String, B))(implicit ev1: A => JValue, ev2: B => JValue): JObject =
|
||||||
|
this.~(right)
|
||||||
|
def ~~(right: JObject)(implicit ev: A => JValue): JObject = this.~(right)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class JsonListAssoc(private val left: List[JField]) extends AnyVal {
|
||||||
|
def ~(right: (String, JValue)): JObject = JObject(left ::: List(JField(right._1, right._2)))
|
||||||
|
def ~(right: JObject): JObject = JObject(left ::: right.obj)
|
||||||
|
def ~~(right: (String, JValue)): JObject = this.~(right)
|
||||||
|
def ~~(right: JObject): JObject = this.~(right)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>ml.dmlc</groupId>
|
<groupId>ml.dmlc</groupId>
|
||||||
<artifactId>xgboost-jvm_2.12</artifactId>
|
<artifactId>xgboost-jvm_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>xgboost4j_2.12</artifactId>
|
<artifactId>xgboost4j_2.12</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.5.2</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
import logging
|
||||||
import distutils
|
import distutils
|
||||||
|
from typing import Optional, List
|
||||||
import sys
|
import sys
|
||||||
from platform import system
|
from platform import system
|
||||||
from setuptools import setup, find_packages, Extension
|
from setuptools import setup, find_packages, Extension
|
||||||
@@ -36,7 +37,7 @@ NEED_CLEAN_FILE = set()
|
|||||||
BUILD_TEMP_DIR = None
|
BUILD_TEMP_DIR = None
|
||||||
|
|
||||||
|
|
||||||
def lib_name():
|
def lib_name() -> str:
|
||||||
'''Return platform dependent shared object name.'''
|
'''Return platform dependent shared object name.'''
|
||||||
if system() == 'Linux' or system().upper().endswith('BSD'):
|
if system() == 'Linux' or system().upper().endswith('BSD'):
|
||||||
name = 'libxgboost.so'
|
name = 'libxgboost.so'
|
||||||
@@ -47,13 +48,13 @@ def lib_name():
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
def copy_tree(src_dir, target_dir):
|
def copy_tree(src_dir: str, target_dir: str) -> None:
|
||||||
'''Copy source tree into build directory.'''
|
'''Copy source tree into build directory.'''
|
||||||
def clean_copy_tree(src, dst):
|
def clean_copy_tree(src: str, dst: str) -> None:
|
||||||
distutils.dir_util.copy_tree(src, dst)
|
distutils.dir_util.copy_tree(src, dst)
|
||||||
NEED_CLEAN_TREE.add(os.path.abspath(dst))
|
NEED_CLEAN_TREE.add(os.path.abspath(dst))
|
||||||
|
|
||||||
def clean_copy_file(src, dst):
|
def clean_copy_file(src: str, dst: str) -> None:
|
||||||
distutils.file_util.copy_file(src, dst)
|
distutils.file_util.copy_file(src, dst)
|
||||||
NEED_CLEAN_FILE.add(os.path.abspath(dst))
|
NEED_CLEAN_FILE.add(os.path.abspath(dst))
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ def copy_tree(src_dir, target_dir):
|
|||||||
clean_copy_file(lic, os.path.join(target_dir, 'LICENSE'))
|
clean_copy_file(lic, os.path.join(target_dir, 'LICENSE'))
|
||||||
|
|
||||||
|
|
||||||
def clean_up():
|
def clean_up() -> None:
|
||||||
'''Removed copied files.'''
|
'''Removed copied files.'''
|
||||||
for path in NEED_CLEAN_TREE:
|
for path in NEED_CLEAN_TREE:
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
@@ -87,7 +88,7 @@ def clean_up():
|
|||||||
|
|
||||||
class CMakeExtension(Extension): # pylint: disable=too-few-public-methods
|
class CMakeExtension(Extension): # pylint: disable=too-few-public-methods
|
||||||
'''Wrapper for extension'''
|
'''Wrapper for extension'''
|
||||||
def __init__(self, name):
|
def __init__(self, name: str) -> None:
|
||||||
super().__init__(name=name, sources=[])
|
super().__init__(name=name, sources=[])
|
||||||
|
|
||||||
|
|
||||||
@@ -97,7 +98,14 @@ class BuildExt(build_ext.build_ext): # pylint: disable=too-many-ancestors
|
|||||||
logger = logging.getLogger('XGBoost build_ext')
|
logger = logging.getLogger('XGBoost build_ext')
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments,no-self-use
|
# pylint: disable=too-many-arguments,no-self-use
|
||||||
def build(self, src_dir, build_dir, generator, build_tool=None, use_omp=1):
|
def build(
|
||||||
|
self,
|
||||||
|
src_dir: str,
|
||||||
|
build_dir: str,
|
||||||
|
generator: str,
|
||||||
|
build_tool: Optional[str] = None,
|
||||||
|
use_omp: int = 1,
|
||||||
|
) -> None:
|
||||||
'''Build the core library with CMake.'''
|
'''Build the core library with CMake.'''
|
||||||
cmake_cmd = ['cmake', src_dir, generator]
|
cmake_cmd = ['cmake', src_dir, generator]
|
||||||
|
|
||||||
@@ -116,13 +124,14 @@ class BuildExt(build_ext.build_ext): # pylint: disable=too-many-ancestors
|
|||||||
|
|
||||||
if system() != 'Windows':
|
if system() != 'Windows':
|
||||||
nproc = os.cpu_count()
|
nproc = os.cpu_count()
|
||||||
|
assert build_tool is not None
|
||||||
subprocess.check_call([build_tool, '-j' + str(nproc)],
|
subprocess.check_call([build_tool, '-j' + str(nproc)],
|
||||||
cwd=build_dir)
|
cwd=build_dir)
|
||||||
else:
|
else:
|
||||||
subprocess.check_call(['cmake', '--build', '.',
|
subprocess.check_call(['cmake', '--build', '.',
|
||||||
'--config', 'Release'], cwd=build_dir)
|
'--config', 'Release'], cwd=build_dir)
|
||||||
|
|
||||||
def build_cmake_extension(self):
|
def build_cmake_extension(self) -> None:
|
||||||
'''Configure and build using CMake'''
|
'''Configure and build using CMake'''
|
||||||
if USER_OPTIONS['use-system-libxgboost'][2]:
|
if USER_OPTIONS['use-system-libxgboost'][2]:
|
||||||
self.logger.info('Using system libxgboost.')
|
self.logger.info('Using system libxgboost.')
|
||||||
@@ -174,14 +183,14 @@ class BuildExt(build_ext.build_ext): # pylint: disable=too-many-ancestors
|
|||||||
self.logger.warning('Disabling OpenMP support.')
|
self.logger.warning('Disabling OpenMP support.')
|
||||||
self.build(src_dir, build_dir, gen, build_tool, use_omp=0)
|
self.build(src_dir, build_dir, gen, build_tool, use_omp=0)
|
||||||
|
|
||||||
def build_extension(self, ext):
|
def build_extension(self, ext: Extension) -> None:
|
||||||
'''Override the method for dispatching.'''
|
'''Override the method for dispatching.'''
|
||||||
if isinstance(ext, CMakeExtension):
|
if isinstance(ext, CMakeExtension):
|
||||||
self.build_cmake_extension()
|
self.build_cmake_extension()
|
||||||
else:
|
else:
|
||||||
super().build_extension(ext)
|
super().build_extension(ext)
|
||||||
|
|
||||||
def copy_extensions_to_source(self):
|
def copy_extensions_to_source(self) -> None:
|
||||||
'''Dummy override. Invoked during editable installation. Our binary
|
'''Dummy override. Invoked during editable installation. Our binary
|
||||||
should available in `lib`.
|
should available in `lib`.
|
||||||
|
|
||||||
@@ -196,7 +205,7 @@ class Sdist(sdist.sdist): # pylint: disable=too-many-ancestors
|
|||||||
'''Copy c++ source into Python directory.'''
|
'''Copy c++ source into Python directory.'''
|
||||||
logger = logging.getLogger('xgboost sdist')
|
logger = logging.getLogger('xgboost sdist')
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
copy_tree(os.path.join(CURRENT_DIR, os.path.pardir),
|
copy_tree(os.path.join(CURRENT_DIR, os.path.pardir),
|
||||||
os.path.join(CURRENT_DIR, 'xgboost'))
|
os.path.join(CURRENT_DIR, 'xgboost'))
|
||||||
libxgboost = os.path.join(
|
libxgboost = os.path.join(
|
||||||
@@ -213,7 +222,7 @@ class InstallLib(install_lib.install_lib):
|
|||||||
'''Copy shared object into installation directory.'''
|
'''Copy shared object into installation directory.'''
|
||||||
logger = logging.getLogger('xgboost install_lib')
|
logger = logging.getLogger('xgboost install_lib')
|
||||||
|
|
||||||
def install(self):
|
def install(self) -> List[str]:
|
||||||
outfiles = super().install()
|
outfiles = super().install()
|
||||||
|
|
||||||
if USER_OPTIONS['use-system-libxgboost'][2] != 0:
|
if USER_OPTIONS['use-system-libxgboost'][2] != 0:
|
||||||
@@ -255,7 +264,7 @@ class Install(install.install): # pylint: disable=too-many-instance-attributes
|
|||||||
user_options = install.install.user_options + list(
|
user_options = install.install.user_options + list(
|
||||||
(k, v[0], v[1]) for k, v in USER_OPTIONS.items())
|
(k, v[0], v[1]) for k, v in USER_OPTIONS.items())
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self) -> None:
|
||||||
super().initialize_options()
|
super().initialize_options()
|
||||||
self.use_openmp = 1
|
self.use_openmp = 1
|
||||||
self.use_cuda = 0
|
self.use_cuda = 0
|
||||||
@@ -271,7 +280,7 @@ class Install(install.install): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
self.use_system_libxgboost = 0
|
self.use_system_libxgboost = 0
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
# setuptools will configure the options according to user supplied command line
|
# setuptools will configure the options according to user supplied command line
|
||||||
# arguments, then here we propagate them into `USER_OPTIONS` for visibility to
|
# arguments, then here we propagate them into `USER_OPTIONS` for visibility to
|
||||||
# other sub-commands like `build_ext`.
|
# other sub-commands like `build_ext`.
|
||||||
@@ -341,7 +350,9 @@ if __name__ == '__main__':
|
|||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Programming Language :: Python :: 3.7',
|
'Programming Language :: Python :: 3.7',
|
||||||
'Programming Language :: Python :: 3.8'],
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: 3.9',
|
||||||
|
'Programming Language :: Python :: 3.10'],
|
||||||
python_requires='>=3.6',
|
python_requires='>=3.6',
|
||||||
url='https://github.com/dmlc/xgboost')
|
url='https://github.com/dmlc/xgboost')
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.5.0
|
1.5.2
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ def _numpy2ctypes_type(dtype):
|
|||||||
}
|
}
|
||||||
if np.intc is not np.int32: # Windows
|
if np.intc is not np.int32: # Windows
|
||||||
_NUMPY_TO_CTYPES_MAPPING[np.intc] = _NUMPY_TO_CTYPES_MAPPING[np.int32]
|
_NUMPY_TO_CTYPES_MAPPING[np.intc] = _NUMPY_TO_CTYPES_MAPPING[np.int32]
|
||||||
if dtype not in _NUMPY_TO_CTYPES_MAPPING.keys():
|
if dtype not in _NUMPY_TO_CTYPES_MAPPING:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
f"Supported types: {_NUMPY_TO_CTYPES_MAPPING.keys()}, got: {dtype}"
|
f"Supported types: {_NUMPY_TO_CTYPES_MAPPING.keys()}, got: {dtype}"
|
||||||
)
|
)
|
||||||
@@ -266,7 +266,7 @@ def ctypes2cupy(cptr, length, dtype):
|
|||||||
from cupy.cuda.memory import UnownedMemory
|
from cupy.cuda.memory import UnownedMemory
|
||||||
|
|
||||||
CUPY_TO_CTYPES_MAPPING = {cupy.float32: ctypes.c_float, cupy.uint32: ctypes.c_uint}
|
CUPY_TO_CTYPES_MAPPING = {cupy.float32: ctypes.c_float, cupy.uint32: ctypes.c_uint}
|
||||||
if dtype not in CUPY_TO_CTYPES_MAPPING.keys():
|
if dtype not in CUPY_TO_CTYPES_MAPPING:
|
||||||
raise RuntimeError(f"Supported types: {CUPY_TO_CTYPES_MAPPING.keys()}")
|
raise RuntimeError(f"Supported types: {CUPY_TO_CTYPES_MAPPING.keys()}")
|
||||||
addr = ctypes.cast(cptr, ctypes.c_void_p).value
|
addr = ctypes.cast(cptr, ctypes.c_void_p).value
|
||||||
# pylint: disable=c-extension-no-member,no-member
|
# pylint: disable=c-extension-no-member,no-member
|
||||||
@@ -386,7 +386,7 @@ class DataIter: # pylint: disable=too-many-instance-attributes
|
|||||||
raise exc # pylint: disable=raising-bad-type
|
raise exc # pylint: disable=raising-bad-type
|
||||||
|
|
||||||
def __del__(self) -> None:
|
def __del__(self) -> None:
|
||||||
assert self._temporary_data is None, self._temporary_data
|
assert self._temporary_data is None
|
||||||
assert self._exception is None
|
assert self._exception is None
|
||||||
|
|
||||||
def _reset_wrapper(self, this: None) -> None: # pylint: disable=unused-argument
|
def _reset_wrapper(self, this: None) -> None: # pylint: disable=unused-argument
|
||||||
@@ -410,19 +410,19 @@ class DataIter: # pylint: disable=too-many-instance-attributes
|
|||||||
feature_names: Optional[List[str]] = None,
|
feature_names: Optional[List[str]] = None,
|
||||||
feature_types: Optional[List[str]] = None,
|
feature_types: Optional[List[str]] = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
):
|
) -> None:
|
||||||
from .data import dispatch_proxy_set_data
|
from .data import dispatch_proxy_set_data
|
||||||
from .data import _proxy_transform
|
from .data import _proxy_transform
|
||||||
|
|
||||||
transformed, feature_names, feature_types = _proxy_transform(
|
new, cat_codes, feature_names, feature_types = _proxy_transform(
|
||||||
data,
|
data,
|
||||||
feature_names,
|
feature_names,
|
||||||
feature_types,
|
feature_types,
|
||||||
self._enable_categorical,
|
self._enable_categorical,
|
||||||
)
|
)
|
||||||
# Stage the data, meta info are copied inside C++ MetaInfo.
|
# Stage the data, meta info are copied inside C++ MetaInfo.
|
||||||
self._temporary_data = transformed
|
self._temporary_data = (new, cat_codes)
|
||||||
dispatch_proxy_set_data(self.proxy, transformed, self._allow_host)
|
dispatch_proxy_set_data(self.proxy, new, cat_codes, self._allow_host)
|
||||||
self.proxy.set_info(
|
self.proxy.set_info(
|
||||||
feature_names=feature_names,
|
feature_names=feature_names,
|
||||||
feature_types=feature_types,
|
feature_types=feature_types,
|
||||||
@@ -1103,7 +1103,7 @@ class _ProxyDMatrix(DMatrix):
|
|||||||
self.handle = ctypes.c_void_p()
|
self.handle = ctypes.c_void_p()
|
||||||
_check_call(_LIB.XGProxyDMatrixCreate(ctypes.byref(self.handle)))
|
_check_call(_LIB.XGProxyDMatrixCreate(ctypes.byref(self.handle)))
|
||||||
|
|
||||||
def _set_data_from_cuda_interface(self, data):
|
def _set_data_from_cuda_interface(self, data) -> None:
|
||||||
"""Set data from CUDA array interface."""
|
"""Set data from CUDA array interface."""
|
||||||
interface = data.__cuda_array_interface__
|
interface = data.__cuda_array_interface__
|
||||||
interface_str = bytes(json.dumps(interface, indent=2), "utf-8")
|
interface_str = bytes(json.dumps(interface, indent=2), "utf-8")
|
||||||
@@ -1111,11 +1111,11 @@ class _ProxyDMatrix(DMatrix):
|
|||||||
_LIB.XGProxyDMatrixSetDataCudaArrayInterface(self.handle, interface_str)
|
_LIB.XGProxyDMatrixSetDataCudaArrayInterface(self.handle, interface_str)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _set_data_from_cuda_columnar(self, data):
|
def _set_data_from_cuda_columnar(self, data, cat_codes: list) -> None:
|
||||||
"""Set data from CUDA columnar format."""
|
"""Set data from CUDA columnar format."""
|
||||||
from .data import _cudf_array_interfaces
|
from .data import _cudf_array_interfaces
|
||||||
|
|
||||||
_, interfaces_str = _cudf_array_interfaces(data)
|
interfaces_str = _cudf_array_interfaces(data, cat_codes)
|
||||||
_check_call(_LIB.XGProxyDMatrixSetDataCudaColumnar(self.handle, interfaces_str))
|
_check_call(_LIB.XGProxyDMatrixSetDataCudaColumnar(self.handle, interfaces_str))
|
||||||
|
|
||||||
def _set_data_from_array(self, data: np.ndarray):
|
def _set_data_from_array(self, data: np.ndarray):
|
||||||
@@ -1805,7 +1805,7 @@ class Booster(object):
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
See `Prediction
|
See `Prediction
|
||||||
<https://xgboost.readthedocs.io/en/latest/tutorials/prediction.html>`_
|
<https://xgboost.readthedocs.io/en/latest/prediction.html>`_
|
||||||
for issues like thread safety and a summary of outputs from this function.
|
for issues like thread safety and a summary of outputs from this function.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@@ -1986,13 +1986,6 @@ class Booster(object):
|
|||||||
preds = ctypes.POINTER(ctypes.c_float)()
|
preds = ctypes.POINTER(ctypes.c_float)()
|
||||||
|
|
||||||
# once caching is supported, we can pass id(data) as cache id.
|
# once caching is supported, we can pass id(data) as cache id.
|
||||||
try:
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
if isinstance(data, pd.DataFrame):
|
|
||||||
data = data.values
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
args = {
|
args = {
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"training": False,
|
"training": False,
|
||||||
@@ -2027,7 +2020,20 @@ class Booster(object):
|
|||||||
f"got {data.shape[1]}"
|
f"got {data.shape[1]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .data import _is_pandas_df, _transform_pandas_df
|
||||||
from .data import _array_interface
|
from .data import _array_interface
|
||||||
|
if (
|
||||||
|
_is_pandas_df(data)
|
||||||
|
or lazy_isinstance(data, "cudf.core.dataframe", "DataFrame")
|
||||||
|
):
|
||||||
|
ft = self.feature_types
|
||||||
|
if ft is None:
|
||||||
|
enable_categorical = False
|
||||||
|
else:
|
||||||
|
enable_categorical = any(f == "c" for f in ft)
|
||||||
|
if _is_pandas_df(data):
|
||||||
|
data, _, _ = _transform_pandas_df(data, enable_categorical)
|
||||||
|
|
||||||
if isinstance(data, np.ndarray):
|
if isinstance(data, np.ndarray):
|
||||||
from .data import _ensure_np_dtype
|
from .data import _ensure_np_dtype
|
||||||
data, _ = _ensure_np_dtype(data, data.dtype)
|
data, _ = _ensure_np_dtype(data, data.dtype)
|
||||||
@@ -2080,9 +2086,11 @@ class Booster(object):
|
|||||||
)
|
)
|
||||||
return _prediction_output(shape, dims, preds, True)
|
return _prediction_output(shape, dims, preds, True)
|
||||||
if lazy_isinstance(data, "cudf.core.dataframe", "DataFrame"):
|
if lazy_isinstance(data, "cudf.core.dataframe", "DataFrame"):
|
||||||
from .data import _cudf_array_interfaces
|
from .data import _cudf_array_interfaces, _transform_cudf_df
|
||||||
|
data, cat_codes, _, _ = _transform_cudf_df(
|
||||||
_, interfaces_str = _cudf_array_interfaces(data)
|
data, None, None, enable_categorical
|
||||||
|
)
|
||||||
|
interfaces_str = _cudf_array_interfaces(data, cat_codes)
|
||||||
_check_call(
|
_check_call(
|
||||||
_LIB.XGBoosterPredictFromCudaColumnar(
|
_LIB.XGBoosterPredictFromCudaColumnar(
|
||||||
self.handle,
|
self.handle,
|
||||||
|
|||||||
@@ -1606,8 +1606,9 @@ class DaskScikitLearnBase(XGBModel):
|
|||||||
should use `worker_client' instead of default client.
|
should use `worker_client' instead of default client.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
asynchronous = getattr(self, "_asynchronous", False)
|
|
||||||
if self._client is None:
|
if self._client is None:
|
||||||
|
asynchronous = getattr(self, "_asynchronous", False)
|
||||||
try:
|
try:
|
||||||
distributed.get_worker()
|
distributed.get_worker()
|
||||||
in_worker = True
|
in_worker = True
|
||||||
@@ -1620,7 +1621,7 @@ class DaskScikitLearnBase(XGBModel):
|
|||||||
return ret
|
return ret
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
return self.client.sync(func, **kwargs, asynchronous=asynchronous)
|
return self.client.sync(func, **kwargs, asynchronous=self.client.asynchronous)
|
||||||
|
|
||||||
|
|
||||||
@xgboost_model_doc(
|
@xgboost_model_doc(
|
||||||
@@ -1833,7 +1834,7 @@ class DaskXGBClassifier(DaskScikitLearnBase, XGBClassifierBase):
|
|||||||
vstack = update_wrapper(
|
vstack = update_wrapper(
|
||||||
partial(da.vstack, allow_unknown_chunksizes=True), da.vstack
|
partial(da.vstack, allow_unknown_chunksizes=True), da.vstack
|
||||||
)
|
)
|
||||||
return _cls_predict_proba(getattr(self, "n_classes_", None), predts, vstack)
|
return _cls_predict_proba(getattr(self, "n_classes_", 0), predts, vstack)
|
||||||
|
|
||||||
# pylint: disable=missing-function-docstring
|
# pylint: disable=missing-function-docstring
|
||||||
def predict_proba(
|
def predict_proba(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# pylint: disable=too-many-arguments, too-many-branches
|
# pylint: disable=too-many-arguments, too-many-branches, too-many-lines
|
||||||
# pylint: disable=too-many-return-statements, import-error
|
# pylint: disable=too-many-return-statements, import-error
|
||||||
'''Data dispatching for DMatrix.'''
|
'''Data dispatching for DMatrix.'''
|
||||||
import ctypes
|
import ctypes
|
||||||
@@ -12,7 +12,7 @@ import numpy as np
|
|||||||
from .core import c_array, _LIB, _check_call, c_str
|
from .core import c_array, _LIB, _check_call, c_str
|
||||||
from .core import _cuda_array_interface
|
from .core import _cuda_array_interface
|
||||||
from .core import DataIter, _ProxyDMatrix, DMatrix
|
from .core import DataIter, _ProxyDMatrix, DMatrix
|
||||||
from .compat import lazy_isinstance
|
from .compat import lazy_isinstance, DataFrame
|
||||||
|
|
||||||
c_bst_ulong = ctypes.c_uint64 # pylint: disable=invalid-name
|
c_bst_ulong = ctypes.c_uint64 # pylint: disable=invalid-name
|
||||||
|
|
||||||
@@ -217,36 +217,48 @@ _pandas_dtype_mapper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _invalid_dataframe_dtype(data) -> None:
|
||||||
|
# pandas series has `dtypes` but it's just a single object
|
||||||
|
# cudf series doesn't have `dtypes`.
|
||||||
|
if hasattr(data, "dtypes") and hasattr(data.dtypes, "__iter__"):
|
||||||
|
bad_fields = [
|
||||||
|
str(data.columns[i])
|
||||||
|
for i, dtype in enumerate(data.dtypes)
|
||||||
|
if dtype.name not in _pandas_dtype_mapper
|
||||||
|
]
|
||||||
|
err = " Invalid columns:" + ", ".join(bad_fields)
|
||||||
|
else:
|
||||||
|
err = ""
|
||||||
|
|
||||||
|
msg = """DataFrame.dtypes for data must be int, float, bool or category. When
|
||||||
|
categorical type is supplied, DMatrix parameter `enable_categorical` must
|
||||||
|
be set to `True`.""" + err
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
def _transform_pandas_df(
|
def _transform_pandas_df(
|
||||||
data,
|
data: DataFrame,
|
||||||
enable_categorical: bool,
|
enable_categorical: bool,
|
||||||
feature_names: Optional[List[str]] = None,
|
feature_names: Optional[List[str]] = None,
|
||||||
feature_types: Optional[List[str]] = None,
|
feature_types: Optional[List[str]] = None,
|
||||||
meta=None,
|
meta: Optional[str] = None,
|
||||||
meta_type=None,
|
meta_type: Optional[str] = None,
|
||||||
):
|
) -> Tuple[np.ndarray, Optional[List[str]], Optional[List[str]]]:
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from pandas.api.types import is_sparse, is_categorical_dtype
|
from pandas.api.types import is_sparse, is_categorical_dtype
|
||||||
|
|
||||||
if not all(dtype.name in _pandas_dtype_mapper or is_sparse(dtype) or
|
if not all(
|
||||||
(is_categorical_dtype(dtype) and enable_categorical)
|
dtype.name in _pandas_dtype_mapper
|
||||||
for dtype in data.dtypes):
|
or is_sparse(dtype)
|
||||||
bad_fields = [
|
or (is_categorical_dtype(dtype) and enable_categorical)
|
||||||
str(data.columns[i]) for i, dtype in enumerate(data.dtypes)
|
for dtype in data.dtypes
|
||||||
if dtype.name not in _pandas_dtype_mapper
|
):
|
||||||
]
|
_invalid_dataframe_dtype(data)
|
||||||
|
|
||||||
msg = """DataFrame.dtypes for data must be int, float, bool or category. When
|
|
||||||
categorical type is supplied, DMatrix parameter `enable_categorical` must
|
|
||||||
be set to `True`."""
|
|
||||||
raise ValueError(msg + ', '.join(bad_fields))
|
|
||||||
|
|
||||||
# handle feature names
|
# handle feature names
|
||||||
if feature_names is None and meta is None:
|
if feature_names is None and meta is None:
|
||||||
if isinstance(data.columns, pd.MultiIndex):
|
if isinstance(data.columns, pd.MultiIndex):
|
||||||
feature_names = [
|
feature_names = [" ".join([str(x) for x in i]) for i in data.columns]
|
||||||
' '.join([str(x) for x in i]) for i in data.columns
|
|
||||||
]
|
|
||||||
elif isinstance(data.columns, (pd.Int64Index, pd.RangeIndex)):
|
elif isinstance(data.columns, (pd.Int64Index, pd.RangeIndex)):
|
||||||
feature_names = list(map(str, data.columns))
|
feature_names = list(map(str, data.columns))
|
||||||
else:
|
else:
|
||||||
@@ -263,21 +275,24 @@ def _transform_pandas_df(
|
|||||||
else:
|
else:
|
||||||
feature_types.append(_pandas_dtype_mapper[dtype.name])
|
feature_types.append(_pandas_dtype_mapper[dtype.name])
|
||||||
|
|
||||||
# handle categorical codes.
|
# handle category codes.
|
||||||
transformed = pd.DataFrame()
|
transformed = pd.DataFrame()
|
||||||
if enable_categorical:
|
if enable_categorical:
|
||||||
for i, dtype in enumerate(data.dtypes):
|
for i, dtype in enumerate(data.dtypes):
|
||||||
if is_categorical_dtype(dtype):
|
if is_categorical_dtype(dtype):
|
||||||
transformed[data.columns[i]] = data[data.columns[i]].cat.codes
|
# pandas uses -1 as default missing value for categorical data
|
||||||
|
transformed[data.columns[i]] = (
|
||||||
|
data[data.columns[i]]
|
||||||
|
.cat.codes.astype(np.float32)
|
||||||
|
.replace(-1.0, np.NaN)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
transformed[data.columns[i]] = data[data.columns[i]]
|
transformed[data.columns[i]] = data[data.columns[i]]
|
||||||
else:
|
else:
|
||||||
transformed = data
|
transformed = data
|
||||||
|
|
||||||
if meta and len(data.columns) > 1:
|
if meta and len(data.columns) > 1:
|
||||||
raise ValueError(
|
raise ValueError(f"DataFrame for {meta} cannot have multiple columns")
|
||||||
f"DataFrame for {meta} cannot have multiple columns"
|
|
||||||
)
|
|
||||||
|
|
||||||
dtype = meta_type if meta_type else np.float32
|
dtype = meta_type if meta_type else np.float32
|
||||||
arr = transformed.values
|
arr = transformed.values
|
||||||
@@ -287,7 +302,7 @@ def _transform_pandas_df(
|
|||||||
|
|
||||||
|
|
||||||
def _from_pandas_df(
|
def _from_pandas_df(
|
||||||
data,
|
data: DataFrame,
|
||||||
enable_categorical: bool,
|
enable_categorical: bool,
|
||||||
missing,
|
missing,
|
||||||
nthread,
|
nthread,
|
||||||
@@ -300,6 +315,7 @@ def _from_pandas_df(
|
|||||||
feature_types)
|
feature_types)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _is_pandas_series(data):
|
def _is_pandas_series(data):
|
||||||
try:
|
try:
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -318,13 +334,26 @@ def _is_modin_series(data):
|
|||||||
|
|
||||||
def _from_pandas_series(
|
def _from_pandas_series(
|
||||||
data,
|
data,
|
||||||
missing,
|
missing: float,
|
||||||
nthread,
|
nthread: int,
|
||||||
|
enable_categorical: bool,
|
||||||
feature_names: Optional[List[str]],
|
feature_names: Optional[List[str]],
|
||||||
feature_types: Optional[List[str]],
|
feature_types: Optional[List[str]],
|
||||||
):
|
):
|
||||||
|
from pandas.api.types import is_categorical_dtype
|
||||||
|
|
||||||
|
if (data.dtype.name not in _pandas_dtype_mapper) and not (
|
||||||
|
is_categorical_dtype(data.dtype) and enable_categorical
|
||||||
|
):
|
||||||
|
_invalid_dataframe_dtype(data)
|
||||||
|
if enable_categorical and is_categorical_dtype(data.dtype):
|
||||||
|
data = data.cat.codes
|
||||||
return _from_numpy_array(
|
return _from_numpy_array(
|
||||||
data.values.astype("float"), missing, nthread, feature_names, feature_types
|
data.values.reshape(data.shape[0], 1).astype("float"),
|
||||||
|
missing,
|
||||||
|
nthread,
|
||||||
|
feature_names,
|
||||||
|
feature_types,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -428,7 +457,7 @@ def _is_cudf_df(data):
|
|||||||
return hasattr(cudf, 'DataFrame') and isinstance(data, cudf.DataFrame)
|
return hasattr(cudf, 'DataFrame') and isinstance(data, cudf.DataFrame)
|
||||||
|
|
||||||
|
|
||||||
def _cudf_array_interfaces(data) -> Tuple[list, bytes]:
|
def _cudf_array_interfaces(data, cat_codes: list) -> bytes:
|
||||||
"""Extract CuDF __cuda_array_interface__. This is special as it returns a new list of
|
"""Extract CuDF __cuda_array_interface__. This is special as it returns a new list of
|
||||||
data and a list of array interfaces. The data is list of categorical codes that
|
data and a list of array interfaces. The data is list of categorical codes that
|
||||||
caller can safely ignore, but have to keep their reference alive until usage of array
|
caller can safely ignore, but have to keep their reference alive until usage of array
|
||||||
@@ -440,23 +469,27 @@ def _cudf_array_interfaces(data) -> Tuple[list, bytes]:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from cudf.utils.dtypes import is_categorical_dtype
|
from cudf.utils.dtypes import is_categorical_dtype
|
||||||
|
|
||||||
cat_codes = []
|
|
||||||
interfaces = []
|
interfaces = []
|
||||||
if _is_cudf_ser(data):
|
if _is_cudf_ser(data):
|
||||||
interfaces.append(data.__cuda_array_interface__)
|
if is_categorical_dtype(data.dtype):
|
||||||
|
interface = cat_codes[0].__cuda_array_interface__
|
||||||
|
else:
|
||||||
|
interface = data.__cuda_array_interface__
|
||||||
|
if "mask" in interface:
|
||||||
|
interface["mask"] = interface["mask"].__cuda_array_interface__
|
||||||
|
interfaces.append(interface)
|
||||||
else:
|
else:
|
||||||
for col in data:
|
for i, col in enumerate(data):
|
||||||
if is_categorical_dtype(data[col].dtype):
|
if is_categorical_dtype(data[col].dtype):
|
||||||
codes = data[col].cat.codes
|
codes = cat_codes[i]
|
||||||
interface = codes.__cuda_array_interface__
|
interface = codes.__cuda_array_interface__
|
||||||
cat_codes.append(codes)
|
|
||||||
else:
|
else:
|
||||||
interface = data[col].__cuda_array_interface__
|
interface = data[col].__cuda_array_interface__
|
||||||
if "mask" in interface:
|
if "mask" in interface:
|
||||||
interface["mask"] = interface["mask"].__cuda_array_interface__
|
interface["mask"] = interface["mask"].__cuda_array_interface__
|
||||||
interfaces.append(interface)
|
interfaces.append(interface)
|
||||||
interfaces_str = bytes(json.dumps(interfaces, indent=2), "utf-8")
|
interfaces_str = bytes(json.dumps(interfaces, indent=2), "utf-8")
|
||||||
return cat_codes, interfaces_str
|
return interfaces_str
|
||||||
|
|
||||||
|
|
||||||
def _transform_cudf_df(
|
def _transform_cudf_df(
|
||||||
@@ -470,25 +503,57 @@ def _transform_cudf_df(
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from cudf.utils.dtypes import is_categorical_dtype
|
from cudf.utils.dtypes import is_categorical_dtype
|
||||||
|
|
||||||
|
if _is_cudf_ser(data):
|
||||||
|
dtypes = [data.dtype]
|
||||||
|
else:
|
||||||
|
dtypes = data.dtypes
|
||||||
|
|
||||||
|
if not all(
|
||||||
|
dtype.name in _pandas_dtype_mapper
|
||||||
|
or (is_categorical_dtype(dtype) and enable_categorical)
|
||||||
|
for dtype in dtypes
|
||||||
|
):
|
||||||
|
_invalid_dataframe_dtype(data)
|
||||||
|
|
||||||
|
# handle feature names
|
||||||
if feature_names is None:
|
if feature_names is None:
|
||||||
if _is_cudf_ser(data):
|
if _is_cudf_ser(data):
|
||||||
feature_names = [data.name]
|
feature_names = [data.name]
|
||||||
elif lazy_isinstance(data.columns, "cudf.core.multiindex", "MultiIndex"):
|
elif lazy_isinstance(data.columns, "cudf.core.multiindex", "MultiIndex"):
|
||||||
feature_names = [" ".join([str(x) for x in i]) for i in data.columns]
|
feature_names = [" ".join([str(x) for x in i]) for i in data.columns]
|
||||||
|
elif (
|
||||||
|
lazy_isinstance(data.columns, "cudf.core.index", "RangeIndex")
|
||||||
|
or lazy_isinstance(data.columns, "cudf.core.index", "Int64Index")
|
||||||
|
# Unique to cuDF, no equivalence in pandas 1.3.3
|
||||||
|
or lazy_isinstance(data.columns, "cudf.core.index", "Int32Index")
|
||||||
|
):
|
||||||
|
feature_names = list(map(str, data.columns))
|
||||||
else:
|
else:
|
||||||
feature_names = data.columns.format()
|
feature_names = data.columns.format()
|
||||||
|
|
||||||
|
# handle feature types
|
||||||
if feature_types is None:
|
if feature_types is None:
|
||||||
feature_types = []
|
feature_types = []
|
||||||
if _is_cudf_ser(data):
|
|
||||||
dtypes = [data.dtype]
|
|
||||||
else:
|
|
||||||
dtypes = data.dtypes
|
|
||||||
for dtype in dtypes:
|
for dtype in dtypes:
|
||||||
if is_categorical_dtype(dtype) and enable_categorical:
|
if is_categorical_dtype(dtype) and enable_categorical:
|
||||||
feature_types.append(CAT_T)
|
feature_types.append(CAT_T)
|
||||||
else:
|
else:
|
||||||
feature_types.append(_pandas_dtype_mapper[dtype.name])
|
feature_types.append(_pandas_dtype_mapper[dtype.name])
|
||||||
return data, feature_names, feature_types
|
|
||||||
|
# handle categorical data
|
||||||
|
cat_codes = []
|
||||||
|
if _is_cudf_ser(data):
|
||||||
|
# unlike pandas, cuDF uses NA for missing data.
|
||||||
|
if is_categorical_dtype(data.dtype) and enable_categorical:
|
||||||
|
codes = data.cat.codes
|
||||||
|
cat_codes.append(codes)
|
||||||
|
else:
|
||||||
|
for col in data:
|
||||||
|
if is_categorical_dtype(data[col].dtype) and enable_categorical:
|
||||||
|
codes = data[col].cat.codes
|
||||||
|
cat_codes.append(codes)
|
||||||
|
|
||||||
|
return data, cat_codes, feature_names, feature_types
|
||||||
|
|
||||||
|
|
||||||
def _from_cudf_df(
|
def _from_cudf_df(
|
||||||
@@ -499,10 +564,10 @@ def _from_cudf_df(
|
|||||||
feature_types: Optional[List[str]],
|
feature_types: Optional[List[str]],
|
||||||
enable_categorical: bool,
|
enable_categorical: bool,
|
||||||
) -> Tuple[ctypes.c_void_p, Any, Any]:
|
) -> Tuple[ctypes.c_void_p, Any, Any]:
|
||||||
data, feature_names, feature_types = _transform_cudf_df(
|
data, cat_codes, feature_names, feature_types = _transform_cudf_df(
|
||||||
data, feature_names, feature_types, enable_categorical
|
data, feature_names, feature_types, enable_categorical
|
||||||
)
|
)
|
||||||
_, interfaces_str = _cudf_array_interfaces(data)
|
interfaces_str = _cudf_array_interfaces(data, cat_codes)
|
||||||
handle = ctypes.c_void_p()
|
handle = ctypes.c_void_p()
|
||||||
config = bytes(json.dumps({"missing": missing, "nthread": nthread}), "utf-8")
|
config = bytes(json.dumps({"missing": missing, "nthread": nthread}), "utf-8")
|
||||||
_check_call(
|
_check_call(
|
||||||
@@ -707,8 +772,9 @@ def dispatch_data_backend(
|
|||||||
return _from_pandas_df(data, enable_categorical, missing, threads,
|
return _from_pandas_df(data, enable_categorical, missing, threads,
|
||||||
feature_names, feature_types)
|
feature_names, feature_types)
|
||||||
if _is_pandas_series(data):
|
if _is_pandas_series(data):
|
||||||
return _from_pandas_series(data, missing, threads, feature_names,
|
return _from_pandas_series(
|
||||||
feature_types)
|
data, missing, threads, enable_categorical, feature_names, feature_types
|
||||||
|
)
|
||||||
if _is_cudf_df(data) or _is_cudf_ser(data):
|
if _is_cudf_df(data) or _is_cudf_ser(data):
|
||||||
return _from_cudf_df(
|
return _from_cudf_df(
|
||||||
data, missing, threads, feature_names, feature_types, enable_categorical
|
data, missing, threads, feature_names, feature_types, enable_categorical
|
||||||
@@ -732,8 +798,9 @@ def dispatch_data_backend(
|
|||||||
return _from_pandas_df(data, enable_categorical, missing, threads,
|
return _from_pandas_df(data, enable_categorical, missing, threads,
|
||||||
feature_names, feature_types)
|
feature_names, feature_types)
|
||||||
if _is_modin_series(data):
|
if _is_modin_series(data):
|
||||||
return _from_pandas_series(data, missing, threads, feature_names,
|
return _from_pandas_series(
|
||||||
feature_types)
|
data, missing, threads, enable_categorical, feature_names, feature_types
|
||||||
|
)
|
||||||
if _has_array_protocol(data):
|
if _has_array_protocol(data):
|
||||||
array = np.asarray(data)
|
array = np.asarray(data)
|
||||||
return _from_numpy_array(array, missing, threads, feature_names, feature_types)
|
return _from_numpy_array(array, missing, threads, feature_names, feature_types)
|
||||||
@@ -747,7 +814,7 @@ def dispatch_data_backend(
|
|||||||
|
|
||||||
def _to_data_type(dtype: str, name: str):
|
def _to_data_type(dtype: str, name: str):
|
||||||
dtype_map = {'float32': 1, 'float64': 2, 'uint32': 3, 'uint64': 4}
|
dtype_map = {'float32': 1, 'float64': 2, 'uint32': 3, 'uint64': 4}
|
||||||
if dtype not in dtype_map.keys():
|
if dtype not in dtype_map:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
f'Expecting float32, float64, uint32, uint64, got {dtype} ' +
|
f'Expecting float32, float64, uint32, uint64, got {dtype} ' +
|
||||||
f'for {name}.')
|
f'for {name}.')
|
||||||
@@ -866,8 +933,7 @@ def dispatch_meta_backend(matrix: DMatrix, data, name: str, dtype: str = None):
|
|||||||
_meta_from_dt(data, name, dtype, handle)
|
_meta_from_dt(data, name, dtype, handle)
|
||||||
return
|
return
|
||||||
if _is_modin_df(data):
|
if _is_modin_df(data):
|
||||||
data, _, _ = _transform_pandas_df(
|
data, _, _ = _transform_pandas_df(data, False, meta=name, meta_type=dtype)
|
||||||
data, False, meta=name, meta_type=dtype)
|
|
||||||
_meta_from_numpy(data, name, dtype, handle)
|
_meta_from_numpy(data, name, dtype, handle)
|
||||||
return
|
return
|
||||||
if _is_modin_series(data):
|
if _is_modin_series(data):
|
||||||
@@ -917,30 +983,38 @@ def _proxy_transform(
|
|||||||
)
|
)
|
||||||
if _is_cupy_array(data):
|
if _is_cupy_array(data):
|
||||||
data = _transform_cupy_array(data)
|
data = _transform_cupy_array(data)
|
||||||
return data, feature_names, feature_types
|
return data, None, feature_names, feature_types
|
||||||
if _is_dlpack(data):
|
if _is_dlpack(data):
|
||||||
return _transform_dlpack(data), feature_names, feature_types
|
return _transform_dlpack(data), None, feature_names, feature_types
|
||||||
if _is_numpy_array(data):
|
if _is_numpy_array(data):
|
||||||
return data, feature_names, feature_types
|
return data, None, feature_names, feature_types
|
||||||
if _is_scipy_csr(data):
|
if _is_scipy_csr(data):
|
||||||
return data, feature_names, feature_types
|
return data, None, feature_names, feature_types
|
||||||
if _is_pandas_df(data):
|
if _is_pandas_df(data):
|
||||||
arr, feature_names, feature_types = _transform_pandas_df(
|
arr, feature_names, feature_types = _transform_pandas_df(
|
||||||
data, enable_categorical, feature_names, feature_types
|
data, enable_categorical, feature_names, feature_types
|
||||||
)
|
)
|
||||||
return arr, feature_names, feature_types
|
return arr, None, feature_names, feature_types
|
||||||
raise TypeError("Value type is not supported for data iterator:" + str(type(data)))
|
raise TypeError("Value type is not supported for data iterator:" + str(type(data)))
|
||||||
|
|
||||||
|
|
||||||
def dispatch_proxy_set_data(proxy: _ProxyDMatrix, data: Any, allow_host: bool) -> None:
|
def dispatch_proxy_set_data(
|
||||||
|
proxy: _ProxyDMatrix,
|
||||||
|
data: Any,
|
||||||
|
cat_codes: Optional[list],
|
||||||
|
allow_host: bool,
|
||||||
|
) -> None:
|
||||||
"""Dispatch for DeviceQuantileDMatrix."""
|
"""Dispatch for DeviceQuantileDMatrix."""
|
||||||
if not _is_cudf_ser(data) and not _is_pandas_series(data):
|
if not _is_cudf_ser(data) and not _is_pandas_series(data):
|
||||||
_check_data_shape(data)
|
_check_data_shape(data)
|
||||||
|
|
||||||
if _is_cudf_df(data):
|
if _is_cudf_df(data):
|
||||||
proxy._set_data_from_cuda_columnar(data) # pylint: disable=W0212
|
# pylint: disable=W0212
|
||||||
|
proxy._set_data_from_cuda_columnar(data, cat_codes)
|
||||||
return
|
return
|
||||||
if _is_cudf_ser(data):
|
if _is_cudf_ser(data):
|
||||||
proxy._set_data_from_cuda_columnar(data) # pylint: disable=W0212
|
# pylint: disable=W0212
|
||||||
|
proxy._set_data_from_cuda_columnar(data, cat_codes)
|
||||||
return
|
return
|
||||||
if _is_cupy_array(data):
|
if _is_cupy_array(data):
|
||||||
proxy._set_data_from_cuda_interface(data) # pylint: disable=W0212
|
proxy._set_data_from_cuda_interface(data) # pylint: disable=W0212
|
||||||
|
|||||||
@@ -1354,9 +1354,7 @@ class XGBClassifier(XGBModel, XGBClassifierBase):
|
|||||||
iteration_range=iteration_range
|
iteration_range=iteration_range
|
||||||
)
|
)
|
||||||
# If model is loaded from a raw booster there's no `n_classes_`
|
# If model is loaded from a raw booster there's no `n_classes_`
|
||||||
return _cls_predict_proba(
|
return _cls_predict_proba(getattr(self, "n_classes_", 0), class_probs, np.vstack)
|
||||||
getattr(self, "n_classes_", None), class_probs, np.vstack
|
|
||||||
)
|
|
||||||
|
|
||||||
def evals_result(self) -> TrainingCallback.EvalsLog:
|
def evals_result(self) -> TrainingCallback.EvalsLog:
|
||||||
"""Return the evaluation results.
|
"""Return the evaluation results.
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class RabitTracker(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, hostIP, nslave, port=9091, port_end=9999, use_logger: bool = True
|
self, hostIP, nslave, port=9091, port_end=9999, use_logger: bool = False
|
||||||
) -> None:
|
) -> None:
|
||||||
"""A Python implementation of RABIT tracker.
|
"""A Python implementation of RABIT tracker.
|
||||||
|
|
||||||
@@ -384,16 +384,17 @@ def start_rabit_tracker(args):
|
|||||||
----------
|
----------
|
||||||
args: arguments to start the rabit tracker.
|
args: arguments to start the rabit tracker.
|
||||||
"""
|
"""
|
||||||
envs = {'DMLC_NUM_WORKER': args.num_workers,
|
envs = {"DMLC_NUM_WORKER": args.num_workers, "DMLC_NUM_SERVER": args.num_servers}
|
||||||
'DMLC_NUM_SERVER': args.num_servers}
|
rabit = RabitTracker(
|
||||||
rabit = RabitTracker(hostIP=get_host_ip(args.host_ip), nslave=args.num_workers)
|
hostIP=get_host_ip(args.host_ip), nslave=args.num_workers, use_logger=True
|
||||||
|
)
|
||||||
envs.update(rabit.slave_envs())
|
envs.update(rabit.slave_envs())
|
||||||
rabit.start(args.num_workers)
|
rabit.start(args.num_workers)
|
||||||
sys.stdout.write('DMLC_TRACKER_ENV_START\n')
|
sys.stdout.write("DMLC_TRACKER_ENV_START\n")
|
||||||
# simply write configuration to stdout
|
# simply write configuration to stdout
|
||||||
for k, v in envs.items():
|
for k, v in envs.items():
|
||||||
sys.stdout.write(f"{k}={v}\n")
|
sys.stdout.write(f"{k}={v}\n")
|
||||||
sys.stdout.write('DMLC_TRACKER_ENV_END\n')
|
sys.stdout.write("DMLC_TRACKER_ENV_END\n")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
rabit.join()
|
rabit.join()
|
||||||
|
|
||||||
|
|||||||
@@ -58,14 +58,15 @@ __forceinline__ __device__ BitFieldAtomicType AtomicAnd(BitFieldAtomicType* addr
|
|||||||
template <typename VT, typename Direction, bool IsConst = false>
|
template <typename VT, typename Direction, bool IsConst = false>
|
||||||
struct BitFieldContainer {
|
struct BitFieldContainer {
|
||||||
using value_type = std::conditional_t<IsConst, VT const, VT>; // NOLINT
|
using value_type = std::conditional_t<IsConst, VT const, VT>; // NOLINT
|
||||||
using pointer = value_type*; // NOLINT
|
using index_type = size_t; // NOLINT
|
||||||
|
using pointer = value_type*; // NOLINT
|
||||||
|
|
||||||
static value_type constexpr kValueSize = sizeof(value_type) * 8;
|
static index_type constexpr kValueSize = sizeof(value_type) * 8;
|
||||||
static value_type constexpr kOne = 1; // force correct type.
|
static index_type constexpr kOne = 1; // force correct type.
|
||||||
|
|
||||||
struct Pos {
|
struct Pos {
|
||||||
std::remove_const_t<value_type> int_pos {0};
|
index_type int_pos{0};
|
||||||
std::remove_const_t<value_type> bit_pos {0};
|
index_type bit_pos{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -73,13 +74,13 @@ struct BitFieldContainer {
|
|||||||
static_assert(!std::is_signed<VT>::value, "Must use unsiged type as underlying storage.");
|
static_assert(!std::is_signed<VT>::value, "Must use unsiged type as underlying storage.");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
XGBOOST_DEVICE static Pos ToBitPos(value_type pos) {
|
XGBOOST_DEVICE static Pos ToBitPos(index_type pos) {
|
||||||
Pos pos_v;
|
Pos pos_v;
|
||||||
if (pos == 0) {
|
if (pos == 0) {
|
||||||
return pos_v;
|
return pos_v;
|
||||||
}
|
}
|
||||||
pos_v.int_pos = pos / kValueSize;
|
pos_v.int_pos = pos / kValueSize;
|
||||||
pos_v.bit_pos = pos % kValueSize;
|
pos_v.bit_pos = pos % kValueSize;
|
||||||
return pos_v;
|
return pos_v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ struct BitFieldContainer {
|
|||||||
/*\brief Compute the size of needed memory allocation. The returned value is in terms
|
/*\brief Compute the size of needed memory allocation. The returned value is in terms
|
||||||
* of number of elements with `BitFieldContainer::value_type'.
|
* of number of elements with `BitFieldContainer::value_type'.
|
||||||
*/
|
*/
|
||||||
XGBOOST_DEVICE static size_t ComputeStorageSize(size_t size) {
|
XGBOOST_DEVICE static size_t ComputeStorageSize(index_type size) {
|
||||||
return common::DivRoundUp(size, kValueSize);
|
return common::DivRoundUp(size, kValueSize);
|
||||||
}
|
}
|
||||||
#if defined(__CUDA_ARCH__)
|
#if defined(__CUDA_ARCH__)
|
||||||
@@ -138,14 +139,14 @@ struct BitFieldContainer {
|
|||||||
#endif // defined(__CUDA_ARCH__)
|
#endif // defined(__CUDA_ARCH__)
|
||||||
|
|
||||||
#if defined(__CUDA_ARCH__)
|
#if defined(__CUDA_ARCH__)
|
||||||
__device__ auto Set(value_type pos) {
|
__device__ auto Set(index_type pos) {
|
||||||
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
||||||
value_type& value = bits_[pos_v.int_pos];
|
value_type& value = bits_[pos_v.int_pos];
|
||||||
value_type set_bit = kOne << pos_v.bit_pos;
|
value_type set_bit = kOne << pos_v.bit_pos;
|
||||||
using Type = typename dh::detail::AtomicDispatcher<sizeof(value_type)>::Type;
|
using Type = typename dh::detail::AtomicDispatcher<sizeof(value_type)>::Type;
|
||||||
atomicOr(reinterpret_cast<Type *>(&value), set_bit);
|
atomicOr(reinterpret_cast<Type *>(&value), set_bit);
|
||||||
}
|
}
|
||||||
__device__ void Clear(value_type pos) {
|
__device__ void Clear(index_type pos) {
|
||||||
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
||||||
value_type& value = bits_[pos_v.int_pos];
|
value_type& value = bits_[pos_v.int_pos];
|
||||||
value_type clear_bit = ~(kOne << pos_v.bit_pos);
|
value_type clear_bit = ~(kOne << pos_v.bit_pos);
|
||||||
@@ -153,13 +154,13 @@ struct BitFieldContainer {
|
|||||||
atomicAnd(reinterpret_cast<Type *>(&value), clear_bit);
|
atomicAnd(reinterpret_cast<Type *>(&value), clear_bit);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void Set(value_type pos) {
|
void Set(index_type pos) {
|
||||||
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
||||||
value_type& value = bits_[pos_v.int_pos];
|
value_type& value = bits_[pos_v.int_pos];
|
||||||
value_type set_bit = kOne << pos_v.bit_pos;
|
value_type set_bit = kOne << pos_v.bit_pos;
|
||||||
value |= set_bit;
|
value |= set_bit;
|
||||||
}
|
}
|
||||||
void Clear(value_type pos) {
|
void Clear(index_type pos) {
|
||||||
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
Pos pos_v = Direction::Shift(ToBitPos(pos));
|
||||||
value_type& value = bits_[pos_v.int_pos];
|
value_type& value = bits_[pos_v.int_pos];
|
||||||
value_type clear_bit = ~(kOne << pos_v.bit_pos);
|
value_type clear_bit = ~(kOne << pos_v.bit_pos);
|
||||||
@@ -175,7 +176,7 @@ struct BitFieldContainer {
|
|||||||
value_type result = test_bit & value;
|
value_type result = test_bit & value;
|
||||||
return static_cast<bool>(result);
|
return static_cast<bool>(result);
|
||||||
}
|
}
|
||||||
XGBOOST_DEVICE bool Check(value_type pos) const {
|
XGBOOST_DEVICE bool Check(index_type pos) const {
|
||||||
Pos pos_v = ToBitPos(pos);
|
Pos pos_v = ToBitPos(pos);
|
||||||
return Check(pos_v);
|
return Check(pos_v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
* Copyright 2020 by XGBoost Contributors
|
* Copyright 2020-2021 by XGBoost Contributors
|
||||||
* \file categorical.h
|
* \file categorical.h
|
||||||
*/
|
*/
|
||||||
#ifndef XGBOOST_COMMON_CATEGORICAL_H_
|
#ifndef XGBOOST_COMMON_CATEGORICAL_H_
|
||||||
@@ -42,6 +42,11 @@ inline XGBOOST_DEVICE bool Decision(common::Span<uint32_t const> cats, bst_cat_t
|
|||||||
return !s_cats.Check(cat);
|
return !s_cats.Check(cat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void CheckCat(bst_cat_t cat) {
|
||||||
|
CHECK_GE(cat, 0) << "Invalid categorical value detected. Categorical value "
|
||||||
|
"should be non-negative.";
|
||||||
|
}
|
||||||
|
|
||||||
struct IsCatOp {
|
struct IsCatOp {
|
||||||
XGBOOST_DEVICE bool operator()(FeatureType ft) {
|
XGBOOST_DEVICE bool operator()(FeatureType ft) {
|
||||||
return ft == FeatureType::kCategorical;
|
return ft == FeatureType::kCategorical;
|
||||||
|
|||||||
@@ -711,6 +711,12 @@ constexpr std::pair<int, int> CUDAVersion() {
|
|||||||
constexpr std::pair<int32_t, int32_t> ThrustVersion() {
|
constexpr std::pair<int32_t, int32_t> ThrustVersion() {
|
||||||
return std::make_pair(THRUST_MAJOR_VERSION, THRUST_MINOR_VERSION);
|
return std::make_pair(THRUST_MAJOR_VERSION, THRUST_MINOR_VERSION);
|
||||||
}
|
}
|
||||||
|
// Whether do we have thrust 1.x with x >= minor
|
||||||
|
template <int32_t minor>
|
||||||
|
constexpr bool HasThrustMinorVer() {
|
||||||
|
return (ThrustVersion().first == 1 && ThrustVersion().second >= minor) ||
|
||||||
|
ThrustVersion().first > 1;
|
||||||
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -725,10 +731,8 @@ class TypedDiscard : public thrust::discard_iterator<T> {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using TypedDiscard =
|
using TypedDiscard =
|
||||||
std::conditional_t<((ThrustVersion().first == 1 &&
|
std::conditional_t<HasThrustMinorVer<12>(), detail::TypedDiscardCTK114<T>,
|
||||||
ThrustVersion().second >= 12) ||
|
detail::TypedDiscard<T>>;
|
||||||
ThrustVersion().first > 1),
|
|
||||||
detail::TypedDiscardCTK114<T>, detail::TypedDiscard<T>>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class AllReducer
|
* \class AllReducer
|
||||||
@@ -1442,24 +1446,39 @@ void ArgSort(xgboost::common::Span<U> keys, xgboost::common::Span<IdxT> sorted_i
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
// Wrapper around cub sort for easier `descending` sort.
|
// Wrapper around cub sort for easier `descending` sort.
|
||||||
template <bool descending, typename KeyT, typename ValueT,
|
template <bool descending, typename KeyT, typename ValueT,
|
||||||
typename OffsetIteratorT>
|
typename BeginOffsetIteratorT, typename EndOffsetIteratorT>
|
||||||
void DeviceSegmentedRadixSortPair(
|
void DeviceSegmentedRadixSortPair(
|
||||||
void *d_temp_storage, size_t &temp_storage_bytes, const KeyT *d_keys_in, // NOLINT
|
void *d_temp_storage, size_t &temp_storage_bytes, const KeyT *d_keys_in, // NOLINT
|
||||||
KeyT *d_keys_out, const ValueT *d_values_in, ValueT *d_values_out,
|
KeyT *d_keys_out, const ValueT *d_values_in, ValueT *d_values_out,
|
||||||
size_t num_items, size_t num_segments, OffsetIteratorT d_begin_offsets,
|
size_t num_items, size_t num_segments, BeginOffsetIteratorT d_begin_offsets,
|
||||||
OffsetIteratorT d_end_offsets, int begin_bit = 0,
|
EndOffsetIteratorT d_end_offsets, int begin_bit = 0,
|
||||||
int end_bit = sizeof(KeyT) * 8) {
|
int end_bit = sizeof(KeyT) * 8) {
|
||||||
cub::DoubleBuffer<KeyT> d_keys(const_cast<KeyT *>(d_keys_in), d_keys_out);
|
cub::DoubleBuffer<KeyT> d_keys(const_cast<KeyT *>(d_keys_in), d_keys_out);
|
||||||
cub::DoubleBuffer<ValueT> d_values(const_cast<ValueT *>(d_values_in),
|
cub::DoubleBuffer<ValueT> d_values(const_cast<ValueT *>(d_values_in),
|
||||||
d_values_out);
|
d_values_out);
|
||||||
using OffsetT = int32_t; // num items in dispatch is also int32_t, no way to change.
|
// In old version of cub, num_items in dispatch is also int32_t, no way to change.
|
||||||
CHECK_LE(num_items, std::numeric_limits<int32_t>::max());
|
using OffsetT =
|
||||||
|
std::conditional_t<BuildWithCUDACub() && HasThrustMinorVer<13>(), size_t,
|
||||||
|
int32_t>;
|
||||||
|
CHECK_LE(num_items, std::numeric_limits<OffsetT>::max());
|
||||||
|
// For Thrust >= 1.12 or CUDA >= 11.4, we require system cub installation
|
||||||
|
|
||||||
|
#if (THRUST_MAJOR_VERSION == 1 && THRUST_MINOR_VERSION >= 13) || THRUST_MAJOR_VERSION > 1
|
||||||
safe_cuda((cub::DispatchSegmentedRadixSort<
|
safe_cuda((cub::DispatchSegmentedRadixSort<
|
||||||
descending, KeyT, ValueT, OffsetIteratorT,
|
descending, KeyT, ValueT, BeginOffsetIteratorT, EndOffsetIteratorT,
|
||||||
OffsetT>::Dispatch(d_temp_storage, temp_storage_bytes, d_keys,
|
OffsetT>::Dispatch(d_temp_storage, temp_storage_bytes, d_keys,
|
||||||
d_values, num_items, num_segments,
|
d_values, num_items, num_segments,
|
||||||
d_begin_offsets, d_end_offsets, begin_bit,
|
d_begin_offsets, d_end_offsets, begin_bit,
|
||||||
end_bit, false, nullptr, false)));
|
end_bit, false, nullptr, false)));
|
||||||
|
#else
|
||||||
|
safe_cuda((cub::DispatchSegmentedRadixSort<
|
||||||
|
descending, KeyT, ValueT, BeginOffsetIteratorT,
|
||||||
|
OffsetT>::Dispatch(d_temp_storage, temp_storage_bytes, d_keys,
|
||||||
|
d_values, num_items, num_segments,
|
||||||
|
d_begin_offsets, d_end_offsets, begin_bit,
|
||||||
|
end_bit, false, nullptr, false)));
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ void RemoveDuplicatedCategories(
|
|||||||
int32_t device, MetaInfo const &info, Span<bst_row_t> d_cuts_ptr,
|
int32_t device, MetaInfo const &info, Span<bst_row_t> d_cuts_ptr,
|
||||||
dh::device_vector<Entry> *p_sorted_entries,
|
dh::device_vector<Entry> *p_sorted_entries,
|
||||||
dh::caching_device_vector<size_t> *p_column_sizes_scan) {
|
dh::caching_device_vector<size_t> *p_column_sizes_scan) {
|
||||||
|
info.feature_types.SetDevice(device);
|
||||||
auto d_feature_types = info.feature_types.ConstDeviceSpan();
|
auto d_feature_types = info.feature_types.ConstDeviceSpan();
|
||||||
CHECK(!d_feature_types.empty());
|
CHECK(!d_feature_types.empty());
|
||||||
auto &column_sizes_scan = *p_column_sizes_scan;
|
auto &column_sizes_scan = *p_column_sizes_scan;
|
||||||
|
|||||||
@@ -124,6 +124,11 @@ void MakeEntriesFromAdapter(AdapterBatch const& batch, BatchIter batch_iter,
|
|||||||
|
|
||||||
void SortByWeight(dh::device_vector<float>* weights,
|
void SortByWeight(dh::device_vector<float>* weights,
|
||||||
dh::device_vector<Entry>* sorted_entries);
|
dh::device_vector<Entry>* sorted_entries);
|
||||||
|
|
||||||
|
void RemoveDuplicatedCategories(
|
||||||
|
int32_t device, MetaInfo const &info, Span<bst_row_t> d_cuts_ptr,
|
||||||
|
dh::device_vector<Entry> *p_sorted_entries,
|
||||||
|
dh::caching_device_vector<size_t> *p_column_sizes_scan);
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Compute sketch on DMatrix.
|
// Compute sketch on DMatrix.
|
||||||
@@ -132,9 +137,10 @@ HistogramCuts DeviceSketch(int device, DMatrix* dmat, int max_bins,
|
|||||||
size_t sketch_batch_num_elements = 0);
|
size_t sketch_batch_num_elements = 0);
|
||||||
|
|
||||||
template <typename AdapterBatch>
|
template <typename AdapterBatch>
|
||||||
void ProcessSlidingWindow(AdapterBatch const& batch, int device, size_t columns,
|
void ProcessSlidingWindow(AdapterBatch const &batch, MetaInfo const &info,
|
||||||
size_t begin, size_t end, float missing,
|
int device, size_t columns, size_t begin, size_t end,
|
||||||
SketchContainer* sketch_container, int num_cuts) {
|
float missing, SketchContainer *sketch_container,
|
||||||
|
int num_cuts) {
|
||||||
// Copy current subset of valid elements into temporary storage and sort
|
// Copy current subset of valid elements into temporary storage and sort
|
||||||
dh::device_vector<Entry> sorted_entries;
|
dh::device_vector<Entry> sorted_entries;
|
||||||
dh::caching_device_vector<size_t> column_sizes_scan;
|
dh::caching_device_vector<size_t> column_sizes_scan;
|
||||||
@@ -142,6 +148,7 @@ void ProcessSlidingWindow(AdapterBatch const& batch, int device, size_t columns,
|
|||||||
thrust::make_counting_iterator(0llu),
|
thrust::make_counting_iterator(0llu),
|
||||||
[=] __device__(size_t idx) { return batch.GetElement(idx); });
|
[=] __device__(size_t idx) { return batch.GetElement(idx); });
|
||||||
HostDeviceVector<SketchContainer::OffsetT> cuts_ptr;
|
HostDeviceVector<SketchContainer::OffsetT> cuts_ptr;
|
||||||
|
cuts_ptr.SetDevice(device);
|
||||||
detail::MakeEntriesFromAdapter(batch, batch_iter, {begin, end}, missing,
|
detail::MakeEntriesFromAdapter(batch, batch_iter, {begin, end}, missing,
|
||||||
columns, num_cuts, device,
|
columns, num_cuts, device,
|
||||||
&cuts_ptr,
|
&cuts_ptr,
|
||||||
@@ -151,8 +158,14 @@ void ProcessSlidingWindow(AdapterBatch const& batch, int device, size_t columns,
|
|||||||
thrust::sort(thrust::cuda::par(alloc), sorted_entries.begin(),
|
thrust::sort(thrust::cuda::par(alloc), sorted_entries.begin(),
|
||||||
sorted_entries.end(), detail::EntryCompareOp());
|
sorted_entries.end(), detail::EntryCompareOp());
|
||||||
|
|
||||||
auto const& h_cuts_ptr = cuts_ptr.ConstHostVector();
|
if (sketch_container->HasCategorical()) {
|
||||||
|
auto d_cuts_ptr = cuts_ptr.DeviceSpan();
|
||||||
|
detail::RemoveDuplicatedCategories(device, info, d_cuts_ptr,
|
||||||
|
&sorted_entries, &column_sizes_scan);
|
||||||
|
}
|
||||||
|
|
||||||
auto d_cuts_ptr = cuts_ptr.DeviceSpan();
|
auto d_cuts_ptr = cuts_ptr.DeviceSpan();
|
||||||
|
auto const &h_cuts_ptr = cuts_ptr.HostVector();
|
||||||
// Extract the cuts from all columns concurrently
|
// Extract the cuts from all columns concurrently
|
||||||
sketch_container->Push(dh::ToSpan(sorted_entries),
|
sketch_container->Push(dh::ToSpan(sorted_entries),
|
||||||
dh::ToSpan(column_sizes_scan), d_cuts_ptr,
|
dh::ToSpan(column_sizes_scan), d_cuts_ptr,
|
||||||
@@ -222,6 +235,12 @@ void ProcessWeightedSlidingWindow(Batch batch, MetaInfo const& info,
|
|||||||
|
|
||||||
detail::SortByWeight(&temp_weights, &sorted_entries);
|
detail::SortByWeight(&temp_weights, &sorted_entries);
|
||||||
|
|
||||||
|
if (sketch_container->HasCategorical()) {
|
||||||
|
auto d_cuts_ptr = cuts_ptr.DeviceSpan();
|
||||||
|
detail::RemoveDuplicatedCategories(device, info, d_cuts_ptr,
|
||||||
|
&sorted_entries, &column_sizes_scan);
|
||||||
|
}
|
||||||
|
|
||||||
auto const& h_cuts_ptr = cuts_ptr.ConstHostVector();
|
auto const& h_cuts_ptr = cuts_ptr.ConstHostVector();
|
||||||
auto d_cuts_ptr = cuts_ptr.DeviceSpan();
|
auto d_cuts_ptr = cuts_ptr.DeviceSpan();
|
||||||
|
|
||||||
@@ -274,8 +293,8 @@ void AdapterDeviceSketch(Batch batch, int num_bins,
|
|||||||
device, num_cuts_per_feature, false);
|
device, num_cuts_per_feature, false);
|
||||||
for (auto begin = 0ull; begin < batch.Size(); begin += sketch_batch_num_elements) {
|
for (auto begin = 0ull; begin < batch.Size(); begin += sketch_batch_num_elements) {
|
||||||
size_t end = std::min(batch.Size(), size_t(begin + sketch_batch_num_elements));
|
size_t end = std::min(batch.Size(), size_t(begin + sketch_batch_num_elements));
|
||||||
ProcessSlidingWindow(batch, device, num_cols,
|
ProcessSlidingWindow(batch, info, device, num_cols, begin, end, missing,
|
||||||
begin, end, missing, sketch_container, num_cuts_per_feature);
|
sketch_container, num_cuts_per_feature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "array_interface.h"
|
#include "array_interface.h"
|
||||||
#include "../c_api/c_api_error.h"
|
#include "../c_api/c_api_error.h"
|
||||||
|
#include "../common/math.h"
|
||||||
|
|
||||||
namespace xgboost {
|
namespace xgboost {
|
||||||
namespace data {
|
namespace data {
|
||||||
@@ -80,6 +81,24 @@ struct COOTuple {
|
|||||||
float value{0};
|
float value{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IsValidFunctor {
|
||||||
|
float missing;
|
||||||
|
|
||||||
|
XGBOOST_DEVICE explicit IsValidFunctor(float missing) : missing(missing) {}
|
||||||
|
|
||||||
|
XGBOOST_DEVICE bool operator()(float value) const {
|
||||||
|
return !(common::CheckNAN(value) || value == missing);
|
||||||
|
}
|
||||||
|
|
||||||
|
XGBOOST_DEVICE bool operator()(const data::COOTuple& e) const {
|
||||||
|
return !(common::CheckNAN(e.value) || e.value == missing);
|
||||||
|
}
|
||||||
|
|
||||||
|
XGBOOST_DEVICE bool operator()(const Entry& e) const {
|
||||||
|
return !(common::CheckNAN(e.fvalue) || e.fvalue == missing);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -987,18 +987,19 @@ uint64_t SparsePage::Push(const AdapterBatchT& batch, float missing, int nthread
|
|||||||
|
|
||||||
// Second pass over batch, placing elements in correct position
|
// Second pass over batch, placing elements in correct position
|
||||||
|
|
||||||
|
auto is_valid = data::IsValidFunctor{missing};
|
||||||
#pragma omp parallel num_threads(nthread)
|
#pragma omp parallel num_threads(nthread)
|
||||||
{
|
{
|
||||||
exec.Run([&]() {
|
exec.Run([&]() {
|
||||||
int tid = omp_get_thread_num();
|
int tid = omp_get_thread_num();
|
||||||
size_t begin = tid*thread_size;
|
size_t begin = tid * thread_size;
|
||||||
size_t end = tid != (nthread-1) ? (tid+1)*thread_size : batch_size;
|
size_t end = tid != (nthread - 1) ? (tid + 1) * thread_size : batch_size;
|
||||||
for (size_t i = begin; i < end; ++i) {
|
for (size_t i = begin; i < end; ++i) {
|
||||||
auto line = batch.GetLine(i);
|
auto line = batch.GetLine(i);
|
||||||
for (auto j = 0ull; j < line.Size(); j++) {
|
for (auto j = 0ull; j < line.Size(); j++) {
|
||||||
auto element = line.GetElement(j);
|
auto element = line.GetElement(j);
|
||||||
const size_t key = (element.row_idx - base_rowid);
|
const size_t key = (element.row_idx - base_rowid);
|
||||||
if (!common::CheckNAN(element.value) && element.value != missing) {
|
if (is_valid(element)) {
|
||||||
builder.Push(key, Entry(element.column_idx, element.value), tid);
|
builder.Push(key, Entry(element.column_idx, element.value), tid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,29 +15,6 @@
|
|||||||
namespace xgboost {
|
namespace xgboost {
|
||||||
namespace data {
|
namespace data {
|
||||||
|
|
||||||
struct IsValidFunctor : public thrust::unary_function<Entry, bool> {
|
|
||||||
float missing;
|
|
||||||
|
|
||||||
XGBOOST_DEVICE explicit IsValidFunctor(float missing) : missing(missing) {}
|
|
||||||
|
|
||||||
__device__ bool operator()(float value) const {
|
|
||||||
return !(common::CheckNAN(value) || value == missing);
|
|
||||||
}
|
|
||||||
|
|
||||||
__device__ bool operator()(const data::COOTuple& e) const {
|
|
||||||
if (common::CheckNAN(e.value) || e.value == missing) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
__device__ bool operator()(const Entry& e) const {
|
|
||||||
if (common::CheckNAN(e.fvalue) || e.fvalue == missing) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CudfAdapterBatch : public detail::NoMetaInfo {
|
class CudfAdapterBatch : public detail::NoMetaInfo {
|
||||||
friend class CudfAdapter;
|
friend class CudfAdapter;
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ void IterativeDeviceDMatrix::Initialize(DataIterHandle iter_handle, float missin
|
|||||||
|
|
||||||
if (batches == 1) {
|
if (batches == 1) {
|
||||||
this->info_ = std::move(proxy->Info());
|
this->info_ = std::move(proxy->Info());
|
||||||
|
this->info_.num_nonzero_ = nnz;
|
||||||
CHECK_EQ(proxy->Info().labels_.Size(), 0);
|
CHECK_EQ(proxy->Info().labels_.Size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,8 @@ struct GBLinearTrainParam : public XGBoostParameter<GBLinearTrainParam> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void LinearCheckLayer(unsigned layer_begin, unsigned layer_end) {
|
void LinearCheckLayer(unsigned layer_begin) {
|
||||||
CHECK_EQ(layer_begin, 0) << "Linear booster does not support prediction range.";
|
CHECK_EQ(layer_begin, 0) << "Linear booster does not support prediction range.";
|
||||||
CHECK_EQ(layer_end, 0) << "Linear booster does not support prediction range.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -152,7 +151,7 @@ class GBLinear : public GradientBooster {
|
|||||||
void PredictBatch(DMatrix *p_fmat, PredictionCacheEntry *predts,
|
void PredictBatch(DMatrix *p_fmat, PredictionCacheEntry *predts,
|
||||||
bool training, unsigned layer_begin, unsigned layer_end) override {
|
bool training, unsigned layer_begin, unsigned layer_end) override {
|
||||||
monitor_.Start("PredictBatch");
|
monitor_.Start("PredictBatch");
|
||||||
LinearCheckLayer(layer_begin, layer_end);
|
LinearCheckLayer(layer_begin);
|
||||||
auto* out_preds = &predts->predictions;
|
auto* out_preds = &predts->predictions;
|
||||||
this->PredictBatchInternal(p_fmat, &out_preds->HostVector());
|
this->PredictBatchInternal(p_fmat, &out_preds->HostVector());
|
||||||
monitor_.Stop("PredictBatch");
|
monitor_.Stop("PredictBatch");
|
||||||
@@ -161,7 +160,7 @@ class GBLinear : public GradientBooster {
|
|||||||
void PredictInstance(const SparsePage::Inst &inst,
|
void PredictInstance(const SparsePage::Inst &inst,
|
||||||
std::vector<bst_float> *out_preds,
|
std::vector<bst_float> *out_preds,
|
||||||
unsigned layer_begin, unsigned layer_end) override {
|
unsigned layer_begin, unsigned layer_end) override {
|
||||||
LinearCheckLayer(layer_begin, layer_end);
|
LinearCheckLayer(layer_begin);
|
||||||
const int ngroup = model_.learner_model_param->num_output_group;
|
const int ngroup = model_.learner_model_param->num_output_group;
|
||||||
for (int gid = 0; gid < ngroup; ++gid) {
|
for (int gid = 0; gid < ngroup; ++gid) {
|
||||||
this->Pred(inst, dmlc::BeginPtr(*out_preds), gid,
|
this->Pred(inst, dmlc::BeginPtr(*out_preds), gid,
|
||||||
@@ -177,8 +176,8 @@ class GBLinear : public GradientBooster {
|
|||||||
HostDeviceVector<bst_float>* out_contribs,
|
HostDeviceVector<bst_float>* out_contribs,
|
||||||
unsigned layer_begin, unsigned layer_end, bool, int, unsigned) override {
|
unsigned layer_begin, unsigned layer_end, bool, int, unsigned) override {
|
||||||
model_.LazyInitModel();
|
model_.LazyInitModel();
|
||||||
LinearCheckLayer(layer_begin, layer_end);
|
LinearCheckLayer(layer_begin);
|
||||||
const auto& base_margin = p_fmat->Info().base_margin_.ConstHostVector();
|
const auto &base_margin = p_fmat->Info().base_margin_.ConstHostVector();
|
||||||
const int ngroup = model_.learner_model_param->num_output_group;
|
const int ngroup = model_.learner_model_param->num_output_group;
|
||||||
const size_t ncolumns = model_.learner_model_param->num_feature + 1;
|
const size_t ncolumns = model_.learner_model_param->num_feature + 1;
|
||||||
// allocate space for (#features + bias) times #groups times #rows
|
// allocate space for (#features + bias) times #groups times #rows
|
||||||
@@ -214,7 +213,7 @@ class GBLinear : public GradientBooster {
|
|||||||
void PredictInteractionContributions(DMatrix* p_fmat,
|
void PredictInteractionContributions(DMatrix* p_fmat,
|
||||||
HostDeviceVector<bst_float>* out_contribs,
|
HostDeviceVector<bst_float>* out_contribs,
|
||||||
unsigned layer_begin, unsigned layer_end, bool) override {
|
unsigned layer_begin, unsigned layer_end, bool) override {
|
||||||
LinearCheckLayer(layer_begin, layer_end);
|
LinearCheckLayer(layer_begin);
|
||||||
std::vector<bst_float>& contribs = out_contribs->HostVector();
|
std::vector<bst_float>& contribs = out_contribs->HostVector();
|
||||||
|
|
||||||
// linear models have no interaction effects
|
// linear models have no interaction effects
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ void GBLinearModel::SaveModel(Json* p_out) const {
|
|||||||
j_weights[i] = weight[i];
|
j_weights[i] = weight[i];
|
||||||
}
|
}
|
||||||
out["weights"] = std::move(j_weights);
|
out["weights"] = std::move(j_weights);
|
||||||
|
out["boosted_rounds"] = Json{this->num_boosted_rounds};
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBLinearModel::LoadModel(Json const& in) {
|
void GBLinearModel::LoadModel(Json const& in) {
|
||||||
@@ -27,6 +28,13 @@ void GBLinearModel::LoadModel(Json const& in) {
|
|||||||
for (size_t i = 0; i < n_weights; ++i) {
|
for (size_t i = 0; i < n_weights; ++i) {
|
||||||
weight[i] = get<Number const>(j_weights[i]);
|
weight[i] = get<Number const>(j_weights[i]);
|
||||||
}
|
}
|
||||||
|
auto const& obj = get<Object const>(in);
|
||||||
|
auto boosted_rounds = obj.find("boosted_rounds");
|
||||||
|
if (boosted_rounds != obj.cend()) {
|
||||||
|
this->num_boosted_rounds = get<Integer const>(boosted_rounds->second);
|
||||||
|
} else {
|
||||||
|
this->num_boosted_rounds = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DMLC_REGISTER_PARAMETER(DeprecatedGBLinearModelParam);
|
DMLC_REGISTER_PARAMETER(DeprecatedGBLinearModelParam);
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ class GBTree : public GradientBooster {
|
|||||||
uint32_t tree_begin, tree_end;
|
uint32_t tree_begin, tree_end;
|
||||||
std::tie(tree_begin, tree_end) =
|
std::tie(tree_begin, tree_end) =
|
||||||
detail::LayerToTree(model_, tparam_, layer_begin, layer_end);
|
detail::LayerToTree(model_, tparam_, layer_begin, layer_end);
|
||||||
|
CHECK_LE(tree_end, model_.trees.size()) << "Invalid number of trees.";
|
||||||
std::vector<Predictor const *> predictors{
|
std::vector<Predictor const *> predictors{
|
||||||
cpu_predictor_.get(),
|
cpu_predictor_.get(),
|
||||||
#if defined(XGBOOST_USE_CUDA)
|
#if defined(XGBOOST_USE_CUDA)
|
||||||
|
|||||||
@@ -585,6 +585,7 @@ struct GPUHistMakerDevice {
|
|||||||
CHECK_LT(candidate.split.fvalue, std::numeric_limits<bst_cat_t>::max())
|
CHECK_LT(candidate.split.fvalue, std::numeric_limits<bst_cat_t>::max())
|
||||||
<< "Categorical feature value too large.";
|
<< "Categorical feature value too large.";
|
||||||
auto cat = common::AsCat(candidate.split.fvalue);
|
auto cat = common::AsCat(candidate.split.fvalue);
|
||||||
|
common::CheckCat(cat);
|
||||||
std::vector<uint32_t> split_cats(LBitField32::ComputeStorageSize(std::max(cat+1, 1)), 0);
|
std::vector<uint32_t> split_cats(LBitField32::ComputeStorageSize(std::max(cat+1, 1)), 0);
|
||||||
LBitField32 cats_bits(split_cats);
|
LBitField32 cats_bits(split_cats);
|
||||||
cats_bits.Set(cat);
|
cats_bits.Set(cat);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: cpu_test
|
name: macos_test
|
||||||
channels:
|
channels:
|
||||||
- conda-forge
|
- conda-forge
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -38,6 +38,14 @@ TEST(BitField, Check) {
|
|||||||
ASSERT_FALSE(bits.Check(i));
|
ASSERT_FALSE(bits.Check(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// regression test for correct index type.
|
||||||
|
std::vector<RBitField8::value_type> storage(33, 0);
|
||||||
|
storage[32] = static_cast<uint8_t>(1);
|
||||||
|
auto bits = RBitField8({storage.data(), storage.size()});
|
||||||
|
ASSERT_TRUE(bits.Check(256));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BitFieldT, typename VT = typename BitFieldT::value_type>
|
template <typename BitFieldT, typename VT = typename BitFieldT::value_type>
|
||||||
|
|||||||
@@ -392,6 +392,52 @@ TEST(HistUtil, AdapterSketchSlidingWindowWeightedMemory) {
|
|||||||
EXPECT_GE(dh::GlobalMemoryLogger().PeakMemory(), bytes_required);
|
EXPECT_GE(dh::GlobalMemoryLogger().PeakMemory(), bytes_required);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestCategoricalSketchAdapter(size_t n, size_t num_categories,
|
||||||
|
int32_t num_bins, bool weighted) {
|
||||||
|
auto h_x = GenerateRandomCategoricalSingleColumn(n, num_categories);
|
||||||
|
thrust::device_vector<float> x(h_x);
|
||||||
|
auto adapter = AdapterFromData(x, n, 1);
|
||||||
|
MetaInfo info;
|
||||||
|
info.num_row_ = n;
|
||||||
|
info.num_col_ = 1;
|
||||||
|
info.feature_types.HostVector().push_back(FeatureType::kCategorical);
|
||||||
|
|
||||||
|
if (weighted) {
|
||||||
|
std::vector<float> weights(n, 0);
|
||||||
|
SimpleLCG lcg;
|
||||||
|
SimpleRealUniformDistribution<float> dist(0, 1);
|
||||||
|
for (auto& v : weights) {
|
||||||
|
v = dist(&lcg);
|
||||||
|
}
|
||||||
|
info.weights_.HostVector() = weights;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(info.feature_types.Size(), 1);
|
||||||
|
SketchContainer container(info.feature_types, num_bins, 1, n, 0);
|
||||||
|
AdapterDeviceSketch(adapter.Value(), num_bins, info,
|
||||||
|
std::numeric_limits<float>::quiet_NaN(), &container);
|
||||||
|
HistogramCuts cuts;
|
||||||
|
container.MakeCuts(&cuts);
|
||||||
|
|
||||||
|
thrust::sort(x.begin(), x.end());
|
||||||
|
auto n_uniques = thrust::unique(x.begin(), x.end()) - x.begin();
|
||||||
|
ASSERT_NE(n_uniques, x.size());
|
||||||
|
ASSERT_EQ(cuts.TotalBins(), n_uniques);
|
||||||
|
ASSERT_EQ(n_uniques, num_categories);
|
||||||
|
|
||||||
|
auto& values = cuts.cut_values_.HostVector();
|
||||||
|
ASSERT_TRUE(std::is_sorted(values.cbegin(), values.cend()));
|
||||||
|
auto is_unique = (std::unique(values.begin(), values.end()) - values.begin()) == n_uniques;
|
||||||
|
ASSERT_TRUE(is_unique);
|
||||||
|
|
||||||
|
x.resize(n_uniques);
|
||||||
|
h_x.resize(n_uniques);
|
||||||
|
thrust::copy(x.begin(), x.end(), h_x.begin());
|
||||||
|
for (decltype(n_uniques) i = 0; i < n_uniques; ++i) {
|
||||||
|
ASSERT_EQ(h_x[i], values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(HistUtil, AdapterDeviceSketchCategorical) {
|
TEST(HistUtil, AdapterDeviceSketchCategorical) {
|
||||||
int categorical_sizes[] = {2, 6, 8, 12};
|
int categorical_sizes[] = {2, 6, 8, 12};
|
||||||
int num_bins = 256;
|
int num_bins = 256;
|
||||||
@@ -404,6 +450,8 @@ TEST(HistUtil, AdapterDeviceSketchCategorical) {
|
|||||||
auto adapter = AdapterFromData(x_device, n, 1);
|
auto adapter = AdapterFromData(x_device, n, 1);
|
||||||
ValidateBatchedCuts(adapter, num_bins, adapter.NumColumns(),
|
ValidateBatchedCuts(adapter, num_bins, adapter.NumColumns(),
|
||||||
adapter.NumRows(), dmat.get());
|
adapter.NumRows(), dmat.get());
|
||||||
|
TestCategoricalSketchAdapter(n, num_categories, num_bins, true);
|
||||||
|
TestCategoricalSketchAdapter(n, num_categories, num_bins, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,4 +452,47 @@ TEST(GBTree, FeatureScore) {
|
|||||||
test_eq("gain");
|
test_eq("gain");
|
||||||
test_eq("cover");
|
test_eq("cover");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(GBTree, PredictRange) {
|
||||||
|
size_t n_samples = 1000, n_features = 10, n_classes = 4;
|
||||||
|
auto m = RandomDataGenerator{n_samples, n_features, 0.5}.GenerateDMatrix(true, false, n_classes);
|
||||||
|
|
||||||
|
std::unique_ptr<Learner> learner{Learner::Create({m})};
|
||||||
|
learner->SetParam("num_class", std::to_string(n_classes));
|
||||||
|
|
||||||
|
learner->Configure();
|
||||||
|
for (size_t i = 0; i < 2; ++i) {
|
||||||
|
learner->UpdateOneIter(i, m);
|
||||||
|
}
|
||||||
|
HostDeviceVector<float> out_predt;
|
||||||
|
ASSERT_THROW(learner->Predict(m, false, &out_predt, 0, 3), dmlc::Error);
|
||||||
|
|
||||||
|
auto m_1 =
|
||||||
|
RandomDataGenerator{n_samples, n_features, 0.5}.GenerateDMatrix(true, false, n_classes);
|
||||||
|
HostDeviceVector<float> out_predt_full;
|
||||||
|
learner->Predict(m_1, false, &out_predt_full, 0, 0);
|
||||||
|
ASSERT_TRUE(std::equal(out_predt.HostVector().begin(), out_predt.HostVector().end(),
|
||||||
|
out_predt_full.HostVector().begin()));
|
||||||
|
|
||||||
|
{
|
||||||
|
// inplace predict
|
||||||
|
HostDeviceVector<float> raw_storage;
|
||||||
|
auto raw = RandomDataGenerator{n_samples, n_features, 0.5}.GenerateArrayInterface(&raw_storage);
|
||||||
|
std::shared_ptr<data::ArrayAdapter> x{new data::ArrayAdapter{StringView{raw}}};
|
||||||
|
|
||||||
|
HostDeviceVector<float>* out_predt;
|
||||||
|
learner->InplacePredict(x, nullptr, PredictionType::kValue,
|
||||||
|
std::numeric_limits<float>::quiet_NaN(), &out_predt, 0, 2);
|
||||||
|
auto h_out_predt = out_predt->HostVector();
|
||||||
|
learner->InplacePredict(x, nullptr, PredictionType::kValue,
|
||||||
|
std::numeric_limits<float>::quiet_NaN(), &out_predt, 0, 0);
|
||||||
|
auto h_out_predt_full = out_predt->HostVector();
|
||||||
|
|
||||||
|
ASSERT_TRUE(std::equal(h_out_predt.begin(), h_out_predt.end(), h_out_predt_full.begin()));
|
||||||
|
|
||||||
|
ASSERT_THROW(learner->InplacePredict(x, nullptr, PredictionType::kValue,
|
||||||
|
std::numeric_limits<float>::quiet_NaN(), &out_predt, 0, 3),
|
||||||
|
dmlc::Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace xgboost
|
} // namespace xgboost
|
||||||
|
|||||||
@@ -186,6 +186,37 @@ Arrow specification.'''
|
|||||||
assert len(Xy.feature_types) == X.shape[1]
|
assert len(Xy.feature_types) == X.shape[1]
|
||||||
assert all(t == "c" for t in Xy.feature_types)
|
assert all(t == "c" for t in Xy.feature_types)
|
||||||
|
|
||||||
|
# test missing value
|
||||||
|
X = cudf.DataFrame({"f0": ["a", "b", np.NaN]})
|
||||||
|
X["f0"] = X["f0"].astype("category")
|
||||||
|
df, cat_codes, _, _ = xgb.data._transform_cudf_df(
|
||||||
|
X, None, None, enable_categorical=True
|
||||||
|
)
|
||||||
|
for col in cat_codes:
|
||||||
|
assert col.has_nulls
|
||||||
|
|
||||||
|
y = [0, 1, 2]
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
xgb.DMatrix(X, y)
|
||||||
|
Xy = xgb.DMatrix(X, y, enable_categorical=True)
|
||||||
|
assert Xy.num_row() == 3
|
||||||
|
assert Xy.num_col() == 1
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
xgb.DeviceQuantileDMatrix(X, y)
|
||||||
|
|
||||||
|
Xy = xgb.DeviceQuantileDMatrix(X, y, enable_categorical=True)
|
||||||
|
assert Xy.num_row() == 3
|
||||||
|
assert Xy.num_col() == 1
|
||||||
|
|
||||||
|
X = X["f0"]
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
xgb.DMatrix(X, y)
|
||||||
|
|
||||||
|
Xy = xgb.DMatrix(X, y, enable_categorical=True)
|
||||||
|
assert Xy.num_row() == 3
|
||||||
|
assert Xy.num_col() == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(**tm.no_cudf())
|
@pytest.mark.skipif(**tm.no_cudf())
|
||||||
@pytest.mark.skipif(**tm.no_cupy())
|
@pytest.mark.skipif(**tm.no_cupy())
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import sys
|
import sys
|
||||||
from hypothesis import strategies, given, settings, assume
|
from hypothesis import strategies, given, settings, assume, note
|
||||||
import pytest
|
import pytest
|
||||||
import numpy
|
|
||||||
import xgboost as xgb
|
import xgboost as xgb
|
||||||
sys.path.append("tests/python")
|
sys.path.append("tests/python")
|
||||||
import testing as tm
|
import testing as tm
|
||||||
@@ -17,10 +16,14 @@ parameter_strategy = strategies.fixed_dictionaries({
|
|||||||
'top_k': strategies.integers(1, 10),
|
'top_k': strategies.integers(1, 10),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def train_result(param, dmat, num_rounds):
|
def train_result(param, dmat, num_rounds):
|
||||||
result = {}
|
result = {}
|
||||||
xgb.train(param, dmat, num_rounds, [(dmat, 'train')], verbose_eval=False,
|
booster = xgb.train(
|
||||||
evals_result=result)
|
param, dmat, num_rounds, [(dmat, 'train')], verbose_eval=False,
|
||||||
|
evals_result=result
|
||||||
|
)
|
||||||
|
assert booster.num_boosted_rounds() == num_rounds
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +36,7 @@ class TestGPULinear:
|
|||||||
param['updater'] = 'gpu_coord_descent'
|
param['updater'] = 'gpu_coord_descent'
|
||||||
param = dataset.set_params(param)
|
param = dataset.set_params(param)
|
||||||
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
||||||
|
note(result)
|
||||||
assert tm.non_increasing(result)
|
assert tm.non_increasing(result)
|
||||||
|
|
||||||
# Loss is not guaranteed to always decrease because of regularisation parameters
|
# Loss is not guaranteed to always decrease because of regularisation parameters
|
||||||
@@ -49,6 +53,7 @@ class TestGPULinear:
|
|||||||
param['lambda'] = lambd
|
param['lambda'] = lambd
|
||||||
param = dataset.set_params(param)
|
param = dataset.set_params(param)
|
||||||
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
||||||
|
note(result)
|
||||||
assert tm.non_increasing([result[0], result[-1]])
|
assert tm.non_increasing([result[0], result[-1]])
|
||||||
|
|
||||||
@pytest.mark.skipif(**tm.no_cupy())
|
@pytest.mark.skipif(**tm.no_cupy())
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class TestLinear:
|
|||||||
param.update(coord_param)
|
param.update(coord_param)
|
||||||
param = dataset.set_params(param)
|
param = dataset.set_params(param)
|
||||||
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
||||||
|
note(result)
|
||||||
assert tm.non_increasing(result, 5e-4)
|
assert tm.non_increasing(result, 5e-4)
|
||||||
|
|
||||||
# Loss is not guaranteed to always decrease because of regularisation parameters
|
# Loss is not guaranteed to always decrease because of regularisation parameters
|
||||||
@@ -48,6 +49,7 @@ class TestLinear:
|
|||||||
param.update(coord_param)
|
param.update(coord_param)
|
||||||
param = dataset.set_params(param)
|
param = dataset.set_params(param)
|
||||||
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
||||||
|
note(result)
|
||||||
assert tm.non_increasing([result[0], result[-1]])
|
assert tm.non_increasing([result[0], result[-1]])
|
||||||
|
|
||||||
@given(parameter_strategy, strategies.integers(10, 50),
|
@given(parameter_strategy, strategies.integers(10, 50),
|
||||||
@@ -57,6 +59,7 @@ class TestLinear:
|
|||||||
param['updater'] = 'shotgun'
|
param['updater'] = 'shotgun'
|
||||||
param = dataset.set_params(param)
|
param = dataset.set_params(param)
|
||||||
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
||||||
|
note(result)
|
||||||
# shotgun is non-deterministic, so we relax the test by only using first and last
|
# shotgun is non-deterministic, so we relax the test by only using first and last
|
||||||
# iteration.
|
# iteration.
|
||||||
if len(result) > 2:
|
if len(result) > 2:
|
||||||
@@ -75,4 +78,5 @@ class TestLinear:
|
|||||||
param['lambda'] = lambd
|
param['lambda'] = lambd
|
||||||
param = dataset.set_params(param)
|
param = dataset.set_params(param)
|
||||||
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
result = train_result(param, dataset.get_dmat(), num_rounds)['train'][dataset.metric]
|
||||||
|
note(result)
|
||||||
assert tm.non_increasing([result[0], result[-1]])
|
assert tm.non_increasing([result[0], result[-1]])
|
||||||
|
|||||||
@@ -705,8 +705,7 @@ async def run_from_dask_array_asyncio(scheduler_address: str) -> xgb.dask.TrainR
|
|||||||
async def run_dask_regressor_asyncio(scheduler_address: str) -> None:
|
async def run_dask_regressor_asyncio(scheduler_address: str) -> None:
|
||||||
async with Client(scheduler_address, asynchronous=True) as client:
|
async with Client(scheduler_address, asynchronous=True) as client:
|
||||||
X, y, _ = generate_array()
|
X, y, _ = generate_array()
|
||||||
regressor = await xgb.dask.DaskXGBRegressor(verbosity=1,
|
regressor = await xgb.dask.DaskXGBRegressor(verbosity=1, n_estimators=2)
|
||||||
n_estimators=2)
|
|
||||||
regressor.set_params(tree_method='hist')
|
regressor.set_params(tree_method='hist')
|
||||||
regressor.client = client
|
regressor.client = client
|
||||||
await regressor.fit(X, y, eval_set=[(X, y)])
|
await regressor.fit(X, y, eval_set=[(X, y)])
|
||||||
|
|||||||
@@ -138,9 +138,22 @@ class TestPandas:
|
|||||||
X, enable_categorical=True
|
X, enable_categorical=True
|
||||||
)
|
)
|
||||||
|
|
||||||
assert np.issubdtype(transformed[:, 0].dtype, np.integer)
|
|
||||||
assert transformed[:, 0].min() == 0
|
assert transformed[:, 0].min() == 0
|
||||||
|
|
||||||
|
# test missing value
|
||||||
|
X = pd.DataFrame({"f0": ["a", "b", np.NaN]})
|
||||||
|
X["f0"] = X["f0"].astype("category")
|
||||||
|
arr, _, _ = xgb.data._transform_pandas_df(X, enable_categorical=True)
|
||||||
|
assert not np.any(arr == -1.0)
|
||||||
|
|
||||||
|
X = X["f0"]
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
xgb.DMatrix(X, y)
|
||||||
|
|
||||||
|
Xy = xgb.DMatrix(X, y, enable_categorical=True)
|
||||||
|
assert Xy.num_row() == 3
|
||||||
|
assert Xy.num_col() == 1
|
||||||
|
|
||||||
def test_pandas_sparse(self):
|
def test_pandas_sparse(self):
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
rows = 100
|
rows = 100
|
||||||
|
|||||||
Reference in New Issue
Block a user