提交新事件

谢谢!您的提交已收到!
糟糕!提交表单时出错了。

提交新闻报道

谢谢!您的提交已收到!
糟糕!提交表单时出错了。

订阅时事通讯

谢谢!您的提交已收到!
糟糕!提交表单时出错了。
Aug 6, 2020

比较 Dask-ML 与 Ray Tune 的模型选择算法

作者

超参数优化是推断无法从数据中学习的模型参数的过程。这个过程通常耗时且耗资源,尤其在深度学习领域。关于此过程的良好描述可以在“调整估算器的超参数”中找到,以及出现的问题在 Dask-ML 的“超参数搜索”文档中有简洁的总结。

有许多库和框架可以解决这个问题。Scikit-Learn 的模块 已被 Dask-MLauto-sklearn 效仿,它们都提供了先进的超参数优化技术。其他不遵循 Scikit-Learn 接口的实现包括 Ray TuneAutoMLOptuna

Ray 最近提供了一个 Ray Tune 的包装器,该包装器模仿了 Scikit-Learn API,名为 tune-sklearn(文档源码)。该库的介绍中提到以下内容

 前沿的超参数调优技术(贝叶斯优化、早期停止、分布式执行)相比网格搜索和随机搜索可以显著加速。 

然而,机器学习生态系统中缺乏一种解决方案,既能让用户利用这些新算法,又能让他们留在 Scikit-Learn API 中。在这篇博客文章中,我们介绍了 tune-sklearn [Ray 的调优库] 来弥合这一差距。Tune-sklearn 是 Scikit-Learn 模型选择模块的直接替代品,具有最先进的优化功能。

 

GridSearchCV 2.0 — 新改进

这个说法不准确:一年多以来,Dask-ML 一直通过 Scikit-Learn 兼容的 API 提供对“前沿超参数调优技术”的访问。为了纠正他们的说法,让我们看看 Ray 的 tune-sklearn 提供的每项功能,并与 Dask-ML 进行比较

 以下是 [Ray 的] tune-sklearn 所提供的: 
       
  1. 与 Scikit-Learn API 的一致性
  2.    
  3. 现代超参数调优技术
  4.    
  5. 框架支持
  6.    
  7. 扩展能力 … [扩展到] 多核甚至多机。
  8.  
 

[Ray 的] Tune-sklearn 也很快

Dask-ML 的模型选择模块具备所有这些功能

     
  • 与 Scikit-Learn API 的一致性:Dask-ML 的模型选择 API 模仿了 Scikit-Learn 模型选择 API。
  •  
  • 现代超参数调优技术:Dask-ML 提供最先进的超参数调优技术。
  •  
  • 框架支持:Dask-ML 模型选择支持许多库,包括 Scikit-Learn、PyTorch、Keras、LightGBM 和 XGBoost。
  •  
  • 扩展能力:Dask-ML 支持分布式调优(怎么可能不支持?)以及大于内存的数据集。

Dask-ML 也很快。在“速度”中,我们展示了 Dask-ML、Ray 和 Scikit-Learn 之间的基准测试

只有解决时间是相关的;所有这些方法产生的模型分数都相似。详情请见“速度”。

现在,让我们详细介绍如何使用 Dask-ML 来获得上述 5 项功能。

与 Scikit-Learn API 的一致性

Dask-ML 与 Scikit-Learn API 保持一致。

以下是如何使用 Scikit-Learn、Dask-ML 和 Ray 的 tune-sklearn 进行超参数优化

## 精简示例;详情请参阅附录
from sklearn.model_selection import RandomizedSearchCV
search = RandomizedSearchCV(model, params, ...)
search.fit(X, y)

from dask_ml.model_selection import HyperbandSearchCV
search = HyperbandSearchCV(model, params, ...)
search.fit(X, y, classes=[0, 1])

from tune_sklearn import TuneSearchCV
search = TuneSearchCV(model, params, ...)
search.fit(X, y, classes=[0, 1])

model 和 params 的定义遵循正常的 Scikit-Learn 定义,详情请参阅附录

显然,Dask-ML 和 Ray 的 tune-sklearn 都兼容 Scikit-Learn。现在我们来看看每种搜索的表现和配置方式。

现代超参数调优技术

Dask-ML 在 Scikit-Learn 接口中提供最先进的超参数调优技术。

Ray 的 tune-sklearn 的介绍提出了这个说法

 tune-sklearn 是唯一允许您通过简单地切换几个参数即可轻松利用贝叶斯优化、HyperBand 和其他优化技术的 Scikit-Learn 接口。

超参数优化的最先进技术目前是“Hyperband”。Hyperband 通过一种原则性的早期停止方案减少了所需的计算量;除此之外,它与 Scikit-Learn 流行的 RandomizedSearchCV 相同。

Hyperband 有效。因此,它非常流行。自 2016 年 Li 等人引入 Hyperband 以来,该论文已被引用超过 470 次,并已在许多不同的库中实现,包括 Dask-MLRay Tunekeras-tuneOptunaAutoML1 以及 微软的 NNI。原始论文显示,相比所有相关实现,Hyperband 有相当显著的改进2,并且这种显著改进在后续工作中也持续存在3。以下是 Hyperband 的一些说明性结果

 除了“random2x”执行两倍的工作量外,所有算法都配置为执行相同的工作量。“hyperband (finite)”类似于 Dask-ML 的默认实现,而“bracket s=4”类似于 Ray 的默认实现。“random”是随机搜索。SMAC4、spearmint5 和 TPE6 是流行的贝叶斯算法。

Hyperband 毫无疑问是一种“前沿”超参数优化技术。Dask-ML 和 Ray 都提供了该算法的 Scikit-Learn 实现,它们依赖于相似的实现方式,Dask-ML 的实现还有一个配置经验法则。Dask-ML 和 Ray 的文档都鼓励使用 Hyperband。

Ray 确实支持在名为贝叶斯抽样的技术之上使用其 Hyperband 实现。这改变了模型初始化的超参数抽样方案。这可以与 Hyperband 的早期停止方案结合使用。将此选项添加到 Dask-ML 的 Hyperband 实现是 Dask-ML 未来的工作。

框架支持

Dask-ML 模型选择支持许多库,包括 Scikit-Learn、PyTorch、Keras、LightGBM 和 XGBoost。

Ray 的 tune-sklearn 支持这些框架

 tune-sklearn 主要用于调优 Scikit-Learn 模型,但它也支持并提供了许多其他具有 Scikit-Learn 包装器的框架的示例,例如 Skorch (Pytorch)、KerasClassifiers (Keras) 和 XGBoostClassifiers (XGBoost)。

显然,Dask-ML 和 Ray 都支持许多相同的库。

然而,Dask-ML 和 Ray 都有一些限制。某些库不提供 partial_fit 的实现7,因此并非所有现代超参数优化技术都能提供。下面是比较不同库及其在 Dask-ML 模型选择和 Ray 的 tune-sklearn 中的支持情况的表格

           模型库      Dask-ML 支持      Ray 支持      Dask-ML: 早期停止?      Ray: 早期停止?                  Scikit-Learn      ✔      ✔      ✔*      ✔*              PyTorch (通过 Skorch)      ✔      ✔      ✔      ✔              Keras (通过 SciKeras)      ✔      ✔      ✔**      ✔**              LightGBM      ✔      ✔      ❌      ❌              XGBoost      ✔      ✔      ❌      ❌      

* 仅适用于实现 partial_fit 的模型
** 感谢 Dask 开发者围绕scikeras#24所做的工作。

以此衡量,Dask-ML 和 Ray 模型选择在框架支持方面具有相同的水平。当然,Dask 通过 Dask-ML 的 xgboost 模块dask-lightgbm 与 LightGBM 和 XGBoost 有间接集成。

扩展能力

Dask-ML 支持分布式调优(怎么可能不支持?),也就是在多机/多核上的并行化。此外,它还支持大于内存的数据。

 [Ray 的] Tune-sklearn 利用 Ray Tune(一个用于分布式超参数调优的库)来高效且透明地在多核甚至多机上并行化交叉验证。

自然地,Dask-ML 也能扩展到多核/多机,因为它依赖于 Dask。Dask 对不同的部署选项有广泛支持,范围从您的个人电脑到超级计算机。Dask 极有可能在您可用的任何计算系统上工作,包括 Kubernetes、SLURM、YARN 和 Hadoop 集群,以及您的个人电脑。

Dask-ML 的模型选择也能扩展到大于内存的数据集,并经过了彻底测试。Ray 中对大于内存数据的支持未经测试,并且没有详细说明如何在 PyTorch/Keras 中使用 Ray Tune 与分布式数据集实现的示例。

此外,我还对 Dask-ML 的模型选择模块进行了基准测试,以查看 Dask Worker 数量如何影响解决时间,详见“使用 Dask 进行更好更快的超参数优化”。也就是说,达到特定精度所需的时间如何随 Worker 数量 $P$ 扩展?起初,它会像 $1/P$ 那样扩展,但当 Worker 数量很大时,串行部分将根据阿姆达尔定律决定解决时间。简而言之,我发现 Dask-ML 的 HyperbandSearchCV 在特定搜索中,加速效果在大约 24 个 Worker 时开始饱和。

速度

Dask-ML 和 Ray 都比 Scikit-Learn 快得多。

Ray 的 tune-sklearn 在介绍中运行了一些基准测试,使用了 Scikit-Learn 和 Dask-ML 中的 GridSearchCV 类。一个更公平的基准测试应该使用 Dask-ML 的 HyperbandSearchCV,因为它与 Ray 的 tune-sklearn 中的算法几乎相同。具体来说,我感兴趣的是比较这些方法

     
  • Scikit-Learn 的 RandomizedSearchCV。这是一个流行的实现,我使用自定义模型对其进行了引导。
  •  
  • Dask-ML 的 HyperbandSearchCV。这是 RandomizedSearchCV 的一种早期停止技术。
  •  
  • Ray tune-sklearn 的 TuneSearchCV。这是一种与 HyperbandSearchCV 略有不同的早期停止技术。

每次搜索都配置为执行相同的任务:抽样 100 个参数并训练不超过 100 个“周期”或数据遍历。8 每个估算器都按照其相应文档的建议进行配置。每次搜索使用 8 个 Worker 和一个交叉验证分割,partial_fit 调用处理 50,000 个示例需要一秒钟。完整的设置可以在附录中找到。

以下是每个库完成相同搜索所需的时间

值得注意的是,我们没有为了这次基准测试改进 Dask-ML 代码库,而是运行了过去一年中的代码。9 尽管如此,有偏见的基准测试中的其他因素也可能悄悄进入了这次基准测试。

显然,与 Scikit-Learn 相比,Ray 和 Dask-ML 在 8 个 Worker 下提供了相似的性能。值得称赞的是,Ray 的实现在 8 个 Worker 下比 Dask-ML 快约 15%。我们怀疑这种性能提升来自于 Ray 实现了 Hyperband 的异步变体。我们应该调查 Dask 和 Ray 之间的这种差异,以及它们如何平衡权衡,即 FLOPs 数量与解决时间。这会随 Worker 数量而变化:如果只使用单个 Worker,Hyperband 的异步变体不会带来任何好处。

Dask-ML 在串行环境或 Worker 数量较少时能快速达到分数。Dask-ML 优先拟合高分模型:如果需要拟合 100 个模型而只有 4 个 Worker 可用,Dask-ML 会选择得分最高的模型。这在串行环境中最为相关10;请参阅“使用 Dask 进行更好更快的超参数优化”获取基准测试。此功能在此基准测试中被省略,该测试仅关注解决时间。

结论

Dask-ML 和 Ray 在模型选择方面提供相同的功能:具有 Scikit-Learn 兼容 API 的最先进功能,并且两种实现都对不同框架有相当广泛的支持,并依赖于可以扩展到许多机器的后端。

此外,Ray 的实现为进一步开发提供了动力,特别是在以下方面

     
  1. 增加对更多库的支持,包括 Keras (dask-ml#696,dask-ml#713, scikeras#24)。SciKeras 是 Keras 的一个 Scikit-Learn 包装器,(现在)可以与 Dask-ML 模型选择一起工作,因为 SciKeras 模型实现了 Scikit-Learn 模型 API。
  2.  
  3. 更好地记录 Dask-ML 支持的模型(dask-ml#699)。Dask-ML 支持任何实现 Scikit-Learn 接口的模型,并且有 Keras、PyTorch、LightGBM 和 XGBoost 的包装器。现在,Dask-ML 的文档突出强调了这一事实。

Ray 的实现也帮助激发和明确了未来的工作。Dask-ML 应该包含以下实现

     
  1. 一个类似于 Ray 和 BOHB 的 Hyperband 实现的贝叶斯抽样方案 (dask-ml#697)。
  2.  
  3. HyperbandSearchCV 的一种配置,非常适合探索性超参数搜索。一个初始实现在dask-ml#532 中,应该与 Ray 进行基准测试。

幸运的是,所有这些开发工作都是直接的修改,因为 Dask-ML 模型选择框架相当灵活。

感谢 Tom AugspurgerMatthew RocklinJulia SignellBenjaminZaitlen 提供的反馈、建议和编辑。

附录

基准测试设置

这是 Dask-ML、Scikit-Learn 和 Ray 之间基准测试的完整设置。完整详情可在stsievert/dask-hyperband-comparison 找到。

我们创建一个虚拟模型,partial_fit 调用处理 50,000 个示例需要 1 秒钟。这适用于本次基准测试;我们只关注完成搜索所需的时间,而不是模型表现的好坏。Scikit-learn、Ray 和 Dask-ML 在选择要评估的超参数方面方法非常相似;它们的区别在于早期停止技术。

from scipy.stats import uniform
from sklearn.model_selection import make_classification
from benchmark import ConstantFunction # custom module

# 该模型会先休眠 \`latency * len(X)\` 秒
# 然后报告分数为 \`value\`。
model = ConstantFunction(latency=1 / 50e3, max_iter=max_iter)

params = {"value": uniform(0, 1)}
# 这个模拟数据集模仿了 MNIST 数据集
X_train, y_train = make_classification(n_samples=int(60e3), n_features=784)

此模型训练 100 个周期(即数据遍历 100 次)需要 2 分钟。详细信息可以在 stsievert/dask-hyperband-comparison 找到。

我们将搜索配置为使用 8 个 Worker 和一个交叉验证分割

from sklearn.model_selection import RandomizedSearchCV, ShuffleSplit
split = ShuffleSplit(test_size=0.2, n_splits=1)
kwargs = dict(cv=split, refit=False)

search = RandomizedSearchCV(model, params, n_jobs=8, n_iter=n_params, **kwargs)
search.fit(X_train, y_train)  # 20.88 分钟

from dask_ml.model_selection import HyperbandSearchCV
dask_search = HyperbandSearchCV(
   model, params, test_size=0.2, max_iter=max_iter, aggressiveness=4
)

from tune_sklearn import TuneSearchCV
ray_search = TuneSearchCV(
   model, params, n_iter=n_params, max_iters=max_iter, early_stopping=True, **kwargs
)

dask_search.fit(X_train, y_train)  # 2.93 分钟
ray_search.fit(X_train, y_train)  # 2.49 分钟

完整示例用法

from sklearn.linear_model import SGDClassifier
from scipy.stats import uniform, loguniform
from sklearn.datasets import make_classification
model = SGDClassifier()
params = {"alpha": loguniform(1e-5, 1e-3), "l1_ratio": uniform(0, 1)}
X, y = make_classification()

from sklearn.model_selection import RandomizedSearchCV
search = RandomizedSearchCV(model, params, ...)
search.fit(X, y)

from dask_ml.model_selection import HyperbandSearchCV
HyperbandSearchCV(model, params, ...)
search.fit(X, y, classes=[0, 1])

from tune_sklearn import TuneSearchCV
search = TuneSearchCV(model, params, ...)
search.fit(X, y, classes=[0, 1])

 

       
  1.      他们在 HpBandSter 中的 Hyperband 实现包含在 Auto-PyTorchBOAH 中。    
  2.    
  3.      参见“Hyperband:一种基于 Bandit 的新型超参数优化方法”中的图 4、7 和 8。    
  4.    
  5.      参见BOHB 论文的图 1 以及一篇增强现实公司的论文    
  6.    
  7.      SMAC 在“用于通用算法配置的序贯模型优化”中描述,并且在 AutoML 中可用。    
  8.    
  9.      Spearmint 在“机器学习算法的实用贝叶斯优化”中描述,并且在 HIPS/spearmint 中可用。    
  10.    
  11.      TPE 在“超参数优化算法”的第 4 节中描述,并且通过 Hyperopt 可用。    
  12.    
  13.      摘自Ray 的 README.md:“如果估算器不支持 partial_fit,将显示警告,表明无法进行早期停止,并且它将仅在 Ray 的并行后端上运行交叉验证。”    
  14.    
  15.      我选择对随机搜索而不是网格搜索进行基准测试,因为随机搜索产生更好的结果,而网格搜索需要估计每个参数的重要性;更多详情请参阅 Bergstra 和 Bengio 的“超参数优化的随机搜索”。    
  16.    
  17.      尽管在 dask-ml#527 中有相关的实现。    
  18.    
  19.      因为如果 Worker 数量是无限的,优先级就没有意义。    
  20.