[Tidy Modeling With R] 13. Grid Search with XGBoost

2023. 12. 22. 18:45·Data Science/Modeling

 

그동안 Tidymodels를 통해 parsnip 모델과 formula 또는 recipe 전처리기를 포함하는 워크플로 객체를 생성했습니다.

이때, 회귀계수와 같은 파라미터는 훈련 데이터만을 사용하여 값을 추정할 수 있었고 검증 데이터나 테스트 데이터에 대한 성과 지표(MSE, AUC)를 측정해 퍼포먼스가 얼마나 좋은지 판단할 수 있었습니다.

다만 저번 챕터에서 훈련 데이터로는 값을 추정할 수 없는 하이퍼파라미터에 대해 언급하였고 tune 함수를 통해 하이퍼파라미터를 지정할 수 있음을 배웠습니다. 

이번 포스팅은 이렇게 지정된 하이퍼파라미터를 튜닝하는 방법 중 하나인 그리드서치(Grid Search)에 대해 소개하는 챕터 13에 대해 알아보려고 합니다.

 

 

13 Grid Search | Tidy Modeling with R

The tidymodels framework is a collection of R packages for modeling and machine learning using tidyverse principles. This book provides a thorough introduction to how to use tidymodels, and an outline of good methodology and statistical practice for phases

www.tmwr.org

 

 

그리드 서치는 하이퍼 파라미터의 값을 사전에 여러 개 생성하여 성능을 측정하고 제일 좋은 하이퍼 파라미터의 값을 선택하는 방법입니다.

그리드 서치는 Regular grid와 Non-Regular grid 두가지 방식이 있습니다.

Regular grid는 규칙적인 격자라는 뜻 처럼 각 파라미터의 값을 모두 조합하여 생성하는 방식이고

Non-Regular grid는 불규칙한 격자라는 뜻 처럼 모든 파라미터 공간(Parameter Space)에서 임의의 불규칙한 격자를 생성하는 방식입니다.

 

본격적인 설명에 앞서 준비한 코드부터 설명하도록 하겠습니다.
처음으로 데이터는 아래와 같이 Train-Test 분할 후 Train data에 5 Repeated 10-fold CV를 적용하였습니다.

# Data Split
data(cells)
cells <- modeldata::cells
cells |> ggplot(mapping=aes(x=class, fill=class)) + geom_bar()

cells_split <- cells |> rsample::initial_split(strata = class, prop=0.75)
cells_train <- cells_split |> training()
cells_test <- cells_split |> testing()
cells_folds <- cells_train %>% rsample::vfold_cv(v=10, repeats = 5, strata = class)



아래는 그리드 서치를 설명하기 위한 모델 및 레시피 코드로 본문에서는 MLP 모델을 생성했는데 이번 포스팅에서는 부스팅 모델로 설명하겠습니다.  전처리로는 아래와 같은 사항을 고려했습니다.

  1. 이진형 반응변수(case)는 데이터 불균형이 심하지 않기때문에 오버샘플링이나 언더샘플링을 적용하지 않음
  2. 결측치 확인 후 결측치가 없어 Imputation 고려하지 않음
  3. 설명변수의 스케일 차이가 커서 표준화(평균이 0이고 분산이 1을 따르도록) 설정
  4. 따로 데이터 분할을 진행하므로 case에 새로운 룰을 부여하여 고려하지 않도록 설정
  5. 변수의 수가 많아 차원축소 적용 (부스팅에서는 필수적으로 적용하지 않아도 됨)
    (주성분 수를 하이퍼파라미터로 설정하였으며 unknown와 finalize 함수를 사용해 데이터에 맞게 자동으로 설정되도록 함)
### Regular and Non-Regular Grids
# Regular Grid : combines each parameter factorially
# Non-Regular Grid : parameter combinations are not formed from a small set of points

xgboost_reipce <- 
  recipe(formula = class ~ ., data = cells_train) |> 
  update_role(case, new_role ="splitting variable") |> 
  step_zv(all_predictors()) |> 
  step_normalize(all_predictors()) |> 
  step_pca(all_double_predictors(), num_comp = tune())

xgboost_model <- 
  boost_tree(trees = tune(), min_n=tune(), tree_depth = tune(),
             learn_rate = tune(), 
             loss_reduction = tune(),
             sample_size = tune()) |> 
  set_mode(mode = "classification") |> 
  set_engine(engine = "xgboost")

xgboost_workflow <- 
  workflow() |> 
  add_recipe(xgboost_reipce) |> 
  add_model(xgboost_model)

# 하이퍼파라미터 설정
xgboost_param <- xgboost_workflow |> extract_parameter_set_dials()
xgboost_workflow |> extract_parameter_dials("trees") # 1~2000
xgboost_workflow |> extract_parameter_dials("min_n") # 2~40
xgboost_workflow |> extract_parameter_dials("sample_size") # 0.1~1
xgboost_workflow |> extract_parameter_dials("tree_depth")  # 1~15
xgboost_workflow |> extract_parameter_dials("num_comp")    # 1~4

xgboost_param <- xgboost_param |> 
  update(trees = trees(range = c(1L, 500L)),
         min_n = min_n(range = c(1L, 50L)),
         num_comp = num_comp(range = c(0L, unknown()))) |> 
  finalize(cells_train)
  
xgboost_param |> extract_parameter_dials("num_comp") # 0~58

 

(좌) 종속변수의 분포로 데이터 불균형이 심하지 않음 (우) 설명변수 별로 규모의 차이가 큼

 

 

 


1. Regular Grid

Regular Grid는 각 파라미터의 값들을 모두 조합한 격자(Grid)를 의미하며 아래와 같이 다양한 방법으로 생성할 수 있습니다.

tidyr::crossing, tidyr::expand_grid를 통한 생성

  • crossing은 중복된 조합을 출력하지 않지만 expand_grid는 같은 값을 가지는 조합을 출력한다.

# Results are same
expand_grid(hidden_units = 1:3, 
            penalty = c(0.0, 0.1),
            epochs = c(100, 200))

crossing(hidden_units = 1:3,
         penalty = c(0.0, 0.1),
         epochs = c(100, 200))

 

dials::grid_regular(param, levels)를 통한 생성

  • param은 extract_parameter_set_dials의 출력 객체
  • levels는 각 하이퍼파라미터 별로 설정할 수준의 수로 파라미터 별로 지정할 수 있으며, 정수 하나만 작성시에는 각 하이퍼파라미터가 가질 수 있는 조합의 수는 levels와 같으며 총 $p^{levels}$의 조합이 생김
xgboost_param |> grid_regular(levels=5)
xgboost_param |> grid_regular(levels=c(3,2,1,1,2,3,5))

  • levels = 5로 실행한 결과 7개의 하이퍼 파라미터의 값이 각각 5가지씩, 총 $7^5$개의 조합이 생성되었습니다.
  • levels = c(3,2,1,1,2,3,5)로 실행한결과 xgboost_param의 첫번째 파라미터부터 순서대로 3, 2, 1, 1, 2, 3, 5가지의 수준을 생성하여 총 180가지의 조합이 생성되었습니다.

 

 


2. Irregular Grid

Irregular Grid는 아래와 같은 방식으로 만들 수 있습니다.

  • grid_random(param, size) 
    • 각 하이퍼파라미터 범위에서 독립적인 다변량 균등 분포를 이용한 샘플링을 적용하여 샘플을 추출하는 방식으로 간단하나, 커버리지가 떨어질 수 있음
      (* 변환이 적용되었다면 Transformation scale에서 적용)

    • size : 총 몇 개의 하이퍼파라미터 값의 조합을 만들지에 대한 인자

  • grid_latin_hypercube(param, size) / grid_max_entropy(param, size)
    • 공간 채우기(Space-filling) 설계를 통한 샘플링으로 오버래핑(overlapping, 중복)을 최소화 하는 방법
      (* grid_latin_hypercube는 라틴 하이퍼큐브 샘플링을 통해 불규칙 그리드를 생성하여 샘플링의 중복성을 줄이고 다양한 조합을 테스트하는 데 유리하며 grid_max_entropy는 최대 엔트로피를 보장하는 설계로, 가능한 한 탐색 공간을 골고루 채우는 방식이며 복잡한 모델에서 성능이 좋습니다.) (추후 grid_tune의 default로 사용됨)

    • size : 총 몇 개의 하이퍼파라미터 값의 조합을 만들지에 대한 인자

 

 


3. Evaluating the Grid

최고의 성능을 보이는 하이퍼파라미터의 조합을 선택하기 위해서 각 조합별로 측정한 성과 지표를 통해 평가해야 할 것 입니다.

위에서 말한 것 처럼, Train data는 모델을 훈련시킬 때 사용하기 때문에 하이퍼파라미터를 평가할 때 사용하는 것은 적절하지 않으며
Test data로 하이퍼파라미터를 평가한다면 하이퍼파라미터가 적합된 모델을 최종 평가할 데이터가 없기 때문에 Test data로 평가하는 것 역시 적절하지 못하므로 Validation data를 만들어서 평가해야 합니다.

# Data Split
data(cells)
cells <- modeldata::cells
cells |> ggplot(mapping=aes(x=class, fill=class)) + geom_bar()

cells_split <- cells |> rsample::initial_split(strata = class, prop=0.75)
cells_train <- cells_split |> training()
cells_test <- cells_split |> testing()
cells_folds <- cells_train %>% rsample::vfold_cv(v=10, repeats = 5, strata = class)

 

맨 처음에 작성한 코드와 같이 리샘플링 데이터가 준비되었다면 하이퍼파라미터의 최적화를 위한 평가를 tune_grid 함수를 통해 진행 할 수 있습니다. 

 

tune_grid : 성과 지표를 통한 하이퍼파라미터 튜닝 함수

  • object : parsnip model specification 또는 workflow object
  • preprocessor : model formula 또는 recipe created using recipes::recipe
  • resamples : resample object created from rsample function
  • param_info :dials::extract_parameter_set_dials의 결과 또는 NULL(다른 인자로부터 자동으로 추출됨)
  • grid : data frame of tuning combinations(grid_* 함수도 가능) 또는 positive integer
  • metrics : performace metrics created from yardstick::metric_set 또는 NULL(디폴트 성과 지표 사용)
  • control : control_grid() object to fine tune the resampling process

 

저는 아래 코드와 같이 설정하여 튜닝을 진행하였습니다.

library(doMC)
registerDoMC(cores=8)
xgboost_tune <- 
  tune_grid(xgboost_workflow,
            resamples = cells_folds,
            metrics = metric_set(roc_auc),
            grid = 250, 
            param_info = xgboost_param,
            control = control_grid(verbose=T, allow_par = T))
  • grid = 250을 통해 하이퍼파라미터 공간에서 최대 엔트로피 설계 기법을 사용한 250개의 파라미터 조합값을 사용합니다.
  • Classificaition 문제이기 때문에, 대표적으로 많이 사용하는 ROC AUC를 사용하여 평가하도록 했습니다.
  • [번외] 컴퓨터 사양이 8코어라 코어수를 8개로 설정했습니다.

 

fit_resamples와 마찬가지로 collect_metrics 함수를 사용할 수 있습니다.

xgboost_tune |> collect_metrics()
xgboost_tune |> collect_metrics(summarize = F)

 

 

tune_grid를 통해 튜닝하고 나면 두가지 간편한 함수를 통해 결과를 이해할 수 있습니다.

  • autoplot(object, type = "marginals", metric) : 성능 프로파일을 튜닝 파라미터의 값에 따라 표현한 시각화 제공
  • show_best(object, n, metric) : metric이 높은 n개의 파라미터 조합을 출력
xgboost_tune |> autoplot(metric = "roc_auc", type = "marginal")
xgboost_tune |> show_best(metric = "roc_auc")

 

 

 


4. Finalizing the Model 

그리드 서치를 통해 평가할 하이퍼파라미터 값을 지정하고 tune_grid 함수를 통해 하이퍼파라미터를 튜닝까지 했다면, 어떤 조합에서 성능이 좋은지 파악할 수 있습니다. 하지만 여기서 끝내면 안되고 테스트 데이터에 대해서도 성능이 어느정도 나올지 평가해야 합니다.
tune_grid 함수의 결과는 적절한 하이퍼파라미터의 값을 지표와 함께 제공해 합리적인 선택을 도울 뿐 최종 모델을 적합한 것이 아니므로 select_best라는 함수를 사용해서 성능이 제일 좋게 나온 하이퍼파라미터 값을 사용하도록 finalize_workflow 함수를 통해 지정해야 합니다.

(수동으로 show_best에 나온 파라미터를 확인 후 직접 타이핑해도 상관없습니다.)

### Finalizing the model
final_xgboost_workflow <- 
  xgboost_tune |> select_best(metric = "roc_auc") |> 
  finalize_workflow(x=xgboost_workflow)
  
final_xgboost_workflow |> extract_spec_parsnip()

 

리샘플링에서 성능이 제일 좋은 하이퍼파라미터 값이 최종 워크플로 모델에 제대로 들어간 것을 확인할 수 있습니다.

이제, 테스트 데이터에 대해 성능을 확인하기 위해 Training set(=Assessment + Analysis)으로 학습을 진행하도록 하겠습니다.

final_xgboost_fit <- final_xgboost_workflow |> 
  last_fit(split = cells_split) 
final_xgboost_fit |> collect_metrics()

 

last_fit 함수를 통해 training set에 대해 학습을 진행하고 test set에 대해 평가를 진행하였습니다. 
최종적으로는 정확도(Accuracy) 기준 83%, ROC-AUC 기준 0.899의 성능을 보이는 모델을 생성하였네요.

 

 

 


5. Tools for Efficient grid search (summary)

1) Submodel Optimization 

단일 모델을 한번 학습하더라도 여러 하이퍼파라미터의 값을 평가할 수 있는 모델들이 있습니다.

(eg, Boosting - number of iterations, Regularization model - amount of regularization, PLS - number of PLS components)

tune 패키지는 자동적으로 submodel 최적화가 가능한 모델들이 튜닝될때 여러 하이퍼파라미터의 값을 평가할 수 있도록 지원합니다.

 

 

2) Parallel Processing

  1. tune_grid(parallel_over = "resamples")
    논리적 코어가 k개일 때, 각 코어가 하나의 리샘플링 데이터(예: k-fold cross-validation의 각 fold)를 처리하며 병렬 작업을 수행하는 방식
    • 장점: 전처리가 복잡한 경우에는 리샘플링된 데이터에 대한 전처리를 병렬로 진행할 수 있어 성능이 좋아집니다.
    • 단점: 논리적 코어가 k보다 많은 경우 사용하지 않는 코어가 발생하여 전체 성능이 떨어질 수 있습니다. 
               또한, 전처리가 간단한 경우에는 이 방식이 오히려 비효율적일 수 있습니다.

  2. tune_grid(parallel_over = "everything")
    논리적 코어가 많을 때 성능을 최적화할 수 있도록 각 코어가 리샘플링 데이터와 하이퍼파라미터 값 쌍을 병렬로 처리하는 방식
    • 장점: 논리적 코어가 k보다 훨씬 많으면 이 방식이 더 효율적일 수 있습니다.
    • 단점: 리샘플링마다 복잡한 전처리가 필요하다면, 이 방식은 비효율적입니다. 리샘플링 데이터마다 별도로 전처리 후 하이퍼파라미터 튜닝을 진행하는 것이 더 나은 성능을 제공할 수 있습니다.

  3. 전역 변수 참조시
    • 일반적으로 병렬 처리 시, 함수 외부의 전역 변수를 직접 참조하기보다는, 사용할 변수를 함수에 인자로 전달하여 사용하는 것이 성능 면에서 더 효율적임 (rlang으로 하는 동적 변수 참조와 환경 https://moogie.tistory.com/149 참조)
    • 객체에 있는 단일 값을 동적으로 전달할 때 !!object 사용
    • 객체에 있는 여러 값을 동적으로 전달할 때 !!!object 사용

(* 참고) 코어수 확인  : parallel::detectCores() / future::availableCores()

 

 

 

'Data Science > Modeling' 카테고리의 다른 글

[Tidy Modeling with R] 15. Many Models with Workflow sets  (0) 2024.01.01
[Tidy Modeling With R] 14. Iterative Search with XGBoost  (2) 2023.12.26
[Tidy Modeling with R] 12. 하이퍼파라미터 튜닝  (0) 2023.10.11
[Tidy Modeling with R] 11. Model Comparison (모델 비교)  (0) 2023.10.09
[Tidy Modeling with R] 10. Resampling  (0) 2023.10.01
'Data Science/Modeling' 카테고리의 다른 글
  • [Tidy Modeling with R] 15. Many Models with Workflow sets
  • [Tidy Modeling With R] 14. Iterative Search with XGBoost
  • [Tidy Modeling with R] 12. 하이퍼파라미터 튜닝
  • [Tidy Modeling with R] 11. Model Comparison (모델 비교)
임파카
임파카
[ML & Statistics] 모바일 버전에서 수식 오류가 있어 PC 환경에서 접속하는 것을 권장합니다.
  • 임파카
    무기의 스탯(Stat)
    임파카
  • 전체
    오늘
    어제
    • Study (148)
      • Data Science (44)
        • Modeling (18)
        • Manipulation (21)
        • Visualization (4)
      • Statistics (5)
        • Mathmetical Statistics (53)
      • Web Programming (17)
      • AI (26)
        • Machine Learning (16)
        • Deep Learning (10)
      • 활동 및 프로젝트 (3)
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
임파카
[Tidy Modeling With R] 13. Grid Search with XGBoost
상단으로

티스토리툴바