본문 바로가기
ML & DL/tensorflow

Regularization 적용에 따른 학습 비교

by 별준 2020. 11. 16.

(tensorflow v2.3.0 - Colab)

 

이번에는 Courser Deep Learning 특화과정 2번째 강의 1주차 실습 중에 하나인 Regularization에 대해서 텐서플로우로 다시 살펴보도록 하겠습니다.

2020/09/26 - [Coursera 강의/Deep Learning] - [실습] Regularization(L2 Regularization, Dropout)

 

[실습] Regularization(L2 Regularization, Dropout)

해당 내용은 Coursera의 딥러닝 특화과정(Deep Learning Specialization)의 두 번째 강의 Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization를 듣고 정리한 내용입니다. (..

junstar92.tistory.com

이진분류 문제에 대해서 Regularization을 적용하지 않은 경우, L2 Regularization 그리고 Dropout을 적용한 경우를 살펴 볼 계획입니다. 

 

1. Dataset 및 필요한 함수 Setting

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import sklearn
import sklearn.datasets
import scipy.io

%matplotlib inline
plt.rcParams['figure.figsize'] = (7.0, 4.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'

def load_2D_dataset():
    data = scipy.io.loadmat('data.mat')
    train_X = data['X']
    train_Y = data['y']
    test_X = data['Xval']
    test_Y = data['yval']

    plt.scatter(train_X[:, 0], train_X[:, 1], c=train_Y, s=40, cmap=plt.cm.Spectral);
    
    return train_X, train_Y, test_X, test_Y

def plot_decision_boundary(model, X, y):
    # Set min and max values and give it some padding
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    h = 0.01
    # Generate a grid of points with distance h between them
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    # Predict the function value for the whole grid
    Z = model(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    # Plot the contour and training examples
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.ylabel('x2')
    plt.xlabel('x1')
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)
    plt.show()
    
train_X, train_Y, test_X, test_Y = load_2D_dataset()

우선 dataset 생성에 필요한 함수와 우리가 예측한 decision boundary를 그래프로 나타내어주는 함수를 준비합니다. Cousera 실습에서 사용되는 'data.mat' 파일이 필요한데, 필요하시면 댓글을 부탁드립니다. 아니면, 아래글에서 사용했던 dataset 생성 함수를 사용하셔도 괜찮을 것 같습니다.

2020/11/15 - [ML & DL/tensorflow] - Initialization에 따른 학습 비교

 

Initialization에 따른 학습 비교

이번에는 Coursera Deep Learning 특화과정 두번째 강의 1주차에서 실습한 initialization 선택에 따른 학습비교를 tensorflow에서 구현해보도록 하겠습니다. 2020/09/26 - [Coursera 강의/Deep Learning] - [실습..

junstar92.tistory.com

총 211개의 training set이 존재하며, feature x1, x2는 point의 좌표값입니다. label은 0 or 1로 구성되어 있으므로, 우리는 이진분류를 위한 모델을 생성해야 합니다.

 

2. Model 구현

시작하기에 앞서 말씀드린대로 1)regularization을 적용하지 않은 경우, 2)L2 regularization을 적용한 경우, 3)Dropout을 적용한 경우, 이 3가지 방법으로 각각 학습해볼 것입니다. 각 regularization에 대해서는 아래 글을 참조하시기 바랍니다.

2020/09/23 - [Coursera 강의/Deep Learning] - Practical aspects of Deep Learning 1

 

Practical aspects of Deep Learning 1

해당 내용은 Coursera의 딥러닝 특화과정(Deep Learning Specialization)의 두 번째 강의 Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization를 듣고 정리한 내용입니다. (..

junstar92.tistory.com

 

L2 Regularization

이 방법을 적용할 때, loss는 아래와 같은 방법으로 구하게 됩니다.

\[J(W^{[1]}, b^{[1]}, \cdots, W^{[L]}, b^{[L]}) = \frac{1}{m}\sum_{i = 1}^{m}\mathscr{L}(\hat{y}^{(i)}, y^{(i)}) + {\color{blue}\frac{\lambda}{2m}\sum_{l = 1}^{L}\| W^{[l]} \|^2}\]

여기서 \(\lambda\)가 hyperparameter가 되며 우리가 학습 시에 선택해주는 옵션이 됩니다. 만약 이 파라미터의 값을 0으로 둔다면, regularization을 적용하지 않은 것과 동일합니다.

 

tensorflow에서는 tf.keras.regularizer.l2를 사용하면 되는데, 인자로 이 \(\lambda\)값을 입력하면 됩니다. 자세한 적용은 아래 Model 함수의 전체 코드를 살펴보시기 바랍니다.

 

Dropout

Dropout은 무작위로 노드를 삭제해서 학습을 진행하는 방법입니다.

L2 Regularization과는 다르게 layer를 추가해서 적용할 수 있으며, tf.keras.layers.Dropout을 사용하게 됩니다. 여기서 인자로 rate의 값을 받는데, 이 값은 무작위로 삭제할 노드의 비율을 의미합니다. 따라서 강의를 들으신 분이라면 keep_prob라는 매개변수가 익숙할텐데, 이 keep_prob는 삭제하지 않을 노드의 비율이므로, 우리는 drop_prob, 즉, 삭제할 노드의 비율을 인자로 입력해주어야 합니다.

 

전체 Model 구성 코드 입니다.

def Model(X_train, Y_train, X_test, Y_test, learning_rate=0.3, num_iterations=30000, lambd=0., keep_prob=1.):
    tf.random.set_seed(2)
    initializer=tf.initializers.random_normal(0.0, 1.0, seed=1)

    layers_dims = [20, 3, 1]
    n_layers = len(layers_dims)

    # input -> linear(20) -> relu -> dropout -> linear(3) -> relu -> dropout -> output -> sigmoid 
    model = tf.keras.models.Sequential([
        tf.keras.layers.Input(shape=(X_train.shape[1],))
    ])

    regularizer=tf.keras.regularizers.l2(lambd)

    for i in range(n_layers):
        if i != n_layers-1:
            model.add(tf.keras.layers.Dense(layers_dims[i],
                                             activation='relu',
                                             kernel_initializer=initializer,
                                             kernel_regularizer=regularizer))

            if keep_prob != 1.:
                model.add(tf.keras.layers.Dropout(1-keep_prob, seed=2))
        else:
            model.add(tf.keras.layers.Dense(layers_dims[i],
                                             activation='sigmoid',
                                             kernel_initializer=initializer,
                                             kernel_regularizer=regularizer))
    
    # model.summary()

    model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate),
        loss='binary_crossentropy',
        metrics=['accuracy'])
    
    # training
    hist = model.fit(X_train, Y_train, epochs=num_iterations, verbose=0)

    costs=[]
    for i in range(0, num_iterations, 1000):
        costs.append(hist.history['loss'][i])

        if i % 10000 == 0:
            print(f"Cost after interation {i}: {hist.history['loss'][i]}")
    
    # plot the cost
    plt.plot(costs)
    plt.ylabel('cost')
    plt.xlabel('iterations (x1,000)')
    plt.title('Learning rate ='+ str(learning_rate))
    plt.show()

    # evaluate for test set
    model.evaluate(X_test, Y_test)

    train_acc = non_reg_hist.history['accuracy'][-1]
    y_pred = model.predict(X_test) > 0.5
    test_acc = np.mean(non_reg_pred_test[:,0]==Y_test[:,0])

    print (f"On the training set: {train_acc*100}%")
    print (f"On the test set: {test_acc*100}%")

    # plot decision boundary
    plt.title('Model without regularization')
    axes = plt.gca()
    axes.set_xlim([-0.75, 0.40])
    axes.set_ylim([-0.75, 0.65])
    plot_decision_boundary(lambda x: model.predict(x) > 0.5, X_train, Y_train)

    return model, hist

파라미터 초기화방법으로는 평균 0, 표준편차가 1의 정규분포를 따르는 무작위 초기화를 사용했으며, 최적화 알고리즘으로 단순 Batch Gradient Descent를 사용했습니다. 그리고, 학습 진행 후에는 loss의 그래프를 그려주어서 loss의 변화 추이를 살펴볼 수 있고, training accuracy와 test accuracy를 비교하게 됩니다. 마지막에는 학습한 decision boundary를 그려줍니다.

 

3-1. Non-regularized model

학습을 진행해보겠습니다.

m1, h2 = Model(train_X, train_Y, test_X, test_Y)

결과는 위와 같습니다. training accuracy가 97%, test accuracy가 93% 입니다. Decision Boundary를 보면, training set에 overfitting된 것을 확인할 수 있습니다.

3-2. L2 Regularization

1) lambd = 0.7

m0, h0 = Model(train_X, train_Y, test_X, test_Y, lambd=0.7)

실습과 동일하게 \(\lambda=0.7\)로 설정했을 때의 결과입니다.

람다값이 너무 커서, 파라미터의 값들이 매우 작아져서 되어서 학습이 제대로 이루어지지 않은 것으로 추측됩니다. 파라미터 값들을 확인해보니 실제로 파라미터들이 매우 작은 값을 가지고 있는 것을 볼 수 있습니다.

아래는 레이어 순으로 weight/bias 파라미터의 값입니다. 

 

2) lambd = 0.01

m1, h2 = Model(train_X, train_Y, test_X, test_Y, lambd=0.01)

0.7이 너무 큰 것으로 추측되고, 이번에는 \(\lambda = 0.01\)로 설정하여서 학습을 진행해보았습니다. 

training acc가 88%, test acc가 92%로 나왔습니다. 이전보다 training set에서의 정확도는 떨어지지만, 꽤 일반화를 잘 시키도록 학습이 된 것으로 보입니다.

 

3) lambd = 0.001

\(\lambda\) 값을 10배 줄여서 다시 테스트 해보겠습니다.

m3, h3 = Model(train_X, train_Y, test_X, test_Y, lambd=0.001)

0.01일 때보다 조금 더 괜찮은 결과가 나왔습니다.

 

3-3. Dropout

Dropout의 효과를 알아보기 위해서 조금 많은 경우(0.86, 0.9, 0.8, 0.7, 0.6)를 살펴보았습니다. 

1) keep_prob = 0.86

m4, h4 = Model(train_X, train_Y, test_X, test_Y, keep_prob=0.86)

확실히 Non-regularized나 L2 regularization과 비교해서 좋은 결과지만, Decision Boundary를 봐서는 무언가 약간 overfitting의 느낌이 조금 나고 있습니다. keep_prob의 비율에 따라서 어떻게 다른지, 비율을 다르게 해서 학습을 더 해보도록 하겠습니다.

 

2) keep_prob = 0.9

m5, h5 = Model(train_X, train_Y, test_X, test_Y, keep_prob=0.9)

0.9일 때도 0.86과 유사한 결과가 나왔습니다. (삭제되는 노드가 0.86보다 적음)

 

3) keep_prob = 0.8

m6, h6 = Model(train_X, train_Y, test_X, test_Y, keep_prob=0.8)

0.8인 경우에는 조금 overfitting이 사라지고, 새로운 data에 일반화가 잘 되는 것으로 보입니다. test acc의 경우에는 94%로 이때까지 학습한 결과 중에 가장 좋은 결과를 나타내고 있습니다.

 

4) keep_prob = 0.7

m7, h7 = Model(train_X, train_Y, test_X, test_Y, keep_prob=0.7)

0.7의 경우에도 꽤 좋은 결과를 얻었습니다만, 0.8과 큰 차이는 없어보입니다. 왼쪽 아래 부분에서 조금 더 일반화가 된 것으로 보이네요.

 

5) keep_prob = 0.6

m8, h8 = Model(train_X, train_Y, test_X, test_Y, keep_prob=0.6)

0.6의 결과도 0.7, 0.8과 큰 차이는 없지만, 가장 낮은 training acc를 보이고 있습니다. 삭제하는 노드가 많이질수록 일반화하는 정도가 커지는 것 같습니다.

 

 

4. Result

Regularization Traing acc(%) Test acc(%)
Non-regularization 97.1 93.0
L2 regularization (lambda=0.7) 46.9 43.5
L2 regularization (lambda=0.01) 88.6 92.0
L2 regularization (lambda=0.001) 90.9 93.0
Dropout (keep_prob=0.86) 94.3 94.0
Dropout (keep_prob=0.9) 92.4 92.5
Dropout (keep_prob=0.8) 91.9 94.0
Dropout (keep_prob=0.7) 90.0 93.5
Dropout (keep_prob=0.6) 87.2 94.0

 

댓글