Benchmark Parallel Predictions

This benchmark was run on a MacBook Pro 2021 M1 Pro. If you rerun this result on your machine, your results will differ - both in relative and absolute values and maybe by a lot. This is due to the multicore performance component of your CPU and how efficient the overhead introduced by parallelization is handled (i.e. splitting and combining the chunks).

{terra} is using a socker-based parallelization by default (which the user cannot change). The equivalent in {future} is plan("multisession"). Using plan(multicore) on UNIX based systems might speed up the {mlr3} approach even more. This might also be a major part of the speedup of the mlr3-all-cores setting.

Also note that using all available cores does not always result in faster processing. The parallelization overhead can be substantial and for small tasks you might be better of using less cores. Nevertheless, if your processing time is the range of minutes or higher, you might usually be better of using all cores (if possible).

library(mlr3spatial)
library(mlr3learners)
library(future)

Preparations

stack = generate_stack(list(
  numeric_layer("x_1"),
  factor_layer("y", levels = c("a", "b"))),
layer_size = 10)
vector = sample_stack(stack, n = 500)
task_train = as_task_classif_st(vector, id = "test_vector", target = "y")
learner = lrn("classif.ranger", num.threads = 1)
learner$train(task_train)
terra_rf = ranger::ranger(y ~ ., data = task_train$data(), num.threads = 1)
stack$y = NULL
task_predict = as_task_unsupervised(stack, id = "test")
learner$parallel_predict = TRUE

Benchmark

bm = bench::mark(

  "01-mlr3-4-cores" = {
    plan(multicore, workers = 4)
    pred = predict_spatial(task_predict, learner, chunksize = 10L)
  },

  "02-terra-4-cores" = {
    library(terra)
    pred = predict(stack, terra_rf, cores = 4, cpkgs = "ranger",
      fun = function(model, ...) predict(model, ...)$predictions)
  },

  "03-mlr3-all-cores" = {
    plan(multicore)
    pred = predict_spatial(task_predict, learner, chunksize = 10L)
  },

  "04-terra-all-cores" = {
    library(terra)
    pred = predict(stack, terra_rf, cores = parallelly::availableCores(), cpkgs = "ranger",
      fun = function(model, ...) predict(model, ...)$predictions)
  },

  check = FALSE, filter_gc = FALSE, min_iterations = 3,
  max_iterations = 3, memory = FALSE)

bm$`itr/sec` = NULL
bm$result = NULL
bm$`gc/sec` = NULL
bm$memory = NULL
bm$mem_alloc = NULL

print(bm)
#> # A tibble: 4 × 8
#>   expression              min   median n_itr  n_gc total_time time           gc              
#>   <bch:expr>         <bch:tm> <bch:tm> <int> <dbl>   <bch:tm> <list>         <list>          
#> 1 01-mlr3-4-cores       20.7s    21.4s     3    57      1.07m <bench_tm [3]> <tibble [3 × 3]>
#> 2 02-terra-4-cores      21.9s    23.1s     3    31      1.14m <bench_tm [3]> <tibble [3 × 3]>
#> 3 03-mlr3-all-cores     12.5s    12.5s     3    51     37.45s <bench_tm [3]> <tibble [3 × 3]>
#> 4 04-terra-all-cores    32.6s    32.7s     3    77      1.64m <bench_tm [3]> <tibble [3 × 3]>
library(ggplot2)
autoplot(bm, type = "ridge")
#> Picking joint bandwidth of 0.00417