Как я могу контролировать количество процессов, запущенных с JobLib Scikit-Learn? - PullRequest
1 голос
/ 30 апреля 2020

Справочная информация При выполнении смущающей параллельной задачи на больших наборах данных с помощью 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 друг с другом:

  1. n_jobs=1 и n_cpus=1: 360,24 it / s, htop показывает один занятый процессор, pstree PID показывает один поток
  2. n_jobs=2 и n_cpus=2: 658,40 it / s, htop показывает занятость двух процессоров, pstree PID показывает 6 работающих потоков.
  3. n_jobs=2 и n_cpus=1 : 336.80 ит / с, htop показывает занятость одного процессора, pstree PID показывает 6 запущенных потоков.
  4. n_jobs=1 и n_cpus=2: 358.60 ед / с, htop показывает занятость одного процессора, pstree PID показывает один запущенный поток.

Кажется, что pstree всегда зависит от количества потоков, запрошенных в scikit-learn API. Количество процессоров, показанное htop как активное, равно числу процессоров, которые доступны для сценариев и , которые также используются. Таким образом, только сценарий 2 приводит к тому, что два процессора заняты. Аналогично, скорость обработки (измеряемая в итерациях в секунду) увеличивается только в параллельном случае, если доступны процессоры и (также сценарий 2). Важно отметить, что количество потоков, равное шести в соответствии с pstree и, следовательно, больше, чем количество процессоров, не указывало на то, что они мешали друг другу для ограниченных процессоров. Только сценарий 3 показал, что обработка выполнялась медленнее, когда запрашивались два задания, но был доступен только один ЦП. Это было медленнее, чем в сценарии 1.

Я начинаю задумываться, действительно ли pstree действительно хорошая диагностика c для эффективности параллельной обработки и чем она отличается от htop.

...