My Data Story

[회귀] 선형 회귀 모델 훈련 본문

Machine Learning/2. 지도 학습 알고리즘

[회귀] 선형 회귀 모델 훈련

Hwasss 2021. 8. 6. 09:33
728x90

◈  '회귀' 목차 

1. 선형 회귀 개념

2. 선형 회귀 모델 훈련

     선형 회귀 모델의 회귀 계수 추정 원리를 알아보고, Jupyter 통해 선형 회귀 모델 훈련시키는 방법에 대해 살펴보자.

3. 선형 회귀 모델 평가 및 모델 선택

4. 선형 회귀로 새로운 데이터 예측

5. 선형 회귀 모델 해석

6. 선형 회귀 가설 검정 : 회귀 진단

7. 비선형 회귀 - 다항 회귀, 스플라인 회귀

8. 규제가 있는 선형 회귀


1. 선형 회귀 모델 훈련시키기

모델을 훈련시킨다는 것은 모델이 훈련 데이터에 가장 잘 맞도록 모델 파라미터를 구하는 것이다.

즉 모델을 훈련시키는 것은 선형 회귀 모델의 각 특성에 대한 회귀 계수와 편향(상수) 을 추정하는 것이다.

1.1 선형 회귀 계수 추정 원리

선형 회귀 계수를 어떻게 구할까?

모든 데이터가 정확히 선형 회귀 모델 위(한 직선 위)에 존재하지 않기에 실제값과 예측값 사이에 잔차가 존재한다.

 

 

< 잔차 = 실제값 - 예측값 >

 

 

잔차들을 제곱한 값들의 합인 잔차제곱합을 최소화하도록 선형 회귀 계수를 추정한다.

이는 각 특성의 계수에 대한 잔차제곱합의 편미분을하면 구할 수 있다. 

 

 

< 선형 회귀 모델 회귀 계수 추정 >

 

 

1.2 선형 회귀 계수 구하기

(1) 정규 방정식 활용

선형 회귀 계수 추정하는 원리 바탕으로 정규 방정식을  컴퓨터(Jupyter)에서 계산할 수 있는 방법은 3가지 있다. 

 

[방법1] 비용 함수를 최소화하는 가중치를 찾기 위한 해석적인 방법이다. 

theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)

 

 

[방법2] 사이킷런에서 특잇값 분해 SVD 를 활용하여 구할 수도 있다. 

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
theta_best_svd, residuals, rank, s = np.linalg.lstq(X_b, y, rcond=le-6)

 

 

[방법3] 유사역행렬 X+ 직접 구해서 최적의 세타 구하기 

theta_best = np.linalg.pinv(X_b).dot(y)

 

 

계산 복잡도

정규 방정식과 SVD 방법 모두 특성수가 많아지면 (ex. 100000) 매우 느려진다. 

다행히 훈련 세트의 샘플 수에 대해서 선형적으로 증가한다. 

따라서 메모리 공간이 허락된다면 큰 훈련세트도 효율적으로 처리할 수 있다.

 

(2) 경사 하강법 활용

위에서 설명한 것 처럼 회귀 계수 추정하는 정규 방정식을 컴퓨터(Jupyter)에서 계산하면 좋겠지만,

특성 수가 많아지면 매우 느려져 비효율적이다.

대신, 경사 하강법 알고리즘을 활용하여 모델 파라미터를 계산할 수 있다.

 

경사 하강법 Gradient Descent 는 선형 회귀 모델 뿐 아니라

여러 종류의 문제에서 최적의 해법을 찾을 수 있는 일반적인 최적화 알고리즘이다. 

 

경사 하강법의 아이디어는 비용함수를 최소화하기 위해 반복적으로 파라미터를 조정해 나가는 것이다. 

즉 gradient 가 감소하는 방향으로 진행하고 gradient = 0 이 되면 최솟값에 도달한 것이다. 

 

경사 하강법에서 중요한 파라미터는 스텝의 크기로 학습률 learning rate 이다. 

학습률이 작으면 알고리즘이 수렴하기 위해 오랜 시간 소요되고 학습률이 크면 더 큰 값으로 발산할 수 있는 리스크가 있다. 

 

 

 

 

 

이때 비용 함수가 패인 곳, 산마루, 평지 등 특이한 지형이 있으면 최솟값으로 수렴하기 어렵다. 

즉 전역 최솟값보다 지역 최솟값에 가까울 경우 잘못 수렴할 수 있는 문제가 존재한다.

 

하지만 선형 회귀의 비용함수 MSE는 볼록함수라, 지역 최솟값이 없고 전역 최솟값만 존재하여 문제 없다. 

 

 

Gradient Descent 사용 시 반드시 모든 특성이 같은 스케일을 갖도록 만들어야 한다. 

스케일 조정 안 하면 수렴하는 데 훨씬 오랜 시간이 소요된다. 

 

 

 

<특성 스케일 적용 여부에 따른 경사하강법>

 

 

경사 하강법은 배치 경사 하강법, 확률적 경사 하강법, 미니 배치 경사 하강법 3가지가 있다. 

 

1) 배치 경사 하강법

경사 하강법을 구하려면 각 모델 파라미터에 대한 비용 함수의 gradient 를 계산해야 한다. 

즉 각 모델 파라미터가 조금 변경될 때 비용함수가 얼마나 바뀌는 지 계산한다. 

 

각 모델 파라미터에 대한 편도 함수는 다음과 같다.

 

 

<비용함수의 편도함수>

 

 

위 편도함수를 각각 계산하는 대신,

각 모델 파라미터에 대한 비용함수의 편도함수를 모두 담으면 그레이디언트 벡터로 표현할 수 있다. 

 

 

<비용 함수의 그레이디언트 벡터>

 

 

위 공식은 매 경사 하강법 스텝에서 전체 훈련 세트 X에 대해 계산한다. 

그래서 매우 큰 훈련 세트에서는 느릴 수 있다.

 

하지만 경사하강법은 특성 수에 민감하지 않기 때문에

수십만 개의 특성에서 선형회귀를 훈련시킬 경우 정규방정식이나 SVD 분해보다 경사 하강법이 훨씬 빠를 것이다. 

 

 

그레이디언트 벡터가 구해지면, 학습률에 따라 모델의 파라미터는 다음과 같이 결정된다. 

 

 

<경사 하강법의 스텝>

 

 

아까도 언급했듯이, 경사 하강법에서는 학습률이 중요하다.  

적절한 학습률을 찾기 위해 Grid Search 를 진행한다.

 

하지만 Grid Search 에서 수렴하는 데 너무 오래 걸리는 모델을 막기 위해 반복 횟수를 제한해야 한다. 

 

일단 반복 횟수를 아주 크게 지정하고 벡터의 노름이 허용오차보다 작아지면 

경사 하강법이 최솟값에 도달했다 판단하고 알고리즘을 중단한다. 

 

cf. 더 정확한 최솟값을 구하기 위해 허용 오차를 1/10 줄이면 알고리즘의 반복은 10배 늘어날 것이다. 

 

2) 확률적 경사 하강법 SGD

매 스텝에서 한 개의 샘플을 무작위로 선택하고 그 하나의 샘플에 대한 gradient를 계산한다. 

 

매 반복에서 다뤄야 하는 데이터가 매우 적기 때문에

훨씬 빠르고 하나의 샘플만 메모리에 있으면 되므로 매우 큰 훈련 세트도 훈련 가능하다. 

 

확률적 경사 하강법은 외부 메모리 학습 알고리즘 으로 구현 가능하다. 

 

cf. 외부 메모리 학습

더보기

컴퓨터 한 대의 메인 메모리에 들어갈 수 없는 아주 큰 데이터 셋을 학습하는 시스템에도 온라인 학습 알고리즘을 사용할 수 있다. 알고리즘이 데이터 일부를 읽어 들이고 훈련 단계를 수행한 후 전체 데이터가 모두 적용될 때까지 이 과정을 반복한다. 이를 외부 메모리 학습이라고 한다. 외부메모리 학습은 보통 오프라인으로 실행된다. (실시간 시스템에서 수행되는 것이 아님) 

 

 

반면 확률적(무작위적) 이기 때문에 훨씬 불안정하고 불규칙적이다. 

비용 함수가 최솟값에 다를 때까지 위아래로 요동을 치면서 평균적으로 감소한다. 

시간이 지나면 최솟값에 매우 근접하겠지만, 계속 요동치면 최솟값에 도달하지 못한다.

 

하지만 비용 함수가 불규칙해 알고리즘이 지역 최솟값을 건너 뛰도록 도와주기도 한다.

배치 경사 하강법보다 전역 최솟값을 찾을 가능성이 더 높다. 

 

 

 

 

무작위성은 지역 최솟값을 탈출시켜주지만 전역 최솟값에 도달하지 못하게 하기도 한다.

이를 해결하기 위해서 시작할 때 학습률을 크게 하여 수렴을 빠르게 하고 지역 최솟값에 빠지지 않도록 한 후, 

점진적으로 학습률을 감소시켜 전역 최솟값에 도달하도록 한다. 

 

 

확률적 경사 하강법의 진행과정을 정리하면 다음과 같다. 

step1. 모델의 파라미터 초기화 

           - 임의로 하나 선정

step2. 에포크 시작

           a. 훈련 데이터 섞기

           b. 훈련 세트에서 샘플 하나 추출 (비복원 랜덤)

           c. 경사 하강법 진행

           d. 모델 파라미터 수정

           e. 모든 훈련 데이터가 뽑힐 때까지 a-d과정 반복

           f. 훈련 데이터 수 만큼 반복 후 에포크 종료 

 

 

위 내용대로 확률적 경사 하강법 직접 구현하면 다음과 같다.

 

# 전체 샘플을 모두 사용하는 걸 50번 반복
n_epochs = 50 
# 학습 스케쥴 파라미터
t0, t1 = 5, 50

# 학습할 수록 learning rate 줄이도록 정의
def learning_schedule(t) : 
    return t0 / (t + t1) 

# 모델 파라미터 무작위 초기화
theta = np.random.randn(2,1)

for epoch in range(n_epochs) : 
    for i in range(m) : #m:전체샘플수
        random_index = np.random.randint(m) #복원 추출 샘플링으로 설계되어 있지만,
                                            #SGDRegressor/SGDClassifier는 비복원 랜덤추출
        xi = X_b[random_index:random_index+1]
        yi = y[random_index:random_index+1]
        gradients = 2 * xi.T.dot(xi.dot(theta) - yi)
        eta = learning_schedule(epcoh * m + i)
        theta = theta - eta*gradients

 

 

사이킷런에서 SGD 방식으로 선형회귀 사용하면 다음과 같다. 

 

from sklearn.linear_model import SGDRegressor

#max_iter : epoch횟수
#tol : 줄어드는 손실값이 tol 이하이면 stop 
#penalty : 규제 ex. 라소, 릿지
#eta0 : 학습률로 SGDRegressor 는 invsacling, SGDClassifier 는 optimal 방식을 default로 지정

sgd_reg = SGDRegressor(max_iter=1000, tol=1e-3, penalty=None, eta0=0.1)
sgd_reg.fit(X, y)
print(sgd_reg.intercept_, sgd_reg,coef_)

 

 

Tip!

SGD 사용할 때 훈련 샘플은 IID Independent Identical Distributed 를 만족해야 평균적으로 파라미터가 전역 최적점을 향해 진행한다고 보장할 수 있다. IID를 만족하도록 하는 방법은 각 샘플을 랜덤하게 선택하거나 에포크 시작할 때 훈련 세트를 섞는 것이다. 

 

 

3) 미니배치 경사 하강법

임의이 작은 샘플 세트에 대해 gradient 계산한다.

미니배치 경사 하강법이 SGD보다 최솟값에 더 가까이 도달하지만 지역 최솟값에서 빠져나오기는 더 힘들지도 모른다.

for epoch in range(n_iterations) :
    shuffled_indicies = np.random.permutation(m) #비복원랜덤샘플링으로 m개 추출
    X_b_shuffled = X_b[shuffled_indicies]
    y_shuffled = y[shuffled_indicies]
    for i in range(0, m, min_batch_size) :
        xi = X_b_shuffled[i, i + min_batch_size]
        yi = y_shuffled[i, i + min_batch_size]
        ....

 

 

 

※ 선형 회귀를 구현한 알고리즘 비교

알고리즘 m n 하이퍼파라미터 수 스케일 조정 필요 외부메모리 학습지원 사이킷런
정규방정식 빠름 느림 0 No No N/A
SVD 빠름 느림 0 No No LinearRegression
배치 경사 하강법 느림 빠름 2 Yes No SGDRegressor
확률적 경사 하강법 빠름 빠름 >=2 Yes Yes SGDRegressor
미니배치 경사 하강법 빠름 빠름 >=2 Yes Yes SGDRegressor