-
-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Expand file tree
/
Copy pathmultioutput_reduced_gradient.py
More file actions
121 lines (89 loc) · 3.21 KB
/
multioutput_reduced_gradient.py
File metadata and controls
121 lines (89 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
A demo for multi-output regression using reduced gradient
=========================================================
See :doc:`/tutorials/multioutput` for more information.
.. versionadded:: 3.2.0
.. note::
The implementation is experimental and many features are missing.
.. seealso:: :ref:`sphx_glr_python_examples_multioutput_regression.py`
"""
import argparse
from typing import Tuple
import numpy as np
import xgboost as xgb
from sklearn.base import BaseEstimator
from sklearn.datasets import make_regression
from xgboost.objective import Objective
class LsObjMean(Objective):
"""Least squared error. Reduce the size of the gradient using mean value."""
def __init__(self, device: str) -> None:
self.device = device
def __call__(
self, iteration: int, y_pred: np.ndarray, dtrain: xgb.DMatrix
) -> Tuple[np.ndarray, np.ndarray]:
y_true = dtrain.get_label()
grad = y_pred - y_true
if self.device == "cpu":
hess = np.ones(grad.shape)
return grad, hess
import cupy as cp
hess = cp.ones(grad.shape)
return cp.array(grad), cp.array(hess)
def split_grad(
self, iteration: int, grad: np.ndarray, hess: np.ndarray
) -> Tuple[np.ndarray, np.ndarray]:
if self.device == "cpu":
from numpy import mean
else:
from cupy import mean # type: ignore[no-redef]
sgrad = mean(grad, axis=1)
shess = mean(hess, axis=1)
return sgrad, shess
def svd_class() -> BaseEstimator:
"""One of the methods in the sketch boost paper."""
from sklearn.decomposition import TruncatedSVD
svd_params = {"algorithm": "arpack", "n_components": 2, "n_iter": 8}
svd = TruncatedSVD(**svd_params)
return svd
class LsObjSvd(LsObjMean):
"""Reduce the size of the gradient using SVD."""
def __init__(self, device: str) -> None:
super().__init__(device=device)
def split_grad(
self, iteration: int, grad: np.ndarray, hess: np.ndarray
) -> Tuple[np.ndarray, np.ndarray]:
svd = svd_class()
if self.device == "cuda":
grad = grad.get() # type: ignore
hess = hess.get() # type: ignore
svd.fit(grad)
grad = svd.transform(grad)
hess = svd.transform(hess)
if self.device == "cpu":
hess = np.clip(hess, 0.01, None)
else:
import cupy as cp
hess = cp.clip(hess, 0.01, None)
return grad, hess
def main() -> None:
"""Entry point to the demo, use `--device` to choose between CPU and GPU."""
parser = argparse.ArgumentParser()
parser.add_argument("--device", choices=["cpu", "cuda"], default="cpu")
args = parser.parse_args()
X, y = make_regression(
n_samples=8192, n_features=32, n_targets=8, random_state=2026
)
Xy = xgb.QuantileDMatrix(X, y)
for obj in (LsObjMean(args.device), LsObjSvd(args.device)):
xgb.train(
{
"device": args.device,
"multi_strategy": "multi_output_tree",
},
Xy,
evals=[(Xy, "Train")],
obj=obj,
num_boost_round=16,
)
if __name__ == "__main__":
main()