Skip to content

Commit

Permalink
[backport] [CI] Build a CPU-only wheel under name xgboost-cpu (#10603
Browse files Browse the repository at this point in the history
…) (#10614)

* [CI] Build a CPU-only wheel under name `xgboost-cpu` (#10603)

* [CI] Fix test environment. (#10609)

* [CI] Fix test environment.

* Remove shell.

* Remove.

* Update Dockerfile.i386

* replace channel for sycl dependencies (#10576)

Co-authored-by: Dmitry Razdoburdin <>

* Optionally skip cupy on windows. (#10611)

---------

Co-authored-by: Jiaming Yuan <[email protected]>
Co-authored-by: Dmitry Razdoburdin <[email protected]>
  • Loading branch information
3 people authored Jul 21, 2024
1 parent ea7bd91 commit 9fe50c4
Show file tree
Hide file tree
Showing 16 changed files with 209 additions and 118 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/i386.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
with:
submodules: 'true'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v3.4.0
with:
driver-opts: network=host
- name: Build and push container
Expand Down
14 changes: 14 additions & 0 deletions dev/release-artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
tqdm, sh are required to run this script.
"""

import argparse
import os
import shutil
Expand Down Expand Up @@ -106,6 +107,15 @@ def make_pysrc_wheel(
if not os.path.exists(dist):
os.mkdir(dist)

# Apply patch to remove NCCL dependency
# Save the original content of pyproject.toml so that we can restore it later
with DirectoryExcursion(ROOT):
with open("python-package/pyproject.toml", "r") as f:
orig_pyproj_lines = f.read()
with open("tests/buildkite/remove_nccl_dep.patch", "r") as f:
patch_lines = f.read()
subprocess.run(["patch", "-p0"], input=patch_lines, text=True)

with DirectoryExcursion(os.path.join(ROOT, "python-package")):
subprocess.check_call(["python", "-m", "build", "--sdist"])
if rc is not None:
Expand All @@ -117,6 +127,10 @@ def make_pysrc_wheel(
target = os.path.join(dist, name)
shutil.move(src, target)

with DirectoryExcursion(ROOT):
with open("python-package/pyproject.toml", "w") as f:
print(orig_pyproj_lines, file=f, end="")


def download_py_packages(
branch: str, major: int, minor: int, commit_hash: str, outdir: str
Expand Down
13 changes: 13 additions & 0 deletions doc/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ Capabilities of binary wheels for each platform:
| Windows | |tick| | |cross| |
+---------------------+---------+----------------------+

Minimal installation (CPU-only)
*******************************
The default installation with ``pip`` will install the full XGBoost package, including the support for the GPU algorithms and federated learning.

You may choose to reduce the size of the installed package and save the disk space, by opting to install ``xgboost-cpu`` instead:

.. code-block:: bash
pip install xgboost-cpu
The ``xgboost-cpu`` variant will have drastically smaller disk footprint, but does not provide some features, such as the GPU algorithms and
federated learning.

Conda
*****

Expand Down
6 changes: 3 additions & 3 deletions python-package/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ build-backend = "packager.pep517"

[project]
name = "xgboost"
version = "2.1.0"
description = "XGBoost Python Package"
readme = { file = "README.rst", content-type = "text/x-rst" }
authors = [
{ name = "Hyunsu Cho", email = "[email protected]" },
{ name = "Jiaming Yuan", email = "[email protected]" }
]
description = "XGBoost Python Package"
readme = { file = "README.rst", content-type = "text/x-rst" }
version = "2.1.0"
requires-python = ">=3.8"
license = { text = "Apache-2.0" }
classifiers = [
Expand Down
40 changes: 11 additions & 29 deletions python-package/xgboost/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
get_cancer,
get_digits,
get_sparse,
make_batches,
memory,
)

Expand Down Expand Up @@ -161,7 +162,16 @@ def no_cudf() -> PytestSkip:


def no_cupy() -> PytestSkip:
return no_mod("cupy")
skip_cupy = no_mod("cupy")
if not skip_cupy["condition"] and system() == "Windows":
import cupy as cp

# Cupy might run into issue on Windows due to missing compiler
try:
cp.array([1, 2, 3]).sum()
except Exception: # pylint: disable=broad-except
skip_cupy["condition"] = True
return skip_cupy


def no_dask_cudf() -> PytestSkip:
Expand Down Expand Up @@ -247,34 +257,6 @@ def as_arrays(
return X, y, w


def make_batches(
n_samples_per_batch: int,
n_features: int,
n_batches: int,
use_cupy: bool = False,
*,
vary_size: bool = False,
) -> Tuple[List[np.ndarray], List[np.ndarray], List[np.ndarray]]:
X = []
y = []
w = []
if use_cupy:
import cupy

rng = cupy.random.RandomState(1994)
else:
rng = np.random.RandomState(1994)
for i in range(n_batches):
n_samples = n_samples_per_batch + i * 10 if vary_size else n_samples_per_batch
_X = rng.randn(n_samples, n_features)
_y = rng.randn(n_samples)
_w = rng.uniform(low=0, high=1, size=n_samples)
X.append(_X)
y.append(_y)
w.append(_w)
return X, y, w


def make_regression(
n_samples: int, n_features: int, use_cupy: bool
) -> Tuple[ArrayLike, ArrayLike, ArrayLike]:
Expand Down
31 changes: 31 additions & 0 deletions python-package/xgboost/testing/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Callable,
Dict,
Generator,
List,
NamedTuple,
Optional,
Tuple,
Expand Down Expand Up @@ -501,6 +502,36 @@ def get_mq2008(
)


def make_batches( # pylint: disable=too-many-arguments,too-many-locals
n_samples_per_batch: int,
n_features: int,
n_batches: int,
use_cupy: bool = False,
*,
vary_size: bool = False,
random_state: int = 1994,
) -> Tuple[List[np.ndarray], List[np.ndarray], List[np.ndarray]]:
"""Make batches of dense data."""
X = []
y = []
w = []
if use_cupy:
import cupy # pylint: disable=import-error

rng = cupy.random.RandomState(random_state)
else:
rng = np.random.RandomState(random_state)
for i in range(n_batches):
n_samples = n_samples_per_batch + i * 10 if vary_size else n_samples_per_batch
_X = rng.randn(n_samples, n_features)
_y = rng.randn(n_samples)
_w = rng.uniform(low=0, high=1, size=n_samples)
X.append(_X)
y.append(_y)
w.append(_w)
return X, y, w


RelData = Tuple[sparse.csr_matrix, npt.NDArray[np.int32], npt.NDArray[np.int32]]


Expand Down
33 changes: 0 additions & 33 deletions tests/buildkite/build-manylinux2014-aarch64.sh

This file was deleted.

33 changes: 0 additions & 33 deletions tests/buildkite/build-manylinux2014-x86_64.sh

This file was deleted.

63 changes: 63 additions & 0 deletions tests/buildkite/build-manylinux2014.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/bash

set -euo pipefail

if [ $# -ne 1 ]; then
echo "Usage: $0 {x86_64,aarch64}"
exit 1
fi

arch=$1

source tests/buildkite/conftest.sh

WHEEL_TAG="manylinux2014_${arch}"
command_wrapper="tests/ci_build/ci_build.sh ${WHEEL_TAG}"
python_bin="/opt/python/cp310-cp310/bin/python"

echo "--- Build binary wheel for ${WHEEL_TAG}"
# Patch to add warning about manylinux2014 variant
patch -p0 < tests/buildkite/remove_nccl_dep.patch
patch -p0 < tests/buildkite/manylinux2014_warning.patch
$command_wrapper bash -c \
"cd python-package && ${python_bin} -m pip wheel --no-deps -v . --wheel-dir dist/"
git checkout python-package/pyproject.toml python-package/xgboost/core.py # discard the patch

$command_wrapper auditwheel repair --plat ${WHEEL_TAG} python-package/dist/*.whl
$command_wrapper ${python_bin} tests/ci_build/rename_whl.py \
--wheel-path wheelhouse/*.whl \
--commit-hash ${BUILDKITE_COMMIT} \
--platform-tag ${WHEEL_TAG}
rm -rf python-package/dist/
mkdir python-package/dist/
mv -v wheelhouse/*.whl python-package/dist/

echo "--- Build binary wheel for ${WHEEL_TAG} (CPU only)"
# Patch to rename pkg to xgboost-cpu
patch -p0 < tests/buildkite/remove_nccl_dep.patch
patch -p0 < tests/buildkite/cpu_only_pypkg.patch
$command_wrapper bash -c \
"cd python-package && ${python_bin} -m pip wheel --no-deps -v . --wheel-dir dist/"
git checkout python-package/pyproject.toml # discard the patch

$command_wrapper auditwheel repair --plat ${WHEEL_TAG} python-package/dist/xgboost_cpu-*.whl
$command_wrapper ${python_bin} tests/ci_build/rename_whl.py \
--wheel-path wheelhouse/xgboost_cpu-*.whl \
--commit-hash ${BUILDKITE_COMMIT} \
--platform-tag ${WHEEL_TAG}
rm -v python-package/dist/xgboost_cpu-*.whl
mv -v wheelhouse/xgboost_cpu-*.whl python-package/dist/

echo "--- Upload Python wheel"
for wheel in python-package/dist/*.whl
do
buildkite-agent artifact upload "${wheel}"
done
if [[ ($is_pull_request == 0) && ($is_release_branch == 1) ]]
then
for wheel in python-package/dist/*.whl
do
aws s3 cp "${wheel}" s3://xgboost-nightly-builds/${BRANCH_NAME}/ \
--acl public-read --no-progress
done
fi
55 changes: 55 additions & 0 deletions tests/buildkite/cpu_only_pypkg.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
diff --git python-package/README.rst python-package/README.rst
index 1fc0bb5a0..f1c68470b 100644
--- python-package/README.rst
+++ python-package/README.rst
@@ -1,20 +1,15 @@
-======================
-XGBoost Python Package
-======================
+=================================
+XGBoost Python Package (CPU only)
+=================================

|PyPI version|

-Installation
-============
+The ``xgboost-cpu`` package provides for a minimal installation, with no support for the GPU algorithms
+or federated learning. It is provided to allow XGBoost to be installed in a space-constrained
+environments.

-From `PyPI <https://pypi.python.org/pypi/xgboost>`_
----------------------------------------------------
+Note. ``xgboost-cpu`` package is only provided for x86_64 (amd64) Linux and Windows platforms.
+For other platforms, please install ``xgboost`` from https://pypi.org/project/xgboost/.

-For a stable version, install using ``pip``::
-
- pip install xgboost
-
-.. |PyPI version| image:: https://badge.fury.io/py/xgboost.svg
- :target: http://badge.fury.io/py/xgboost
-
-For building from source, see `build <https://xgboost.readthedocs.io/en/latest/build.html>`_.
+Note. ``xgboost-cpu`` does not provide an sdist (source distribution). You may install sdist
+from https://pypi.org/project/xgboost/.
diff --git python-package/pyproject.toml python-package/pyproject.toml
index 46c1451c2..c5dc908d9 100644
--- python-package/pyproject.toml
+++ python-package/pyproject.toml
@@ -6,7 +6,7 @@ backend-path = ["."]
build-backend = "packager.pep517"

[project]
-name = "xgboost"
+name = "xgboost-cpu"
description = "XGBoost Python Package"
readme = { file = "README.rst", content-type = "text/x-rst" }
authors = [
@@ -82,3 +82,6 @@ class-attribute-naming-style = "snake_case"

# Allow single-letter variables
variable-rgx = "[a-zA-Z_][a-z0-9_]{0,30}$"
+
+[tool.hatch.build.targets.wheel]
+packages = ["xgboost/"]
14 changes: 0 additions & 14 deletions tests/buildkite/manylinux2014_warning.patch
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
diff --git python-package/pyproject.toml python-package/pyproject.toml
index a273d8c13..dee49686a 100644
--- python-package/pyproject.toml
+++ python-package/pyproject.toml
@@ -30,8 +30,7 @@ classifiers = [
]
dependencies = [
"numpy",
- "scipy",
- "nvidia-nccl-cu12 ; platform_system == 'Linux' and platform_machine != 'aarch64'"
+ "scipy"
]

[project.urls]
diff --git python-package/xgboost/core.py python-package/xgboost/core.py
index e8bc735e6..030972ef2 100644
--- python-package/xgboost/core.py
Expand Down
Loading

0 comments on commit 9fe50c4

Please sign in to comment.