Ako zrýchliť XGBoost v R: Benchmark trénovania modelu na CPU vs. GPU 150 150 cleandata

Ako zrýchliť XGBoost v R: Benchmark trénovania modelu na CPU vs. GPU

cpu-vs-gpu-blog

Ako rýchlo dokážete vytrénovať model na veľkých datasetoch? Toto je otázka, ktorú si kladie mnoho analytikov a data scientistov, keď začínajú pracovať s pokročilými algoritmami strojového učenia, ako je XGBoost. V tomto článku si ukážeme, ako vytvoriť klasifikačný model pomocou XGBoost v R a porovnáme si dĺžku výpočtu pri použití CPU a GPU.

Štandardná verzia knižnice XGBoost na CRAN však nepodporuje parameter device = “cuda”. Preto je potrebné nainštalovať špeciálnu verziu XGBoostu – buď skompilovať z repozitára na GitHube, alebo využiť poskytovaný inštalačný balík (napríklad pre Windows takto):

Inštalácia xgboost
options(timeout = 1200)
xgboost_url <- "https://s3-us-west-2.amazonaws.com/xgboost-nightly-builds/release_2.0.0/xgboost_r_gpu_win64_82d846bbeb83c652a0b1dff0e3519e67569c4a3d.tar.gz"
install.packages(xgboost_url, repos = NULL, type = "source")

CPU vs GPU

Na veľkých datasetoch môže trénovanie modelov trvať hodiny, ak nie dni, najmä na bežných procesoroch (CPU). Moderné grafické karty (GPU) od spoločnosti Nvidia však umožňujú paralelné spracovanie dát, čo dramaticky zrýchľuje niektoré výpočtové operácie.

CPU je ako pracovník, ktorý rieši úlohy sekvenčne, zatiaľ čo GPU je tím tisícov pracovníkov, ktorí dokážu riešiť mnohé úlohy naraz.

Ešte predtým, než prejdeme k modelovaniu, môžeme si zistiť, aký hardvér vlastne používame.

AMD Ryzen 9 7900X je vysoko výkonný desktopový procesor s 12 fyzickými jadrami (24 vláknami), ktorý je všeobecne považovaný za high-end/výkonný segment pre multivláknové operácie (aktuálne je dostupná už novšia generácia AMD procesorov). K nemu je 67.8 GB RAM, čo dáva dostatočnú rezervu na spracovanie stredne veľkých až väčších datasetov. Grafická karta Nvidia RTX 4060Ti s 8 GB VRAM sa radí do strednej až vyššej strednej triedy, no pri veľmi rozsiahlych datasetoch môže byť 8 GB VRAM limitujúce. Napriek tomu dokáže pri bežných projektoch a primerane veľkých dátach výrazne zrýchliť trénovanie XGBoost modelov v porovnaní s CPU. Viac info nájdete v staršom blogu.

1. Načítanie knižníc a príprava prostredia

Na začiatku si načítame potrebné balíky. Je dobré nastaviť aj niektoré globálne možnosti, napríklad options(scipen = 999), aby sme obmedzili vedecký zápis čísel.

Knižnice
options(scipen = 999)
library(data.table)
library(readr)
library(xgboost)
library(tidymodels)
library(dplyr)
library(stringr)
library(doParallel)
library(tictoc)

data.table nám umožní rýchle nahratie .csv. tidymodels je framework pre tvorbu a ladenie modelov. xgboost je samotná implementácia gradient boosting algoritmov. tictoc nám zmeria čas operácie (funkcie tic() a toc())

2. Načítanie, čistenie a rozdelenie dát

Začneme s dvoma datasetmi: train.csv a test.csv. Oba súbory sú dostupné na Kaggle.

Dátový stĺpec id odstránime (neobsahuje relevantné informácie pre model). Premennú class transformujeme tak, aby hodnota “e” mala label 0, a “p” label 1. Prázdne stringy (textové premenné) nahradíme za “missing”, pretože chceme explicitne ošetriť chýbajúce hodnoty.

Príprava dát
## data prep ----
train <- data.table::fread("data/train.csv") |> 
  select(-id) |> 
  mutate(class = factor(class, levels = c("p", "e"), labels = c(1, 0))) |> 
  mutate(across(where(is.character), ~ if_else(. == "", "missing", .)))

dim(train)
[1] 3116945      21

Finálny trénovací dataset má 21 stĺpcov vrátane triedy, ktorú budeme predikovať a 3 116 945 záznamov.

Nasleduje klasické rozdelenie pomocou initial_split z rsample: prop = 0.7 znamená, že 70 % záznamov ide do trénovacej množiny a 30 % do testovacej, strata = class zachováva približný pomer tried v oboch množinách.

Pri ladení modelu použijeme 10-násobnú cross validáciu.

Rozdelenie dát
set.seed(123)
split <- initial_split(train, prop = 0.7, strata = class)

train_set <- training(split)
test_set <- testing(split)

set.seed(123)
folds <- vfold_cv(train_set, strata = class)

3. Pre-Processing

V recipe() si definujeme jednotlivé kroky v tzv. recipe pipeline.

step_other() s threshold = 0.005 zlúči veľmi vzácne kategórie (s podielom < 0.5 %) do kategórie “other”. step_string2factor() prevedie stringové atribúty na faktory. step_dummy() vytvorí dummy premenné z faktorov.

Nastavenie pre-processingu
recipe <- recipe(class ~ ., data = train_set) |> 
  step_other(all_nominal_predictors(), threshold = 0.005) |> 
  step_string2factor(all_nominal_predictors()) |>
  step_dummy(all_nominal_predictors())

4. Definícia XGBoost modelov (CPU a GPU)

4.1. Základné XGBoost parametre

  • trees = 1000: Počet stromov.
  • tree_depth = tune(): Hĺbka stromu, ktorú budeme ladiť.
  • min_n = tune(): Minimálny počet záznamov v koncovom uzle stromu (v XGBoost často min_child_weight).
  • loss_reduction = tune(): (v XGBoost označované ako gamma) – ovplyvňuje, o koľko sa musí znížiť chyba, aby došlo k deleniu uzla.
  • sample_size = tune(): (v XGBoost subsample) – podiel vzoriek použitých pre každý strom.
  • mtry = tune(): (v XGBoost colsample_bynode) – podiel stĺpcov vyberaných pri každom delení.
  • learn_rate = tune(): (v XGBoost eta) – reguluje rýchlosť učenia.

Rozdiel medzi CPU a GPU modelmi: Zásadné je device = “cuda” a tree_method = “hist”. Týmito parametrami vravíme xgboostu, že chceme použiť GPU. Nastavujeme nthread = 12, aby sme využili všetky dostupné jadrá CPU.

4.2. Model pre CPU

Definovanie CPU modelu
xgb_cpu <- boost_tree(
  trees = 1000,
  tree_depth = tune(), min_n = tune(),
  loss_reduction = tune(),                     ## first three: model complexity
  sample_size = tune(), mtry = tune(),         ## randomness
  learn_rate = tune()                          ## step size
) |> 
  set_engine("xgboost", nthread = 12) |> 
  set_mode("classification")

4.3. Model pre GPU

Definovanie GPU modelu
xgb_gpu <- boost_tree(
  trees = 1000,
  tree_depth = tune(), min_n = tune(),
  loss_reduction = tune(),                     ## first three: model complexity
  sample_size = tune(), mtry = tune(),         ## randomness
  learn_rate = tune()                          ## step size
) |> 
  set_engine("xgboost", device = "cuda", tree_method = "hist", nthread = 12) |> 
  set_mode("classification")

5. Workflows

V tidymodels je workflow elegantný spôsob, ako zlúčiť recept a model:

Vytvorenie workflows
xgb_cpu_wf <- workflow() |> 
  add_recipe(recipe) |> 
  add_model(xgb_cpu)

xgb_gpu_wf <- workflow() |> 
  add_recipe(recipe) |> 
  add_model(xgb_gpu)

Aby sme mohli ladiť hyperparametre, vytvoríme si ešte bayes_param objekt. Použijeme finalize(mtry(), train_set), aby sme odhadli maximálnu hodnotu mtry na základe počtu stĺpcov.

Extrakcia hyperparametrov
bayes_param <- xgb_gpu_wf %>% 
  extract_parameter_set_dials() %>% 
  update(mtry = finalize(mtry(), train_set))

6. Bayesovské ladenie a meranie času

Ladenie bude prebiehať v 6 iteráciách (parametrizovaných v iter = 6). Ide len o ukážku, v reálnom projekte by sme spravidla volili viac iterácií (10, 20, či viac), aby sme dôkladnejšie preskúmali priestor parametrov.

6.1. CPU – tune_bayes

Tuning CPU modelu
tic()
set.seed(234)
cpu_xgb_res <- tune_bayes(
  xgb_cpu_wf,
  param_info = bayes_param,
  resamples = folds, 
  iter = 6
)
toc()
# 24278.11 sec elapsed

6.2. GPU – tune_bayes

Tuning GPU modelu
tic()
set.seed(345)
gpu_xgb_res <- tune_bayes(
  xgb_gpu_wf,
  param_info = bayes_param,
  resamples = folds, 
  iter = 6
)
toc()
# 7345.68 sec elapsed

Porovnanie času výpočtu

  • CPU: ~ 6 hodín 45 minút
  • GPU: ~ 2 hodiny

GPU model je teda približne 3x rýchlejší, čo predstavuje významnú úsporu času pri práci na veľkých datasetoch. V praxi ešte záleží na type GPU, verzii CUDA, atď.

7. Výber najlepších parametrov a finálny model

Po skončení hyperparameter tuningu si môžeme pozrieť metriky cez collect_metrics(), a vybrať najlepšie nastavenia napr. na základe metriky roc_auc.

Výsledné CPU metriky
metrics_cpu <- collect_metrics(cpu_xgb_res)
best_cpu <- select_best(cpu_xgb_res, metric = "roc_auc")

cpu_roc_auc <- metrics_cpu |> 
  filter(.metric == "roc_auc") |> 
  slice_max(mean) |> 
  pull(mean)

Pre CPU model je výsledná hodnota 0.9971878.

Výsledné GPU metriky
metrics_gpu <- collect_metrics(gpu_xgb_res)
best_gpu <- select_best(gpu_xgb_res, metric = "roc_auc")

gpu_roc_auc <- metrics_gpu |> 
  filter(.metric == "roc_auc") |> 
  slice_max(mean) |> 
  pull(mean)

Pre GPU je to 0.9972345.

GPU model nielen že trénuje rýchlejšie, ale dosahuje aj lepšiu presnosť. Je to však veľmi individuálne, závisí od datasetu i parametrov.

Zhrnutie

Čo sme videli?

  • XGBoost sa dá používať na CPU aj GPU pomocou jednoduchých parametrov (device = “cuda”, tree_method = “hist”).
  • Čas výpočtu môže klesnúť až na zlomok, ak máme vhodnú GPU a väčší dataset.
  • Pri ladení parametrov sme použili Bayesovskú optimalizáciu, ktorá je síce efektívnejšia vo vyhľadávaní správnych hyperparametrov, ale je aj výpočtovo náročnejšia než jednoduchšie metódy.

Praktické tipy a nuansy

  • Pamäť GPU môže byť limitujúca. Veľké datasety nemusia vojsť do GPU pamäte.
  • Overheads: Pri relatívne malých datasetoch môže byť efekt GPU nižší alebo dokonca negatívny pre “overheads” spojené s kopírovaním dát medzi CPU a GPU.
  • Data pre-processing: Prechod na GPU je nápomocný hlavne pri trénovaní modelu, ale pre-processing zostáva často na CPU. Ak máte rozsiahlu prípravu dát, toto stále môže byť “bottleneck”. Aj z tohto dôvodu ponechávame nthreads na dostatočne vysokej hodnote.
  • Viac iterácií v Bayesovskej optimalizácii obvykle pomôže presnejšie nájsť najlepšie hyperparametre.

Záver

Modelovanie s XGBoost algoritmom na GPU môže drasticky skrátiť čas trénovania oproti CPU, najmä pri veľkých datasetoch. Ak je to aj Váš prípad a navyše pravidelne pracujete so zložitými modelmi, GPU je dlhodobou investíciou, ktorá šetrí čas a zvyšuje efektivitu práce. Pre menšie projekty však bude postačujúci aj výkon moderného CPU.

  • EDA časových radov: Ako odhaliť vzory skryté v čase 150 150 cleandata EDA časových radov: Ako odhaliť vzory skryté v čase
  • susR: Zjednodušenie práce s dátami Štatistického úradu SR v R 150 150 cleandata susR: Zjednodušenie práce s dátami Štatistického úradu SR v R
  • Ako vytvoriť interaktívny dashboard v R pomocou Quarto 150 150 cleandata Ako vytvoriť interaktívny dashboard v R pomocou Quarto

Leave a Reply

Your email address will not be published.