Справочная информация При выполнении смущающей параллельной задачи на больших наборах данных с помощью scikit-learn это удобно делать в кластере в среде высокопроизводительных вычислений (HP C). Scikit-learn обеспечивает поддержку распараллеливания, позволяя пользователю указать количество ядер для параллельного использования через аргумент n_jobs . В принципе это должно упростить сопоставление числа ядер, используемых в конвейере анализа, с числом процессоров, запрошенных у планировщика в среде HP C.
Проблема У него есть указал мне, что число процессов, запущенных на одно задание (а именно 7), превысило количество запрошенных мной процессоров (а именно 2), хотя я фактически установил аргумент n_job в scikit-learn как 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
выясняется, что именно количество процессоров работает на 100% что я действительно запросил через n_jobs=2
и n_cpus=2
- два в этом случае. Однако, когда я смотрю на потоки, используя pstree PID
, я вижу 6 запущенных процессов вместо ожидаемых двух процессов.
Запрос только n_jobs=1
и n_cpus=1
приводит к htop
, показывающему, что один процессор работает 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
... и о процессорах согласно 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
. Поэтому я могу отдельно управлять количеством задач, запрошенных для параллельного запуска в scikit-learn (n_jobs
), и количеством доступных процессоров (n_cpus
). Это позволило мне сравнить четыре сценария ios друг с другом:
n_jobs=1
и n_cpus=1
: 360,24 it / s, htop
показывает один занятый процессор, pstree PID
показывает один поток n_jobs=2
и n_cpus=2
: 658,40 it / s, htop
показывает занятость двух процессоров, pstree PID
показывает 6 работающих потоков. n_jobs=2
и n_cpus=1
: 336.80 ит / с, htop
показывает занятость одного процессора, pstree PID
показывает 6 запущенных потоков. n_jobs=1
и n_cpus=2
: 358.60 ед / с, htop
показывает занятость одного процессора, pstree PID
показывает один запущенный поток.
Кажется, что pstree
всегда зависит от количества потоков, запрошенных в scikit-learn API. Количество процессоров, показанное htop
как активное, равно числу процессоров, которые доступны для сценариев и , которые также используются. Таким образом, только сценарий 2 приводит к тому, что два процессора заняты. Аналогично, скорость обработки (измеряемая в итерациях в секунду) увеличивается только в параллельном случае, если доступны процессоры и (также сценарий 2). Важно отметить, что количество потоков, равное шести в соответствии с pstree
и, следовательно, больше, чем количество процессоров, не указывало на то, что они мешали друг другу для ограниченных процессоров. Только сценарий 3 показал, что обработка выполнялась медленнее, когда запрашивались два задания, но был доступен только один ЦП. Это было медленнее, чем в сценарии 1.
Я начинаю задумываться, действительно ли pstree
действительно хорошая диагностика c для эффективности параллельной обработки и чем она отличается от htop
.