Я хотел бы использовать R-пакеты mlr3* для построения алгоритмов машинного обучения воспроизводимым образом. Я пытался использовать regr.glmboost с тюнером mbo и терминатором run_time. Я поиграл с частью HPO, но мне не удалось воспроизвести ее с более высоким временем выполнения. Где я неправ?
Вот репрекс об этом явлении:
library(mlr3verse)
library(mlr3mbo)
library(mlr3misc)
library(magrittr)
library(nycflights13)
dt <- as.data.table(weather)
dt <- dt[order(time_hour), .(origin = as.factor(origin), month = as.factor(month), hour = as.factor(hour), temp, dewp, humid, wind_dir, wind_speed, precip, visib, pressure, time_hour = as.numeric(time_hour))]
dt <- na.omit(dt)
best_ones <- map_dtr(
1L:3L,
function(i) {
my_learner <- lrn("regr.glmboost",
family = to_tune(p_fct(levels = c("Gaussian", "Laplace", "Huber"))),
nuirange = to_tune(p_dbl(lower = 0, upper = 1000, logscale = FALSE)),
mstop = to_tune(p_int(lower = 1, upper = 3, trafo = function(x) 10**x)),
nu = to_tune(p_dbl(lower = 0.01, upper = 0.3, logscale = TRUE)),
risk = to_tune(p_fct(levels = c("inbag", "oobag", "none"))),
trace = to_tune(c(TRUE, FALSE)),
stopintern = to_tune(c(TRUE, FALSE))
)
my_task <- as_task_regr(
x = dt,
target = "pressure",
id = "weather_data"
)
my_instance <- ti(
task = my_task,
learner = my_learner,
resampling = rsmp("cv", folds = 3),
measure = msr("regr.mae"),
terminator = trm("run_time", secs = 300)
)
my_tuner <- tnr("mbo")
set.seed(1234L, kind = "L'Ecuyer-CMRG")
my_tuner$optimize(my_instance)
my_instance$archive$best()
}
)
best_ones[]
Это несколько разные гиперпараметры, которые у меня есть:
Я предполагаю, что проблема связана с раздачей, но я не знаю, как сделать это правильно в этом случае. Любая помощь будет оценена по достоинству!
Поэтому я думаю, что в вашем коде есть два возможных источника ошибок:
map_dtr(...)
, просто чтобы быть уверенным.Обращение к обоим, кажется, дает воспроизводимые результаты (некоторые части кода немного изменены, чтобы сократить время выполнения).
Я надеюсь, что это также работает для вас.
library(mlr3verse)
#> Loading required package: mlr3
library(mlr3mbo)
#> Loading required package: mlr3tuning
#> Loading required package: paradox
library(mlr3misc)
library(magrittr)
#>
#> Attaching package: 'magrittr'
#> The following objects are masked from 'package:mlr3misc':
#>
#> set_class, set_names
library(nycflights13)
dt <- as.data.table(weather)
dt <- dt[order(time_hour), .(origin = as.factor(origin), month = as.factor(month), hour = as.factor(hour), temp, dewp, humid, wind_dir, wind_speed, precip, visib, pressure, time_hour = as.numeric(time_hour))]
dt <- na.omit(dt)
best_ones <- map_dtr(
1L:3L,
function(i) {
set.seed(1234L, kind = "L'Ecuyer-CMRG")
my_learner <- lrn("regr.glmboost",
family = to_tune(p_fct(levels = c("Gaussian", "Laplace", "Huber"))),
nuirange = to_tune(p_dbl(lower = 0, upper = 1000, logscale = FALSE)),
mstop = to_tune(p_int(lower = 1, upper = 3, trafo = function(x) 10**x)),
nu = to_tune(p_dbl(lower = 0.01, upper = 0.3, logscale = TRUE)),
risk = to_tune(p_fct(levels = c("inbag", "oobag", "none"))),
trace = to_tune(c(TRUE, FALSE)),
stopintern = to_tune(c(TRUE, FALSE))
)
my_task <- as_task_regr(
x = dt,
target = "pressure",
id = "weather_data"
)
my_instance <- ti(
task = my_task,
learner = my_learner,
resampling = rsmp("holdout"),
measure = msr("regr.mae"),
terminator = trm("evals", n_evals = 2)
)
my_tuner <- tnr("mbo")
my_tuner$optimize(my_instance)
my_instance$archive$best()
}
)
#> INFO [22:33:53.565] [bbotk] Starting to optimize 7 parameter(s) with '<OptimizerMbo>' and '<TerminatorEvals> [n_evals=2, k=0]'
#> ... (A LOT OF LOG OUTPUT THAT IS OMITTED)
best_ones[]
#> family nuirange mstop nu risk trace stopintern regr.mae warnings
#> 1: Huber 85.45087 3 -2.572761 none FALSE FALSE 4.74076 0
#> 2: Huber 85.45087 3 -2.572761 none FALSE FALSE 4.74076 0
#> 3: Huber 85.45087 3 -2.572761 none FALSE FALSE 4.74076 0
#> errors runtime_learners uhash x_domain
#> 1: 0 3.406 653adf83-6fbc-4ef5-b6dd-7e12e97b49d6 <list[7]>
#> 2: 0 3.773 f70dec6a-073a-45c8-b795-29ef5b662625 <list[7]>
#> 3: 0 3.673 dc18e13f-2e7d-4fe9-9845-187ebf0db3b3 <list[7]>
#> timestamp batch_nr
#> 1: 2023-01-10 22:34:17 1
#> 2: 2023-01-10 22:34:41 1
#> 3: 2023-01-10 22:35:05 1
Created on 2023-01-10 by the reprex package (v2.0.1)
Еще один комментарий о том, почему сид должен попасть в топ здесь:
HPO — это, по сути, шумная оптимизация черного ящика с шумом в основном из-за:
Алгоритм учащегося недетерминирован
Цель, т. е. ошибка обобщения, оцениваемая с помощью метода повторной выборки
Чтобы уменьшить шум во время оптимизации, мы можем зафиксировать повторную выборку, т. Е. instantiate ее на Task (и, следовательно, использовать те же разбиения обучающего теста для оценки конфигураций гиперпараметров).
Когда вы строите TuningInstance:
my_instance <- ti(
task = my_task,
learner = my_learner,
resampling = rsmp("cv", folds = 3),
measure = msr("regr.mae"),
terminator = trm("run_time", secs = 300)
)
Вы передаете Resampling, экземпляр которого (еще) не был создан на Task. Однако во время построения ObjectiveTuning в рамках построения TuningInstance он будет автоматически создан (чтобы сделать оптимизацию менее шумной и «более легкой»).
Следовательно, если вы не зададите построение my_instance, разделение тестов поезда на основе сверток CV будет другим, и вы, естественно, получите разные прогоны оптимизатора и результаты.
По сути, то, что вы наблюдали в своем невоспроизводимом примере, - это эффект шума из-за различной передискретизации!
Последнее замечание: Если ваш Objective зашумлен, mlr3mbo по умолчанию определит результат настройки, выбрав конфигурацию с лучшим предсказанием среднего значения суррогатной модели, то есть my_instance$result будет получен с использованием result_by_surrogate_design вместо result_by_default (что аналогично использованию my_instance$archive$best()).
Поэтому будьте осторожны при использовании my_instance$result по сравнению с my_instance$archive$best(), но это также зависит от ваших пользовательских предпочтений и того, что вас интересует.
Хорошо, я понял, что терминатор "run_time" не связан с воспроизводимостью. Спасибо за помощь! Тем не менее, я только что попробовал итерацию с перемещенным заполнением, и терминатор «run_time» остался прежним, и это дало стабильные результаты. Так что это стало казаться воспроизводимым.