우당탕탕 개발일지

[혼공머신] 4-2. 확률적 경사 하강법 본문

인공지능

[혼공머신] 4-2. 확률적 경사 하강법

민아당긴아 2025. 1. 14. 10:10

💡 확률적 경사 하강법

ⓒ https://cdn.analyticsvidhya.com/wp-content/uploads/2024/09/631731_P7z2BKhd0R-9uyn9ThDasA.webp

훈련 세트에서 샘플을 하나씩 꺼내 최적의 모델을 찾는 점진적 학습 알고리즘

여기서 점진적 학습이란 새로운 데이터에 대해 조금씩 더 훈련하는 방법이다.

하나씩 샘플을 꺼내서 훈련하며 경사를 내려가는 과정이다.

 

  확률적 경사 하강법 프로세스 

1. 훈련 세트에서 하나의 샘플을 랜덤하게 선택

2. 가파른 경사를 조금 내려간다. 

3. 1, 2 반복하며 전체 샘플을 모두 사용할 때까지 지속 

4. 모든 샘플을 사용했는데도 경사를 다 내려오지 못했다면 훈련 세트에 모든 샘플 다시 채워넣기

 

  에포크

이 반복하는 과정에서 에포크라는 개념이 등장하는데, 에포크(epoch)는 훈련 세트를 한 번 모두 사용하는 과정이다.

ⓒ https://media.geeksforgeeks.org/wp-content/uploads/20241024155237307614/epoch-in-machine-learning_.webp

일반적으로 경사 하강법은 수십, 수백 번 이상의 에포크를 수행한다.

예를 들어 에포크 = 100이라면 훈련 세트를 100번 모두 사용함을 뜻한다.

 

💡 손실 함수

머신러닝 모델의 손실을 측정하는 함수로, 분류 모델에서는 '잘못 분류한 정도'를 측정하는 함수이다.

분류 모델이 이진 분류인지, 다중 분류인지에 따라 사용되는 손실함수가 다르다.

  이진 분류 다중 분류
손실 함수
로지스틱 손실 함수(logistic loss function), 이진 크로스엔트로피 손실 함수(binary cross-entrpy loss function)이라고도 부른다.
크로스엔트로피 손실 함수(cross-entrpy loss function)

이건 그냥 알아두기만 하고, 이 책에서는 이진분류에서 사용되는 로지스틱 손실 함수에 대해 말하고 있다.

 

💡 로지스틱 손실 함수

최종 손실 값이 모두 양수가 되도록 하기 위해 양성 클래스음성 클래스에 다른 함수식을 사용한다.

https://miro.medium.com/v2/resize:fit:783/1*6oBgYMy4wOls9zGC-frSQg.png

위 식에서 h_theta(x)는 예측 확률을 의미한다.

 

💡 SGDClassifier

이렇게 확률적 경사 하강법의 개념에 대해 알아봤다.

파이썬에서는 제공되는 SGDClassifier를 이용해서 간단하게 손실값을 구할 수 있다.

# SGDClassifier 이용해서 확률적 경사 하강법 진행
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))
print(sc.score(test_scaled, test_target))

매개변수를 살펴보면

loss 어떤 종류의 손실 함수를 사용할 것인지를 나타낸다. 로지스틱 손실 함수의 경우 'log_loss'이다.
max_iter 반복 횟수를 의미한다.즉, 에포크(epoch)를 의미한다.
random_state 다음에 해도 랜덤하지만 같은 결과

이것도 다른 LogisticRegression이나 DecisionTree 모델처럼 개체를 부른 다음에 fit해서 학습하고, score로 점수를 보면 된다. 

 

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

ⓒ https://i.sstatic.net/Z2BOz.png

에포크가 작은 경우

- 즉 반복 횟수가 적은 경우, 훈련 세트를 많이 사용하지 않으므로 과소적합 발생

에포크가 큰 경우

- 즉 반복 횟수가 많은 경우, 훈련 세트를 많이 사용하므로 과대적합 발생

조기종료

따라서 에포크 횟수가 커질수록 과대적합이 발생할 가능성이 높아지므로, 과대적합이 시작하지 전에 훈련을 멈추어야 한다. 이것을 조기 종료 라고 한다.

# 데이터셋 준비
import numpy as np

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

train_score = []
test_score = []
classes = np.unique(train_target) # 7개의 물고기 종류

# 300번의 에포크동안 훈련 반복 진행
for _ in range(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))
  
  # 300번의 에포크동안 기록한 훈련 세트와 테스트 세트의 점수를 시각화하기
import matplotlib.pyplot as plt
plt.plot(train_score)
plt.plot(test_score)
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.show() # 100번째 이후 훈련 세트와 테스트 세트의 정확도 차이가 벌어진다. 100번의 에포크가 적절한 반복 횟수로 결론짓는다.

결과를 보면 반복횟수가 100이 적절하다는 결론을 도출할 수 있다.따라서 SGDClassifier의 max_iter 매개변수에 100을 할당하고 다시 훈련한다.

# 100번의 에포크 진행
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))
print(sc.score(test_scaled, test_target))

 

💡 손코딩의 흔적