"смущающее параллельное" программирование с использованием python и PBS на кластере
У меня есть функция (модель нейронной сети), которая производит цифры. Я хочу проверить несколько параметров, методов и различных входов (что означает сотни прогонов функции) из python, используя PBS на стандартном кластере с Torque.
Примечание. Я пробовал параллельно iphone и т.д. и никогда не был полностью удовлетворен, так как я хочу что-то более простое. Кластер находится в заданной конфигурации, которую я не могу изменить, и такое решение, интегрирующее python + qsub, безусловно, принесет пользу сообществу.
Для упрощения вещей у меня есть простая функция, например:
import myModule
def model(input, a= 1., N=100):
do_lots_number_crunching(input, a,N)
pylab.savefig('figure_' + input.name + '_' + str(a) + '_' + str(N) + '.png')
где input
- объект, представляющий вход, input.name
- это строка, а do_lots_number_crunching
может длиться несколько часов.
Мой вопрос: есть ли правильный способ трансформировать что-то вроде сканирования таких параметров, как
for a in pylab.linspace(0., 1., 100):
model(input, a)
в "что-то", которое запустило бы PBS script для каждого вызова функции model
?
#PBS -l ncpus=1
#PBS -l mem=i1000mb
#PBS -l cput=24:00:00
#PBS -V
cd /data/work/
python experiment_model.py
Я думал о функции, которая включала бы шаблон PBS и вызывала бы его из python script, но еще не могла понять его (декоратор?).
Ответы
Ответ 1
pbs_python [1] может работать для этого. Если experiment_model.py 'a' в качестве аргумента вы могли бы сделать
import pbs, os
server_name = pbs.pbs_default()
c = pbs.pbs_connect(server_name)
attopl = pbs.new_attropl(4)
attropl[0].name = pbs.ATTR_l
attropl[0].resource = 'ncpus'
attropl[0].value = '1'
attropl[1].name = pbs.ATTR_l
attropl[1].resource = 'mem'
attropl[1].value = 'i1000mb'
attropl[2].name = pbs.ATTR_l
attropl[2].resource = 'cput'
attropl[2].value = '24:00:00'
attrop1[3].name = pbs.ATTR_V
script='''
cd /data/work/
python experiment_model.py %f
'''
jobs = []
for a in pylab.linspace(0.,1.,100):
script_name = 'experiment_model.job' + str(a)
with open(script_name,'w') as scriptf:
scriptf.write(script % a)
job_id = pbs.pbs_submit(c, attropl, script_name, 'NULL', 'NULL')
jobs.append(job_id)
os.remove(script_name)
print jobs
[1]: https://oss.trac.surfsara.nl/pbs_python/wiki/TorqueUsage pbs_python
Ответ 2
Вы можете сделать это легко, используя jug (который я разработал для аналогичной настройки).
Вы пишете в файле (например, model.py
):
@TaskGenerator
def model(param1, param2):
res = complex_computation(param1, param2)
pyplot.coolgraph(res)
for param1 in np.linspace(0, 1.,100):
for param2 in xrange(2000):
model(param1, param2)
И что это!
Теперь вы можете запускать "задания кувшина" в вашей очереди: jug execute model.py
, и это будет автоматически распараллеливаться. Что происходит, так это то, что каждое задание в цикле сделает что-то вроде:
while not all_done():
for t in tasks in tasks_that_i_can_run():
if t.lock_for_me(): t.run()
(На самом деле это сложнее, но вы получаете точку).
Он использует файловую систему для блокировки (если вы находитесь в системе NFS) или redis-сервер, если хотите. Он также может обрабатывать зависимости между задачами.
Это не совсем то, о чем вы просили, но я считаю, что это более чистая архитектура, чтобы отделить это от системы очередей заданий.
Ответ 3
Похоже, я немного опаздываю на вечеринку, но у меня также был вопрос о том, как несколько лет назад сопоставлять смущающие параллельные проблемы на кластере в python и написал собственное решение. Недавно я загрузил его в github: https://github.com/plediii/pbs_util
Чтобы написать вашу программу с помощью pbs_util, я бы сначала создал pbs_util.ini в рабочем каталоге, содержащем
[PBSUTIL]
numnodes=1
numprocs=1
mem=i1000mb
walltime=24:00:00
Тогда python script как этот
import pbs_util.pbs_map as ppm
import pylab
import myModule
class ModelWorker(ppm.Worker):
def __init__(self, input, N):
self.input = input
self.N = N
def __call__(self, a):
myModule.do_lots_number_crunching(self.input, a, self.N)
pylab.savefig('figure_' + self.input.name + '_' + str(a) + '_' + str(self.N) + '.png')
# You need "main" protection like this since pbs_map will import this file on the compute nodes
if __name__ == "__main__":
input, N = something, picklable
# Use list to force the iterator
list(ppm.pbs_map(ModelWorker, pylab.linspace(0., 1., 100),
startup_args=(input, N),
num_clients=100))
И это будет сделано.
Ответ 4
Я только начал работать с кластерами и приложениями EP. Моя цель (я с библиотекой) состоит в том, чтобы выучить достаточно, чтобы помочь другим исследователям в доступе к кампусу HPC с приложениями EP... особенно исследователи вне STEM. Я все еще очень новичок, но думал, что это может помочь этому вопросу указать на использование GNU Parallel в PBS script для запуска основного скрипты python с различными аргументами. В файле .pbs есть две строки:
module load gnu-parallel # this is required on my environment
parallel -j 4 --env PBS_O_WORKDIR --sshloginfile $PBS_NODEFILE \
--workdir $NODE_LOCAL_DIR --transfer --return 'output.{#}' --clean \
`pwd`/simple.py '{#}' '{}' ::: $INPUT_DIR/input.*
# `-j 4` is the number of processors to use per node, will be cluster-specific
# {#} will substitute the process number into the string
# `pwd`/simple.py `{#}` `{}` this is the command that will be run multiple times
# ::: $INPUT_DIR/input.* all of the files in $INPUT_DIR/ that start with 'input.'
# will be substituted into the python call as the second(3rd) argument where the
# `{}` resides. These can be simple text files that you use in your 'simple.py'
# script to pass the parameter sets, filenames, etc.
Как новый метод суперкомпьютера EP, хотя я еще не понял все остальные опции на "параллельном", эта команда позволила мне запускать скрипты python параллельно с разными параметрами. Это будет хорошо работать, если вы можете генерировать множество файлов параметров заблаговременно, что будет распараллелить вашу проблему. Например, запуск моделирования в пространстве параметров. Или обрабатывать много файлов с тем же кодом.