我正在使用nimble
包来使用并行计算运行 MCMC 链。nimbleMCMC
Nimble 通常对于使用集成功能或runMCMC
组件功能按顺序运行的每个链都有很好的进度条。
nimble
您需要创建一个包含所有模型代码的自定义函数,包括该函数runMCMC
,然后parLapply
用于在集群上并行运行不同链的自定义函数。
https://r-nimble.org/nimbleExamples/parallelizing_NIMBLE.html
这计算得很好,但它会丢失原始进度条并且不显示进度。
这里有解决方案,但我认为它们不适用于 Nimble 框架:如何在 R 中显示并行计算中的代码进度?
可以使用 来创建进度条pblapply
,但这会将进度计算为基于已完成链/总链的百分比。例如,如果在 8 个内核上并行运行 8 个链,这基本上是没有信息的,因为它保持在 0%,直到所有链同时并行完成并跳转到 100%。
有没有办法从runMCMC
自定义函数中打印原始进度条?或者,以其他方式显示进度?
这是一个玩具 CJS 隐藏马尔可夫模型来说明:
library(nimble)
library(parallel)
library(pbapply)
ymat <- matrix(sample(c(0,1),120,replace = TRUE),ncol = 6, nrow = 20)
y <- ymat
detectCores() # Number of cores on the machine = 8
this_cluster <- makeCluster(4)
index <- c(1:4)
paraChain_code <- function(index, y){
library(nimble)
first <- apply(y, 1, function(x) min(which(x!= 0),na.rm = TRUE))
hmm.model<- nimbleCode({
# Priors
phi ~ dunif(0,1) # prior for survival φ
p ~ dunif(0,1) # prior for detection p
# Vector of initial state probabilities δ
delta[1] <- 1 # Alive
delta[2] <- 0 # Dead
# Transition matrix Γ
gamma[1,1] <- phi # transition Pr(alive t --> alive t+1)
gamma[1,2] <- 1-phi # transition Pr(alive t --> dead t+1)
gamma[2,1] <- 0 # transition Pr(dead t --> alive t+1)
gamma[2,2] <- 1 # transition Pr(dead t --> dead t+1)
# Observation matrix Ω
omega[1,1] <- 1-p # observation Pr(alive t --> not detected t)
omega[1,2] <- p # observation Pr(alive t --> detected t)
omega[2,1] <- 1 # observation Pr(dead t --> not detected t)
omega[2,2] <- 0 # observation Pr(dead t --> detected t)
# Likelihood
for(i in 1:N){ # Loops over each individual (row)
z[i,first[i]] ~ dcat(delta[1:2]) # Draws an initial state
for(j in (first[i]+1):T){ # Loops through each time point (column)
z[i,j] ~ dcat(gamma[z[i,j-1], 1:2]) # Draws current state based on previous state
y[i,j] ~ dcat(omega[z[i,j], 1:2]) # Draws an observation based on current state.
}
}
})
# Defines constants in the model
my.constants <- list(N = nrow(y), # N individual
T = ncol(y), # N of time points
first = first) # occasions of first capture
# Defines data in the model
# To remove 0s. 1 is non-detected, 2 is detected
my.data <- list(y = y+1)
# Defines initial values for states and probabilities
zinits <- y + 1
zinits[zinits == 2] <- 1
zinits[is.na(zinits) == TRUE] <- 1
initial.values <- list(phi = runif(1,0,1),
p = runif(1,0,1),
z = zinits)
# Specfies the parameters of interest to record in output
parameters.to.save <- c("phi","p","z")
#MCMC model details
n.iter <- 1000
n.burnin <- 200
myModel <- nimbleModel(code = hmm.model,
constants = my.constants,
data = my.data,
inits = initial.values)
#monitors = parameters.to.save)
#niter = n.iter,
#nburnin = n.burnin)
#nchains = n.chains,
CmyModel <- compileNimble(myModel)
myMCMC <- buildMCMC(CmyModel, monitors = parameters.to.save, enableWAIC = TRUE)
CmyMCMC <- compileNimble(myMCMC)
### This is the Nimble function that normally produces the progress bar. ###
results <- runMCMC(CmyMCMC, niter = n.iter, nburnin = n.burnin, WAIC = TRUE)
############################################################################
return(results)
}
# Function works correctly for multiple chains with parLapply
system.time({
chain_output <- parLapply(cl = this_cluster, index,
fun = paraChain_code,
y = ymat)
})
# The pblapply function includes a progress bar, but only for completed chains/total chains.
system.time({
chain_output <- pblapply(X = index, cl = this_cluster,
FUN = paraChain_code,
y = ymat)
})
stopCluster(this_cluster)