본문 바로가기
Machine Learning

[혼자 공부하는 머신러닝+딥러닝] 확률적 경사 하강법

by 가론노미 2023. 5. 2.
[혼자 공부하는 머신러닝+딥러닝] 책의 내용을 정리한 글입니다.

개념

훈련한 모델을 버리지 않고 새로운 데이터에 대해서만 조금씩 더 훈련할 수는 없을까?

→ 이런 식의 훈련방식을 점진적 학습 또는 온라인 학습이라고 부른다.

확률적 경사 하강법

: 대표적인 점진적 학습 알고리즘으로, 훈련 세트에서 랜덤하게 하나의 샘플을 골라 손실 함수의 경사를 따라 최적의 모델을 찾는다.

 

  • 무작위로 선택하는 샘플의 개수를 여러 개 사용하는 경우 미니배치 경사 하강법이라고 한다.
  • 한 번에 전체 샘플을 사용하는 경우 배치 경사 하강법이라고 한다.
  • 확률적 경사 하강법에서 훈련 세트를 한 번 모두 사용하는 과정을 에포크라고 부르며, 일반적으로 수십에서 수백 번의 에포크를 반복한다.

 

확률적 경사 하강법에서 말하는 손실 함수란 무엇일까?

손실 함수

: 확률적 경사 하강법이 최적화할 대상이며, 어떤 문제에서 머신러닝 알고리즘이 얼마나 엉터리인지를 측정하는 기준이다.

 

  • 얼마나 안 좋은지를 측정하는 값이기에 손실함수의 값이 작을수록 좋다.
  • 어떤 값이 최솟값인지는 알지 못한다.
  • 손실 함수는 미분 가능해야 한다.

손실 함수의 종류

 

  • 로지스틱 손실 함수
    • 이진 분류에서 사용하는 손실 함수로, 이진 크로스엔트로피 손실 함수라고도 부른다.
    • 이 손실 함수를 사용하면 로지스틱 회귀 모델이 만들어진다.
    • 타깃 = 1일 때 -log(예측확률)
      • 예측 확률이 1에서 멀어질수록 손실은 아주 큰 양수가 된다.
    • 타깃 = 0일 때 -log(1-예측 확률)
      • 예측 확률이 0에서 멀어질 수록 손실은 아주 큰 양수가 된다.
  • 크로스엔트로피 손실 함수
    • 다중 분류에서 사용하는 손실 함수
  • 평균 제곱 오차
    • 회귀에서 사용하는 손실 함수
    • 타깃에서 예측을 뺀 값을 제곱한 다음 모든 샘플에 평균한 값

코드 작성

확률적 경사 하강법을 사용해 점진적으로 학습하는 로지스틱 회귀 모델을 훈련해 보자.

데이터 준비

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

train_input, test_input, train_target, test_target = train_test_split(
    fish_input, fish_target, random_state=42)
    
# 표준화 전처리
from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)

 

확률적 경사 하강법을 사용한 로지스틱 회귀 모델 훈련

from sklearn.linear_model import SGDClassifier

# 에포크 횟수 10회로 지정
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

# partial_fit()를 사용해 1 에포크 이어서 훈련 진행 후 점수 확인
sc.partial_fit(train_scaled, train_target)

print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
# => 0.8151260504201681
# => 0.85

에포크 횟수에 따라 과소적합이나 과대적합이 될 수 있기 때문에 가장 적합한 에포크 횟수 찾기

import numpy as np

sc = SGDClassifier(loss='log', random_state=42)

train_score = []
test_score = []

classes = np.unique(train_target)

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))
    
import matplotlib.pyplot as plt

plt.plot(train_score)
plt.plot(test_score)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()

에포크 횟수에 따른 훈련 세트(파랑)와 테스트 세트(주황) 점수

과대적합이 시작되기 직전 횟수인 100이 가장 적절한 반복 횟수로 판단하고 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))
# => 0.957983193277311
# => 0.925

 

이 장에서 사용된 핵심 패키지와 함수

scikit-learn

  • SGDClassfier
    • 확률적 경사 하강법을 사용한 분류 모델을 만든다.
    • loss - 최적화할 손실 함수를 지정, 기본값은 hinge(서포트 벡터 머신 알고리즘을 위한 손실 함수)
    • penalty - 규제의 종류를 지정, 기본값은 L2 규제를 위한 l2이며 규제 강도는 alpha 매개변수에서 지정
    • max_iter - 에포크 횟수를 지정, 기본값은 1000
    • tol - 반복을 멈출 조건으로 n_iter_no_change 매개변수에서 지정한 에포크 동안 손실이 tol만큼 줄어들지 않으면 알고리즘이 중단, 기본값은 0.001이며 n_iter_no_change 기본값은 5
  • SGDRegressor
    • 확률적 경사 하강법을 사용한 회귀 모델
    • loss - 최적화할 손실 함수를 지정, 기본값은 제곱 오차를 나타내는 squared_loss