代码之家  ›  专栏  ›  技术社区  ›  meduz

在集群上使用python和pbs进行“令人尴尬的并行”编程

  •  10
  • meduz  · 技术社区  · 14 年前

    我有一个函数(神经网络模型),它产生数字。我希望使用带扭矩的标准集群上的PBS测试来自Python的几个参数、方法和不同的输入(意味着数百次函数运行)。

    注意:我尝试过parallelpython、ipython等,但从来没有完全满意过,因为我想要更简单的东西。集群处于一个我无法更改的给定配置中,这样一个集成了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脚本 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脚本调用它,但还不能弄清楚(decorator?).

    4 回复  |  直到 11 年前
        1
  •  4
  •   Avision    11 年前

    pbs_python[1]可以解决这个问题。如果实验用“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 PbSyPython

        2
  •  3
  •   luispedro    14 年前

    你可以很容易地用 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 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服务器。它还可以处理任务之间的依赖关系。

    这不是你想要的,但我相信把它和工作排队系统分开是一个更干净的架构。

        3
  •  2
  •   plediii    13 年前

    看起来我参加聚会有点晚了,但我也有同样的问题,如何将令人尴尬的并行问题映射到几年前在Python中的集群上,并编写了自己的解决方案。我最近上传到Github这里: https://github.com/plediii/pbs_util

    要用pbs-util编写程序,我首先要在包含

    [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))
    

    这样就可以了。

        4
  •  0
  •   Steve Koch robince    11 年前

    我刚开始使用集群和EP应用程序。我的目标(我在图书馆)是学习足够的知识来帮助校园里的其他研究人员使用ep应用程序访问hpc,尤其是STEM之外的研究人员。我还是个新手,但我认为这可能有助于这个问题指出 GNU Parallel 在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脚本。如果您能够提前生成大量参数文件来并行处理您的问题,那么这将很好地工作。例如,在参数空间中运行模拟。或处理具有相同代码的多个文件。

    推荐文章