Python/ML & DL 공부

[ML] 04-2 확률적 경사 하강법

dori_0 2022. 3. 10. 22:36

혼자 공부하는 머신러닝+딥러닝 책을 바탕으로 공부한 내용입니다.

 

CH4 다양한 분류 알고리즘 ②

점진적 학습을 위한 확률적 경사 하강법

 


 

한빛 마켓은 럭키백의 폭발적인 인기에 힘입어 생선을 실시간으로 학습하기 위한 새로운 머신러닝 모델을 필요로 한다. 확률적 경사 하강법을 사용해 점진적으로 학습하는 로지스틱 회귀 모델을 만들어보자

 

 

▶ 점진적인 학습

키워드로 먼저 공부해보자!

 

점진적 학습

  • 온라인 학습이라고도 부름
  • 학습이 끝난 모델에 대하여 작은 묶음 단위의 데이터를 주입해 모델을 학습시키는 방법
  • 가장 대표적인 점진적 학습 알고리즘은 확률적 경사 하강법

 

확률적 경사 하강법

  • 훈련 세트에서 샘플을 하나씩 꺼내 손실 함수의 경사를 따라 최적의 모델을 찾는 알고리즘

 

미니배치 경사 하강법

  • 샘플을 하나씩 사용하지 않고 여러 개를 사용하여 최적의 모델을 찾는 알고리즘

 

배치 경사 하강법

  • 한 번에 전체 샘플을 사용하여 최적의 모델을 찾는 알고리즘

 

손실 함수

  • 확률적 경사 하강법이 최적화 할 대상
  • 이진 분류에는 로지스틱 회귀 손실 함수 사용
  • 다중 분류에는 크로스엔트로피 손실 함수 사용
  • 회귀 문제에는 평균 제곱 오차 손실 함수 사용

 

에포크

  • 확률적 경사 하강법에서 전체 샘플을 모두 사용하는 한 번 반복을 의미
  • 일반적으로 경사 하강법 알고리즘은 수십에서 수백 번의 에포크를 반복함

 

 

▶ SGDClassifier

데이터를 불러온 후 train, test set의 표준화 전처리까지 해주자

# 데이터 불러오기
import pandas as pd
fish = pd.read_csv("https://bit.ly/fish_csv_data")
fish.head()

# Species 열은 타깃, 나머지 열은 입력 데이터로
fish_input = fish[['Weight', 'Length', 'Diagonal', 'Height', 'Width']].to_numpy()
fish_target = fish['Species'].to_numpy()

# train set, test set으로 나누기
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(
    fish_input, fish_target, random_state = 42)
    
# train set, test set 표준화 전처리
# 꼭 train set에서 학습한 통계 값으로 test set 변환하기
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
  • 특성값의 스케일을 맞춘 train_scaled, test_scaled 두 넘파이 배열을 준비하였다.

 

 

이제 사이킷런에서 확률적 경사 하강법을 제공하는 SGDClassifier을 사용해 정확도를 출력해보자

손실 함수의 종류는 log로, 수행할 에포크 횟수는 10회로 지정하였다.

from sklearn.linear_model import SGDClassifier

# 2개의 매개변수 지정 (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))

  • train set, test set 모두 정확도가 낮은 것이 확인된다.
  • 우리가 지정한 반복 횟수 10번이 부족해서 그런 것으로 보인다.
  • 모델이 충분히 수렴하지 않았다는 경고가 뜸 (max_iter 매개변수 값 늘려주기)

 

 

확률적 경사 하강법은 점진적 학습이 가능하다

SGDClassifier 객체를 다시 만들지 않고 훈련한 모델 sc를 추가로 더 훈련해보자

# 1 에포크 추가로 훈련
sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))  #0.8151260504201681
print(sc.score(test_scaled, test_target))  #0.85
  • 모델을 이어서 훈련 할 때는 partial_fit() 메서드를 사용
  • 한번 할 때마다 1 에포크씩 이어서 훈련 가능하다

 

정확도가 향상된 것으로 보아 에프코를 더 훈련해보면 더 좋은 성능을 낼 것으로 보여진다.

 

 

▶ 에포크와 과대/과소적합

확률적 경사 하강법을 사용한 모델은 에포크 횟수에 따라 과소적합이나 과대적합이 될 수 있다.

  • 적은 에포크 횟수 - 과소적합될 가능성이 높음
  • 많은 에포크 횟수 - 훈련 세트에 너무 잘 맞아 테스트 세트에는 오히려 점수가 나쁜 과대적합이 될 가능성이 높음

 

 

훈련 세트 점수는 에포크가 진행될수록 증가하지만 테스트 세트 점수는 어느 순간 감소하기 시작한다.

바로 그 지점이 과대적합이 시작하는 곳이다. 

 

 

직접 그래프로 확인해보며 에크포를 몇 번 반복해야 모델이 좋은 성능을 낼지 확인해보자

import numpy as np
sc = SGDClassifier(loss='log', random_state=42)

# 점수 기록할 리스트 준비
train_score = []
test_score = []

classes = np.unique(train_target)

# 300번의 에포크 훈련 후 점수 계산
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))
  • partial_fit() 메서드만 사용하기 위해 훈련 세트에 있는 전체 클래스의 레이블을 classes 변수를 통해 지정해주었다.

 

 

이제 300번의 에포크 동안 기록한 train set, test set의 점수를 그래프로 그려보자

# 그래프로 그려보기
import matplotlib.pyplot as plt
plt.plot(train_score)
plt.plot(test_score)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()

  • 100번째 에포크가 적절한 반복 횟수로 보여진다.

 

이제 SGDClassifier의 반복 횟수를 100으로 맞추고 다시 모델을 훈련해보자

 

sc = SGDClassifier(loss='log', max_iter=100, tol=None, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))

  • 정확도 점수가 비교적 높게 나왔다.

 

SGDClassifier은 일정 에포크동안 성능이 향상되지 않으면 훈련을 자동으로 멈춘다. (tool 매개변수로 조정)

tool 매개변수를 None으로 지정하여 자동으로 멈추지 않고 100번 반복하도록 하였다

 

 

 

▶ 힌지 손실

우리는 지금까지 loss='log'로 지정하여 로지스틱 손실 함수를 사용하였다.

SGDClassifier의 loss 매개변수 기본값은 'hinge'이다.

 

힌지 손실을 사용해 같은 반복 횟수동안 모델을 훈련해보자

# 힌지 손실도 사용 가능
sc = SGDClassifier(loss='hinge', max_iter=100, tol=None, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))

  • SGDClassifier가 여러 종류의 손실 함수를 loss 매개변수에 지정하여 다양한 머신러닝 알고리즘을 지원하는 것을 기억하고 있자!

 

 

'Python > ML & DL 공부' 카테고리의 다른 글

[ML] 05-2 교차 검증과 그리드 서치  (0) 2022.03.11
[ML] 05-1 결정 트리  (0) 2022.03.11
[ML] 04-1 로지스틱 회귀  (0) 2022.03.07
[ML] 03-3 특성 공학과 규제  (0) 2022.03.07
[ML] 03-2 선형 회귀  (2) 2022.03.06