Почему многопроцессорная обработка Dynesty с ThreadPoolExecutor не использует все ядра? - PullRequest
0 голосов
/ 28 августа 2018

Я пытаюсь запустить простой пример с вложенной выборкой и dynesty.

Я установил dynesty с GitHub: https://github.com/joshspeagle/dynesty


Настройка компьютера

ОС: Mac OSX El Capitan (10.11.6)
Процессор: 8 ядер
Оперативная память: 16,0 ГБ

gcc: 4.8.5 через conda install gcc


Настройка проблемы

Я запустил приведенный ниже код (смоделируйте данные, настройте предварительные / вероятности, отправьте на dynesty.

Чтобы установить многопроцессорность, я использовал multiprocessing.Pool, concurrent.futures.ProcessPoolExecutor и concurrent.futures.ThreadPoolExecutor.

Я попробовал код в Jupyter Lab, ipython и (скрипт) python run_dynesty_test.py.

Проблема: Весь скрипт работает нормально; но dynesty / python запускается с использованием всех ядер; затем он медленно начинает использовать все меньше и меньше ядер. Наконец, примерно через 5 минут dynesty / python использует почти ровно 1 ядро.

Доказательства: htop начинает считывать 780%, затем 550%, затем 350%, затем 100% ЦП - и остается на 100% ЦП для остальной части операции; кроме раз в две минуты, htop будет показывать ~ 250-300% CPU.


Вопрос

Почему dynesty / ThreadPoolExecutor / python / etc не используют все мои ядра все время?


Фрагмент кода, включающий Dynesty и многопроцессорность

with ThreadPoolExecutor(max_workers=cpu_count()-1) as executor:

    sampler = dynesty.DynamicNestedSampler(
                            loglike,
                            prior,
                            ndim=ndims,
                            nparam=ndims,
                            bound='multi',
                            sample='unif',
                            pool=executor,
                            queue_size=cpu_count())

    sampler.run_nested(nlive_init=100,nlive_batch=100)

    res = sampler.results

Тест полного сценария для настройки

from __future__ import absolute_import,\
              unicode_literals, print_function

from multiprocessing import set_start_method
set_start_method('forkserver')

import dynesty
import math
import os
import threading, subprocess

from sys import platform
from numpy import pi, sin, cos, linspace
from pylab import *#;ion()

from multiprocessing import Pool, cpu_count

if not os.path.exists("chains"): os.mkdir("chains")

# plotting
import matplotlib
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def gaussian1Dp(cube):
    center = cube[0]
    width  = cube[1]
    height = cube[2]
    return lambda y: height*np.exp(-0.5*(( (center - y) / width)**2))

np.random.seed(42)

param0a= -0.5
param0b= 0.5
param1a= 0.1
param1b= 0.1
param2a= 0.8
param2b= 0.8

yunc  = 0.1
nPts  = int(100)
nThPts= int(1e3)

xmin  = -1
xmax  =  1
dx    = 0.1*(xmax - xmin)

yuncs = np.random.normal(yunc, 1e-2 * yunc, nPts)
thdata= np.linspace(xmin-dx, xmax+dx, nThPts)

xdata = np.linspace(xmin,xmax,nPts)

ydata = model([param0a,param1a,param2a])(xdata) \
        + model([param0b,param1b,param2b])(xdata)

yerr  = np.random.normal(0, yuncs, nPts)
zdata = ydata + yerr

figure(figsize=(10,10))
plot(thdata, model([param0a,param1a,param2a])(thdata) \
        + model([param0b,param1b,param2b])(thdata))
errorbar(xdata, zdata, yunc*ones(zdata.size), fmt='o')
show()

def prior(cube):
    cube[0] = cube[0]*2 - 1
    cube[1] = cube[1]*2
    cube[2] = cube[2]*2

    return cube

def loglike(cube):
    modelNow = model(cube)(xdata)
    return -0.5*((modelNow - ydata)**2./yuncs**2.).sum()

from concurrent.futures import ThreadPoolExecutor,\
                               ProcessPoolExecutor

if __name__ == '__main__':
    if not os.path.exists("chains"): os.mkdir("chains")
    n_params = len(parameters)
    ndims = 3

    with ThreadPoolExecutor(max_workers=cpu_count()-1) as executor:

        sampler = dynesty.DynamicNestedSampler(
                                loglike,
                                prior,
                                ndim=ndims,
                                nparam=ndims,
                                bound='multi',
                                sample='unif',
                                pool=executor,
                                queue_size=cpu_count())

        sampler.run_nested(nlive_init=100, nlive_batch=100)

        res = sampler.results

from dynesty import plotting as dyplot

# evidence check
fig, axes = dyplot.runplot(res, color='red',
                lnz_truth=lnz_truth,
                truth_color='black',
                logplot=True)

fig.tight_layout()

joblib.dump(res,'dynesty_double_gaussian_test_results.joblib.save')
...