들어가며

이전 글에서는 데이터 간의 비선형관계를 구하기 위한 다항회귀에 대해서 알아보았습니다. 이제 데이터에 적합한 차수(degree( 2차, 3차 등 ))를 어떻게 구할지 고민해야합니다. 이번에는 학습곡선을 통해서 다항회귀를 할때 차수를 적절하게 구하는 방법에 대해서 알아보도록 하겠습니다.

목차

1. 차수의 중요성

2. 학습곡선을 통한 적합성파악

3. 모델의 일반화 오차

 

1. 차수의 중요성

출처 : https://github.com/ageron/handson-ml2/blob/master/04_training_linear_models.ipynb

위 그림은 이전 글(다항회귀)에서 사용한 2차곡선형의 데이터 샘플입니다. 만약 Degree를 300이나 1로 지정할 경우 어떻게 되는지 한번 알아보도록 하겠습니다.

from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

for style, width, degree in (("g-", 1, 300), ("b--", 2, 2), ("r-+", 2, 1)):
    polybig_features = PolynomialFeatures(degree=degree, include_bias=False)
    std_scaler = StandardScaler()
    lin_reg = LinearRegression()
    polynomial_regression = Pipeline([
            ("poly_features", polybig_features),
            ("std_scaler", std_scaler),
            ("lin_reg", lin_reg),
        ])
    polynomial_regression.fit(X, y)
    y_newbig = polynomial_regression.predict(X_new)
    plt.plot(X_new, y_newbig, style, label=str(degree), linewidth=width)

plt.plot(X, y, "b.", linewidth=3)
plt.legend(loc="upper left")
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.axis([-3, 3, 0, 10])
save_fig("high_degree_polynomials_plot")
plt.show()

코드 구현결과를 보면 300차인 경우 2차에 비해서 데이터에 최대한 맞추려고 계속 지그재그로 진행하는 모습이 보입니다. 

반면 1차의 경우 2차에 비해서 데이터에 비적합한 모습을 보입니다. 즉 너무 degree가 높은 경우 데이터에 과대적합되며 너무 낮은 경우 과소적합이 될 수 있습니다. 이번에는 학습곡선을 이용해서 이 적합도를 한 눈에 파악하도록 구현하겠습니다.

2. 학습곡선을 통한 적합성파악

데이터에서 훈련,검증 세트를 추출하고 훈련세트를 하나부터 점차 학습시키면서 RMSE를 구하여 이를 그래프로 나타내는 학습곡선을 구현하도록 하겠습니다. (여기서는 PolynomialFeatures를 사용하지 않으므로 degree를 1차로 진행하는 직선방정식이라고 생각하시면됩니다.)

from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

def plot_learning_curves(model, X, y):
    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=10)
    train_errors, val_errors = [], []
    for m in range(1, len(X_train)):
        model.fit(X_train[:m], y_train[:m])
        y_train_predict = model.predict(X_train[:m])
        y_val_predict = model.predict(X_val)
        train_errors.append(mean_squared_error(y_train[:m], y_train_predict))
        val_errors.append(mean_squared_error(y_val, y_val_predict))

    plt.plot(np.sqrt(train_errors), "r-+", linewidth=2, label="train")
    plt.plot(np.sqrt(val_errors), "b-", linewidth=3, label="val")
    plt.legend(loc="upper right", fontsize=14)   # not shown in the book
    plt.xlabel("Training set size", fontsize=14) # not shown
    plt.ylabel("RMSE", fontsize=14)
lin_reg = LinearRegression()
plot_learning_curves(lin_reg, X, y)
plt.axis([0, 80, 0, 3])                         # not shown in the book
save_fig("underfitting_learning_curves_plot")   # not shown
plt.show() 

곡선을 보니 사이즈가 15이하인 경우까지는 학습이 점차 진행되어 훈련세트와 검증세트의 괴리가 줄어드는 것이 보입니다. 그러나 그 이후 만나는 지점이 1.5 ~ 2.0으로 둘 다 상당한 오차가 발생하는 것으로 보입니다. 이는 전형적인 과소적합의 형태입니다. 이번에는 degree를 10정도로 지정하여 학습곡선을 그려보겠습니다.

from sklearn.pipeline import Pipeline

polynomial_regression = Pipeline([
        ("poly_features", PolynomialFeatures(degree=10, include_bias=False)),
        ("lin_reg", LinearRegression()),
    ])

plot_learning_curves(polynomial_regression, X, y)
plt.axis([0, 80, 0, 3])           # not shown
save_fig("learning_curves_plot")  # not shown
plt.show()   

이번에는 두 곡선의 평균점이 1내외로 이전보다는 나아진것으로 보입니다. 그러나 45부터는 훈련 세트가 증가해도 검증세트와 훈련세트의 RMSE 괴리가 줄어들지 않는 것을 알 수 있습니다. 이는 전형적인 과대적합 모델입니다. 이렇게 degree를 바꿔가며 학습곡선을 파악하면 최적화된 degree를 구할 수 있습니다.

3. 모델의 일반화 오차

모델의 예측값과 결과값 사이의 오차는 일반적으로 3가지 요인을 들 수 있습니다.

1. 편향 : 데이터를 분석할 모델을 잘못 가정하는 것을 의미합니다. 모델 자체의 종류를 잘못 선택하거나 위에서처럼 하이퍼파라미터(degree)를 잘못 설정한 경우입니다. 보통 모델이 복잡할 수록 편향 또한 증가합니다.

2. 분산 : 데이터의 분포정도에 따른 오차발생 정도입니다. 보통 모델이 간단할 경우 예측값과의 분산 정도가 증가합니다.

3. 가우시안 노이즈 : 데이터 자체의 노이즈 정도입니다.

들어가며

지난 시간에는 신경망 학습을 위한 지표인 손실 함수에 대해서 알아보았습니다. 이번에는 신경망의 학습하는 과정에 대해서 설명하도록 하겠습니다. 확률적 경사 하강법(Stochastic gradient discent)을 이용한  신경망 학습과정을 한 문장으로 정리하면

1. 미니 배치 추출 -> 2. 기울기 계산 -> 3. 매개변수 갱신 -> 4. 1~3의 반복입니다.

이제부터 각 과정에 대해서 설명하겠습니다.

 

 

1. 미니 배치 추출

 

미니 배치란?

신경망 학습을 위해서 학습 데이터에서 랜덤으로 일부분만 추출한 데이터의 집합

 

미니 배치의 사용

학습을 시작하기 전 학습 데이터에서 일부분을 추출하는 과정입니다.

대부분 학습 데이터는 수 만에서 수 천만까지 매우 큰 용량을 가지고 있습니다. 신경망이 학습을 할 때는 매개변수를 조정할 때마다 매 번 손실 함수 또한 새로 계산해야 합니다. 모든 학습 데이터를 매번 새로 계산하는 것은 시간이 매우 소요되기 때문에 매번 미니 배치를 추출하여 일부분으로만 손실함수를 계산합니다. 이러한 방식의 학습 방법을 미니배치 학습이라고 칭합니다.

 

2. 기울기 계산

 

기울기란?

신경망에서 말하는 기울기는 손실 함수에 대한 각 매개변수의 수치 미분입니다.

 

수치 미분이란?

수치 미분은 위에 사진과 같이 △x의 값이 0으로 수렴하는 게 아니라 아주 작은 수(ex. 0.0000001 = 1e-7)로 설정되어 컴퓨터에서 물리적으로 구현하기 위한 미분을 의미합니다.

기울기(손실 함수에 대한 각 매개변수의 수치 미분)의 의미?

미분은 기본적으로 변수의 미세한 변화에 따라 결과 함수의 미세한 변화를 의미합니다. 

즉 손실 함수에 대한 각 매개변수의 수치 미분은 컴퓨터가 매개변수의 값을 미세하게 움직였을 경우 손실 함수의 변화를 의미합니다.

우리는 손실 함수의 값을 줄임으로서 학습률을 올리는 것을 목표로하고 있습니다. 그러므로 매개변수의 증가가 손실함수의 감소로 이어진다면 매개변수를 증가시켜 학습률을 올릴 수 있습니다. 

 

기울기를 통해서 학습률을 높이기 위한 매개변수의 방향을 알 수 있습니다. 

 

기울기를 구하는 방법

손실 함수는 여러 가지 매개변수로 이루어진 함수이므로 하나의 매개변수에 대한 수치 미분을 구하기 위해서는 편미분을 사용해야 합니다. 여기서 편미분에 대한 정의는 따로 언급하지 않겠습니다. 

여기서는 이해를 높이기 위해서 실제 파이썬 코드를 이용해서 f(x) = x0^2 + x1^2의 기울기를 구해보겠습니다.

위 그래프는 f(x0, x1) = x0^2 + x1^2와 같은 형상인 f(x, y) = x^2 + y^2의 그래프입니다.

이를 손실 함수라고 가정해 봅시다. 우리는 손실 함수를 가장 낮게 하는 것이 목적이므로 x0=0, x1=0을 목표로 해야 합니다. 

그리고 각 변수들의 기울기는 (0,0)을 가리키는 방향으로 값이 출력되어야 합니다. 실제 기울기의 결괏값을 보면 다음과 같습니다.

이렇든 기울기는 손실 함수의 낮은 지점을 가리키므로 이 방향으로 매개변수를 이동시키면 신경망의 학습률을 올릴 수 있습니다.

실제 코드 예시

https://colab.research.google.com/drive/1eqVqXNzOJE06vwv42TAsYzHAP30KsvtP#scrollTo=-2_AIKQT3Ya_& line=63&uniqifier=1

 

Google Colaboratory

 

colab.research.google.com

기울기의 문제점

기울기의 문제점은 기울기는 함수의 최솟값이 아니라 극솟값으로 이동합니다. 따라서 최소가 아닌 극솟값으로 매개변수가 이동할 경우 손실 함수는 아직 최솟값이 아니지만 기울기가 0이라 매개변수의 갱신이 정체되어 학습 자체가 정체될 수 있습니다. 현상을 배재하기 위해서 매개변수에 관성을 주는 모멘텀(Momentum) 방식이 있지만 이를 따로 언급하지 않겠으니 궁금하시다면 찾아보시기 바랍니다.

 

3. 매개변수의 갱신

기울기를 통해서 우리는 매개변수의 갱신 방향에 대해서 파악하게 되었습니다.

여기서 정해야 할 것은 학습방향으로 매개변수를 어느 정도 움직일지입니다. 이 움직임의 크기를 학습률이라고 하며 이 학습률은 하이퍼 파라미터라고 하며 이는 사람이 직접 설정해줘야 하는 변수입니다.

 

완벽한 하이퍼 파라미터는 없으며 보통 여러 후보를 테스트하고 효율이 좋은 변수를 선택하여 사용합니다.

 

학습률이 매우 작은 경우

학습률이 매우 작은 경우 계속 매개변수의 변화량이 매우 작기 때문에 갱신을 여러 번 반복해도 손실 함수의 최솟값까지 변화되지 않습니다. 계속해서 반복한다면 거의 정확하게 손실 함수를 최소화할 수 있지만 시간이 매우 오래 걸리기에 현실적으로 잘 사용하지 않습니다.

학습률이 매우 큰 경우

학습률이 매우 큰 경우 학습 도중 손실 함수의 최솟값을 지나쳐 너무 큰 값으로 발산하여 학습률을 떨어트릴 우려가 있기에 이는 지양하고 있습니다.

 

적절한 학습률을 설정하고 매개변수의 갱신을 반복할 경우 확률적 경사 하강법을 통해 신경망이 학습을 할 수 있습니다.

 

학습을 지나치게 진행 할 경우

오버피팅의 예시

위와 같은 방식이면 훈련 데이터에 대한 정확도는 확실히 상승할 것입니다. 그러나 우리가 원하는 것은 모든 데이터에 대한 정확도의 상승입니다. 그러나 실제로 훈련 데이터로 학습한 신경망에게 테스터 데이터를 주었을 경우 위처럼 어떤 구간은 기점으로 학습을 하면 할수록 훈련 데이터의 특징에만 학습되어 오히려 범용적인 정확도가 떨어지는 현상이 발생할 수 있습니다. 이러한 경우를 오버 피팅이라고 하며 이를 방지하기 위해서는 오버피팅이 발생하기 시작한 구간에서 학습을 멈춰야 합니다.  

+ Recent posts