[Basic] 확률적 경사 하강법

고보·2024년 3월 11일

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

  • 최적화 문제, 특히 대규모 데이터셋에 대한 머신 러닝 모델의 파라미터를 학습할 때 널리 사용되는 방법(머신러닝 알고리즘이 아니라 훈련 방법). 비용 함수의 경사(기울기)를 사용해서 파라미터를 업데이트 하는 방식으로 모델을 최적화.
  • 기본적인 경사 하강법과 비교했을 때, SGD는 매 스텝에서 전체 데이터셋 대신 하나의 샘플(혹은 소수의 샘플)을 무작위로 선택해 그래디언트를 계산.
  • 경사 하강법의 기본 원리: 손실 함수(비용 함수) J의 최솟값을 찾기 위해 사용. 여기서 θ는 모델의 파라미터로, ∇θJ(θ)는 각 파라미터에 대한 비용 함수의 변화율(비용함수의 그래디언트, 기울기))를 나타낸다. η는 학습률(learning rate)로 각 스텝에서 파라미터를 얼마나 조정할지 결정. 경사 하강법은 이 그래디언트를 사용해서 파라미터를 업그레이드.
  • 확률적 경사하강법은, 매 업데이트 시 전체 데이터셋 대신 무작위로 선택한 하나의 샘플(혹은 소수의 샘플)에 대한 그래디언트를 계산. => 한 번의 업데이트에 필요한 계산량이 적어 대규모 데이터셋에 적합.
  • 자세한 이해 더 필요

1-1

  • 데이터 마련: 아래는 기존 과정과 똑같다
fish = pd.read_csv('')

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

#log_loss: 이진 분류 모델을 만듬, 도미는 양성, 나머지는 모두 음성
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))

#partial_fit 기존의 학습했던 것을 가지고 w, b를 업데이트함
sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
  • SGDClassifier: 확률적 경사 하강법을 사용한 선형 분류기.
    • loss는 매개변수에 사용하는 손실 함수를 지정. 손실 함수는 모델의 예측이 실제 레이블과 얼마나 잘 일치하는지 측정하는 지표.
      여기서는 log_loss. 이는 로지스틱 회귀를 위한 손실 함수로, 이진분류, 다중분류(softmax)까지 사용 가능. log_loss는 모델의 예측 확률과 실제 레이블 간의 로그 우도를 최대화 하는 방식으로 작동.
    • max_iter은 최적화 과정에서의 최대 반복 횟수 지정. 모델이 학습 데이터셋에 대해 수행할 에포크(epoch) 수. epoch는 전체 학습 데이터셋을 한 번 통과하는 과정.
    • tol=None: 최적화 과정 중 조기 종료(early stopping)의 기준 설정. 반복 간 손실 감소가 이 값보다 작으면, 더 이상 학습을 중단하고 최적화 종료. 여기서 None이면, 중간에 조기 종료하지 않고, 정해진 횟수만큼 수행 후 멈춤 설정.
  • partial_fit: 점진적 학습을 지원하는 모델에서 사용되는 메서드로, 학습 데이터의 전체 세트를 한 번에 사용하는 대신, 데이터를 작은 배치(batch)로 나누어 모델을 점진적으로 학습. => 메모리에 전체 데이터셋 한 번에 로드할 필요 없으며 점진적 업데이트. 처음부터 다시 학습하지 않고, 이전 학습 단계에서 학습된 모델 파라미터를 기반으로 추가 데이터에 대해 모델을 학습. => 스트리밍 데이터에 적합
    학습을 한다는 것은, 가중치(w, 계수)와 절편(b)를 업데이트한다는 것. 여기서 partial은 이전에 학습한 파라미터 기반으로, 새 데이터에 대해 추가 학습을 수행. 처음부터 하지 않고. => 새로운 데이터 배치에 대한 그래디언트(기울기)를 계산. 이 그래디언트는 모델이 새 데이터에 얼마나 잘 맞지 않는지 나타내고, 모델을 개선하기 위해 가중치를 어떤 방향으로 조정해야 하는지 알려준다. => 계산된 그래디언트로 가중치와 절편을 업데이트. 이때 학습률이라는 매개변수가 업데이트 크기 결정. => 이 업데이트된 파라미터를 적용.
import numpy as np
sc = SGDClassifier(loss= 'log_loss', 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, label='Train Score')
plt.plot(test_score, label='Test Score')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend()
plt.show()

  • epoch(max_iter)를 몇 회 해야 가장 좋은지 찾기.
  • partial_fit을 호출할 때마다, SGDClassifier는 훈련 데이터의 한 배치(이 경우는 전체 데이터셋)을 사용해서 가중치를 업데이트한다. 여기서는 for문을 통해 300번의 epoch(전체 학습 데이터셋을 한 번 통과하는 과정)동안 모델을 업데이트한다.
  • for문으로 300번 돌리나, max_iter=300으로 설정하나, 결과는 같다. 단, max_iter를 사용할거면 partial_fit이 아닌 fit 메서드를 호출하는 거고, for문은 중간 과정을 우리가 알기 위해서 쓴 것.
  • 그래프에서 봤을 때 epoch = 100 언저리가 좋다. 이유는 train_set이 너무 높으면 과대 적합이다. test_set이 너무 낮으면 과소 적합이다. => 따라서 둘의 간극이 좁을수록 좋다.
  • epoch가 너무 크면 계산이 오래 걸린다.
sc = SGDClassifier(loss = 'log_loss', max_iter = 100, random_state = 42, tol=None)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))

sc = SGDClassifier(loss = 'hinge', max_iter = 100, random_state = 42, tol=None)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
  • 찾은 epoch 100으로 2가지 손실 함수를 이용해서 비교. 이 경우 log_loss가 더 성능이 좋다.
  • hinge는 손실 함수로 힌지 손실(Hinge loss)를 지정. 힌지 손실은 주로 SVM 분류에서 사용되는 손실 함수.
  • 힌지 손실은 클래스 사이의 마진을 최대화해서, 모델이 더 일반화 성능이 좋게 만든다.
  • 기본적으로 Hinge loss는 이진 분류 문제에 적합하고, 다중 클래스 분류를 위해서는 다중 클래스 힌지 손실(Multi-class Hinge Loss)를 사용.
profile
일본에서 일하는 게임 기획자. 시시해서 죽어버리지 않게, 재밌고 의미 있는 컨텐츠에 관심 있습니다. 그 도구로 데이터, AI도 찝적댑니다.

0개의 댓글