如何控制使用 scikit-learn 的 joblib 启动的进程数量?

问题描述 投票:0回答:1

背景 当使用 scikit-learn 在大型数据集上执行极其并行的任务时,在高性能计算 (HPC) 环境中的集群上执行此操作会很方便。 Scikit-learn 允许用户通过 n_jobs 参数指定并行使用的核心数量,从而提供对并行化的支持。原则上,这应该可以轻松地将分析管道中使用的核心数量与 HPC 环境中的调度程序请求的处理器数量进行匹配。

问题 IT 部门向我指出,每个作业运行的进程数量(即 7)超过了我请求的处理器数量(即 2),尽管我实际上已将 scikit-learn 的 n_job 参数设置为 2。据了解,结果是这些进程现在互相阻止使用有限的计算资源(我想象有点像音乐椅),从而产生不必要的开销并使集群的使用效率低下。通过运行

pstree PID
检测到线程数。

问题 额外的5个进程从哪里来?如何控制 scikit-learn 中的进程数量以匹配实际分配给集群作业的处理器数量?

代码示例 我创建了一个小示例来说明这种行为(Python 3.6.8、numpy 1.18.1、scikit-learn 0.20.3)

#!/usr/bin/env python
import numpy as np
import os
import time
from sklearn.model_selection import permutation_test_score
from sklearn import datasets, svm

n_folds = 3
n_perm = 12000
n_jobs = 2  # The number of tasks to run in parallel
n_cpus = 2  # Number of CPUs assigned to this process

pid = os.getpid()
print("PID: %i" % pid)

print("loading iris dataset")
X, y = datasets.load_iris(return_X_y=True)

# Control which CPUs are made available for this script
cpu_arg = ''.join([str(ci) + ',' for ci in list(range(n_cpus))])[:-1]
cmd = 'taskset -cp %s %i' % (cpu_arg, pid)
print("executing command '%s' ..." % cmd)
os.system(cmd)

t1 = time.time()
res = permutation_test_score(svm.SVC(kernel='linear'), X, y, cv=n_folds,
                             n_permutations=n_perm, n_jobs=n_jobs,
                             verbose=3)
t_delta = time.time() - t1
ips = n_perm / t_delta
print("number of iterations per second: %.02f it/s" % ips)

当使用

htop
检查时,似乎正是我通过
n_jobs=2
n_cpus=2
请求的 CPU 数量以 100% 运行 - 在本例中是两个。然而,当我使用
pstree PID
查看线程时,我可以看到 6 个进程正在运行,而不是预期的两个进程。

仅请求

n_jobs=1
n_cpus=1
会导致
htop
显示一个 CPU 100% 繁忙,而
pstree PID
同样仅显示单个处理正在运行,如预期的那样。

其他信息和进一步的尝试

有关我的操作系统的一些信息,如

uname -a

Linux COMPUTERNAME 4.15.0-96-generic #97-Ubuntu SMP Wed Apr 1 03:25:46 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

...以及关于 CPU 的信息,如下

lscpu | grep -e CPU -e core
:

CPU op-mode(s):      32-bit, 64-bit
CPU(s):              8
On-line CPU(s) list: 0-7
Thread(s) per core:  2
CPU family:          6
Model name:          Intel(R) Xeon(R) W-2123 CPU @ 3.60GHz
CPU MHz:             1200.050
CPU max MHz:         3900,0000
CPU min MHz:         1200,0000
NUMA node0 CPU(s):   0-7

我的示例代码现在允许使用

taskset
命令控制可用于代码执行的 CPU 数量。因此,我可以分别操纵 scikit-learn 中请求并行运行的任务数量 (
n_jobs
) 和可用 CPU 的数量 (
n_cpus
)。这使我能够相互比较四种场景:

  1. n_jobs=1
    n_cpus=1
    :360.24 it/s,
    htop
    显示1个CPU繁忙,
    pstree PID
    显示1个线程正在运行。
  2. n_jobs=2
    n_cpus=2
    :658.40 it/s,
    htop
    显示两个CPU繁忙,
    pstree PID
    显示6个线程正在运行。
  3. n_jobs=2
    n_cpus=1
    :336.80 it/s,
    htop
    显示 1 个 CPU 忙碌,
    pstree PID
    显示 6 个线程正在运行。
  4. n_jobs=1
    n_cpus=2
    :358.60 it/s,
    htop
    显示1个CPU繁忙,
    pstree PID
    显示1个线程正在运行。

似乎

pstree
始终取决于 scikit-learn API 中请求的线程数。
htop
显示的活动 CPU 数量是可用于脚本 且正在使用的 CPU 数量。因此只有场景 2 会导致两个 CPU 繁忙。同样,如果 CPU 可用且已使用(也是场景 2),则处理速度(以每秒迭代次数衡量)只会在并行情况下提高。至关重要的是,根据 pstree,线程数量为 6,因此大于 CPU 数量,但这并不表明它们在有限的 CPU 上相互干扰。只有场景 3 表明,当请求两个作业但只有一个 CPU 可用时,处理速度显得较慢。这比场景 1 慢。
我开始想知道 

pstree

是否真的是并行处理效率的良好诊断以及它与

htop
有何不同。
    

python scikit-learn hpc joblib
1个回答
0
投票

from joblib import parallel_backend</code> with parallel_backend("threading", n_jobs=1): model.fit(X,y)

您可能还需要设置 scikit-learn 模型的 n_jobs:

import sklearn.neighbors.KNeighborsClassifier as KNN model = KNN(n_jobs=1)

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.