ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 핸즈온 머신러닝[4] 모델 훈련(1)
    핸즈온머신러닝 2022. 5. 13. 18:58

    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가 무엇인지 서술하시오

     

     

     

    댓글

Designed by Tistory.