AI

[혼자 공부하는 머신러닝+딮러닝] 다양한 분류 알고리즘 - 확률적 경사 하강법

래모 2023. 10. 29. 20:14

확률적 경사 하강법 (Stochastic Gradient Descent)

훈련한 모델을 버리지 않고 새로운 데이터에 대해서 조금씩 훈련하는 방식을 점진적 학습 또는 온라인 학습이라고 부른다.

대표적인 점진적 학습 알고리즘이 SGD이다.

 

확률적 경사 하강법에서 확률적이란 말은 '무작위하게' 혹은 '랜덤하게'의 기술적인 표현이다

그다음 경사는 기울기를 말하고 하강법은 내려가는 방법을 말한다.

 

전체 샘플을 사용하지 않고 딱 하나의 샘플을 훈련 세트에서 랜덤하게 골라 가장 가파른 길을 찾는 것이 바로 SGD이다.

더 자세히 설명하자면 SGD는 훈련 세트에서 랜덤하게 하나의 샘플을 선택하여 가파른 경사를 조금씩 내려간다.

그 다음 훈련 세트에서 랜덤하게 또 다른 샘플을 하나 선택하여 경사를 조금 내려간다

이런 식으로 전체 샘플을 모두 사용할 때 까지 계속한다.

 

모든 샘플을 다 사용했는데도 산을 내려오지 못 하면 ? => 첨부터 다시 시작!

훈련 세트에 모든 샘플을 다시 채워 넣은 후 다시 랜덤하게 샘플을 선택해 이어서 경사를 내려간다. 이렇게 만족할만한 위치에 도달할 때까지 계속 내려가면 된다.

SGD에서 훈련 세트를 한 번 모두 사용하는 과정을 에포크(epoch)라고 한다.

 

여러개의 샘플을 사용해 경사하강법을 수행하는 방식  = 미니배치 경사 하강법

극단적으로 한번 경사로를 따라 이동하기 위해 전체 샘플을 사용하는 방법 = 배치 경사 하강법

 

 

SGDClassifier

사이킷런에서 확률적 경사 하강법을 제공하는 대포적인 분류용 클래스이다

SGDClassifier의 객체를 만들 때 2개의 매개변수를 지정한다

loss는 손실 함수의 종류를 지정한다

max_iter은 수행할 에포크 횟수를 지정한다

from sklearn.linear_model import SGDClassifier

sc = SGDClassifier(loss='log_loss', max_iter=10, random_state=42)
sc.fit(train_scaled, train_target)

print(sc.score(train_scaled, train_target)) # 0.8151260504201681
print(sc.score(test_scaled, test_target)) # 0.8

 

에포크 수가 낮아서 정확도가 둘다 낮은걸 확인할 수 있다.

 

모델을 이어서 훈련할 때는 partial_fit() 메서드를 사용한다.

이 메서드는 fit메서드와 사용법이 같지만 호출할 때마다 1에포크씩 이어서 훈련할 수 있다.

 

sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target)) # 0.8487394957983193
print(sc.score(test_scaled, test_target)) # 0.9

몇번 하니까 살작 올라갔다

 

에포크의 과대/과소적합

위 그래프는 에포크가 진행됨에 따라 모델의 정확도를 나타낸 것이다

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

바로 이 지점이 모델이 과적합되기 시작하는 곳이다

과대적합이 시작하기 전에 훈련을 멈추는 것을 조기 종료 라고 한다.

 

300번의 에포크 동안 훈련을 반복하여 진행해보겠다

import numpy as np

sc = SGDClassifier(loss="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))

 

이 결과를 그래프로 그려보자

테이터가 작기 때문에 잘 들어나진 않지만 백번째 에포크 이후에는 훈련 세트와 테스트 세트의 점수가 조금씩 벌어지고 있다

이 모델의 경우 백 번째 에포크가 적절한 반복 횟수로 보인다.

 

from sklearn.linear_model import SGDClassifier

sc = SGDClassifier(loss='log_loss', max_iter=100,tol = None, random_state=42)
sc.fit(train_scaled, train_target)

print(sc.score(train_scaled, train_target)) # 0.957983193277311
print(sc.score(test_scaled, test_target)) # 0.925