테스트 세트로 일반화 성능을 올바르게 예측하려면 가능한 한 테스트 세트를 사용하지 말아야 합니다.
그리고 일반화 성능을 가늠해보려면 테스트 세트에서 얻은 점수를 통해 확인할 수 있습니다.
어떻게 하면 두 가지를 지키면서 최적의 성능을 내는 하이퍼파라미터를 찾을 수 있을까요?
검증 세트(Validation Set)
테스트 세트를 사용하지 않으면 모델이 과대적합인지 과소적합인지 판단하기 어렵습니다.
테스트 세트를 사용하지 않고 이를 측정하는 간단한 방법은 훈련 세트를 나누는겁니다.
이를 바로 검증 세트(Validation Set)이라고 부릅니다.
방법과 비율은 다음과 같습니다.
전체 데이터 중 20%를 테스트 세트로 만들고 나머지 80%를 훈련 세트로 만듭니다.
그리고 훈련 세트 중에서 다시 20%를 떼어 내어 검증 세트로 만듭니다.
그 후 모델 훈련 방식입니다.
1. 훈련 세트에서 모델을 훈련하고 검증 세트로 모델을 평가하는 방식으로
테스트하고 싶은 매개변수를 바꿔가며 가장 좋은 모델을 고릅니다.
2. 이 매개변수를 사용해 훈련세트와 검증 세트를 합쳐 전체 훈련 데이터에서 모델을 다시 훈련합니다.
3. 테스트 세트에서 최종 점수를 평가합니다.
한번 실습해보겠습니다.
우선 필요한 데이터를 불러오고 data, target으로 나누겠습니다.
그 후 훈련 세트와 테스트 세트로 나누겠습니다.
그 다음 train_input과 train_target을 다시 train_test_input() 함수에 넣어 훈련 세트와 검증 세트를 만들건데,
여기에서도 test_size는 0.2로 지정하여 train_input의 약 20%를 val_input으로 만듭니다.
마지막으로 훈련 세트와 검증 세트의 크기를 확인해보겠습니다.
이렇게 하면 훈련 세트와 테스트 세트, 검증 세트를 나눌 수 있습니다.
교차 검증
검증 세트를 만드느라 훈련 세트가 줄었습니다.
보통 많은 데이터를 훈련에 사용하면 좋은 모델이 만들어집니다.
그렇다고 검증 세트를 너무 조금만 만들면 검증 점수가 불안정할 것입니다.
이럴 때 교차 검증을 이용하면 안정적인 검증 정수를 얻고 훈련에 더 많은 데이터를 사용할 수 있습니다.
교차 검증은 검증 세트를 떼어 내어 평가하는 과정을 여러 번 반복합니다.
그다음 이 점수를 평균하여 최종 검증 점수를 얻습니다.
과정을 그림으로 살펴보겠습니다.
다음은 3-폴드 교차 검증입니다.
예시는 3-폴드 교차 검증이지만, 보통 5-폴드 또는 10-폴드 교차 검증을 많이 사용한다고 합니다.
왜냐면 데이터의 80~90%까지 훈련에 사용할 수 있기 때문입니다.
검증 세트는 줄어들지만 각 폴드에서 계산한 검증 점수를 평균하기 때문에 점수가 안정된다고 생각할 수 있습니다.
사이킷런에는 cross_validate()라는 교차 검증 함수가 있습니다.
사용법은 다음과 같습니다.
1. 먼저 평가할 모델 객체를 첫 번째 매개변수로 전달합니다.
2. 앞에서처럼 직접 검증 세트를 떼어 내지 않고 훈련 세트 전체를 cross_validate() 함수에 전달합니다.
한번 실습해보겠습니다.
cross_validate() 함수는 fit_time, score_time, test_score 키를 가진 딕셔너리를 반환합니다.
처음 2개의 키(fit_time, score_time)은 각각 모델을 훈련하는 시간과 검증하는 시간을 의미합니다.
각 키마다 5개의 숫자가 존재하는데, cross_validate()는 기본적으로 5-폴드 교차 검증을 수행합니다.
(cv 매개변수를 통하여 폴드 수 변경 가능)
이렇게 교차 검증을 통해 얻은 최종 점수는 test_score 키에 담긴 5개의 점수를 평균하여 얻을 수 있습니다.
교차 검증을 수행하면 입력한 모델에서 얻을 수 있는 최상의 검증 점수를 가늠해 볼 수 있습니다.
단, 한 가지 주의할 점은 cross_validate()는 훈련 세트를 섞어 폴드를 나누지 않습니다.
앞서 우리는 train_test_split() 함수로 전체 데이터를 섞은 후 훈련 세트를 준비했기 때문에 따로 섞을 필요가 없습니다.
하지만 만약 교차 검증을 할 때 훈련 세트를 섞으려면 분할기(Splitter)를 지정해야 합니다.
사이킷런의 분할기는 교차 검증에서 폴드를 어떻게 나눌지 결정해 줍니다.
cross_validate() 함수는 회귀 모델일 경우 KFold 분할기를 사용하고
분류 모델일 경우 타깃 클래스를 골고루 나누기 위해 StratifiedKFold를 사용합니다.
한 번 실습해보겠습니다.
만약 훈련 세트를 섞은 후 10-폴드 교차 검증을 수행하려면 다음과 같이 수행합니다.
여기까지 교차 검증에 대한 설명이었습니다.
이제 이어서 결정 트리의 매개변수 값을 바꿔가며 가장 좋은 성능이 나오는 모델을 찾아 보겠습니다.
이때 테스트 세트를 사용하지 않고 교차 검증을 통해서 좋은 모델을 고르면 됩니다.
시작해보겠습니다.
하이퍼파라미터 튜닝
머신러닝 모델이 학습하는 파라미터를 모델 파라미터라고 부릅니다.
반면에 모델이 학습할 수 없어서 사용자가 지정해야만 하는 파라미터를 하이퍼파라미터라고 합니다.
사이킷런과 같은 머신러닝 라이브러리를 사용할 때 이런 하이퍼파라미터는 모두 클래스나 메서드의 매개변수로 표현됩니다.
하이퍼파라미터를 튜닝하는 작업은 어떻게 이루어질까요?
결정 트리 모델로 예를 들어보겠습니다.
결정 트리 모델에는 max_depth, min_samples_split이라는 매개변수가 있습니다.
만약, max_depth = 3이라는 최적값을 찾았을 때 이를 고정하고
min_samples_split을 바꿔가며 최적값을 찾아도 될까요?
답은 "안됩니다." 입니다.
최적값을 찾을 때는 매개변수를 동시에 바꿔가며 최적의 값을 찾아야 합니다.
그렇다면 매개변수가 많아지면 더 복잡해지겠죠?
이를 위해 만들어진 도구가 있습니다.
사이킷런에서 제공하는 그리드 서치(Grid Search)입니다.
GridSearchCV 클래스의 장점은 하이퍼파라미터 탐색과 교차 검증을 한 번에 수행합니다.
별도로 cross_validate() 함수를 호출할 필요가 없습니다.
그럼 한 번 간단하게 예시를 들어보겠습니다.
저희는 기본 매개변수를 사용한 결정 트리 모델에서 min_impurity_decrease 매개변수의 최적값을 찾아보겠습니다.
여기서는 0.0001부터 0.0005까지 0.0001씩 증가하는 5개의 값을 시도하겠습니다.
그리고 GridSearchCV 클래스에 탐색 대상 모델과 params 변수를 전달하여 그리드 서치 객체를 만듭니다.
그 다음 일반 모델을 훈련하는 것처럼 gs 객체에 fit() 메서드를 호출합니다.
이 메서드를 호출하면 그리드 서치 객체는 결정 트리 모델 min_impurity_decrease 값을 바꿔가며 총 5번 실행합니다.
GridSearchCV의 cv 매개변수 기본값은 5입니다.
따라서 min_impurity_decrease 값마다 5-폴드 교차 검증을 수행합니다.
결국 5 x 5 = 25개의 모델을 훈련합니다.
많은 모델을 훈련하기 때문에 GridSearchCV 클래스의 n_jobs 매개변수에서
병렬 실행에 사용할 CPU 코어 수를 지정하는 것이 좋습니다.
n_jobs 매개변수의 기본값은 1입니다.
-1로 지정하면 시스템에 있는 모든 코어를 사용합니다.
그럼 이제 그리드 서치를 수행해보겠습니다.
best_estimator_ 메서드는 N개 모델 중에서 검증 점수가 가장 높은 모델을 알 수 있습니다.
그리고 이 모델을 일반 모델처럼 똑같이 사용할 수 있습니다.
자 그러면, 어떤 값이 최적의 매개변수인지 확인해볼까요?
여기서는 0.0001이 최적의 매개변수로 선택되었습니다.
각 매개변수에서 수행한 교차 검증의 평균 점수는 cv_results_ 속성의 'mean_test_score'키에 저장되어 있습니다.
이번엔 조금 더 복잡한 매개변수 조합을 탐색해 보겠습니다.
결정 트리에서 min_impurity_decrease는 노드를 분할하기 위한 불순도 감소 최소량을 지정합니다.
여기에다가 max_depth로 트리의 깊이를 제한하고 min_samples_split으로 노드를 나누기 위한 최소 샘플 수도 골라 보겠습니다.
이 매개변수들로 수행할 교차 검증 횟수는 9 X 15 X 10 = 1,350개입니다.
기본 5-폴드 교차 검증을 수행하므로 만들어지는 모델의 수는 6,750개가 됩니다.
그럼 한 번 n_jobs 매개변수를 -1로 설정하고 실행해 보겠습니다.
최적의 매개변수 값, 교차 검증 점수도 확인해보겠습니다.
이렇게 자동으로 교차 검증을 수행해서 최상의 매개변수를 찾을 수 있습니다.
랜덤 서치
앞에서 탐색한 매개변수의 간격이 0.0001 혹은 1로 설정했었는데 이에 대한 특별한 이유는 없습니다.
이렇게 매개변수의 값이 수치일 때 값의 범위나 간격을 미리 정하기 어려울 수 있습니다.
이럴 땐 랜덤 서치를 사용하면 좋습니다.
랜덤 서치에는 매개변수를 샘플링할 수 있는 확률 분포 객체를 전달합니다.
이는 추후에 설명하고 먼저 싸이파이에서 2개의 확률 분포 클래스를 임포트 하겠습니다.
싸이파이의 stats 서브 패키지에 있는 uniform과 randint 클래스는 모두 주어진 범위에서 고르게 값을 뽑습니다.
이를 "균등 분포에서 샘플링한다"라고 말합니다.
randint는 정숫값을 뽑고, uniform은 실숫값을 뽑습니다.
한번 randint를 사용해서 0에서 10 사이의 범위를 갖는 객체를 만들고 10개의 숫자를 샘플링해보겠습니다.
0에서 10 사이의 랜덤한 숫자가 나온걸 확인할 수 있습니다.
이번에는 uniform을 사용해서 0에서 1사이의 실수를 추출해보겠습니다.
마찬가지로 0에서 1 사이의 실수가 나온걸 확인할 수 있습니다.
이처럼 랜럼 서치에 randint와 uniform 클래스 객체를 넘겨주고 총 몇 번을 샘플링해서 최적의 매개변수를 찾으라 명령할 수 있습니다.
그럼 이제 탐색할 매개변수의 딕셔너리를 만들어 보겠습니다.
그 전에 위의 매개변수 외에도 min_samples_leaf라는 매개변수를 추가할 것인데,
이 매개변수는 리프 노드가 되기 위한 최소 샘플의 개수입니다.
어떤 노드가 분할하여 만들어질 자식 노드의 샘플 수가 이 값보다 작을 경우 분할하지 않습니다.
탐색할 매개변수 범위는 다음과 같습니다.
이제 샘플링 횟수를 사이킷런의 랜덤 서치 클래스인 RandomizedSearchCV의 n_iter에 100으로 지정해 모델을 훈련하겠습니다.
params에 정의된 매개변수 범위에서 100번의 샘플링을 하여 교차 검증을 수행하고 최적의 매개변수 조합을 찾습니다.
앞에서 한 그리드 서치보다 훨씬 교차 검증 수를 줄이면서 넓은 영역을 효과적으로 탐색할 수 있습니다.
한번 결과를 보겠습니다.
출처 : 혼자 공부하는 머신러닝 + 딥러닝
https://product.kyobobook.co.kr/detail/S000001810330
다음 장에서는 트리의 앙상블에 대해서 알아보겠습니다.
'Study > 혼자 공부하는 머신러닝 + 딥러닝' 카테고리의 다른 글
[혼자 공부하는 머신러닝 + 딥러닝] 군집 알고리즘 (0) | 2024.11.13 |
---|---|
[혼자 공부하는 머신러닝 + 딥러닝] 트리의 앙상블 (1) | 2024.11.11 |
[혼자 공부하는 머신러닝 + 딥러닝] 결정 트리 (0) | 2024.10.31 |
[혼자 공부하는 머신러닝 + 딥러닝] 확률적 경사 하강법 (0) | 2024.10.28 |
[혼자 공부하는 머신러닝 + 딥러닝] 로지스틱 회귀(Logistic regression) (1) | 2024.10.22 |