NVIDIA cuML `cuml.solvers` 模块深度解析:CD、QN、SGD 三大 GPU 线性求解器实战指南
2026/9/18 11:14:03 网站建设 项目流程

NVIDIA cuMLcuml.solvers模块深度解析:CD、QN、SGD 三大 GPU 线性求解器实战指南

【免费下载链接】cumlNVIDIA cuML: GPU-Accelerated Machine Learning项目地址: https://gitcode.com/GitHub_Trending/cu/cuml

本篇指南聚焦 NVIDIA cuML(GPU-Accelerated Machine Learning)中位于python/cuml/cuml/solvers/的优化求解器模块,以官方 API 文档 docs/source/api/cuml.solvers.rst 为骨架,系统讲解其暴露的三个核心类——坐标下降(CD)、拟牛顿法(QN)与随机梯度下降(SGD)的算法原理、全部超参数语义、输入输出约束与底层 C++ 调用链。读完本文,你将能根据数据规模、稀疏性与正则化需求,为回归、逻辑回归与 SVM 类任务正确选择并调优 cuML 求解器,并理解它们如何被LogisticRegressionElasticNetMBSGD等高层估计器复用。

模块概览:cuml.solvers暴露了什么

cuml.solvers是一个 Cython 封装的底层优化求解器集合,其 Python 导出非常简单直接,见 python/cuml/cuml/solvers/init.py:

from cuml.solvers.cd import CD from cuml.solvers.qn import QN from cuml.solvers.sgd import SGD

API 文档 cuml.solvers.rst 通过automoduleautosummary指令,将CDQNSGD三个类的完整 docstring(参数、属性、示例)自动渲染成 API 参考页。除此之外,这三个类还会在顶层命名空间再次导出,见 python/cuml/cuml/init.py,因此你也可以直接from cuml import CD, QN, SGD

模块目录结构如下:

文件内容
cd.pyxCD类与fit_cd底层函数,坐标下降求解线性/岭/套索/弹性网
qn.pyxQN类与fit_qn底层函数,L-BFGS / OWL-QN
sgd.pyxSGD类与fit_sgd底层函数,随机梯度下降
cd_mg.pyx多 GPU(MNMG)版坐标下降
qn.pxdqn_params等 C 结构体的 Cython 声明

三个求解器共享同一套输入约定:接受 numpy 数组、cuPy 数组或 cuDF DataFrame/Series 作为输入(QN 额外支持 CSR 稀疏输入),内部统一转换为列主序(Fortran order)的 float32/float64 稠密矩阵后交给 C++ 层计算。

CD:沿坐标方向迭代的弹性网求解器

算法定位与目标函数

坐标下降(Coordinate Descent)是最常见的优化算法之一:每轮迭代固定其它坐标,只沿单个坐标方向做精确极小化,从而逐步逼近全局最小值。cuML 的CD目前只支持线性回归,并可作为岭回归(Ridge)、套索(Lasso)与弹性网(ElasticNet)惩罚的求解器,其最小化目标在 cpp/include/cuml/solvers/solver.hpp 的注释中给出:

f(coef) = 1/2 * || labels - input * coef ||^2 + 1/2 * alpha * (1 - l1_ratio) * ||coef||^2 + alpha * l1_ratio * ||coef||_1

即平方损失 + L2 项(Ridge)+ L1 项(Lasso)的加权组合,l1_ratio正是弹性网的混合系数。

完整参数说明

CD类的全部超参数定义于 cd.pyx 的 docstring 与__init__中,默认值与语义如下:

参数默认值说明
loss'squared_loss'目前唯一支持的损失函数,预测阶段使用线性回归
alpha0.0001正则化强度常数;alpha=0等价于普通最小二乘(可由LinearRegression求解)
l1_ratio0.15弹性网混合参数,取值范围0 <= l1_ratio <= 10时为纯 L2 惩罚,1时为纯 L1 惩罚,中间值为 L1/L2 组合
fit_interceptTrueTrue时模型自动修正 y 的全局均值;为False时要求数据已中心化
max_iter1000训练时遍历整个数据集的轮数上限
tol1e-3优化容差:当参数更新量小于tol时求解器停止
shuffleTrueTrue时每轮随机挑选一个系数更新,而非按特征顺序循环;文档指出在tol高于1e-4时通常能显著加速收敛
verboseFalse日志级别,需取cuml.common.logger.level_*常量
output_typeNone结果输出类型('input'/'cupy'/'numpy'/'cudf'/'pandas'),None时使用模块级cuml.global_settings.output_type

拟合完成后可通过coef_intercept_n_iter_属性获取系数、截距与实际迭代轮数。

实战示例

以下示例取自CD的官方 docstring(cd.pyx),演示用 cuDF + cuPy 数据训练一个无正则化的坐标下降模型:

import cupy as cp import cudf from cuml.solvers import CD cd = CD(alpha=0.0) X = cudf.DataFrame() X['col1'] = cp.array([1, 1, 2, 2], dtype=cp.float32) X['col2'] = cp.array([1, 2, 2, 3], dtype=cp.float32) y = cudf.Series(cp.array([6.0, 8.0, 9.0, 11.0], dtype=cp.float32)) cd.fit(X, y) print(cd.coef_) # 0 1.001... 1 1.998... dtype: float32 print(cd.intercept_) # 3.00... X_new = cudf.DataFrame() X_new['col1'] = cp.array([3, 2], dtype=cp.float32) X_new['col2'] = cp.array([5, 5], dtype=cp.float32) preds = cd.predict(X_new) # 15.997... 14.995...

底层调用链

CD.fit内部调用fit_cd(cd.pyx),该函数完成参数校验(loss必须是'squared_loss'alpha >= 0)、输入检查(dtype 限float32/float64、列主序、至少 2 个样本)后,在nogil块中调用 C++ 入口cdFit,其 float/double 两个重载声明于 solver.hpp,实现位于 cpp/src/solver/solver.cu。C++ 层cdFit会校验loss == 0(即SQRD_LOSS),并转发到模板实现cd.cuh中的cdFit<float/double>,预测阶段则走cdPredict(同样在nogil中执行并handle.sync()同步流)。

值得注意的是,高层估计器 python/cuml/cuml/linear_model/elastic_net.py 直接复用了fit_cdfit_qn:其solver参数取'auto'时,稠密输入走'cd',稀疏输入走'qn'——这正是CD作为"求解器组件"被组合进完整估计器的典型模式。

QN:L-BFGS 与 OWL-QN 的统一入口

算法定位

拟牛顿法(Quasi-Newton)通过迭代逼近目标函数的极值点来优化代价函数。cuML 的QN类依据是否启用 L1 正则化,在两种经典算法间自动切换(见 qn.pyx 的 docstring):

  • 存在 L1 正则化(l1_strength > 0)时,运行Orthant-Wise Limited Memory Quasi-Newton(OWL-QN)
  • 否则运行Limited Memory BFGS(L-BFGS)

两种方法分别引用 Nocedal & Wright《Numerical Optimization》(1999) 与 Andrew, Gao (ICML 2007) 的公开文献实现。OWL-QN 专门用于处理 L1 惩罚产生的非光滑最优点。

损失函数支持矩阵

QN支持的损失在 qn.pyx 中以SUPPORTED_LOSSES字典映射到 C 层枚举(见 cpp/include/cuml/linear_model/qn.h):

Python 字符串对应损失适用任务目标取值
'sigmoid'(默认)QN_LOSS_LOGISTIC二分类逻辑回归{0, 1}
'logistic'QN_LOSS_LOGISTIC二分类逻辑回归(别名){0, 1}
'softmax'QN_LOSS_SOFTMAX多分类逻辑回归{0, 1, ...}
'l2'/'normal'QN_LOSS_SQUAREDL2 回归实数
'l1'QN_LOSS_ABSL1 回归实数
'svc_l1'QN_LOSS_SVC_L1线性 SVM(hinge){0, 1}
'svc_l2'QN_LOSS_SVC_L2线性 SVM(squared-hinge){0, 1}
'svr_l1'QN_LOSS_SVR_L1支持向量回归(epsilon-insensitive)实数
'svr_l2'QN_LOSS_SVR_L2支持向量回归(epsilon-insensitive 平方)实数

init_qn_params(qn.pyx)中还有两条自动推导规则值得注意:loss='logistic'在多分类场景(n_classes > 2)会被自动提升为'softmax'loss='softmax'要求类别数大于 2,而'logistic'/'svc_l1'/'svc_l2'要求恰好二分类,否则抛出ValueError

完整参数说明

QN的超参数比CD更丰富,默认值见 qn.pyx:

参数默认值说明
loss'sigmoid'见上方损失表
fit_interceptTrue是否拟合截距;False要求数据已中心化
l1_strength0.0L1 正则化强度;非零时启用 OWL-QN,否则 L-BFGS。是否除以样本数由penalty_normalized控制
l2_strength0.0L2 正则化强度,同样受penalty_normalized控制
max_iter1000求解器最大迭代轮数
tol1e-4梯度停止准则:norm(current_loss_grad) <= tol * max(current_loss, tol)时停止
deltaNone损失变化停止准则:abs(current_loss - previous_loss) <= delta * max(current_loss, tol)None时取tol * 0.010时禁用该检查
linesearch_max_iter50每轮外层迭代中线搜索(内循环)的最大次数
lbfgs_memory5L-BFGS 逆 Hessian 近似的秩,内存开销为O(lbfgs_memory * D)
warm_startFalseTrue时复用上一次fit的解作为初始化
penalty_normalizedTrueTrue时 L1/L2 参数除以样本数,用于对齐 sklearn 等其它实现的行为
verboseFalse日志级别
output_typeNone输出类型

拟合后的属性包括coef_(形状(n_classes, n_features))、intercept_n_classes_n_iter_objective(最终目标函数值)。

与 sklearn / scipy 的兼容性注意

docstring(qn.pyx)明确指出了三处跨框架差异,是迁移调参时的关键知识:

  1. tol的停止条件(norm(grad) <= tol * max(loss, tol))与 scipyL-BFGS-Bgtol条件(norm(projected_grad) <= gtol)略有不同;
  2. sklearn 的LogisticRegression使用损失之和,而 cuML 使用损失平均值,因此 sklearn 的损失通常约为 cuML 的sample_size倍——若希望 cuML 求解器不比 sklearn 提前停止,可把tol除以样本数;
  3. delta对应 scipy 的ftol(scipy 默认极小值2.2e-9且 sklearn 未暴露),该条件用于防止求解器在线搜索步长过小时"原地踏步/锯齿震荡";设delta = 0可确保 cuML 不比 sklearn 提前停止。

实战示例与底层调用链

官方示例(qn.pyx)演示二分类逻辑回归:

import cupy as cp from cuml.solvers import QN X = cp.array([[1, 1], [1, 2], [2, 2], [2, 3]]) y = cp.array([0, 0, 1, 1]) solver = QN(loss="sigmoid").fit(X, y) solver.predict(X) # array([0, 0, 1, 1], dtype=int32)

调用链上,QN.fitfit_qn(qn.pyx)→init_qn_params填充qn_params结构体(字段定义见 cpp/include/cuml/linear_model/qn.h,含losspenalty_l1penalty_l2grad_tolchange_tolmax_iterlinesearch_max_iterlbfgs_memoryverbosefit_interceptpenalty_normalized)→ 依据输入是否为 CSR 稀疏矩阵,分别调用 C++ 模板qnFit(稠密)或qnFitSparse(稀疏,见 cpp/include/cuml/linear_model/glm.hpp)。此外warm_start=True时会把上一次的coef_intercept_拼接后作为初始点传入。高层估计器 python/cuml/cuml/linear_model/logistic_regression.py 正是通过fit_qn实现 GPU 逻辑回归。

SGD:面向大规模数据的随机梯度下降

算法定位

随机梯度下降通过沿梯度方向迭代步进优化代价函数,非常适合精确解难以求得的大规模问题。cuML 的SGD当前可用于线性回归、岭回归与 SVM 模型(见 sgd.pyx)。与QN不同,SGD目前仅支持二分类——fit_sgd在检测到超过 2 个类别时会抛出ValueError(sgd.pyx)。

完整参数说明

SGD的超参数定义于 sgd.pyx,比CD多出批量、学习率策略等维度:

参数默认值说明
loss'squared_loss''hinge'(线性 SVM)、'log'(逻辑回归)、'squared_loss'(线性回归)
penaltyNone正则化项:'l1'(Lasso)、'l2'(Ridge)、'elasticnet'(L1/L2 加权平均)、None(无惩罚,默认)
alpha0.0001正则化强度常数(校验要求alpha > 0
l1_ratio0.15弹性网混合系数(penalty='elasticnet'时生效)
fit_interceptTrue是否拟合截距
epochs1000遍历整个数据集的轮数
tol1e-3停止准则:current_loss > previous_loss - tol时停止
shuffleTrue每个 epoch 后是否打乱训练数据
eta00.001初始学习率(校验要求eta0 > 0
power_t0.5invscaling学习率策略的指数
batch_size32每个 batch 的样本数
learning_rate'constant''constant'保持学习率不变;'adaptive'在训练损失/验证精度连续n_iter_no_change轮无改善时将学习率除以 5;'invscaling'使用指数衰减
n_iter_no_change5触发adaptive学习率调整的"无改善轮数"
verbose/output_typeFalse/None同前两者

枚举映射与底层调用链

sfit_sgd通过三个 Python 字典把字符串参数映射为整数代码(sgd.pyx):_LEARNING_RATESconstant→1、invscaling→2、adaptive→3)、_LOSSESsquared_loss→0、log→1、hinge→2)、_PENALTIESNone→0、l1→1、l2→2、elasticnet→3)。这些整数在 C++ 层 cpp/src/solver/solver.cu 中又被翻译回ML::lr_typeML::loss_functML::penalty枚举(定义于 cpp/include/cuml/solvers/params.hpp,其中lr_type还包含一个未被 Python 层暴露的OPTIMAL选项),随后调用模板实现sgdFit,并传入handle.get_stream().get()的 CUDA 流以支持异步执行。预测阶段对应sgdPredictsgdPredictBinaryClass(声明见 solver.hpp)。

实战示例

官方示例(sgd.pyx)演示用小批量 SGD 拟合线性回归:

import numpy as np import cudf from cuml.solvers import SGD as cumlSGD X = cudf.DataFrame() X['col1'] = np.array([1, 1, 2, 2], dtype=np.float32) X['col2'] = np.array([1, 2, 2, 3], dtype=np.float32) y = cudf.Series(np.array([1, 1, 2, 2], dtype=np.float32)) pred_data = cudf.DataFrame() pred_data['col1'] = np.asarray([3, 2], dtype=np.float32) pred_data['col2'] = np.asarray([5, 5], dtype=np.float32) cu_sgd = cumlSGD(learning_rate='constant', eta0=0.005, epochs=2000, fit_intercept=True, batch_size=2, tol=0.0, penalty=None, loss='squared_loss') cu_sgd.fit(X, y) cu_pred = cu_sgd.predict(pred_data).to_numpy() print(" cuML intercept : ", cu_sgd.intercept_) # 0.00418... print(" cuML coef : ", cu_sgd.coef_) # 0 0.9841... 1 0.0097... print("cuML predictions : ", cu_pred) # [3.0055... 2.0214...]

高层估计器 mbsgd_classifier.py 与 mbsgd_regressor.py 均直接复用fit_sgd,因此SGD实质上就是 cuML Mini-Batch SGD 分类器/回归器的内核。

三大求解器选型对比

维度CDQNSGD
迭代策略沿单坐标方向精确极小化拟牛顿(近似二阶)随机梯度步进(一阶)
底层算法坐标下降L-BFGS / OWL-QNMini-batch SGD
支持损失squared_loss9 种(分类/回归/SVM/SVR)3 种(回归/逻辑/ hinge)
支持惩罚通过alpha+l1_ratio表达 L1/L2/弹性网独立l1_strength/l2_strengthpenalty+alpha+l1_ratio
稀疏输入不支持(列主序稠密)支持 CSR不支持
分类能力无(纯回归)二分类 + 多分类(softmax)仅二分类
典型上层封装ElasticNet(稠密路径)LogisticRegressionElasticNet(稀疏路径)MBSGDClassifierMBSGDRegressor
收敛停止准则更新量 <tol梯度范数/损失变化双重准则损失不再改善- tol

选择建议(依据上述源码事实推断):追求稠密数据的精确回归解且需要弹性网惩罚,选CD;需要逻辑回归、多分类或 SVM/SVR 损失,或输入为 CSR 稀疏矩阵,选QN;数据规模极大、允许近似解且希望控制 batch 大小与学习率调度,选SGD

测试与工程验证

求解器模块的正确性由仓库测试套件覆盖,主要验证文件包括:

  • python/cuml/tests/test_qn.py:覆盖QN的损失类型、收敛准则、与参考实现的数值一致性;
  • python/cuml/tests/test_sgd.py:覆盖SGD的损失/惩罚/学习率组合与预测;
  • python/cuml/tests/test_elastic_net.py:验证ElasticNet'cd'/'qn'/'auto'求解器下的行为;
  • python/cuml/tests/test_linear_regression.py 与 python/cuml/tests/test_logistic_regression.py:间接回归上述求解器组件;
  • python/cuml/tests/test_lars.py 等其它线性模型测试:验证求解器与 LARS、SGD 等其它算法的交叉一致性。

此外,多 GPU 场景可参考 python/cuml/cuml/dask/solvers/cd.py 与cd_mg.pyx的 Dask 封装,它们把单 GPU 的CD求解能力扩展到多节点环境。

小结

cuml.solvers是 cuML 线性模型体系的地基:CDQNSGD三个类分别对应坐标下降、拟牛顿与随机梯度三类经典优化器,在 Python 侧以一致的参数风格暴露,在 C++ 侧通过 solver.hpp(CD/SGD)与 glm.hpp(QN)提供 float/double 双精度模板实现。理解这三者的损失/惩罚/收敛准则差异,即可在上层LogisticRegressionElasticNetMBSGD估计器中做出有依据的调参决策,也能直接以底层 API 方式构建自定义的 GPU 线性模型。

【免费下载链接】cumlNVIDIA cuML: GPU-Accelerated Machine Learning项目地址: https://gitcode.com/GitHub_Trending/cu/cuml

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询