Как я могу печатать при использовании%dopar%
У меня есть foreach
цикл, который использует %dopar%
с doSNOW
в качестве фона. Как сделать так, чтобы цикл печатал что-то на каждой итерации?
Мой код ниже - это то, что я сейчас использую, но ничего не печатает.
foreach(ntree=rep(25,2),.combine=combine,.packages='randomForest',
.inorder=FALSE) %dopar% {
print("RANDOM FOREST")
randomForest(classForm,data=data,na.action=na.action,do.trace=do.trace,ntree=ntree,mtry=mtry)
}
6 ответов
Здесь опубликовано несколько хороших решений, но я считаю, что проще всего войти в сокет и использовать отдельный процесс для вывода вызовов журнала в консоль.
Я использую следующую функцию:
log.socket <- make.socket(port=4000)
Log <- function(text, ...) {
msg <- sprintf(paste0(as.character(Sys.time()), ": ", text, "\n"), ...)
cat(msg)
write.socket(log.socket, msg)
}
Затем вы можете поместить записи журнала в коде, например:
Log("Processing block %d of %d", i, n.blocks)
Вывод журнала можно просматривать в режиме реального времени с помощью любого простого инструмента прослушивания сокетов. Например, используя netcat в Linux:
nc -l 4000
Вышеуказанный лог-оператор будет отображаться в терминале netcat как:
2014-06-25 12:30:45: Processing block 2 of 13
Этот метод обладает преимуществом удаленной работы и обеспечивает настолько подробный вывод, насколько вы хотите вести журнал.
ps. Для тех, кто работает в Windows, см . порт netcat от Jon Craton.
pps я угадал write.socket
Функция R, вероятно, не является поточно-ориентированной, но если вы не регистрируетесь с высокой частотой, вы вряд ли столкнетесь с какой-либо проблемой. Что-то, чтобы знать, хотя.
Вывод, полученный рабочими снега, по умолчанию отбрасывается, но вы можете использовать опцию makeCluster "outfile", чтобы изменить это. Установка outfile в пустую строку ("") не позволит снегу перенаправить вывод, что часто приводит к выводу ваших сообщений печати, отображаемых на терминале главного процесса.
Просто создайте и зарегистрируйте свой кластер с чем-то вроде:
library(doSNOW)
cl <- makeCluster(4, outfile="")
registerDoSNOW(cl)
Ваш цикл foreach не должен меняться вообще.
Это работает для меня как с кластерами SOCK, так и с кластерами MPI, использующими Rmpi, созданный с помощью Open MPI. В Windows вы не увидите никакого вывода, если используете Rgui. Если вы используете Rterm.exe вместо этого, вы будете.
Обратите внимание, что в дополнение к собственному выводу вы увидите сообщения, созданные снегом, которые также могут быть полезны.
Чтобы использовать индикатор выполнения, doSNOW версии 1.0.14 имеет progress
вариант. Вот полный пример:
library(doSNOW)
library(tcltk)
library(randomForest)
cl <- makeSOCKcluster(3)
registerDoSNOW(cl)
ntasks <- 100
pb <- tkProgressBar(max=ntasks)
progress <- function(n) setTkProgressBar(pb, n)
opts <- list(progress=progress)
x <- matrix(runif(500), 100)
y <- gl(2, 50)
rf <- foreach(ntree=rep(25, ntasks), .combine=combine,
.multicombine=TRUE, .packages='randomForest',
.options.snow=opts) %dopar% {
randomForest(x, y, ntree=ntree)
}
progress
Параметр довольно общий, поэтому вы можете просто напечатать сообщение, используя такую функцию, как:
progress <- function(n) cat(sprintf("task %d is complete\n", n))
Функция может принимать 0, 1 или 2 аргумента. Первый предоставленный аргумент - это общее количество выполненных задач, а второй - номер задачи, которая только что завершила.
Простейший пример просто печатает .
когда задача завершена:
progress <- function() cat('.')
Этот пример отображает оба аргумента и может использоваться для демонстрации того, что задачи не всегда выполняются по порядку:
progress <- function(nfin, tag) {
cat(sprintf('tasks completed: %d; tag: %d\n', nfin, tag))
}
Способ, которым я отслеживал прогресс на узлах при длительных операциях, - это создание индикатора выполнения с использованием tkProgressBar
от tcltk
пакет. Это не совсем то, что вы просили, но это должно позволить вам увидеть что-то из узлов. По крайней мере, это происходит, когда кластер является кластером сокетов, работающим на локальном хосте (который является машиной Windows). Потенциальная проблема заключается в том, что индикатор выполнения либо остается и загромождает ваш монитор, либо он получает close
d и распечатанная информация исчезла. Для меня это не было проблемой, так как я просто хотел узнать, каким был текущий статус.
library(parallel)
library(doSNOW)
cl<-makeCluster(detectCores(),type="SOCK")
registerDoSNOW(cl)
Используя ваш код,
foreach(ntree=rep(25,2),.combine=combine,.packages=c('randomForest','tcltk'),
.inorder=FALSE) %dopar% {
mypb <- tkProgressBar(title = "R progress bar", label = "",
min = 0, max = 1, initial = 0, width = 300)
setTkProgressBar(mypb, 1, title = "RANDOM FOREST", label = NULL)
ans <- randomForest(classForm,data=data,na.action=na.action,do.trace=do.trace,ntree=ntree,mtry=mtry)
close(mypb)
ans
}
Вот более общий пример использования:
jSeq <- seq_len(30)
foreach(i = seq_len(2), .packages = c('tcltk', 'foreach')) %dopar% {
mypb <- tkProgressBar(title = "R progress bar", label = "",
min = 0, max = max(jSeq), initial = 0, width = 300)
foreach(j = jSeq) %do% {
Sys.sleep(.1)
setTkProgressBar(mypb, j, title = "RANDOM FOREST", label = NULL)
}
NULL
}
У меня тоже была такая же проблема. Я настраивал параметры для случайного леса, используя пакет foreach, и хотел выводить строку "Результаты" после каждой итерации, но не мог понять, не пройдя отображение индикатора выполнения и т.п.
Вот что я сделал, В своей функции я добавил эту строку
write.table(result, file=paste("RF_ntree_",ntree,"_dims_",dims,".txt", sep=""),
sep="\t", row.names=F)
Поэтому после каждой итерации результаты записываются в текстовый файл с такими именами, как RF_ntree_250_dims_100.txt.
Поэтому, если я хочу отслеживать прогресс, я просто обновляю папку, в которую записываются текстовые файлы.
PS: результаты накапливаются в кадре данных тоже.
cat("blah-blah-blah\n", file=stdout())
имеет тенденцию работать для меня (linux/emacs/ess). Я думаю, это также работает для некоторых других платформ.
Альтернатива - использовать ведение журнала файлов (например, пакет log4r) и отдельно выводить вывод на экран (например, с помощью tail -f).
Это хорошо работает, если вы все равно планируете создавать логи, и вы можете использовать существующие пакеты со всеми связанными с этим сигналами.