-Learn 的 1.8.0 版本更新, 引入了实验性质的 Array API 支持。这意味着 CuPy 数组或者张量, 现在就可以在 -Learn 的部分组件里面直接使用了。并且计算过程还能保留在 GPU 上面。

1.用户想要了解的是, 版本号为8.0的那一次更新, 它具体包含了哪些更新内容。
-Learn 现在开始正式支持 Array API 标准。这个标准是由 NumPy、CuPy、JAX 这些库一起维护的接口规范。在 1.8.0 这个版本里面, 可以实现以下内容:
目前的这个版本, 它依然是贴着实验性的标签的, 并且还需要去进行显式的开启操作, 可是, 事实是确实如此, 它打破了之前的那种情况, 也就是过去的-Learn, 它存在一种框架, 这种框架的特征是万物皆需NumPy。
交叉验证
如果你平时不怎么去用、或者不去用 CV, 那你可能感觉不到这次更新所带来的一些提速的效果。但是对于大多数从事肃建模方面工作的开发者这些人来说的话, 交叉验证这一块的内容, 一直以来都是属于那些能够让 GPU, 也就是图形处理器, 失去性能的所谓杀手级别的这种东西的表现形式和情况存在的。
在旧版本当中, 就算你的基础模型是在 GPU 上训练的, -Learn 的编排逻辑还是会把数组转回 NumPy, 然后在 CPU 上去重新计算那些指标。
因为要搬来搬去还要在 CPU 上操作, 时间都白白浪费了, 不过 Array API 加进来之后, 能让这种循环基本闭环, 直接在 GPU 内部运行。
开启方式与限制
启用这项特性的时候, 您是需要去把下面的那些配置项全都完成的。要是中间有不管是因为什么原因漏掉任何一个步骤的话, 这个程序就都会在不发出任何警告声音的情况下, 悄悄地把运行方式退回到 NumPy 模式。
需要对环境变量进行设置, 这个操作必须在导入 SciPy 或 -Learn 之前完成。
import os
os.environ["SCIPY_ARRAY_API"] = "1"
配置 -Learn 内部开关:
from sklearn import set_config
set_config(array_api_dispatch=True)
目前在这一点上还存在一个具体的状况, 那就是对cuDF的支持并不具备。可是你仍然能够利用cuDF来实现数据的加载操作和处理步骤, 只是需要在把数据送入模型之前, 一定要保证输入的内容处于一种类似数组的状态。
这就意味着对于那些带有类别性质的特征, 你需要自己去进行编码处理, 同时也不再能够依靠/cuDF这个工具所提供的通过数据类型来自动识别的功能了。
基于 GPU 的 交叉验证
下面, 我们给出了一个运行五次分层交叉验证的示例。为了让完整的链条留在图形处理器上面, 我们对内容做一点小的封装, 并且结合 cuML 的指标计算。
import os
os.environ['SCIPY_ARRAY_API'] = '1'
import cupy as cp
import cudf
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.metrics import make_scorer
from cuml.metrics import roc_auc_score
from xgboost import XGBClassifier
from sklearn import set_config
set_config(array_api_dispatch=True)
# 加载数据并进行简单的预处理
X = cudf.read_csv('/kaggle/input/playground-series-s5e12/train.csv').set_index('id')
y = X.pop('diagnosed_diabetes').astype(int)
# 类别特征编码处理
cat_cols = [c for c in X.columns if X[c].dtype == 'object']
X = X.astype({c: 'category' for c in cat_cols})
for c in cat_cols:
X[c] = X[c].cat.codes
ft = ['c' if c in cat_cols else 'q' for c in X.columns]
kfold = StratifiedKFold(5, shuffle=True, random_state=0)
# 封装 XGB 以适配 CuPy 预测
class cuXGBClassifier(XGBClassifier):
@property
def classes_(self):
return cp.asarray(super().classes_)
def predict_proba(self, X):
p = self.get_booster().inplace_predict(X)
if p.ndim == 1:
p = cp.column_stack([1 - p, p])
return p
def predict(self, X):
return cp.asarray(super().predict(X))
model = cuXGBClassifier(
enable_categorical=True,
feature_types=ft,
device='cuda',
n_jobs=4,
random_state=0
)
# 执行交叉验证
scores = cross_val_score(
model,
X.values,
y.values,
cv=kfold,
scoring=make_scorer(
roc_auc_score,
response_method="predict_proba"
),
n_jobs=1
)
print(f"{scores.mean():.5f} ± {scores.std():.5f}")
尽管这段代码依然有待于进行相应的调整, 可是它却真正确保了交叉验证的循环过程得以继续在 GPU 这个设备上面运行。
现阶段支持的组件
现在这个叫作 Array API 的东西, 它所能做到的事情的范围, 仍然处在一步一步变大的过程当中。在编号为 1.8.0 的这个版本里, 以下的这些部分, 都已经得到了比较不错的支持。
官方提供的一个基于 的 Ridge 管道示例显示,在处理线性代数密集型任务时,这种配置在 Colab 环境下能比单核 CPU 快出 10 倍左右。
ridge_pipeline_gpu = make_pipeline(
feature_preprocessor,
FunctionTransformer(
lambda x: torch.tensor(
x.to_numpy().astype(np.float32),
device="cuda"
)
),
CalibratedClassifierCV(
RidgeClassifierCV(alphas=alphas),
method="temperature"
),
)
with sklearn.config_context(array_api_dispatch=True):
cv_results = cross_validate(
ridge_pipeline_gpu, features, target
)
总结
你问-Learn 是否已经完全准备好接管 GPU , 答案很显然是没有。但是这个版本的意义在于, 它确实已经向着支持 GPU 的方向迈出了第一步。
现阶段的方式对普通人来说并不友好, 依然显得有点"硬核", 可是对于那些追求极致效率的开发者来说, -Learn 1.8.0 这个版本正在朝这个目标进行推进。