为了账号安全,请及时绑定邮箱和手机立即绑定

如何在多核上使用 RandomState 和 Sklearn RandomizedSearchCV

如何在多核上使用 RandomState 和 Sklearn RandomizedSearchCV

慕工程0101907 2021-09-14 15:32:58
我百思不得其解有关的权利的方式来使用np.random.RandomState与sklearn.model_selection.RandomizedSearchCV在多个内核上运行时。我RandomState用来生成伪随机数,以便我的结果是可重复的。我给出RandomizedSearchCV了一个RandomState和 set的实例,n_jobs=-1以便它使用所有六个内核。在多核上运行会引入异步元素。我预计这会导致在不同的运行中以不同的顺序发出来自不同内核的伪随机数请求。因此,不同的运行应该给出不同的结果,而不是显示可重复性。但事实上,结果是可重复的。对于给定的值n_iter(即从参数空间中抽取的次数),找到的最佳超参数值从一次运行到下一次运行是相同的。如果n_jobs是小于核心数的正数,我也会得到相同的值。具体来说,这里是代码:import numpy as npimport scipy.stats as statsfrom sklearn.datasets import load_irisfrom sklearn.ensemble import GradientBoostingClassifierfrom sklearn.model_selection import RandomizedSearchCV, StratifiedKFold, train_test_split# Use RandomState for reproducibility.random_state = np.random.RandomState(42)# Get data. Split it into training and test sets.iris = load_iris()X, y = iris.data, iris.targetX_train, X_test, y_train, y_test = train_test_split(    X, y, test_size=0.4, random_state=random_state, stratify=y)我有几个问题。尽管存在异步方面,为什么我仍能获得可重现的结果?的文档RandomizedSearchCV说明了该random_state参数:“伪随机数生成器状态用于从可能值列表而不是 scipy.stats 分布中随机均匀采样。” 这是否意味着它不会影响参数空间中的分布?上面的代码是否足以确保可重复性,或者我是否需要设置np.random.seed(),或者编写如下内容:distn_learning_rate = stats.uniform(0.05, 0.2)  distn_learning_rate.random_state = random_state  distn_subsample = stats.uniform(0.8, 0.2)  distn_subsample.random_state = random_state  param_space = {'learning_rate': distn_learning_rate,                 'n_estimators': [50, 100, 200],                 'subsample': distn_subsample}  总的来说,这是设置RandomizedSearchCV再现性的正确方法吗?使用的单个实例RandomState确定,或者我应该使用单独的实例为train_test_split,GradientBoostingClassifier,StratifiedKFold,和RandomizedSearchCV?此外,文档np.random.seed说种子是在RandomState初始化时设置的。这如何与RandomizedSearchCV设置种子相互作用?当n_jobs设置为使用少于所有内核时,我仍然看到所有内核上的活动,尽管每个内核的使用水平会随着内核数量的增加而增加并且经过的时间会减少。这只是 sklearn 和/或 macOS 优化机器使用吗?
查看完整描述

2 回答

?
达令说

TA贡献1821条经验 获得超6个赞

参数候选是在使用ParameterSampler 对象传递给多线程功能之前生成的。因此random_state,对于 RandomizedSearchCV 的可重复性,只有一个就足够了。

注意我说的"reproducibility of RandomizedSearchCV"。对于其中使用的估算器(base_clf此处),每个估算器都应该random_state像您一样携带自己的估算器。

现在谈论a single instance of RandomState,对于顺序代码来说非常好。唯一需要担心的情况是多处理开始时。因此,让我们分析一下程序执行期间发生的步骤。

  1. 您设置了一个RandomState带有种子的对象。它现在有一个状态。

  2. 在内部train_test_split,使用了 a StratifiedShuffleSplit(因为您使用了stratifyparam),它将使用传递的RandomState对象在训练和测试数据中拆分和生成排列。所以RandomState现在的内部状态发生了变化。但它的顺序并没有什么可担心的。

  3. 现在您random_stateskf. 但是fit()RandomizedSearchCV调用in之前不会发生分裂。所以状态不变。

  4. 之后,当search_clf.fit被调用时,会发生以下情况

    1. _run_search()执行,它将使用random_state一次生成所有参数组合(根据给定n_iters)。所以仍然没有多线程的任何部分发生,一切都很好。

    2. evaluate_candidates()叫做。有趣的部分是这样的:

out = parallel(delayed(_fit_and_score)(clone(base_estimator),

                                           X, y,

                                           train=train, test=test,

                                           parameters=parameters,

                                           **fit_and_score_kwargs)

                   for parameters, (train, test)

                   in product(candidate_params,

                              cv.split(X, y, groups)))


    • cv.split()将使用random_state(改变其状态)来生成训练测试分割

    • clone(estimator)将克隆估计器的所有参数,(random_state也)。所以RandomStatefromcv.split对象的改变状态变成了 in 的基本状态estimator

    • 上述两个步骤从父线程(没有异步性)发生多次(拆分次数 x 参数组合次数)。并且每次RandomState克隆原始文件以服务于估算器。所以结果是可重复的。

    • 所以当实际的多线程部分开始时,原先RandomState是没有使用的,但是每个估计器(线程)都会有自己的副本RandomState

    1. 后面的部分parallel(delayed(_fit_and_score)仍然是由父线程处理的顺序。

希望这是有道理的,并回答您的问题。Scikit-learn明确要求用户设置如下:

import numpy as np
np.random.seed(42)

使整个执行可重现,但你正在做的也将做。

我不完全确定您的最后一个问题,因为我无法在我的系统上重现该问题。我有 4 个内核,当我设置n_jobs=23我只看到那些内核为 100% 并保持在 20-30% 左右。我的系统规格:

System:

    python: 3.6.6 |Anaconda, Inc.| (default, Jun 28 2018, 17:14:51)  [GCC 7.2.0]

   machine: Linux-4.15.0-20-generic-x86_64-with-debian-buster-sid


Python deps:

       pip: 18.1

setuptools: 40.2.0

   sklearn: 0.20.1

     numpy: 1.15.4

     scipy: 1.1.0

    Cython: 0.29

    pandas: 0.23.4 


查看完整回答
反对 回复 2021-09-14
?
MYYA

TA贡献1868条经验 获得超4个赞

在它不使用所有 cpu 内核的方面:

我有同样的问题,可以通过做两件事来解决它。

  • 我已经编写了自己的分发类,并意识到由于一个问题,它非常慢。加快速度有帮助。

  • 我设置pre_dispatch了一些合理的东西pre_dispatch=10*os.cpu_count()。我认为问题在于它在开始将内容安装到其他内核之前准备了所有数据。


查看完整回答
反对 回复 2021-09-14
  • 2 回答
  • 0 关注
  • 316 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号