[혼자 공부하는 머신러닝+딥러닝] 책에 기반한 정리글입니다.
전체 소스코드는 아래 Github 링크에서 확인할 수 있습니다.
지금까지는 모델을 훈련할 때 훈련 데이터를 가지고 매번 모델을 새로 만들었다. 이번에는 훈련한 모델을 버리지 않고 새로운 데이터에 대해서 조금씩 더 훈련하는 방법을 알아본다. 이를 점진적 학습이라고 하며, 대표적인 점진적 학습 알고리즘 중 하나가 확률적 경사 하강법이다.
확률적 경사 하강법
훈련 세트에서 샘플을 하나씩 꺼내 손실 함수의 경사를 따라 최적의 모델을 찾는 알고리즘이다. 샘플을 여러개씩 사용하면 미니배치 경사 하강법이고, 한번에 전체 샘플을 사용하면 배치 경사 하강법이다.
이들을 꼭 사용하는 알고리즘이 바로 신경망 알고리즘이다. 신경망 모델이 확률적 경사하강법이나 미니배치 경사하강법을 주로 이용한다.
손실 함수
확률적 경사 하강법이 최적화할 대상이다. 대부분의 문제에 잘 맞는 손실 함수가 정의되어 있는데, 이진 분류에는 로지스틱 회귀 손실함수, 다중분류에는 크로스엔트로피 손실함수를 사용한다. 회귀 문제에는 평균 제곱 오차 손실함수를 사용한다.
손실 함수는 어떤 문제에서 머신러닝 알고리즘이 얼마나 엉터리인지 측정하는 기준이며 작을수록 좋다.
손실 함수는 연속적이며 미분 가능해야 한다.
이 손실 함수를 로지스틱 손실 함수, 또는 이진 크로스엔트로피 손실함수 라고한다.
다중 분류에서는 크로스엔트로피 손실함수, 회귀에는 평균 제곱 오차를 사용한다.
먼저 훈련 데이터를 준비한다.
import pandas as pd
fish = pd.read_csv('https://bit.ly/fish_csv_data')
fish_input = fish[['Weight', 'Length', 'Diagonal', 'Height', 'Width']].to_numpy()
fish_target = fish['Species'].to_numpy()
훈련 세트와 테스트 세트를 나누고, 특성을 표준화 전처리한다.
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
train_input, test_input, train_target, test_target = train_test_split(fish_input, fish_target, random_state=42)
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
SGDClassifier
클래스는 확률적 경사 하강법을 제공하는 분류용 클래스이다.
# 확률적 경사 하강법을 제공하는 분류용 클래스
from sklearn.linear_model import SGDClassifier
# loss : 손실 함수의 종류 지정, max_iter : 수행할 에포크 횟수
sc = SGDClassifier(loss='log', max_iter=10, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
출력
0.773109243697479
0.775
정확도가 낮은걸로 보아, 10번의 에포크가 부족했다.
모델을 이어서 훈련할 때는 partial_fit()
메서드를 사용한다.
sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
출력
0.8151260504201681
0.825
에포크를 한번 더 실행하니 정확도가 향상되었다.
에포크 횟수가 적어 모델이 훈련세트를 덜 학습하면 과소적합, 너무 많은 에포크 횟수는 과대적합된 모델일 가능성이 있다.
fit()
메소드 대신 partial_fit()
만 사용하여 적절한 에포크 횟수를 알아본다.
import numpy as np
sc = SGDClassifier(loss='log', random_state=42)
train_score = []
test_score = []
classes = np.unique(train_target) # 7개의 생선의 종류
#partial_fit() 메서드만 사용하려면 훈련 세트의 전체클래스의 레이블을 전달해 주어야 함
for _ in range(0, 300) :
sc.partial_fit(train_scaled, train_target, classes = classes)
train_score.append(sc.score(train_scaled, train_target))
test_score.append(sc.score(test_scaled, test_target))
각 횟수별로 훈련세트와 테스트세트의 점수를 train_score
test_score
리스트에 넣는다.
import matplotlib.pyplot as plt
plt.plot(train_score)
plt.plot(test_score)
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.show()
그래프에 따라서 에포크 횟수 100번 정도가 적절한 반복 횟수임을 알 수 있다.
SGBClassifier 는 일정 에포크 동안 성능이 향상되지 않으면 더 훈련하지 않고 자동으로 멈춘다. tol
매개변수에서 향상될 최솟값을 지정할 수 있는데, None
이라면 자동으로 멈추지 않고 max_iter
만큼 무조건 반복한다.
sc = SGDClassifier(loss='log', max_iter=100, tol=None)
loss
매개변수의 기본값은 hinge
이며 , 힌지 손실은 서포트 벡터 머신 알고리즘을 위한 손실 함수이다.