Превышено максимальное количество DLL в R
Я использую RStan для выборки из большого числа гауссовских процессов (GPs), то есть используя функцию stan(). Для каждого GP, который мне подходит, загружается другая DLL, что видно из запуска команды R
getLoadedDLLs()
Проблема, с которой я сталкиваюсь, заключается в том, что, поскольку мне нужно установить столько уникальных GP, я превысил максимальное количество DLL, которые могут быть загружены, после чего я получаю следующую ошибку:
Error in dyn.load(libLFile) :
unable to load shared object '/var/folders/8x/n7pqd49j4ybfhrm999z3cwp81814xh/T//RtmpmXCRCy/file80d1219ef10d.so':
maximal number of DLLs reached...
Насколько я могу судить, это устанавливается в Rdynload.c базового R-кода следующим образом:
#define MAX_NUM_DLLS 100
Итак, мой вопрос: что можно сделать, чтобы исправить это? Строение R из источника с большим MAX_NUM_DLLS не является вариантом, так как мой код будет запускаться сотрудниками, которые не будут удобны в этом процессе. Я пробовал наивный подход просто выгружать библиотеки DLL, используя dyn.unload() в надежде, что они просто будут перезагружены, когда они понадобятся снова. Разгрузка работает отлично, но когда я пытаюсь снова использовать подгонку, R довольно неудивительно падает с ошибкой, например:
*** caught segfault ***
address 0x121366da8, cause 'memory not mapped'
Я также попытался отсоединить RStan в надежде, что библиотеки DLL будут автоматически выгружены, но они сохраняются даже после разгрузки пакета (как и ожидалось, учитывая следующее в справке для отсоединения: "Отключение вообще не выгружает динамически загружаемый скомпилированный код (DLL)" ).
Из этого вопроса Можно ли выгрузить DLL файлы пакета Rcpp без перезагрузки R?, кажется, что library.dynam.unload()
может иметь определенную роль в решении, но я не знаю, t имел какой-либо успех, используя его для выгрузки DLL, и я подозреваю, что после выгрузки DLL я столкнулся с тем же самым segfault, что и раньше.
EDIT: добавление минимального, полнофункционального примера:
Код R:
require(rstan)
x <- c(1,2)
N <- length(x)
fits <- list()
for(i in 1:100)
{
fits[i] <- stan(file="gp-sim.stan", data=list(x=x,N=N), iter=1, chains=1)
}
Этот код требует, чтобы следующее определение модели находилось в рабочем каталоге в файле gp-sim.stan(эта модель является одним из примеров, включенных в Stan):
// Sample from Gaussian process
// Fixed covar function: eta_sq=1, rho_sq=1, sigma_sq=0.1
data {
int<lower=1> N;
real x[N];
}
transformed data {
vector[N] mu;
cov_matrix[N] Sigma;
for (i in 1:N)
mu[i] <- 0;
for (i in 1:N)
for (j in 1:N)
Sigma[i,j] <- exp(-pow(x[i] - x[j],2)) + if_else(i==j, 0.1, 0.0);
}
parameters {
vector[N] y;
}
model {
y ~ multi_normal(mu,Sigma);
}
Примечание. Этот код занимает довольно много времени для запуска, поскольку он создает модели ~ 100 Stan.
Ответы
Ответ 1
Я не могу говорить о проблемах, связанных с DLL, но вам не нужно собирать эту модель каждый раз. Вы можете скомпилировать модель один раз и повторно использовать ее, что не вызовет этой проблемы, и это ускорит ваш код.
Функция stan
является оболочкой для stan_model
, которая компилирует модель и метод sampling
, который извлекает образцы из модели. Вы должны запустить stan_model
один раз, чтобы скомпилировать модель и сохранить ее для объекта, а затем использовать метод sampling
для этого объекта для рисования образцов.
require(rstan)
x <- c(1,2)
N <- length(x)
fits <- list()
mod <- stan_model("gp-sim.stan")
for(i in 1:100)
{
fits[i] <- sampling(mod, data=list(x=x,N=N), iter=1, chains=1)
}
Это похоже на проблему запуска параллельных цепей, обсуждаемых в Rstan wiki. Ваш код мог бы ускориться, заменив цикл for тем, что параллельно обрабатывает выборку.
Ответ 2
Вот, что я использую для запуска нескольких моделей stan в строке (Win10, R 3.3.0).
Мне нужно было не только выгружать DLL файлы, но и удалять их и другие временные файлы. Затем имя файла для меня отличалось от найденного в объекте stan, как предположил Бен.
dso_filenames <- dir(tempdir(), pattern=.Platform$dynlib.ext)
filenames <- dir(tempdir())
for (i in seq(dso_filenames))
dyn.unload(file.path(tempdir(), dso_filenames[i]))
for (i in seq(filenames))
if (file.exists(file.path(tempdir(), filenames[i])) & nchar(filenames[i]) < 42) # some files w/ long filenames that didn't like to be removeed
file.remove(file.path(tempdir(), filenames[i]))