def get_cost(y, y_pred):
N = len(y)
cost = np.sum(np.square(y - y_pred))/N
return cost
def get_weight_updates(w1, w0, X, y, learning_rate=0.01):
N = len(y)
w1_update = np.zeros_like(w1)
w0_update = np.zeros_like(w0)
y_pred = np.dot(X, w1.T) + w0
diff = y - y_pred
w0_factors = np.ones((N, 1))
w1_update = -(2/N)*learning_rate*(np.dot(X.T, diff))
w0_update = -(2/N)*learning_rate*(np.dot(w0_factors.T, diff))
return w1_update, w0_update
def gradient_descent_steps(X, y, iters=10000):
w0 = np.zeros((1, 1))
w1 = np.zeros((1, 1))
for ind in range(iters):
w1_update, w0_update = get_weight_updates(w1, w0, X, y, learning_rate=0.01)
w1 = w1 - w1_update
w0 = w0 - w0_update
return w1, w0
w1, w0 = gradient_descent_steps(X, y, iters=1000)
print('w1:{:.3f} w0:{:.3f}'.format(w1[0, 0], w0[0,0]))
y_pred = w1[0, 0] * X + w0
print('Gradient Descent Total Cost:{:.4f}'.format(get_cost(y,y_pred)))
이 코드는 Gradient Descent 알고리즘을 사용해 선형 회귀 모델의 파라미터인 가중치 (w1)와 절편 (w0)을 업데이트하고, 그 과정에서 비용 함수 (Cost Function)를 계산하는 방식으로 동작한다.
각 함수의 역할을 살펴보자.
1. get_cost(y, y_pred)
- 주어진 실제 값 y와 예측 값 y_pred 간의 차이를 제곱한 후 평균을 구해서 평균 제곱 오차 (MSE, Mean Squared Error)를 계산한다.

- 여기서 N은 데이터의 개수이다.
2. get_weight_updates(w1, w0, X, y, learning_rate=0.01)
- 주어진 데이터 X와 y를 사용하여 모델의 가중치 w1과 절편 w0에 대한 기울기(Gradient)를 계산하고, 그에 따라 가중치 업데이트 값을 반환한다.
- 기울기 계산:
1) 먼저 예측값 y_pred를 계산한다.

2) 실제 값 y와 예측 값 y_pred의 차이를 diff로 구한다.

3) 가중치 w1과 절편 w0에 대한 기울기를 계산한다.


-
- w1의 업데이트 값은 X와 diff의 곱에 비례한다.
- w0의 업데이트 값은 diff의 합에 비례한다.
3. gradient_descent_steps(X, y, iters=1000)
- 주어진 데이터를 기반으로 가중치 w1와 절편 w0을 경사 하강법을 사용하여 반복적으로 업데이트한다.
- 구체적인 흐름:
- w1, w0을 0으로 초기화한다.
- 주어진 반복 횟수 (iters)만큼 다음을 반복한다:
- get_weight_updates를 호출하여 w1, w0의 기울기 업데이트 값을 계산한다.
- 계산된 기울기를 사용하여 w1, w0를 업데이트한다.
- 업데이트된 값으로 새로운 y_pred를 계산하고, 비용 함수를 업데이트한다.
- 반복이 끝나면 업데이트된 w1과 w0을 반환한다.
코드 흐름 분석
1. w1, w0의 초기화
처음에 w1과 w0은 np.zeros로 초기화된다. 이 값들이 모두 0으로 시작하는 것이 중요하다.
경사 하강법은 초기값이 무엇이든 기울기 계산을 통해 점진적으로 w1과 w0을 업데이트하여 최적화해나가기 때문이다.
- w1 = np.zeros((1, 1))
- w0 = np.zeros((1, 1))
이 상태에서 예측값 y_pred는 0으로 시작한다.
y_pred = np.dot(X, w1.T) + w0에서 w1과 w0이 모두 0이기 때문이다.
2. 첫 번째 비용 함수 계산 (get_cost)
- y_pred = 0일 때, 실제 값 y와의 차이(diff = y - y_pred)는 단순히 y와 동일해진다.
- 비용 함수는 **평균 제곱 오차 (MSE)**로 계산되며, diff가 y와 같으므로 비용은 상대적으로 큰 값이 된다.
즉, 첫 번째 반복에서 비용은 y와 0의 차이에 의한 큰 값이 나오게 된다.
3. 첫 번째 기울기 업데이트 (get_weight_updates)
- 예측값이 0이었기 때문에, diff = y - y_pred는 y다.
- 그에 따라 w1_update와 w0_update가 계산된다:
- w1_update = -(2 / N) * learning_rate * np.dot(X.T, diff)
- w0_update = -(2 / N) * learning_rate * np.dot(w0_factors.T, diff)
- 업데이트가 이루어짐: w1_update는 X.T와 diff의 내적을 계산하여 가중치에 대한 기울기를 구하고, w0_update는 diff의 합을 사용하여 절편에 대한 기울기를 구한다.
4. 첫 번째 업데이트 후 가중치 값
- 첫 번째 업데이트에서 w1과 w0는 0에서 작은 값으로 이동한다. w1은 X와 y의 관계에 맞춰 변화하고, w0는 y와 예측값의 차이를 보정하는 값으로 업데이트 된다.
- 이 과정이 첫 번째 반복에서 이루어진다. 결과적으로 가중치 값은 0에서 점차적으로 변하고, 예측값도 점차적으로 실제 값에 가까워진다.
5. 반복 과정에서 점진적인 학습
- gradient_descent_steps 함수에서 **반복(iterations)**이 계속 진행되면서, 매번 w1과 w0가 기울기에 따라 업데이트된다.
- w1과 w0이 점차적으로 실제 데이터의 관계를 반영하는 값으로 수렴하게 된다. 경사 하강법은 각 반복에서 비용 함수 (MSE)를 줄여가며 최적의 가중치 w1과 w0을 찾는다.
6. 최종적으로 w1, w0 수렴
- 반복을 거치면서 w1과 w0은 점차 최적값에 가까워진다.
- 비용 함수(get_cost)는 각 반복마다 감소하고, 최종적으로는 w1과 w0이 모델의 실제 가중치와 절편 값에 근접하게 된다.
예를 들어, w1과 w0가 w1: 2.5, w0: 1.0으로 수렴한다고 할 때, 이 값은 최적의 선형 회귀 모델에 해당한다.
7. get_cost 최종 출력
- y_pred = np.dot(X, w1.T) + w0로 최종 예측값을 계산한 후, get_cost(y, y_pred)는 예측값과 실제 값의 차이를 평균 제곱 오차로 계산한다.
- 이때, get_cost의 값은 초기 값이 0에서 시작하여 점차 감소하며, 학습이 잘 진행되었음을 나타낸다.
- 초기화: w1과 w0이 0으로 초기화된 상태에서 경사 하강법을 시작한다.
- 첫 번째 예측: 예측값 y_pred는 0이고, 비용 함수는 y와의 차이에 의해 큰 값이 나온다.
- 첫 번째 업데이트: w1과 w0은 X와 y의 관계에 따라 기울기를 계산하여 점진적으로 업데이트된다.
- 반복: 경사 하강법은 여러 반복을 거쳐 w1과 w0을 업데이트하며, 비용 함수는 감소하고, 예측값은 실제 값에 가까워진다.
- 최종 모델: w1과 w0는 학습을 통해 최적화되어, 실제 값에 가까운 선형 모델을 나타낸다.
이 과정이 제대로 수행되기 때문에, w1과 w0는 정상적인 값으로 수렴하며, 비용 함수도 감소하게 된다.
처음에 w1과 w0이 0이었음에도 불구하고, 경사 하강법이 반복을 거치며 제대로 최적화되는 이유는 기울기 계산을 통해 점진적으로 최적의 파라미터로 수렴하기 때문이다.
'데이터 사이언스 공부' 카테고리의 다른 글
| 00. [논문 번역] Attention is All You Need (1) (0) | 2025.04.07 |
|---|---|
| 00. np.log와 np.log1p의 차이 (0) | 2024.11.14 |
| 00. GBM 결정트리의 분할 (0) | 2024.11.12 |
| 00. LightGBM, XGBoost에서의 eval_set 파라미터 (0) | 2024.11.11 |
| 00. cross_val_score가 사용하는 KFold 방식 (0) | 2024.11.10 |