增加n_jobs对GridSearchCV没有影响

时间:2018-06-22 18:36:04

标签: python multithreading scikit-learn knn

我设置了一个简单的实验,以在通过GridSearchCV运行sklearn KNeighborsClassifier时检查多核CPU的重要性。我得到的结果令我感到惊讶,我想知道我是否误解了多核的好处,或者我做得不好。

2-8个工作之间的完成时间没有差异。怎么来的 ?我注意到“ CPU性能”选项卡上的差异。在第一个单元运行时,CPU使用率为〜13%,而最后一个单元则逐渐增加到100%。我期望它能更快完成。也许不是线性地更快,也就是8个工作将比4个工作快2倍,但要快一点。

这是我的设置方式:

我正在使用jupyter-notebook,单元格是指jupyter-notebook单元格。

我已经加载了MNIST,并在0.05中将3000位的X_play位数字用于测试。

from sklearn.datasets import fetch_mldata
from sklearn.model_selection import train_test_split

mnist = fetch_mldata('MNIST original')

X, y = mnist["data"], mnist['target']

X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
_, X_play, _, y_play = train_test_split(X_train, y_train, test_size=0.05, random_state=42, stratify=y_train, shuffle=True)

在下一个单元格中,我设置了KNN和一个GridSearchCV

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV

knn_clf = KNeighborsClassifier()
param_grid = [{'weights': ["uniform", "distance"], 'n_neighbors': [3, 4, 5]}]

然后我为8个n_jobs值完成了8个单元格。我的CPU是4核8线程的i7-4770。

grid_search = GridSearchCV(knn_clf, param_grid, cv=3, verbose=3, n_jobs=N_JOB_1_TO_8)
grid_search.fit(X_play, y_play)

结果

Parallel(n_jobs=1)]: Done  18 out of  18 | elapsed:  2.0min finished
Parallel(n_jobs=2)]: Done  18 out of  18 | elapsed:  1.4min finished
Parallel(n_jobs=3)]: Done  18 out of  18 | elapsed:  1.3min finished
Parallel(n_jobs=4)]: Done  18 out of  18 | elapsed:  1.3min finished
Parallel(n_jobs=5)]: Done  18 out of  18 | elapsed:  1.4min finished
Parallel(n_jobs=6)]: Done  18 out of  18 | elapsed:  1.4min finished
Parallel(n_jobs=7)]: Done  18 out of  18 | elapsed:  1.4min finished
Parallel(n_jobs=8)]: Done  18 out of  18 | elapsed:  1.4min finished

第二项测试

随机森林分类器的使用要好得多。测试大小为0.530000张图片。

from sklearn.ensemble import RandomForestClassifier

rf_clf = RandomForestClassifier()
param_grid = [{'n_estimators': [20, 30, 40, 50, 60], 'max_features': [100, 200, 300, 400, 500], 'criterion': ['gini', 'entropy']}]

Parallel(n_jobs=1)]: Done 150 out of 150 | elapsed: 110.9min finished
Parallel(n_jobs=2)]: Done 150 out of 150 | elapsed: 56.8min finished
Parallel(n_jobs=3)]: Done 150 out of 150 | elapsed: 39.3min finished
Parallel(n_jobs=4)]: Done 150 out of 150 | elapsed: 35.3min finished
Parallel(n_jobs=5)]: Done 150 out of 150 | elapsed: 36.0min finished
Parallel(n_jobs=6)]: Done 150 out of 150 | elapsed: 34.4min finished
Parallel(n_jobs=7)]: Done 150 out of 150 | elapsed: 32.1min finished
Parallel(n_jobs=8)]: Done 150 out of 150 | elapsed: 30.1min finished

1 个答案:

答案 0 :(得分:5)

有一些原因可能是这种行为的原因

  • 随着数量的增加在线程数量方面,初始化和释放每个线程会产生明显的开销。我在i7 7700HQ上运行了您的代码,每次增加n_job时都会看到以下行为
    • n_job=1n_job=2时,每个线程的时间(通过GridSearchCV对模型进行完全训练并进行测试的每个模型评估的时间)为2.9s(总时间约为2分钟)
    • n_job=3时,时间为3.4秒(总时间为1.4分钟)
    • n_job=4时,时间为3.8秒(总时间为58秒)
    • n_job=5时,时间为4.2秒(总时间为51秒)
    • n_job=6时,时间为4.2秒(整个时间约为49秒)
    • n_job=7时,时间为4.2秒(整个时间约为49秒)
    • n_job=8时,时间为4.2秒(整个时间约为49秒)
  • 现在您可以看到,每个线程的时间增加了,但总的时间似乎减少了(尽管超过n_job=4 the different was not exactly linear) and remained constained with n_jobs> = 6`,这是由于以下事实造成的:释放线程。请参见this github issuethis issue

  • 此外,可能还存在其他瓶颈,例如数据量太大,无法同时广播到所有线程,线程在RAM上抢占(或其他资源等),如何将数据压入每个线程线程等。

  • 我建议您阅读有关Ahmdal定律的信息,该定律指出通过公式给出的并行化可以实现加速的理论界限 enter image description here 图片来源:Ahmdal's Law : Wikipedia

  • 最后,这可能是由于数据大小以及您用于训练的模型的复杂性所致。

这里a blog post解释了有关多线程的相同问题。