在 R 中所有处理器的 conda 环境中的计算群集上运行单节点作业时出现问题

Problem running single-node job on computing cluster in conda environment for all processors in R

提问人:peony 提问时间:11/15/2023 更新时间:11/18/2023 访问量:37

问:

我正在尝试在我的大学计算集群上运行单节点作业,该作业通过 qsub 提交,在 conda 环境“myenv”中提交。一旦我在 R 脚本中开始并行化,不同的处理器就会从基本环境开始,而不是从“myenv”开始。测试并行化在基本环境中完美运行,因此问题开始于所有处理器的“myenv”。环境“myenv”也适用于第一个处理器。

我通过 qsub(1 个节点和 20 个处理器)提交以下 bash 脚本:

source /mypath/conda.sh
conda activate myenv
Rscript myscript.R

我正在使用具有最新 R 版本和特定软件包的 conda 环境。集群上的基本环境有一个非常过时的 R 版本,它与我需要的软件包(例如栅格)不兼容。(根据 IT 部门的说法,无法更新集群上的基本环境)。

这是我的 R 脚本:

require(raster)
require(doSNOW)

r1 <- raster("raster1.tif") # works perfectly (conda environment is activated here)

nc = 19
cl = makeSOCKcluster(nc)
registerDoSNOW(cl)

foreach(f=1:19)  %dopar% {

  require(raster) # does not work (conda environment is not activated here)
  # (error: there is no package called raster)

  r2 <- raster("raster2.tif")

}

我试过了(它们都不适合我):

  1. foreach(f=1:19, .packages = c("raster")) %dopar% {...}
  2. 在循环中使用系统调用(通过 R 中的系统)加载 conda 环境sytem2
  3. 并行 for 循环的未来包%dofuture%
  4. 在旧的 base-R 安装中运行作业并通过以下方式从包文件夹加载包: 适用于某些软件包,但不适用于与旧 base-R 版本不兼容的其他软件包.libPaths("mypath")

请问有人可以帮忙吗?非常感谢。

R 并行处理 conda 集群计算

评论


答:

1赞 George Ostrouchov 11/17/2023 #1

请尝试以下使用 MPI 的 shell 脚本。这与套接字群集的等效性较小,只是它使用 MPI,这在 HPC 群集上更为常见。它只会运行 19 个代码副本。您的名称和要求可能因集群而异。在运行此操作之前,还需要在登录节点 R 会话中。module loadinstall.packages("pbdMPI")

#!/bin/bash
#PBS <your-pbs-requests>
#PBS ...

module load conda
module load OpenMPI
module load r

source /mypath/conda.sh
conda activate myenv
mpirun -n 19 Rscript myscript.R

和 R 脚本、myscript。R:

library(raster)
library(pbdMPI)
rank = comm.rank()

# you probably need to form file names from ranks
filename = paste0("raster", rank, ".tif")
r <- raster(filename)

# rest of your code

shell 脚本运行 R 代码的 19 个副本,其中实例排名为 0 到 18,每个副本读取不同的文件。只要您在 shell 脚本中请求资源,该脚本就适用于任意数量的实例。

这简化了 R 代码。如果需要合并 19 份的结果,请考虑 和 pbdMPI。这种方法称为单程序多数据 (SPMD),它比 doSNOW 的经理-工作人员风格更通用、更可扩展。allreduce()allgather()

评论

0赞 George Ostrouchov 11/21/2023
此外,在 R 代码的末尾添加 MPI 的正常退出。finalize()