rmlr3

Error with 'classif.svm' learner while tuning parameters : <simpleError: '<OptimizerMbo>' does not support param sets with dependencies!>


I am tuning parameters for multiple learners using parallel computing. However, I am encountering this error message for the learner 'classif.svm':

<simpleError: '<OptimizerMbo>' does not support param sets with dependencies!>

I don’t understand why I am receiving this error message because there doesn’t seem to be any dependency according to this command:

> learner_svm$param_set$values
$type
[1] "C-classification"

$cost
Tuning over:
range [1e-04, 10000] (log scale)


$kernel
Tuning over:
p_fct(levels = c("polynomial", "radial", "sigmoid", "linear"))

$degree
Tuning over:
range [2, 5]


$gamma
Tuning over:
range [1e-04, 10000] (log scale)

Why am I encountering this issue? But then again, is this normal because in the mlr3 book, it is noted that SVM models have dependencies?

Here is an example to reproduce this problem. I have 7 different learners, but to speed things up, I'm only using two of them:

    library(mlr3)
library(mlr3spatial)
library(mlr3spatiotempcv)
library(mlr3pipelines)
library(mlr3tuningspaces)
library(mlr3extralearners)
library(mlr3learners)
library(remotes)
library(mlr3mbo)
library(glmnet)
library(doSNOW)
library(dplyr)
library(DiceKriging)
library(ranger)
library(rgenoud)
## remotes::install_github("mlr-org/mlr3extralearners@*release")

data <- data.frame(ID = 1:1742, x = runif(1742, -130.88, -61.12), y = runif(1742, 12.12, 61.38), year = runif(1742, 2005, 2020), presence = rep(0:1, each=871), 
                   V1 = runif(1742, -3.66247, 2.95120), V2 = runif(1742, -1.6501, 7.5510))
## head(data)


data$presence <- as.factor(data$presence)
task <- mlr3spatial::as_task_classif_st(x = data, target = "presence", positive = "1", coordinate_names = c("x", "y"), crs = "+proj=longlat +datum=WGS84 +no_defs +type=crs")

task$set_col_roles("ID", roles = "space")
task$set_col_roles("year", roles = "time")

learner_glmnet <- mlr3tuningspaces::lts(mlr3::lrn("classif.glmnet", predict_type = "prob"))
learner_svm <- mlr3tuningspaces::lts(mlr3::lrn("classif.svm", predict_type = "prob", type  = "C-classification"))

learners <- c(learner_glmnet, learner_glmnet, learner_glmnet, learner_glmnet, learner_glmnet, learner_glmnet, learner_svm)

inner_resampling <- mlr3::rsmp("sptcv_cstf", folds = 2)
measures <- c(mlr3::msr("classif.sensitivity"), mlr3::msr("classif.specificity"), mlr3::msr("classif.acc"))
tuner <- mlr3tuning:::tnr("mbo")

cl <- parallel::makeCluster(4, outfile = "test.txt")
doSNOW::registerDoSNOW(cl)

tuned_hyperparameter_list <- foreach::foreach(learner_ID = 1:length(learners), .errorhandling = "pass", .packages = c("dplyr")) %dopar% {
  
  set.seed(1)
  tuning_instance <- mlr3tuning::ti(task = task,
                                    learner = learners[[learner_ID]],
                                    resampling = inner_resampling,
                                    measures = measures,
                                    terminator = mlr3tuning::trm("evals", n_evals = 1))
  
  ## Run the tuning process  
  tuner$optimize(tuning_instance)
  
  df <- data.frame(tuning_instance$result)
  ## print(df)
  
  ## Return a data frame
  return(df)
  
}

parallel::stopCluster(cl)

Solution

  • The culprit is that you use a TunerMbo that is not configured at all (i.e., with respect to the loop function, surrogate, acquisition function and acquisition function optimizer). In such a scenario TunerMbo will "configure itself" prior to optimization (see ?mbo_defaults), i.e., prior to optimizing the instance the fields loop_function, surrogate, acq_function, acq_optimizer, ... will be populated with sensible defaults. You can see this for example when inspecting these fields after tuning.

    In your code, the search space of the glmnet and svm are different in the sense that the svm has dependencies. As the tuner first configures itself suitable to the glmnet search space and does not automatically reconfigure itself to the new search space afterwards, the error as described by you will be triggered. More precisely, once a TunerMbo has configured itself on an instance, it will not automatically reconfigure itself (at least this is the current default). You can, however, force the tuner to reconfigure itself by calling the $reset() method, which will set the relevant fields to NULL.

    One solution to your problem would be to call tuner$reset() prior to tuner$optimize(tuning_instance) within the foreach definition so that the tuner can reconfigure itself for the new search space. Another solution would be to configure the tuner with a suitable surrogate and acquisition function optimizer from the start (i.e., supporting dependencies). I hope this helps.