【问题标题】:Can I use mpiexec to run the same executable with different command line arguments for the executable each time?我可以使用 mpiexec 为可执行文件每次使用不同的命令行参数运行相同的可执行文件吗?
【发布时间】:2019-03-06 02:45:45
【问题描述】:

我是分布式操作系统的新手。而且我需要用超级计算机训练多种机器学习模型。我需要多次运行相同的训练脚本,并且每次运行都使用不同的命令行参数传递脚本。我可以通过使用 mpiexec 来实现这一点,以便我可以使用不同的输入并行训练多个模型吗?

我找到了mpi的单程序多数据模型,但是不知道对应的命令。

我想在集群中的计算节点之间并行运行以下行。

python train.py arg > log.out # arg is the argument that differs for each node

但是,如果我正在使用:

mpiexec train.py arg >log.out 

它只会使用相同的命令行参数运行 train.py:arg 并行多次。

有人可以指出正确的方法吗?谢谢!

【问题讨论】:

  • 谢谢,我们当前的解决方案是使用 shell 脚本在 while 循环中提交所有类似的作业,并将不同的参数传递给作业的每个可执行文件。这有点类似于后台进程在这篇文章中所做的。
  • 您是否需要将来自train.py 进程的任何数据与任何其他train.py 进程共享,还是它们都完全独立,只有arg 不同?
  • @EdSmith 每个节点共享部分训练数据。但是每个节点的处理结果之间没有依赖关系。

标签: mpi spmd


【解决方案1】:

实现您想要的一种方法是使用mpi4py 创建一个顶级脚本mpi_train.py。在一个 MPI 作业中,每个进程都有一个唯一的等级并且都运行相同的代码,所以运行,

from mpi4py import MPI

comm = MPI.COMM_WORLD

print("Hello! I'm rank " + str(comm.rank))

mpiexec -n 4 python mpi_train.py

会给

Hello! I'm rank 0
Hello! I'm rank 1
Hello! I'm rank 3
Hello! I'm rank 2

然后可以使用不同的等级来读取指定参数的单独文件。所以你会有类似的东西,

#All code in train should be in functions or __name__ == "__main__"
import train
from mpi4py import MPI

def get_command_args_from_rank(rank):
     #Some code here to get args from unique rank no.

comm = MPI.COMM_WORLD

args = get_command_args_from_rank(comm.rank)

#Assuming the args can be passed to a run function
out = train.run(args)

请注意,您应该明确指定每个进程的输出,例如,

with open("log.out"+str(comm.rank)) as f:
    f.write(out)

否则所有打印都进入标准输出并变得混乱,因为无法保证各种进程的顺序。

【讨论】:

  • 这有点矫枉过正并且次优,因为可能存在一些负载不平衡,并且mpiexec 在最后一个排名完成时返回(阅读:所有其他排名可能会什么都没有,一些 MPI 库会烧 CPU 这样做)。恕我直言,使用作业数组更简单、更高效。
  • 没错,作业数组看起来像是 OP 的更好解决方案,可能值得添加作为答案?虽然这不是 PBS 的功能,而不是 MPI?对于负载平衡,您始终可以在train.run 上添加一个循环,以便每个进程保持忙碌。
  • 好吧,重点是mpiexec 不是同时运行多个串行程序实例的最佳方式。是的,作业数组是资源管理器(PBS、SLURM、LSF 等)和不是 MPI 的一项功能。
【解决方案2】:

感谢所有 cmets 和答案。以下是我为获得最终解决方案所做的工作:

起初,我有一个 bash 脚本将作业作为作业数组提交到集群,并使用 $PBS_ARRAYID 将不同的命令行参数传递给每个作业:

#PBS -N ondemand/sys/myjobs/default
#PBS -l walltime=24:10:00
#PBS -l file=1gb
#PBS -l nodes=1:ppn=1:gpus=1:default
#PBS -l mem=40MB
#PBS -j oe
#PBS -A PAS0108
#PBS -o Job_array.out


# Move to the directory where the job was submitted
# run the following cmd in shell to submit the job in an array
# qsub -t 1-6 myjob.sh

cd $PBS_O_WORKDIR
cd $TMPDIR
# $PBS_ARRAYID can be used as a variable 

# copy data to local storage of the node
cp ~/code/2018_9_28_training_node_6_OSC/* $TMPDIR
cp -r ~/Datasets_1/Processed/PascalContext/ResNet_Output/ $TMPDIR
cp -r ~/Datasets_1/Processed/PascalContext/Truth/ $TMPDIR
cp -r ~/Datasets_1/Processed/PascalContext/Decision_Tree/ $TMPDIR

# currently in $TMPDIR, load modules
module load python/3.6 cuda
# using $PBS_ARRAYID as a variable to pass the corresponding node ID
python train_decision_tree_node.py $PBS_ARRAYID $TMPDIR  > training_log_${PBS_ARRAYID}

# saving logs
cp training_log ${HOME}/logs/${PBS_ARRAYID}_node_log/
cp my_results $PBS_O_WORKDIR

我用命令行提交上面的脚本:

qsub -t 1-6 myjob.sh

但是,我收到了来自集群的错误,当我运行脚本时,集群中的实际节点无法识别本地目录$TMPDIR

最后,我所做的是使用顶级 bash 脚本在 while 循环中使用不同的命令行参数提交每个作业,并且它起作用了:

run_multiple_jobs.tcsh:

#!/usr/bin/env tcsh
set n = 1
while ( $n <= 5 )
    echo "Submitting job for concept node $n"
    qsub -v NODE=$n job.pbs
    @ n++
end

jobs.pbs:

#PBS -A PAS0108
#PBS -N node_${NODE}
#PBS -l walltime=160:00:00
#PBS -l nodes=1:ppn=1:gpus=1
#PBS -l mem=5GB
#PBS -m ae
#PBS -j oe

# copy data
cp -r ~/Datasets/Processed/PascalContext/Decision_Tree $TMPDIR
cp -r ~/Datasets/Processed/PascalContext/Truth $TMPDIR
cp -r ~/Datasets/Processed/PascalContext/ResNet_Output $TMPDIR

# move to working directory
cd $PBS_O_WORKDIR

# run program
module load python/3.6 cuda/8.0.44
python train_decision_tree_node.py ${NODE} $TMPDIR $HOME

# run with run_multiple_jobs.tcsh script

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 2019-09-27
    • 2014-10-25
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多