Очистка памяти в рабочем процессе Drake R

У меня есть пакет массового рабочего процесса временных рядов (4273 * 10 моделей) для 4273 временных рядов еженедельно в Drake.

Изначально я пытался создать полный рабочий процесс с помощью пакета fable. Это очень удобно для обучения моделей для сгруппированных тсиблей, но после различных испытаний у меня возникло много проблем с управлением памятью. Мой сервер RStudio с 32 ядрами и 244 ГБ ОЗУ постоянно падал, особенно когда я пытался сериализовать модели.

Из-за этого я полностью пропустил свой рабочий процесс, чтобы выявить узкие места, связанные с:

введите описание изображения здесь

To:

введите описание изображения здесь

Затем:

введите описание изображения здесь

Наконец, чтобы:

введите описание изображения здесь

В моем обучающем коде (пример prophet_multiplicative) я использую будущий пакет для обучения этих нескольких басен-моделей, а затем вычисляю точность и сохраняю их. Однако я не знаю, как впоследствии удалить этот объект из рабочего процесса Drake:

  • Должен ли я просто удалить объект с помощью rm?
  • Есть ли способ в Drake иметь отдельные среды для каждого из компонентов рабочего процесса?
  • Это правильное решение?

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

Любые предложения по моему подходу более чем приветствуются. Обратите внимание, что у меня довольно ограниченные аппаратные ресурсы, поэтому установка сервера большего размера - не вариант.

BR /E


person tfkLSTM    schedule 04.07.2020    source источник


Ответы (3)


Всегда есть компромисс между памятью и скоростью. Чтобы сохранить память, мы должны выгрузить некоторые цели из сеанса, что часто требует от нас времени, чтобы позже прочитать их из хранилища. По умолчанию селезень предпочитает скорость. Итак, в вашем случае я бы установил memory_strategy = «autoclean» и garbage_collection = TRUE в make () и связанных функциях. В руководстве пользователя есть глава, посвященная управлению памятью: https://books.ropensci.org/drake/memory.html.

Кроме того, я рекомендую по возможности возвращать небольшие цели. Таким образом, вместо того, чтобы возвращать всю подогнанную модель, вы могли бы вместо этого вернуть небольшой фрейм данных со сводками моделей, которые будут удобнее как для памяти, так и для хранилища. Кроме того, вы можете выбрать один из специализированных форматов хранения по адресу https://books.ropensci.org/drake/plans.html#special-data-formats-for-targets, чтобы повысить эффективность.

person landau    schedule 04.07.2020

garbage_collection = TRUE уже установлено. Попробую добавить авточистку. Что касается форматов файлов, я сохраняю свои модели как .qs с библиотекой qs, используя функцию save_model_x:

saveModels <- function(models, directory_out, max_forecasting_horizon, max_multisession_cores) {
print("Saving the all-mighty mable")
save(x = models, file = paste0(directory_out, attributes(models)$model, "_horizon_", max_forecasting_horizon, ".qs"), 
     nthreads = max_multisession_cores)
#saveRDS(object = models, file = paste0(directory_out, "ts_models_horizon_", max_forecasting_horizon, ".rds"))
print("End workflow")
}

В моем плане это используется как:

prophet_multiplicative = trainModels(input_data = processed_data, 
                               max_forecast_horizon = argument_parser$horizon,
                               max_multisession_cores = 6,
                               model_type = "prophet_multiplicative"),
  accuracy_prophet_multiplicative = accuracy_explorer(type = "train", models = prophet_multiplicative, 
                                                      max_forecast_horizon = argument_parser$horizon,
                                                      directory_out = "/data1/my_folder/"),
  saving_prophet_multiplicative = saveModels(models = prophet_multiplicative, 
                       directory_out = "/data1/my_folder/,
                       max_forecasting_horizon = argument_parser$horizon,
                       max_multisession_cores = 6)

Детали моего плана после вашего предложения следующие:

make(plan = plan, verbose = 2, 
     log_progress = TRUE,
     recover = TRUE,
     lock_envir = FALSE,
     garbage_collection = TRUE,
     memory_strategy = "autoclean")

Какие-либо предложения?

BR

/E

person tfkLSTM    schedule 04.07.2020
comment
Сообщите мне, если у вас по-прежнему возникают проблемы с памятью даже после автоочистки. Вы также можете взглянуть на стратегию без памяти, если действительно хотите получить полное ручное управление. Одним из преимуществ drake является то, что он абстрагирует файлы как объекты R и управляет хранилищем за вас. Так что, если вам это нравится, альтернативой пользовательским вызовам qsave () является drake_plan(target(your_target, your_command(), format = "qs")). - person landau; 04.07.2020
comment
Опять же, если вы продолжаете сталкиваться с проблемами памяти, совершенно противоположная тактика от target(format = "qs") - использовать динамические файлы для всего. В случае динамических файлов drake сохраняет в памяти только путь к файлу, а не сам объект, но вы должны вручную считывать объект в память для каждой цели, которая его использует. - person landau; 04.07.2020
comment
Привет, ландау, по какой-то причине мой последний ответ не был опубликован после вашего комментария. Теперь у меня возникла новая проблема. Я думаю, что модели функционального поезда некорректно оцениваются после добавления auto_clean. - person tfkLSTM; 05.07.2020
comment
Нормально ли работает функция вне drake? Если да, не могли бы вы опубликовать воспроизводимый пример в другом потоке? Похоже на проблему, которую мне нужно будет запустить самостоятельно, чтобы устранить неполадки. - person landau; 05.07.2020
comment
Привет, Ландау, Да, функция отлично работает вне селезня. Добавлю пример. - person tfkLSTM; 05.07.2020
comment
Вы бы открыли для него новый вопрос о переполнении стека или проблему с GitHub? Я не получаю уведомления, когда вы публикуете новый ответ / решение в качестве ответа на этой странице. - person landau; 05.07.2020

Спасибо за быстрые ответы. Я очень признателен. Теперь я столкнулся с другой проблемой, я позволил скрипту запускаться ночью через nohup и обнаружил в журналах следующее:

[1] "DB PROD Connected"
[1] "DB PROD Connected"
[1] "Getting RAW data"
[1] "Maximum forecasting horizon is 52, fetching weekly data"
[1] "Removing duplicates if we have them"
[1] "Original data has 1860590 rows"
[1] "Data without duplicates has 1837995 rows"
`summarise()` regrouping output by 'A', 'B' (override with `.groups` argument)
[1] "Removing non active customers"
[1] "Data without duplicates and without active customers has 1654483 rows"
0.398 sec elapsed
[1] "Removing customers with last data older than 1.5 years"
[1] "Data without duplicates, customers that are not active and old customers has 1268610 rows"
0.223 sec elapsed
[1] "Augmenting data"
12.103 sec elapsed
[1] "Creating tsibble"
7.185 sec elapsed
[1] "Filling gaps for not breaking groups"
9.568 sec elapsed
[1] "Training theta models for forecasting horizon 52"
[1] "Using 12 sessions from as future::plan()"
Repacking large object
[1] "Training auto_arima models for forecasting horizon 52"
[1] "Using 12 sessions from as future::plan()"
Error: target auto_arima failed.
diagnose(auto_arima)error$message:
  object 'ts_models' not found
diagnose(auto_arima)error$calls:
  1. └─global::trainModels(...)
In addition: Warning message:
9 errors (2 unique) encountered for theta
[3] function cannot be evaluated at initial parameters
[6] Not enough data to estimate this ETS model.

Execution halted
            

Объект ts_models - это объект, который создается в моих обучающих сценариях, и в основном это то, что возвращает моя функция trainModels. Мне кажется, что, возможно, параметр входных данных чистый, и поэтому он не работает?

Другой вопрос: почему-то моя модель не сохраняется после обучения тета-моделей. Есть ли способ указать Дрейку, чтобы он не переходил к следующей модели, пока он не вычислит точность одной и не сохранит файл .qs?

Моя тренировочная функция такова:

trainModels <- function(input_data, max_forecast_horizon, model_type, max_multisession_cores) {

  options(future.globals.maxSize = 1500000000)
  future::plan(multisession, workers = max_multisession_cores) #breaking infrastructure once again ;)
  set.seed(666) # reproducibility
  
    if(max_forecast_horizon <= 104) {
      
      print(paste0("Training ", model_type, " models for forecasting horizon ", max_forecast_horizon))
      print(paste0("Using ", max_multisession_cores, " sessions from as future::plan()"))
      
      if(model_type == "prophet_multiplicative") {
        
        ts_models <- input_data %>% model(prophet = fable.prophet::prophet(snsr_val_clean ~ season("week", 2, type = "multiplicative") + 
                                                                             season("month", 2, type = "multiplicative")))
        
      } else if(model_type == "prophet_additive") {
        
        ts_models <- input_data %>% model(prophet = fable.prophet::prophet(snsr_val_clean ~ season("week", 2, type = "additive") + 
                                                                             season("month", 2, type = "additive")))
        
      } else if(model_type == "auto.arima") {
        
        ts_models <- input_data %>% model(auto_arima = ARIMA(snsr_val_clean))
        
      } else if(model_type == "arima_with_yearly_fourier_components") {
        
        ts_models <- input_data %>% model(auto_arima_yf = ARIMA(snsr_val_clean ~ fourier("year", K = 2)))
        
      } else if(model_type == "arima_with_monthly_fourier_components") {
        
        ts_models <- input_data %>% model(auto_arima_mf = ARIMA(snsr_val_clean ~ fourier("month", K=2)))
        
      } else if(model_type == "regression_with_arima_errors") {
        
        ts_models <- input_data %>% model(auto_arima_mf_reg = ARIMA(snsr_val_clean ~ month + year  + quarter + qday + yday + week))
        
      } else if(model_type == "tslm") {
    
        ts_models <- input_data %>% model(tslm_reg_all = TSLM(snsr_val_clean ~ year  + quarter + month + day + qday + yday + week + trend()))
     
      } else if(model_type == "theta") {
        
        ts_models <- input_data %>% model(theta = THETA(snsr_val_clean ~ season()))
        
      } else if(model_type == "ensemble") {
        
        ts_models <- input_data %>% model(ensemble =  combination_model(ARIMA(snsr_val_clean), 
                                              ARIMA(snsr_val_clean ~ fourier("month", K=2)),
                                              fable.prophet::prophet(snsr_val_clean ~ season("week", 2, type = "multiplicative") +
                                              season("month", 2, type = "multiplicative"), 
                                              theta = THETA(snsr_val_clean ~ season()), 
                                              tslm_reg_all = TSLM(snsr_val_clean ~ year  + quarter + month + day + qday + yday + week + trend())))
            )
        
      }
      
    } 
  
    else if(max_forecast_horizon > 104) {
      
        print(paste0("Training ", model_type, " models for forecasting horizon ", max_forecast_horizon))
        print(paste0("Using ", max_multisession_cores, " sessions from as future::plan()"))
        
        
        if(model_type == "prophet_multiplicative") {
          
          ts_models <- input_data %>% model(prophet = fable.prophet::prophet(snsr_val_clean ~ season("month", 2, type = "multiplicative") + 
                                                                               season("month", 2, type = "multiplicative")))
          
        } else if(model_type == "prophet_additive") {
          
          ts_models <- input_data %>% model(prophet = fable.prophet::prophet(snsr_val_clean ~ season("month", 2, type = "additive") + 
                                                                               season("year", 2, type = "additive")))
          
        } else if(model_type == "auto.arima") {
          
          ts_models <- input_data %>% model(auto_arima = ARIMA(snsr_val_clean))
          
        } else if(model_type == "arima_with_yearly_fourier_components") {
          
          ts_models <- input_data %>% model(auto_arima_yf = ARIMA(snsr_val_clean ~ fourier("year", K = 2)))
          
        } else if(model_type == "arima_with_monthly_fourier_components") {
          
          ts_models <- input_data %>% model(auto_arima_mf = ARIMA(snsr_val_clean ~ fourier("month", K=2)))
          
        } else if(model_type == "regression_with_arima_errors") {
          
          ts_models <- input_data %>% model(auto_arima_mf_reg = ARIMA(snsr_val_clean ~ month + year  + quarter + qday + yday))
          
        } else if(model_type == "tslm") {
          
          ts_models <- input_data %>% model(tslm_reg_all = TSLM(snsr_val_clean ~ year  + quarter + month + day + qday + yday + trend()))
          
        } else if(model_type == "theta") {
          
          ts_models <- input_data %>% model(theta = THETA(snsr_val_clean ~ season()))
          
        } else if(model_type == "ensemble") {
          
          ts_models <- input_data %>% model(ensemble =  combination_model(ARIMA(snsr_val_clean), 
                                                                          ARIMA(snsr_val_clean ~ fourier("month", K=2)),
                                                                          fable.prophet::prophet(snsr_val_clean ~ season("month", 2, type = "multiplicative") +
                                                                          season("year", 2, type = "multiplicative"),
                                                                          theta = THETA(snsr_val_clean ~ season()), 
                                                                          tslm_reg_all = TSLM(snsr_val_clean ~ year  + quarter + month + day + qday + 
                                                                                                yday  + trend())))
          )
          
        }
    }
  
  return(ts_models)
}

BR /E

person tfkLSTM    schedule 05.07.2020
comment
Просто вижу это сейчас. Для устранения неполадок было бы действительно полезно увидеть уменьшенную версию всего проекта, в которой воспроизводится ошибка. На первый взгляд функция выглядит хорошо, но мне также нужно увидеть план и другой контекстный код, а также уметь запускать все это самостоятельно. - person landau; 05.07.2020
comment
Привет, Ландау: github.com/ropensci/drake/issues/1293, подробный план там - person tfkLSTM; 05.07.2020
comment
Спасибо, посмотрю. - person landau; 05.07.2020
comment
Спасибо вам за отличную поддержку, очень рад использовать drake! - person tfkLSTM; 05.07.2020