&引用;令人尴尬的平行”;在集群上使用python和PBS编程
我有一个函数(神经网络模型),可以生成数字。我希望在带有Torque的标准集群上使用PBS测试python中的几个参数、方法和不同输入(意味着数百次函数运行) 注意:我尝试了parallelpython、ipython等等,但从未完全满意,因为我想要更简单的东西。集群处于我无法更改的给定配置中,这样一个集成python+qsub的解决方案肯定会使社区受益 为了简化,我有一个简单的函数,例如:&引用;令人尴尬的平行”;在集群上使用python和PBS编程,python,pbs,qsub,embarrassingly-parallel,Python,Pbs,Qsub,Embarrassingly Parallel,我有一个函数(神经网络模型),可以生成数字。我希望在带有Torque的标准集群上使用PBS测试python中的几个参数、方法和不同输入(意味着数百次函数运行) 注意:我尝试了parallelpython、ipython等等,但从未完全满意,因为我想要更简单的东西。集群处于我无法更改的给定配置中,这样一个集成python+qsub的解决方案肯定会使社区受益 为了简化,我有一个简单的函数,例如: import myModule def model(input, a= 1., N=100):
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\u lots\u number\u crunch
可能持续数小时
我的问题是:是否有一种正确的方法来转换像参数扫描这样的东西,例如
for a in pylab.linspace(0., 1., 100):
model(input, a)
进入“某物”,它将为对模型的每次调用启动PBS脚本
函数
#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脚本中调用它,但还没有弄明白(decorator?)。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] :pbs_python您可以使用(我为类似的设置而开发的)轻松完成此操作 您可以在文件中编写(例如,
model.py
):
就这样
现在您可以在队列上启动“jug jobs: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服务器。它还可以处理任务之间的依赖关系
这并不是你想要的,但我相信这是一种更干净的架构,可以将其与工作队列系统分开。看起来我参加聚会有点晚了,但几年前我也遇到了同样的问题,即如何用python将令人尴尬的并行问题映射到集群上,并编写了自己的解决方案。我最近将其上传到github的以下位置: 要使用pbs_util编写程序,我首先在包含以下内容的工作目录中创建一个pbs_util.ini
[PBSUTIL]
numnodes=1
numprocs=1
mem=i1000mb
walltime=24:00:00
然后是这样的python脚本
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))
我刚刚开始使用集群和EP应用程序。我的目标(我在图书馆)是学习足够的知识,帮助校园内的其他研究人员使用EP应用程序访问HPC…特别是STEM以外的研究人员。我还是一个新手,但我认为指出在PBS脚本中使用来启动具有不同参数的基本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超级计算的新手,尽管我还不了解“parallel”上的所有其他选项,但该命令允许我使用不同的参数并行启动python脚本。如果您能够提前生成大量的参数文件来并行化您的问题,那么这将非常有效。例如,在参数空间中运行模拟。或者使用相同的代码处理多个文件
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.