핸즈온 머신러닝[4] 모델 훈련(1)
https://www.youtube.com/watch?v=6omvN1nuZMc&list=PLJN246lAkhQjX3LOdLVnfdFaCbGouEBeb&index=13
선형회귀
MSE를 최소화하는 모델 파라미터를 찾는다.
행렬 곱셈: [θ0,θ1,..,θn][x0,x1,...,xn]^(T)
선형 회귀 계산 방식1: 정규 방정식
import numpy as np
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
rand 함수로 0과 1 사이의 난수를 발생, 100x1 행렬이 생긴다.
randn -> 표준 분포 난수
plt.plot(X, y, "b.")
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.axis([0, 2, 0, 15])
save_fig("generated_data_plot")
plt.show()
식 4-4: 정규 방정식
X_b = np.c_[np.ones((100, 1)), X] # 모든 샘플에 x0 = 1을 추가합니다.
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
# (2, 100)(100, 2) --> (2, 2)
# (2, 2)(2, 100) --> (2, 100)
# (2, 100)(100, 1) --> (2, 1)
c_ 함수: 여러 행렬을 column으로 이어붙임 -> X_b 행렬은 100x2 행렬이 됨
정규 방정식을 사용해서 theta_best를 구한다.
numpy의 linearalgebra 밑의 inverse 함수를 통해 역행렬을 구함
theta_best
array([[4.21509616], [2.77011339]]) -> 절편, 기울기
X_new = np.array([[0], [2]])
X_new_b = np.c_[np.ones((2, 1)), X_new] # 모든 샘플에 x0 = 1을 추가합니다.
y_predict = X_new_b.dot(theta_best)
y_predict
array([[4.21509616], [9.75532293]])
plt.plot(X_new, y_predict, "r-")
plt.plot(X, y, "b.")
plt.axis([0, 2, 0, 15])
plt.show()
plt.plot(X_new, y_predict, "r-", linewidth=2, label="Predictions")
plt.plot(X, y, "b.")
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.legend(loc="upper left", fontsize=14)
plt.axis([0, 2, 0, 15])
save_fig("linear_model_predictions_plot")
plt.show()
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)
lin_reg.intercept_, lin_reg.coef_
(array([4.21509616]), array([[2.77011339]]))
lin_reg.predict(X_new)
array([[4.21509616], [9.75532293]]) -> 예측값
# 싸이파이 lstsq() 함수를 사용하려면 scipy.linalg.lstsq(X_b, y)와 같이 씁니다.
theta_best_svd, residuals, rank, s = np.linalg.lstsq(X_b, y, rcond=1e-6)
# residual: (yhat - y)**2, svd--->특잇값*rcond > 특잇값: 모두 0으로 바꿈
theta_best_svd
array([[4.21509616], [2.77011339]])
np.linalg.pinv(X_b).dot(y)
유사역행렬을 구하는 함수 (역행렬을 구하지 못하는 경우에 역행렬 근삿값을 구할 수 있다.)
array([[4.21509616], [2.77011339]])
경사 하강법(Gradient Descent)
비용 함수를 최소화하기 위해 반복적으로 모델 파라미터를 조정
경사 하강법의 문제 -> 이차함수가 아니기 때문에 지역 최솟값이 존재
경사하강법을 사용할 때는 사용하는 특성의 scale을 맞춰주어야 함
배치 경사 하강법
전체 샘플을 이용해서 경사 하강법 단계를 수행하는 것
미분값 -> 경사, 미분값을 이용해서 경사를 줄여나감
eta = 0.1 # 학습률
n_iterations = 1000
m = 100
theta = np.random.randn(2,1) # 랜덤 초기화
for iteration in range(n_iterations):
gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y)
theta = theta - eta * gradients
theta
array([[4.21509616], [2.77011339]])
X_new_b.dot(theta)
array([[4.21509616], [9.75532293]]) -> 예측값
theta_path_bgd = []
# 그래프를 그리는 함수
def plot_gradient_descent(theta, eta, theta_path=None):
m = len(X_b)
plt.plot(X, y, "b.")
n_iterations = 1000
for iteration in range(n_iterations):
if iteration < 10:
y_predict = X_new_b.dot(theta)
style = "b-" if iteration > 0 else "r--"
plt.plot(X_new, y_predict, style)
gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y)
theta = theta - eta * gradients
if theta_path is not None:
theta_path.append(theta)
plt.xlabel("$x_1$", fontsize=18)
plt.axis([0, 2, 0, 15])
plt.title(r"$\eta = {}$".format(eta), fontsize=16)
np.random.seed(42)
theta = np.random.randn(2,1) # random initialization
plt.figure(figsize=(10,4))
plt.subplot(131); plot_gradient_descent(theta, eta=0.02)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.subplot(132); plot_gradient_descent(theta, eta=0.1, theta_path=theta_path_bgd)
plt.subplot(133); plot_gradient_descent(theta, eta=0.5)
save_fig("gradient_descent_plot")
plt.show()
확률적 경사 하강법
* 모델 파라미터 랜덤 초기화
* 에포크 시작
-> 훈련 세트 섞기
* 훈련 세트에서 샘플 하나 꺼내기
* 경사 하강법 수행
* 모델 파라미터 수정
* 반복
* 종료
theta_path_sgd = []
m = len(X_b)
np.random.seed(42)
n_epochs = 50 # 50번 반복
t0, t1 = 5, 50 # 학습 스케줄 하이퍼파라미터
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):
if epoch == 0 and i < 20: # 책에는 없음
y_predict = X_new_b.dot(theta) # 책에는 없음
style = "b-" if i > 0 else "r--" # 책에는 없음
plt.plot(X_new, y_predict, style) # 책에는 없음
random_index = np.random.randint(m) # 실제로는 중복을 허용하지 않음
xi = X_b[random_index:random_index+1]
yi = y[random_index:random_index+1]
gradients = 2 * xi.T.dot(xi.dot(theta) - yi) # gradient 값을 점점 줄임, 정답에 가까워질 수록 조심
eta = learning_schedule(epoch * m + i)
theta = theta - eta * gradients
theta_path_sgd.append(theta) # 책에는 없음
plt.plot(X, y, "b.") # 책에는 없음
plt.xlabel("$x_1$", fontsize=18) # 책에는 없음
plt.ylabel("$y$", rotation=0, fontsize=18) # 책에는 없음
plt.axis([0, 2, 0, 15]) # 책에는 없음
save_fig("sgd_plot") # 책에는 없음
plt.show() # 책에는 없음
theta
array([[4.21076011], [2.74856079]])
from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor(max_iter=1000, tol=1e-3, penalty=None, eta0=0.1, random_state=42)
sgd_reg.fit(X, y.ravel())
SGDRegressor(eta0=0.1, penalty=None, random_state=42)
sgd_reg.intercept_, sgd_reg.coef_
(array([4.24365286]), array([2.8250878]))
미니배치 경사 하강법
theta_path_mgd = []
n_iterations = 50
minibatch_size = 20
np.random.seed(42)
theta = np.random.randn(2,1) # 랜덤 초기화
t0, t1 = 200, 1000
def learning_schedule(t):
return t0 / (t + t1)
t = 0
for epoch in range(n_iterations):
shuffled_indices = np.random.permutation(m)
X_b_shuffled = X_b[shuffled_indices]
y_shuffled = y[shuffled_indices]
for i in range(0, m, minibatch_size):
t += 1
xi = X_b_shuffled[i:i+minibatch_size]
yi = y_shuffled[i:i+minibatch_size]
gradients = 2/minibatch_size * xi.T.dot(xi.dot(theta) - yi)
eta = learning_schedule(t)
theta = theta - eta * gradients
theta_path_mgd.append(theta)
theta
array([[4.25214635], [2.7896408 ]])
theta_path_bgd = np.array(theta_path_bgd)
theta_path_sgd = np.array(theta_path_sgd)
theta_path_mgd = np.array(theta_path_mgd)
plt.figure(figsize=(7,4))
plt.plot(theta_path_sgd[:, 0], theta_path_sgd[:, 1], "r-s", linewidth=1, label="Stochastic")
plt.plot(theta_path_mgd[:, 0], theta_path_mgd[:, 1], "g-+", linewidth=2, label="Mini-batch")
plt.plot(theta_path_bgd[:, 0], theta_path_bgd[:, 1], "b-o", linewidth=3, label="Batch")
plt.legend(loc="upper left", fontsize=16)
plt.xlabel(r"$\theta_0$", fontsize=20)
plt.ylabel(r"$\theta_1$ ", fontsize=20, rotation=0)
plt.axis([2.5, 4.5, 2.3, 3.9])
save_fig("gradient_descent_paths_plot")
plt.show()
문제
1. 미니 배치 경사하강법, 확률적 경사하강법, 배치 경사하강법의 다른점을 서술하시오
2. rand 함수와 randn 함수는 어떻게 다른가?
3. 유사역행렬이 무엇이며 선형 모델의 파라미터를 구할 때 유사역행렬이 사용되는 경우는 무엇인가?
4. SVD가 무엇인지 서술하시오
5. SGD가 무엇인지 서술하시오