如何控制使用scikitlearn的joblib启动的进程数?

2024-03-29 14:56:08 发布

您现在位置:Python中文网/ 问答频道 /正文

背景 当使用scikit learn在大型数据集上执行令人尴尬的并行任务时,在高性能计算(HPC)环境中的集群上执行此任务非常方便。Scikit learn允许用户通过n_jobs参数指定并行使用的内核数量,从而为并行化提供支持。原则上,这将使分析管道中使用的内核数量与HPC环境中调度程序请求的处理器数量相匹配变得简单

问题 它向我指出,每个作业运行的进程数(即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=2n_cpus=2-2请求的CPU数量正以100%的速度运行。但是,当我使用pstree PID查看线程时,我可以看到6个进程正在运行,而不是预期的两个进程

仅请求n_jobs=1n_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=1n_cpus=1:360.24it/s,htop显示一个CPU正忙,pstree PID显示一个线程正在运行
  2. n_jobs=2和{}:658.40it/s,{}显示两个CPU正忙,pstree PID显示6个线程正在运行
  3. n_jobs=2n_cpus=1:336.80 it/s,htop显示一个CPU正忙,pstree PID显示6个线程正在运行
  4. n_jobs=1n_cpus=2:358.60 it/s,htop显示一个CPU正忙,pstree PID显示一个线程正在运行

似乎pstree始终取决于scikit学习API中请求的线程数。由htop显示为活动的CPU数量是脚本可用且也在使用的CPU数量。因此,只有场景2会导致两个CPU忙。同样,只有在CPU可用且已使用的情况下(也包括场景2),处理速度(以每秒迭代次数衡量)才会在并行情况下提高。关键的是,根据pstree的说法,线程的数量是6个,因此大于CPU的数量,这并不表明它们在有限的CPU中相互干扰。只有场景3显示,当请求两个作业但只有一个CPU可用时,处理速度似乎较慢。这比场景1慢

我开始怀疑pstree是否真的是对并行处理效率的一个很好的诊断,以及它与htop有何不同


Tags: import数量time进程jobsitscikitcpu