본문 바로가기
Computer Science/Machine Learning

Linear Regression (구현)

by BaekDaBang 2024. 6. 11.

1. 회귀 계수 결정법 (Direct Solution)

선형회귀에서 주로 사용하는 Mean Squared Error(MSE) 손실 함수를 사용하면 아래로 볼록한(Convex) 형태의 손실함수를 가짐
$$
\begin{aligned}
&\\
L(\beta) & = \left\|\hat{y}-y \right\|_{2}^{2}\\
& = \left\|\beta X-y \right\|_{2}^{2}\\
& = (\beta X-y)^{\rm T}(\beta X-y)\\
& = \beta^{\rm T}X^{\rm T}X\beta-\beta^{\rm T}X^{\rm T}y-y^{\rm T}X\beta+y^{\rm T}y \\
\end{aligned}$$

아래로 볼록한(Convex) 형태의 손실함수의 최소값은 미분이 0이 되는 지점($\nabla_{\beta} L(\beta)=0$)을 통해 명시적인 해를 구할 수 있음
$$
\begin{aligned}
&\\
\nabla_{\beta} L(\beta)& =X^{\rm T}X\beta+X^{\rm T}X\beta-2X^{\rm T}y=0\\
& \Rightarrow  2X^{\rm T}X\beta=2X^{\rm T}y\\
& \Rightarrow  X^{\rm T}X\beta=X^{\rm T}y\\
\end{aligned}$$

$$\therefore \beta=(X^{\rm T}X)^{-1}X^{\rm T}y$$

beta_direct = np.linalg.inv(Xb.T.dot(Xb)).dot(Xb.T).dot(y)  # 위의 수식을 참고하여 최적의 beta를 찾아보세요
preds = Xb_new.dot(beta_direct)  # 찾은 최적의 beta를 가지고 X_new에 대한 y값을 예측 해보세요

 

2. 회귀 계수 결정법 (Numerical Search)

경사하강법(gradient descent)와 같은 반복적인 방식으로 선형회귀 계수를 구할 수 있음
경사(gradient)란? "임의의 지점에서 함수의 최대 증가 방향"을 의미

$$ \text{경사(gradient)} ⇒ \nabla_{\beta}L(\beta)=[\frac{\partial L(\beta)}{\partial \beta_{0}},\cdots ,\frac{\partial L(\beta)}{\partial \beta_{k}}]\in R^{k+1}$$
결국 경사하강법은 최대 증가의 반대 방향인 최대 감소의 방향으로 회귀 계수를 업데이트 하겠다는 것
$$ \text{경사하강법(gradient descent)} ⇒ \beta^{(t+1)}=\beta^{(t)}-\eta \nabla_{\beta}L(\beta)$$

 

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

파라미터를 업데이트 할 때, 무작위로 샘플링된 학습 데이터를 하나씩만 이용하여 cost function의 gradient를 계산
모델을 자주 업데이트 하며, 성능 개선 정도를 빠르게 확인 가능
Local minima에 빠질 가능성을 줄일 수 있음
$$\nabla_{\beta} L(\beta) = 2 x_{i}(x_{i}^{\rm T}\beta- y) \; : \; \text{gradient}$$
$$\beta^{(t+1)}⇐\beta^{(t)}-\eta \nabla_{\beta}L(\beta) \; : \; \text{update rule}$$

 

beta_sgd_path = []
n_epochs = 50
t0, t1 = 5, 50  # 학습 스케줄 하이퍼파라미터 
n = 100         # 샘플 수 

def learning_schedule(t):
    return t0/(t+t1)

beta_sgd = np.random.randn(2,1)  # beta 무작위 초기화 

####### Empty Module.3 #########
# Stochastic Gradient Descent를 통해서 최적의 Beta를 찾아보세요
for epoch in range(n_epochs):
    for i in range(n):
        eta = learning_schedule(epoch * n + i)

        random_idx = np.random.randint(n)               # 0 ~ n-1 까지 랜덤하게 인덱스 선택
        tx = Xb[random_idx:random_idx+1]                # random_idx를 활용해 샘플 하나 선택
        ty = y[random_idx:random_idx+1]                 # random_idx를 활용해 샘플 하나 선택
        gradients = 2 * tx.T.dot(tx.dot(beta_sgd) - ty) # 확률적 경사 하강법에 해당하는 gradient를 계산하세요 
        beta_sgd = beta_sgd - eta * gradients           # update rule에 따라서 beta_sgd를 update 하세요
        
        beta_sgd_path.append(beta_sgd)
preds = Xb_new.dot(beta_sgd)    # 얻은 회귀 계수를 가지고 X_new에 대해서 y값을 예측하세요
##############################

 

2) 미니 배치 경사 하강법(Mini Batch Gradient Descent)

파라미터를 업데이트 할 때마다 일정량의 일부 데이터를 무작위로 뽑아 cost function의 gradient를 계산
Batch Gradient Descent와 Stochastic Gradient Descent 개념의 혼합
SGD의 노이즈를 줄이면서, GD의 전체 배치보다 효율적
$$\nabla_{\beta}L(\beta)=\frac{2}{m}\sum_{i=1}^{m} x_{i}(x_{i}^{\rm T}\beta-y) \; : \; \text{gradient}$$
$$\beta^{(t+1)}⇐\beta^{(t)}-\eta \nabla_{\beta}L(\beta) \; : \; \text{update rule}$$

 

beta_mgd_path = []

n_epochs = 50
minibatch_size = 20

np.random.seed(42)
beta_mgd = np.random.randn(2,1)  # 랜덤 초기화

t0, t1 = 200, 1000
def learning_schedule(t):
    return t0 / (t + t1)

t = 0

####### Empty Module.4 #########
# Mini Batch Gradient Descent를 통해서 최적의 Beta를 찾아보세요.
for epoch in range(n_epochs):
    shuffled_indices = np.random.permutation(n)
    Xb_shuffled = Xb[shuffled_indices]
    y_shuffled = y[shuffled_indices]
    for i in range(0, n, minibatch_size):
        t += 1
        eta = learning_schedule(t)

        tx = Xb_shuffled[i:i+minibatch_size]                            # minibatch_size를 활용해 batch 단위로 샘플링
        ty = y_shuffled[i:i+minibatch_size]                             # minibatch_size를 활용해 batch 단위로 샘플링
        gradients = 2/minibatch_size * tx.T.dot(tx.dot(beta_mgd) - ty)  # 미니 배치 경사 하강법에 해당하는 gradient를 계산하세요 
        beta_mgd = beta_mgd - eta * gradients                           # update rule에 따라서 beta_mgd를 update 하세요
        
        beta_mgd_path.append(beta_mgd)

preds = Xb_new.dot(beta_mgd)    # 얻은 회귀 계수를 가지고 X_new에 대해서 y값을 예측하세요
##############################