Проблема воспроизвести результаты с параллельного SVM в R - PullRequest
5 голосов
/ 25 сентября 2019

Я не могу установить начальное значение для получения воспроизводимых результатов от parallelSVM().

 library(e1071)
 library(parallelSVM)

 data(iris)
 x <- subset(iris, select = -Species)
 y <- iris$Species

set.seed(1)
model       <- parallelSVM(x, y)
parallelPredictions <- predict(model, x)

set.seed(1)
model2       <- parallelSVM(x, y)
parallelPredictions2 <- predict(model2, x)

all.equal(parallelPredictions,parallelPredictions2) 

Я знаю, что это неправильный способ установить начальное значение для многоядерных операций, но я понятия не имею, что делать альтернативно.

Я знаю, что есть опция,при использовании mclapply, но это не помогает в моей ситуации.


Редактировать:
Я нашел решение, изменив функцию trainSample() в parallelSVM с помощью trace и пакет doRNG для семян с петлей foreach.

Кто-нибудь знает лучшее решение?

1 Ответ

2 голосов
/ 25 сентября 2019

Короче говоря, в parallelSVM нет реализованного метода для решения этой проблемы.Однако пакет использует пакеты foreach и doParallel для обработки своих параллельных операций.И достаточно усердно копаясь в stackoverflow, решение возможно!

Кредиты на этот ответ , на использование пакета doRNG и этот ответ за предоставление мнеидея для более простого закрытого решения.

Решение:

В пакете parallelSVM распараллеливание происходит с помощью функций parallelSVM::registerCores.Эта функция просто вызывает doParallel::registerDoParallel с количеством ядер, без дополнительных аргументов.Моя идея состоит в том, чтобы просто изменить функцию parallelSVM::registerCores таким образом, чтобы она автоматически устанавливала начальное значение после создания нового кластера.

При выполнении параллельных вычислений, в которых вам нужно параллельное начальное число, необходимо обеспечить две вещи:

  1. Начальное число нужно передать каждому узлу в кластере
  2. Генератор должен быть асимптотически случайным в кластерах.

К счастью, пакет doRNG обрабатывает первый и использует начальное число, которое в порядке2. Используя комбинацию unlockNamespace и assign, мы можем перезаписать parallelSVM::registerCores, так что он включает вызов doRNG::registerDoRNG с соответствующим начальным числом (функция в конце ответа).Делая это, мы на самом деле можем получить надлежащую воспроизводимость, как показано ниже:

library(parallelSVM)
library(e1071)
data(magicData)
set.seed.parallelSWM(1) #<=== set seed as we would normally.
#Example from help(parallelSVM)
system.time(parallelSvm1 <- parallelSVM(V11 ~ ., data = trainData[,-1],
                                       numberCores = 4, samplingSize = 0.2, 
                                       probability = TRUE, gamma=0.1, cost = 10))
system.time(parallelSvm2 <- parallelSVM(V11 ~ ., data = trainData[,-1],
                                       numberCores = 4, samplingSize = 0.2, 
                                       probability = TRUE, gamma=0.1, cost = 10))
pred1 <- predict(parallelSvm1)
pred2 <- predict(parallelSvm2)
all.equal(pred1, pred2)
[1] TRUE
identical(parallelSvm1, parallelSvm2)
[1] FALSE

Обратите внимание, что identical не обладает способностью правильно оценивать выходные объекты по parallel::parallelSvm, и поэтому прогнозы лучше проверятьидентичны ли модели.

В целях безопасности давайте проверим, так ли это и в случае воспроизводимого примера в вопросе

x <- subset(iris, select = -Species)
y <- iris$Species
set.seed.parallelSWM(1) #<=== set seed as we would normally (not necessary if above example has been run).
model       <- parallelSVM(x, y)
model2       <- parallelSVM(x, y)
parallelPredicitions <- predict(model, x)
parallelPredicitions2 <- predict(model2, x)
all.equal(parallelPredicitions, parallelPredicitions2)
[1] TRUE

Фу.

И последнее, еслимы закончили, или, если мы снова хотели получить случайные начальные числа, мы можем сбросить начальное значение, выполнив

set.seed.parallelSWM() #<=== set seed to random each execution (standard).
#check:
model       <- parallelSVM(x, y)
model2       <- parallelSVM(x, y)
parallelPredicitions <- predict(model, x)
parallelPredicitions2 <- predict(model2, x)
all.equal(parallelPredicitions, parallelPredicitions2)
[1] "3 string mismatches"

(выходной сигнал будет отличаться, так как начальное значение RNNG не установлено)

setФункция .seed.parallelSWM

кредитует этот ответ .Обратите внимание, что нам, возможно, не придется удваивать назначение, но здесь я просто повторил ответ, не проверяя, можно ли еще уменьшить код.

set.seed.parallelSWM <- function(seed, once = TRUE){
    if(missing(seed) || is.character(seed)){
        out <- function (numberCores) 
        {
            cluster <- parallel::makeCluster(numberCores)
            doParallel::registerDoParallel(cluster)
        }
    }else{
        require("doRNG", quietly = TRUE, character.only = TRUE)
        out <- function(numberCores){
            cluster <- parallel::makeCluster(numberCores)
            doParallel::registerDoParallel(cluster)
            doRNG::registerDoRNG(seed = seed, once = once)
        }
    }
    unlockBinding("registerCores", as.environment("package:parallelSVM"))
    assign("registerCores", out, "package:parallelSVM")
    lockBinding("registerCores", as.environment("package:parallelSVM"))
    unlockBinding("registerCores", getNamespace("parallelSVM"))
    assign("registerCores", out, getNamespace("parallelSVM"))
    lockBinding("registerCores", getNamespace("parallelSVM"))
    #unlockBinding("registerCores", as.environment("package:parallelSVM"))
    invisible()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...