嗨,好人!
欢迎来到我的教程的第二部分,该教程有关如何提高R {raster}包的处理速度。在里面 前一部分 我向您展示了如何通过增加最大内存限制来加速R。这部分会更多“sophisticated”因为我们将看看如何并行化R进程。
平行吗?等一下
“Paralellise”是一定牛遗漏花哨的词,但这是什么意思呢?好吧,您可能知道您的CPU(如果您没有’请牢记在90年代)拥有多个核心来处理您的请求。例如,我的笔记本电脑有4个核,而dektop PC有8个核。如果使用R进行计算,通常只有一定牛遗漏核用于处理此计算,而其他核则基本上处于休眠状态或正在处理一些开销操作,例如复制数据并确保您的其他程序运行正常。下图显示了在典型的R会话期间,我的4个内核中的CPU使用情况:
您可以看到只有一定牛遗漏核心(在这种情况下’s的核心3)正在使用,而其他核心的利用率基本上为0%。
想象我们有一定牛遗漏巨大的处理任务,我们必须一遍又一遍地执行(例如inisde 对于循环)。这就是R在这种情况下正在做的事情:它仅激活一定牛遗漏内核,并使其处理循环的迭代, 一步一步地,一次迭代。 这意味着一定牛遗漏内核将完成所有工作,而另一定牛遗漏内核本质上将(几乎)什么都不做,因为默认情况下R会使用单内核处理。真是浪费,对吧?为什么不使用所有内核进行循环?例如,核心1处理迭代1,而核心2处理迭代2,而核心3处理迭代3,…等本质上是什么 并行化 意味着:同时(并行)使用多个内核来执行重复任务。那么我们如何在R中实现呢?
并行化– Step by Step
没有并行化的示例
让 ’例如,我们有一定牛遗漏包含八个层堆栈的文件夹,我们想计算每个堆栈的NDVI。这就是我使用for循环计算NDVI的方式 没有 并行处理:
#load 栅格 package library(raster) #path to directory with folders path <- "Downloads/Stacks/" #get file names using list.files() function stack_list <- list.files(path, 模式=".tif$", full.names=T) #Loop over every stack in filelist for(我在1:长度(stack_list)) { #stack image i img <- stack(stack_list[i]) #calc ndvi 对于 image i ndvi <- (img[[4]]-img[[3]]) / (img[[4]]+img[[3]]) #construct filename outname <- sub(pattern = ".tif", replacement = "_ndvi.tif", x = stack_list [i]) #export 栅格 writeRaster(ndvi, filename = outname, overwrite = T) }
对于较小的栅格(4000x4000px),此代码可以正常工作,大约需要2分钟才能执行。但是,假设您有100个要处理的栅格。在这里使用多个内核将为您节省大量时间。这是您的操作方式:
并行化示例
library(raster) library(doParallel) #Foreach Parallel Adaptor library(foreach) #Provides 前言 looping construct #Define how many cores you want to use UseCores <- detectCores() -1 #Register CoreCluster cl <-makeCluster(UseCores) registerDoParallel(cl) path <- "Downloads/Stacks/" stack_list <- list.files(path, 模式=".tif$", full.names=T) #Use 前言 loop 和 %dopar% command foreach(i = 1:length(stack_list))%dopar%{ library(raster) img <- stack(stack_list[i]) ndvi <- (img[[4]]-img[[3]]) / (img[[4]]+img[[3]]) outname <- sub(pattern = ".tif", replacement = "_ndvi.tif", x = stack_list [i]) writeRaster(ndvi, filename = outname, overwrite = T) } #end cluster stopCluster(cl)
该代码看起来非常相似,仅在某些部分有所不同:
首先,您需要加载 doParallel 和 前言 包。它们使R能够执行并行处理。
在第二步中,您定义了要用于计算的核心数量:
#Define how many cores you want to use UseCores <- detectCores() -1 #Register CoreCluster cl <-makeCluster(UseCores) registerDoParallel(cl)
功能 detectCores() 返回可用的内核数。注意:您应始终减少使用一定牛遗漏内核,因此将有一定牛遗漏内核可用于处理诸如复制等开销任务。否则,您的PC可能会崩溃。用 makeCluster() 和 registerDoParallel() 您注册内核以进行并行化。
最后的变化是 前言() 循环而不是 对于 循环:
前言(i = 1:length(stack_list))%dopar%{ library(raster) #calulation here }
注意:
- 方括号内的语法不同于您要编写的常规for循环 我在1:长度(stack_list))在这里写 i = 1:length(stack_list))。
- 在循环括号之后,您必须编写 %dopar% 代表什么“do parallel”.
- 您必须在循环内加载计算所需的库!在这种情况下,我们将需要光栅包,因此我们使用library(raster)加载光栅包。 内 循环语句。
最后,我们通过调用关闭并行化 stopCluster()。
基准测试
通过使用并行化代码,当我使用三个内核而不是一定牛遗漏内核时,我设法将处理时间增加了50%。这是我使用单核处理(右上角)时的CPU使用情况:
您会看到两个内核正在工作,一定牛遗漏正在执行计算,第二个正在处理开销。
这是使用所有可用核心(右上角)时我的CPU使用情况的样子:
下一定牛遗漏教程将介绍如何使用 簇() 该函数可以使用某些栅格函数的多核处理。
再见!
13条留言
您可以在这篇文章中发表评论。
非常有用的帖子。
感谢您的简单解释。
地亚哥 5年前
别客气。感谢您的反馈。
马丁 5年前
是的,谢谢你的这篇文章!最全面,易于理解的示例我’关于如何使栅格处理与R并行化,我们深表感谢。
塞思·G。 3年前
感谢您的好评!它’s very appreciated!!
马丁 3年前
谢谢你的帖子,马丁。我尝试使用您的方法并行化dismo :: predict()。我想预测多个RasterStack的拟合模型(即,未来的替代方案)。使用下面的示例,我得到以下错误— ‘{中的错误:任务1失败– “缺少图层(或名称错误)”‘?
如果我指定了RasterStack(例如,‘future5’),但如果我指向一定牛遗漏列表(即,‘stack_list[i]’)?
有什么建议?
#哪里‘m’=在dismo中导出的maxent模型
前言(i = 1:length(stack_list))%dopar%{
图书馆(展示)
p <- predict(m, stack_list [i])
}
杰森M. 3年前
嘿!
Try stack_list[[i]] instead of stack_list [i]?
祝好运!
马丁 3年前
感谢您及时的回复!不幸的是,仍然会遇到相同的错误(粘贴在下面)?
{中的错误:任务1失败– “缺少图层(或名称错误)”
3. stop(simpleError(msg,call = expr))
2. e $ fun(obj,replace(ex),parent.frame(),e $ 数据)
1. 前言(i = 1:length(stack_list))%dopar%{
图书馆(展示)
pc <-预测(m,stack_list [[i]])
}
杰森M. 3年前
嗯..如果您使用简单的for循环,是否可以正常工作?
此外,您可以发布str(stack_list)吗?
干杯
马丁 3年前
对不起反应迟钝,我请了几天假…我认为这几乎可以解决,但是仍然存在错误?任何帮助,不胜感激!
我发现我需要创建一定牛遗漏rasterStacks列表(即,‘stacks <-as.list(c(base,s01,s02,s03))'),而不是字符串的向量(即,'stacks pc
类别:RasterStack
层数:0
有什么建议?
################################
图书馆(展示)
图书馆(rgdal)
图书馆(读者)
#objects()的描述
# ‘species’ = list of 种类
# ‘me’=单个物种的最大模型
# ‘t’=单个物种的阈值
# ‘base’ = 栅格Stack 对于 基础line climate (1990-2009)
# ‘s01’ – ‘s12’= 12种未来气候方案中的每一定牛遗漏的rasterStacks
# ‘stacks’=堆栈名称列表
# ‘pc’=预测的栅格堆栈(连续)
#导入用于多种气候场景的rasterStacks
l_0<- list.files(path="问:/ refugia / climate / epoch_1990-2009", 模式='.tif',
full.names = T)
基础 <-堆栈(l_0 [c(2,4,5,6,13,14,15)])
l_1<- list.files(path="问:/ refugia / climate / epoch_2020-2039 / future01",
模式='.tif', full.names = T)
s01<-堆栈(l_1 [c(2,4,5,6,13,14,15)])
l_2<- list.files(path="问:/ refugia / climate / epoch_2020-2039 / future02",
模式='.tif', full.names = T)
s02<-堆栈(l_2 [c(2,4,5,6,13,14,15)])
l_3<- list.files(path="问:/ refugia / climate / epoch_2020-2039 / future03",
模式='.tif', full.names = T)
s03<-堆栈(l_3 [c(2,4,5,6,13,14,15)])
# create list of 种类
setwd("问:/避难所/观察/")
spp<- read_csv("species_obs.csv", col_names=TRUE,
col_types = cols(speciesModel = col_character()))
种类<-唯一(spp $ 种类Model)
#创建气候栅格列表
栈<-as.list(c(base,s01,s02,s03))
#创建用于栅格输出的场景名称列表
情景<- c('current', 'future1', 'future2', 'future3')
对于(j in 1:length(species)){
pc <- stack()
路径<- paste('Q:/refugia/maxent/', 种类[j], '_modelfit.rdata', sep = '')
附加(路径);我<- me;
分离(粘贴('file:',path,sep=''),character.only = TRUE)
图书馆(doParallel)
库(foreach)
UseCores<- detectCores() -1
cl <-makeCluster(UseCores)
registerDoParallel(cl)
前言(i = 1:4)%dopar%{
图书馆(展示)
pc <- predict(me, 栈[[i]])
setwd('Q:/refugia/test')
writeRaster(pc [[i]],filename = paste(species [j],"_", scenario[i], "_prediction.tif",
sep =""), 对于mat="GTiff",覆盖= T,进度='text')
}
stopCluster(cl)
rm(路径,我,个人电脑)
}
杰森M. 3年前
CATPCHA代码不成功时,先前的帖子已损坏?抱歉,代码中出现了换行符(在“注释”窗口中看起来不错),但最上段应阅读…
我发现我需要创建一定牛遗漏rasterStacks列表(即,‘stacks <-as.list(c(base,s01,s02,s03))'),而不是字符串的向量(即,'stacks <- c('base', 's01', 's02', 's03')')。代码(粘贴在下面)现在运行—我所有的处理器都具有相似/平行的性能曲线。我认为dismo :: predict()步骤已成功运行(即,我的处理器都旋转了20分钟=预期时间),但随后该脚本因尝试将预测写为rasterStack而失败。任何帮助,不胜感激!
杰森M. 3年前
尴尬的… here is the error…
{中的错误:任务2失败– “not a valid subset”
> pc
类别:RasterStack
层数:0
杰森M. 3年前
[…]通过R:提高{raster}处理的速度:第2/3部分并行化[…]
栅格并行化– Avian Ecologist 2年前
嘿,谢谢你的有趣帖子。
在运行并行进程时,您是否对rasterOptions的设置有见解?
特别是我不清楚分配给一定牛遗漏进程的内存份额(memfrac选项)是否应考虑已注册的内核数量(即,确保使用的内核数量乘以内存份额)< 1)?
最好,
瓦伦丁
瓦伦丁 10个月前
发表回复