Я использую пакет RNetLogo для запуска анализов чувствительности на моей модели NetLogo. Моя модель имеет 24 параметра, которые мне нужно изменить - поэтому параллелизм этого процесса был бы идеальным! Я сопровождал пример с виньеткой «Parallel processing with the RNetLogo package» от Thiele, которая использует пакет «parallel» совместно с «RNetLogo».Только один процессор используется во время работы моделей NetLogo с использованием parApply
Мне удалось получить R, чтобы инициализировать модель NetLogo на всех 12 моих процессорах, которые я проверил с помощью gui = TRUE. Проблема возникает, когда я пытаюсь запустить код моделирования на 12 процессорах, используя «parApply». Эта строка работает без ошибок, но работает только на одном из процессоров (используя около 8% от моей общей мощности процессора). Вот макет из моего файла R коды - я включил некоторый закомментированный код в конце, показывая, как я бег моделирования, не пытаясь parallelise:
### Load packages
library(parallel)
### Set up initialisation function
prepro <- function(dummy, gui, nl.path, model.path) {
library(RNetLogo)
NLStart(nl.path, gui=gui)
NLLoadModel(model.path)
}
### Set up finalisation function
postpro <- function(x) {
NLQuit()
}
### Set paths
# For NetLogo
nl.path <- "C:/Program Files/NetLogo 6.0/app"
nl.jarname <- "netlogo-6.0.0.jar"
# For the model
model.path <- "E:/Model.nlogo"
# For the function "sim" code
sim.path <- "E:/sim.R"
### Set base values for parameters
base.param <- c('prey-max-velocity' = 25,
'prey-agility' = 3.5,
'prey-acceleration' = 20,
'prey-deceleration' = 25,
'prey-vision-distance' = 10,
'prey-vision-angle' = 240,
'time-to-turn' = 5,
'time-to-return-to-foraging' = 300,
'time-spent-circling' = 2,
'predator-max-velocity' = 35,
'predator-agility' = 3.5,
'predator-acceleration' = 20,
'predator-deceleration' = 25,
'predator-vision-distance' = 20,
'predator-vision-angle' = 200,
'time-to-give-up' = 120,
'number-of-safe-zones' = 1,
'number-of-target-patches' = 5,
'proportion-obstacles' = 0.05,
'obstacle-radius' = 2.0,
'obstacle-radius-range' = 0.5,
'obstacle-sensitivity-for-prey' = 0.95,
'obstacle-sensitivity-for-predators' = 0.95,
'safe-zone-attractiveness' = 500
)
## Get names of parameters
param.names <- names(base.param)
### Load the code of the simulation function (name: sim)
source(file=sim.path)
### Convert "base.param" to a matrix, as required by parApply
base.param <- matrix(base.param, nrow=1, ncol=24)
### Get the number of simulations we want to run
design.combinations <- length(base.param[[1]])
already.processed <- 0
### Initialise NetLogo
processors <- detectCores()
cl <- makeCluster(processors)
clusterExport(cl, 'sim')
gui <- FALSE
invisible(parLapply(cl, 1:processors, prepro, gui=gui, nl.path=nl.path, model.path=model.path))
### Run the simulation across all processors, using parApply
sim.result.base <- parApply(cl, base.param, 1, sim,
param.names,
no.repeated.sim = 100,
trace.progress = FALSE,
iter.length = design.combinations,
function.name = "base parameters")
### Run the simulation on a single processor
#sim.result.base <- sim(base.param,
# param.names,
# no.repeated.sim = 100,
# my.nl1,
# trace.progress = TRUE,
# iter.length = design.combinations,
# function.name = "base parameters")
Вот макет для «сим» функция (адаптировано из бумаги Тиле в «Облегчение оценки параметров и анализа чувствительности моделей на базе агентов - поваренную книгу, используя NetLogo и R»):
sim <- function(param.set, parameter.names, no.repeated.sim, trace.progress, iter.length, function.name) {
# Some security checks
if (length(param.set) != length(parameter.names))
{ stop("Wrong length of param.set!") }
if (no.repeated.sim <= 0)
{ stop("Number of repetitions must be > 0!") }
if (length(parameter.names) <= 0)
{ stop("Length of parameter.names must be > 0!") }
# Create an empty list to save the simulation results
eval.values <- NULL
# Run the repeated simulations (to control stochasticity)
for (i in 1:no.repeated.sim)
{
# Create a random-seed for NetLogo from R, based on min/max of NetLogo's random seed
NLCommand("random-seed",runif(1,-2147483648,2147483647))
## This is the stuff for one simulation
cal.crit <- NULL
# Set NetLogo parameters to current parameter values
lapply(seq(1:length(parameter.names)), function(x) {NLCommand("set ",parameter.names[x], param.set[x])})
NLCommand("setup")
# This should run "go" until prey-win =/= 5, i.e. when the pursuit ends
NLDoCommandWhile("prey-win = 5", "go")
# Report a value
prey <- NLReport("prey-win")
# Report another value
pred <- NLReport("predator-win")
## Extract the values we are interested in
cal.crit <- rbind(cal.crit, c(prey, pred))
# append to former results
eval.values <- rbind(eval.values,cal.crit)
}
## Make sure eval.values has column names
names(eval.values) <- c("PreySuccess", "PredSuccess")
# Return the mean of the repeated simulation results
if (no.repeated.sim > 1) {
return(colMeans(eval.values))
}
else {
return(eval.values)
}
}
Я думаю, что проблема может лежать в «nl.obj» строки, RNetLogo использует для идентификации экземпляра NetLogo, на котором вы хотите запустить код, однако я пробовал несколько разных способов его исправления, и я не смог прийти p с решением, которое работает. Когда я инициализирую NetLogo на всех процессорах, используя код, представленный в примере Тиле, я не устанавливаю значение «nl.obj» для каждого экземпляра, так что я предполагаю, что RNetLogo использует какой-то список по умолчанию? Однако в оригинальном коде Thiele функция «sim» требует, чтобы вы указали, какой экземпляр NetLogo вы хотите запустить, поэтому R будет выплевывать ошибку при попытке запустить финальную строку (Ошибка в checkForRemoteErrors (val): один узел возникла ошибка: отсутствует аргумент «nl.obj», без значения по умолчанию). Я изменил код функции «sim», так что он не требует этого аргумента и просто принимает значение по умолчанию для nl.obj - но тогда моя симуляция работает только на одном процессоре. Поэтому я считаю, что по умолчанию «sim» должен запускать код только в одном экземпляре NetLogo. Я не уверен, как это исправить.
Это также первый раз, когда я использовал пакет «parallel», поэтому я мог бы пропустить что-то очевидное, чтобы сделать с «parApply». Любое понимание было бы высоко оценено!
Заранее благодарен!
Спасибо за ответ @Tyr! Я попытался изменить свой код, чтобы он соответствовал вашему примеру, но я получаю ошибку: «Ошибка в parApply (cl, base.param, 1, function (x) {: dim (X) должна иметь положительную длину». Но когда Я проверяю длину X (который я предполагаю base.param), это 24. У вас это вообще получилось? – Rebecca
Woops, поцарапайте это @Tyr, я исправил его (перестроил несколько вещей и забыл преобразовать в матрица) .Код работает нормально, но, к сожалению, проблема все еще существует - он использует только один процессор. Если для вас работает один и тот же код для процессоров, мне интересно, есть ли что-то, что мне нужно переопределить в R, чтобы заставить его использовать больше, чем один процессор? Hmmm. – Rebecca
ahh.При этом base.param должен быть матрицей. Я снова проверил ваш код и посмотрел на конструкцию вашей матрицы параметров. Верно ли, что в вашей матрице у вас есть только один эксперимент, то есть одна строка в вашей матрице? Это объясняет, почему используется только одно ядро, потому что есть только один эксперимент.Параллелизация работает только в том случае, если в вашей матрице параметров имеется несколько строк. Затем каждая строка моделируется другим ядром. – Tyr