ML 모델이 실전에서 좋은 성능을 내게 하려면 어떻게 해야될까요 ?
학습 / 테스트 데이터 세트의 학습이 가장 중요할것 입니다. 하지만 테스트 세트로 모델을 튜닝하면 실전에서 좋은 성능을 기대하기 힘듭니다.
답을 알고있는 상태로 시험을 치면 시험을 잘 볼 수 밖에 없고, 만약 시험문제를 조금 바꾸면 좋은 성적을 기대하기 힘들겁니다.
그래서 모델을 튜닝할때 훈련세트,검증세트,테스트세트를 나눠야 합니다.
1. 데이터 세트 준비하기
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
x = cancer.data
y = cancer.target
x_train_all, x_test , y_train_all , y_test = train_test_split(x,y,stratify=y,test_size=0.2,random_state=777)
2.검증세트 분할하기
먼저 훈련세트와 테스트세트를 나눈뒤 , 훈련세트에서 검증세트를 나눕니다.
x_train,x_val,y_train,y_val = train_test_split(x_train_all,y_train_all,stratify=y_train_all,test_size=0.2,random_state=777)
3. 검증 세트 사용해 모델 평가하기
sgd = SGDClassifier(loss='log',random_state=777)
sgd.fit(x_train,y_train)
sgd.score(x_val,y_val)
==============================
0.9230769230769231
데이터 전처리와 특성의 스케일.
머신러닝 패키지 안에 준비되어 있는 데이터의 대부분은 실습을 위하 데이터이므로 전처리할 필요가 없습니다. 하지만 실제로 수집된 데이터는 누락이 있을 수 있고 데이터의 형태가 일정하지 않을 수 있습니다. 이런 경우 데이터를 적절히 가공하는 '데이터 전처리' 과정이 필요합니다.
-스케일-
예를 들어 어떤 값이 100이라고 합시다. 이 값은 큰 값일까요? 작은 값일까요 ? 이처럼 어떤 특성의 값이 크고 작은것을 직관적으로 알기 쉽지 않습니다. 그래서 우리는 스케일 ,특히 평균이 0이고 분산이1되게 하는 StandardScale을 활용하게 됩니다.
먼저 스케일을 조정하지 않고 모델을 훈련해 봅시다.
1. 훈련 데이터를 준비하고 스케일 비교하기.
import matplotlib.pyplot as plt
print(cancer.feature_names[[2,3]])
plt.boxplot(x_train[:,2:4])
plt.show()
2. 가중치를 기록할 변수와 학습률 파라미터 추가하기.
> SingleLayer 클래스에 인스턴스 변수를 추가하여 에포크마다 가중치의 값을 저장하여 가중치의 변화를 관찰할 때 사용하겠습니다.
def __init__(self,leraning_rate=0.1):
self.w = None
self.b = None
self.losses = []
self.w_history = []
self.lr = leraning_rate
learning_rate 란?
하이퍼 파라미터이며 변수명 그대로 학습률을 의미합니다. 이 값으로 가중치의 업데이트 양을 조절합니다.
그림과 같이 적절한 learning_rate 값을 적용해 손실함수의 전역 최솟값에 다가갈수 있도록 합니다.
3.학습을 진행하가면서 w_history에 담긴 가중치 확인하기 .
w2 = []
w3 = []
for w in layer1.w_history:
w2.append(w[2])
w3.append(w[3])
plt.plot(w2,w3) #가중치의 변화
plt.plot(w2[-1],w3[-1],'ro') #최종 가중치
plt.show()
위 그래프(가중치의 값)을 보면 상하로 크게 요동치고 있습니다. 즉 , 최적의 가중치에 도달하는 동안 모델이 불안정하게 수렴하고 있다라고 표현할 수 있습니다. 이런 현상을 개선하기 위해 우리는 스케일링을 합니다.
-표준화 스케일링-
사이킷런에는 표준화를 위한 StandardScaler 클래스가 준비되어 있습니다.
1. 넘파이로 표준화 구현하기 .
train_mean = np.mean(x_train,axis=0)
train_std = np.std(x_train,axis=0)
x_train_scaled = (x_train - train_mean) / train_std
2.모델 훈련하기 후 가중치 그래프 그려보기
#모델 훈련하기
layer2 = SingleLayer()
layer2.fit(x_train_scaled,y_train)
w2 = []
w3 = []
for w in layer2.w_history:
w2.append(w[2])
w3.append(w[3])
plt.plot(w2, w3)
plt.plot(w2[-1], w3[-1], 'ro')
plt.xlabel('w[2]')
plt.ylabel('w[3]')
plt.show()
스케일링을 하기 전 보다 훨씬 안정적으로 최적의 가중치로 수렴하는것을 알 수 있습니다.
3. 스코어 확인하기.
layer2.score(x_val,y_val)
=================
0.37362637362637363
스코어가 낮게 나온이유는 train 세트만 스케일링 하였기 때문입니다. 검증세트도 스케일링 합시다.
4.검증세트 스케일링 후 다시 스코어 확인.
layer2.score(x_val_scaled, y_val)
===============================
0.945054945054945
0.94의 높은 성능을 보이는것을 알 수 있습니다.
이렇게 스케일링을 한 뒤 확인 해야될것이 있습니다. 우리가 방금 훈련세트와 검증세트를 정규화했습니다. 과연 훈련세트와 검증세트가 똑같은 비율로 스케일링 되었을까요? 답은 아닙니다. 훈련세트와 검증세트 각각의 평균과 표준편차를 이용해 정규화한 결과를 보면 살짝 다르게 정규화 되어있다는 것을 알 수있습니다.
위 쪽은 원본데이터 세트의 산점도 이고 아래는 정규화 후 데이터세트의 산점도 입니다. 가운데 오른쪽 부분이 살짝 다른걸 알 수 있습니다.
어떻게 하면 올바르게 검증 세트를 전처리 할 수 있을 까요?
답은 간단합니다. 우리가 원하는것은 검증 세트를 훈련 세트와 같은 비율로 전처리 하는 것입니다. 즉, 훈련세트의 평균,표준편차를 사용하여 검증 세트를 반환하면 됩니다.
*과대적합과 과소적합.
다음 그래프를 통해 과대적합과 과소적합을 알아 보겠습니다.
즉, 과대적합은 훈련세트에서는 좋은 성능을 내지만 검증 세트에서 낮은 성능을 내는 경우를 말하고 , 과소적합은 훈련세트와 검증세트의 성능에는 차이가 크지 않지만 그 값 자체가 전체적으로 낮은 성능을 내는 경우를 말합니다.
과대적합모델을 '분산이 크다'라 말하는데 이는 훈련세트에 충분히 다양한 패턴의 샘플의 포함되지 않은 경우를 말합니다.
하지만 현실적으로 훈련 샘플을 많이 모을 수 없는 경우도 있을 것입니다. 이럴때는 어떻게 해야 할까요 ?
훈련세트에 집착하지 않도록 가중치를 제한해 주면 됩니다. 이를 '모델의 복잡도를 낮춘다'라 표현합니다.
가중치 규제 방법
가중치 규제(regularization)는 과대적합을 해결하는 방법중 하나입니다. 보통 가중치를 규제하면 모델의 일반화 성능이 좋아집니다.
즉 검정선은 특정 훈련샘플에 집착한 나머지 다른 샘플에 대한 정확도가 매우 낮아지는 현상이 일어남을 알 수 있습니다. 즉, 좋은 성능을 갖추지 못했고 , 모델이 일반화되지 않았습니다.
L1 규제
L1규제는 손실 함수에 가중치의 절댓값인 L1 norm을 추가한것.
L2규제
L2규제는 손실 함수에 가중치에 대한 L2 norm의 제곱을 더하면 된다.
훈련데이터 셋이 현실적으로 적을때 가중치를 규제하여 과대적합을 개선하는 방법을 살펴 보았습니다. 실질적으로 샘플 수를 늘릴 수 있는 방법은 없을까요 ? 이럴때에는 교차 검증 (cross validation)을 활용하면 좋습니다.
위 그림과 같이 모든데이터를 훈련데이터로 삼고 , 모든 데이터를 검증 데이터로 중첩되게 하여 훈련하는 방식을 뜻합니다. 처음 훈련세트 k개의 폴드로 나눈다해서 k-fold 교차 검증이라 부릅니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!