同一脚本的 SLURM sbatch 作业数组,但并行输入参数 运行 不同
SLURM sbatch job array for the same script but with different input arguments run in parallel
我遇到了一个问题,我需要使用不同的输入参数启动相同的脚本。
假设我有一个脚本 myscript.py -p <par_Val> -i <num_trial>
,我需要考虑 N
不同的 par_values
(在 x0
和 x1
之间)和 M 试验par_values
的每个值。
M 的每次试验都几乎达到了我正在处理的集群的时间限制(而且我没有权限更改它)。所以在实践中我需要 运行 NxM
独立工作。
因为每个批处理作业具有相同的node/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, the -a --array
option seems promising. But in my case I need to change the input parameters for every script of the NxM
that I have. How can I do this? I would like not to write NxM
batch scripts and then list them in a txt
file as suggested by this post. Nor the solution proposed here 似乎很理想,因为恕我直言,作业数组就是这种情况。此外,我想确保所有 NxM
脚本同时启动,并且上面的脚本调用立即终止,这样就不会与时间限制冲突,我的整个工作都会被系统终止并保持不完整(然而,由于每个 NxM
作业都在这样的限制内,如果它们 运行 并行但独立,则不会发生这种情况)。
最好的方法是使用作业数组。
一种选择是在提交作业脚本时传递参数 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 -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
如果您使用 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 非常相似。因此,我宁愿把它写成评论,但没有足够的声誉。
根据 this page,作业数组会产生大量开销:
If the running time of your program is small, say ten minutes or less, creating a job array will incur a lot of overhead and you should consider packing your jobs.
该页面为运行您的工作类型提供了一些示例,同时使用数组和"packed jobs."
如果您不want/need为您的工作指定资源,这里是另一种方法:我不确定它是否是 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
行
我遇到了一个问题,我需要使用不同的输入参数启动相同的脚本。
假设我有一个脚本 myscript.py -p <par_Val> -i <num_trial>
,我需要考虑 N
不同的 par_values
(在 x0
和 x1
之间)和 M 试验par_values
的每个值。
M 的每次试验都几乎达到了我正在处理的集群的时间限制(而且我没有权限更改它)。所以在实践中我需要 运行 NxM
独立工作。
因为每个批处理作业具有相同的node/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, the -a --array
option seems promising. But in my case I need to change the input parameters for every script of the NxM
that I have. How can I do this? I would like not to write NxM
batch scripts and then list them in a txt
file as suggested by this post. Nor the solution proposed here 似乎很理想,因为恕我直言,作业数组就是这种情况。此外,我想确保所有 NxM
脚本同时启动,并且上面的脚本调用立即终止,这样就不会与时间限制冲突,我的整个工作都会被系统终止并保持不完整(然而,由于每个 NxM
作业都在这样的限制内,如果它们 运行 并行但独立,则不会发生这种情况)。
最好的方法是使用作业数组。
一种选择是在提交作业脚本时传递参数 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 -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
如果您使用 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 非常相似。因此,我宁愿把它写成评论,但没有足够的声誉。
根据 this page,作业数组会产生大量开销:
If the running time of your program is small, say ten minutes or less, creating a job array will incur a lot of overhead and you should consider packing your jobs.
该页面为运行您的工作类型提供了一些示例,同时使用数组和"packed jobs."
如果您不want/need为您的工作指定资源,这里是另一种方法:我不确定它是否是 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
行