【问题标题】:SLURM sbatch job array for the same script but with different input arguments run in parallel用于相同脚本但具有不同输入参数的 SLURM sbatch 作业数组并行运行
【发布时间】:2017-01-27 18:23:23
【问题描述】:

我有一个问题,我需要启动相同的脚本,但输入参数不同。

假设我有一个脚本myscript.py -p <par_Val> -i <num_trial>,我需要考虑N 不同的par_values(在x0x1 之间)和针对par_values 的每个值的M 次试验。

M 的每次试验都几乎达到了我正在处理的集群的时间限制(而且我没有特权来改变它)。所以在实践中我需要运行NxM 独立作业。

因为每个批处理作业都具有相同的节点/cpu 配置,并调用相同的 python 脚本,除了更改输入参数,原则上,在伪语言中,我应该有一个 sbatch 脚本,它应该执行以下操作:

#!/bin/bash
#SBATCH --job-name=cv_01
#SBATCH --output=cv_analysis_eis-%j.out
#SBATCH --error=cv_analysis_eis-%j.err
#SBATCH --partition=gpu2
#SBATCH --nodes=1
#SBATCH --cpus-per-task=4

for p1 in 0.05 0.075 0.1 0.25 0.5
do
    for i in {0..150..5}
    do
        python myscript.py -p p1 -v i
    done
done

脚本的每次调用本身就是一个批处理作业。 查看sbatch doc-a --array 选项似乎很有希望。但就我而言,我需要更改我拥有的 NxM 的每个脚本的输入参数。我怎样才能做到这一点?我不想编写NxM 批处理脚本,然后按照this post 的建议将它们列在txt 文件中。 here 提出的解决方案似乎也不理想,因为这是工作数组的情况。此外,我想确保所有NxM 脚本同时启动,并立即终止上述脚本的调用,以免与时间限制冲突,我的整个工作将被终止系统并保持不完整(然而,由于每个 NxM 作业都在此限制内,如果它们并行但独立地一起运行,则不会发生这种情况)。

【问题讨论】:

    标签: arrays slurm sbatch


    【解决方案1】:

    最好的方法是使用作业数组。

    一种选择是在提交作业脚本时传递参数 p1,这样您将只有一个脚本,但必须多次提交,每个 p1 值一次。

    代码将是这样的(未经测试):

    #!/bin/bash
    #SBATCH --job-name=cv_01
    #SBATCH --output=cv_analysis_eis-%j-%a.out
    #SBATCH --error=cv_analysis_eis-%j-%a.err
    #SBATCH --partition=gpu2
    #SBATCH --nodes=1
    #SBATCH --cpus-per-task=4
    #SBATCH -a 0-150:5
    
    python myscript.py -p $1 -v $SLURM_ARRAY_TASK_ID
    

    你将提交它:

    sbatch my_jobscript.sh 0.05
    sbatch my_jobscript.sh 0.075
    ...
    

    另一种方法是在 bash 数组中定义所有 p1 参数并提交 NxM 作业(未经测试)

    #!/bin/bash
    #SBATCH --job-name=cv_01
    #SBATCH --output=cv_analysis_eis-%j-%a.out
    #SBATCH --error=cv_analysis_eis-%j-%a.err
    #SBATCH --partition=gpu2
    #SBATCH --nodes=1
    #SBATCH --cpus-per-task=4
    #Make the array NxM
    #SBATCH -a 0-150
    
    PARRAY=(0.05 0.075 0.1 0.25 0.5)    
    
    #p1 is the element of the array found with ARRAY_ID mod P_ARRAY_LENGTH
    p1=${PARRAY[`expr $SLURM_ARRAY_TASK_ID % ${#PARRAY[@]}`]}
    #v is the integer division of the ARRAY_ID by the lenght of 
    v=`expr $SLURM_ARRAY_TASK_ID / ${#PARRAY[@]}`
    python myscript.py -p $p1 -v $v
    

    【讨论】:

    • 谢谢,这正是我想要的。然而,在我批准之前,在您提供的第二个示例中,当您分配 p1 时,我不相信 expr 中的 $1 参数。你能澄清一下吗?这对我来说确实没有意义,因为 afaik $ 指的是输入参数......
    • 好的,你的答案是正确的,p1 的赋值有一个小错字,应该是 p1=${PARRAY['expr $SLURM_ARRAY_TASK_ID % ${#PARRAY[@]}']}
    【解决方案2】:

    如果您使用 SLURM 作业数组,您可以线性化两个 for 循环的索引,然后比较循环索引和数组任务 ID:

    #!/bin/bash
    #SBATCH --job-name=cv_01
    #SBATCH --output=cv_analysis_eis-%j.out
    #SBATCH --error=cv_analysis_eis-%j.err
    #SBATCH --partition=gpu2
    #SBATCH --nodes=1
    #SBATCH --cpus-per-task=4
    #SBATCH -a 0-154
    
    # NxM = 5 * 31 = 154
    
    p1_arr=(0.05 0.075 0.1 0.25 0.5)
    
    # SLURM_ARRAY_TASK_ID=154 # comment in for testing
    
    for ip1 in {0..4} # 5 steps
    do
        for i in {0..150..5} # 31 steps
        do
            let task_id=$i/5+31*$ip1
    
            # printf $task_id"\n" # comment in for testing
    
            if [ "$task_id" -eq "$SLURM_ARRAY_TASK_ID" ]
            then
              p1=${p1_arr[ip1]}
              # printf "python myscript.py -p $p1 -v $i\n" # comment in for testing
              python myscript.py -p $p1 -v $i\n
            fi
        done
    done
    

    这个答案与 Carles 非常相似。因此,我更愿意将其写为评论,但没有足够的声誉。

    【讨论】:

      【解决方案3】:

      根据this page,作业数组会产生大量开销:

      如果你的程序运行时间很短,比如十分钟或更短,创建一个作业数组会产生很多开销,你应该考虑打包你的作业。

      该页面提供了一些示例来运行您的作业类型,使用数组和“打包作业”。

      如果您不想/不需要为您的工作指定资源,这里有另一种方法:我不确定这是否是 Slurm 想要的用例,但它似乎可以工作,并且提交脚本看起来更好一点,因为我们不必线性化索引以使其适合作业数组范式。此外,它适用于任意深度的嵌套循环。

      直接作为shell脚本运行:

      #!/bin/bash
      FLAGS="--ntasks=1 --cpus-per-task=1"
      for i in 1 2 3 4 5; do
              for j in 1 2 3 4 5; do
                  for k in 1 2 3 4 5; do
                      sbatch $FLAGS testscript.py $i $j $k
              done
          done
      done
      

      您需要确保testscript.py 在第一行使用#! 指向正确的解释器,例如

      #!/usr/bin/env python 
      import time
      import sys
      time.sleep(5)
      print "This is my script"
      print sys.argv[1], sys.argv[2], sys.argv[3] 
      

      或者(未经测试),您可以像这样使用--wrap 标志

      sbatch $FLAGS --wrap="python testscript.py $i $j $k"
      

      您将不需要testscript.py 中的#!/usr/bin/env python

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-28
        • 2018-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-31
        相关资源
        最近更新 更多