케라스 창시자에게 배우는 딥러닝 - 5. 머신 러닝의 기본 요소

Dobby-HJ

·

2023. 8. 1. 08:09

1. 일반화 : 머신 러닝의 목표

머신 러닝의 근본적인 이슈는 최적화와 일반화 사이의 줄다리기 입니다. 최적화(optimization)는 가능한 훈련 데이터에서 최고의 성능을 얻으려고 모델을 조정하는 과정입니다. 일반화(generalization)는 훈련된 모델이 이전에 본 적 없는 데이터에서 얼마나 잘 수행되는지 의미합니다.

하지만 일반화 성능을 제어할 방법이 없습니다. 단지 모델을 훈련 데이터에 맞출 수만 있습니다.

1.1 과소적합과 과대적합

이전 장에서 본 모델의 경우 홀드아웃(Hold out) 검증 데이터에서 손실이 훈련이 진행됨에 따라 낮아지지만 잠시 후에 필연적으로 다시 높아집니다.

훈련 초기에 최적화와 일반화는 상호 연관되어 있습니다. 훈련 데이터의 손실이 낮아질수록 테스트 데이터의 손실도 낮아집니다. 이런 상황이 발생할 때 모델이 과소적합(underfitting)이 되었다고 말합니다.

모델의 성능이 계속 발전된 여지가 있습니다. 즉, 네트워크가 훈련 데이터에 있는 모든 관련 패턴을 학습하지 못했습니다. 하지만 훈련 데이터에서 훈련을 특정 횟수만큼 반복하고 난 후에는 일반화 성능이 더 이상 높아지지 않으며 검증 세트의 성능이 멈추고 감소되어 시작합니다.

잡음 섞인 훈련 데이터

실제 데이터셋에는 잘못된 입력이 있는 경우가 흔합니다. MNIST에 잘못 기재되어 있다고 생각하는 Sample들입니다.

불확실한 특성

모든 데이터 잡음이 부정확성 때문에 발생하는 것은 아닙니다. “문제” 가 자체에 불확실성과 모호성이 있다면 완벽하고 깔끔하게 레이블이 부여된 데이터라도 잡음이 발생할 수 있습니다. 분류 작업에서 입력 특성 공간의 일부 영역이 동시에 여러 클래스에 연관된 경우가 종종 있습니다. 예를 들어 바나나 이미지를 받아서 이 바나나가 덜 익었는지, 익었는지, 또는 썩었는지 예측하는 모델을 개발 중이라고 가정해보겠습니다. 이런 범주에는 객관적인 경계가 없기 때문에 레이블을 할당하는 사람마다 동일한 사진을 덜 익은 바나나 또는 익은 바나나로 분류할 수 있습니다.

드문 특성과 가짜 상관관계

코드 5-1 MNIST에 백색 잡음 픽셀과 0 픽셀 추가하기

from tensorflow.keras.datasets import mnist
import numpy as np

(train_images, train_labels), _ = mnist.load_data()
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype("float32") / 255

train_images_with_noise_channels = np.concatenate(
    [train_images, np.random.random((len(train_images), 784))], axis=1)

train_images_with_zeros_channels = np.concatenate(
    [train_images, np.zeros((len(train_images), 784))], axis=1)

이 두 훈련 세트에서 2장의 모델을 훈련해보겠습니다.

코드 5-2 백색 잡음과 0을 추가한 MNIST 데이터에서 모델 훈련하기.

from tensorflow import keras
from tensorflow.keras import layers

def get_model():
    model = keras.Sequential([
        layers.Dense(512, activation="relu"),
        layers.Dense(10, activation="softmax")
    ])
    model.compile(optimizer="rmsprop",
                  loss="sparse_categorical_crossentropy",
                  metrics=["accuracy"])
    return model

model = get_model()
history_noise = model.fit(
    train_images_with_noise_channels, train_labels,
    epochs=10,
    batch_size=128,
    validation_split=0.2)

model = get_model()
history_zeros = model.fit(
    train_images_with_zeros_channels, train_labels,
    epochs=10,
    batch_size=128,
    validation_split=0.2)

코드 5-3 검증 정확도 비교 그래프 그리기

import matplotlib.pyplot as plt
val_acc_noise = history_noise.history["val_accuracy"]
val_acc_zeros = history_zeros.history["val_accuracy"]
epochs = range(1, 11)
plt.plot(epochs, val_acc_noise, "b-",
         label="Validation accuracy with noise channels")
plt.plot(epochs, val_acc_zeros, "b--",
         label="Validation accuracy with zeros channels")
plt.title("Effect of noise channels on validation accuracy")
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
plt.show()

두 경우 모두 동일한 정보를 가진 데이터이지만, 잡음이 섞인 데이터에서 훈련된 모델의 검증 정확도가 1퍼센트 포인트 정도 낮습니다. 이는 순전히 “가짜 상관관계”이 영향 때문입니다. 잡음을 더 많이 섞을수록 더 감소될 것입니다.

잡음 특성은 필연적으로 과대적합을 유발시킵니다. 따라서 특성이 모델에 유익한지 또는 모델을 혼란스럽게 만드는지 확실하지 않다면 훈련 전에 특성 선택(Feature selection)을 수행하는 것이 일반적입니다. 예를 들어 IMDB 데이터를 가장 자주 등장하는 최상위 1만개 단어로 제한하는 것은 세련되지 않은 특성 선택 방법입니다.

특성 선택을 하는 일반적인 방법은 가용한 각 특성에 대해 얼마나 유용한지를 정량적으로 측정 가능한 유용성 점수를 계산하는 것입니다. 즉, 특성과 레이블 사이의 상호 의존 정보(mutual information)처럼 작업에 대해 특성이 얼마나 유익한지 측정합니다. 그 다음 일정 임계 값을 넘긴 특성만을 사용합니다. 이렇게 하면 앞선 예제에서 백색 잡음이 걸러질 수 있습니다.

1.2 딥러닝에서 일반화 본질

5-4 랜덤하게 섞은 레이블로 MNIST 모델 훈련하기

(train_images, train_labels), _ = mnist.load_data()
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype("float32") / 255

random_train_labels = train_labels[:]
np.random.shuffle(random_train_labels)

model = keras.Sequential([
    layers.Dense(512, activation="relu"),
    layers.Dense(10, activation="softmax")
])
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
model.fit(train_images, random_train_labels,
          epochs=100,
          batch_size=128,
          validation_split=0.2)

입력과 출력에 따른 일반화 성능을 고려하지 않고 단순히 학습하게 된다면, Python의 Dictionary Type처럼 입력과 타깃사이의 임시 매핑 방법만을 학습하게 될 것입니다. 이것이 새로운 입력에 적용 가능하다고 할 수 있나요?

결국 딥러닝에서 일반화의 본질은 딥러닝 모델 자체와는 거의 관련이 없고, 실제 세상의 정보 구조와 많은 관련이 있습니다.

매니폴드 가설

우선 유효한 손글씨 숫자의 부분 공간은 연속적입니다. 하나의 샘플을 조금 수정해도 여전히 같은 손글씨 숫자로 인식할 수 있습니다. 게다가 유효한 부분 공간 안에 있는 모든 샘플은 이 부분 공간을 가로지르는 매끈한 경로로 연결되어 있습니다. 2개의 MNIST 숫자 A와 B를 무작위로 선택하면 A를 B로 변형시키는 연속적인 중간 이미지가 있다는 의미입니다. 2개의 연속적인 중간 이미지는 서로 매우 비슷합니다. 두 클래스의 경계 부근에서 모호한 모양이 조금 있겠지만, 이런 모양도 여전히 숫자처럼 보일 것입니다.

기술적으로 손글씨 숫자가 가능한 모든 28 x 28 uint8 배열로 이루어진 공간 안에서 매니폴드(manifold)를 형성한다고 말합니다. “매니폴드”는 국부적으로 선형(유클리드) 공간과 비슷하게 보이는 부모 공간의 저차원 부분 공간입니다. 예를 들어 평면상의 매끄러운 한 곡선은 2D 공간 안에 있는 1D매니폴드입니다.

더 일반적으로 매니폴드 가설(manifold hypothesis)은 실제 세상의 모든 데이터가(이 데이터가 인코딩된) 고차원 공간 안에 있는 저차원 매니폴드에 놓여 있다고 가정합니다. 이는 우주에 있는 정보 구조에 관한 매우 강력한 가정입니다. 우리가 아는한 이것이 맞으며 딥러닝이 작동하는 이유입니다.

매니폴드 가설은 다음을 의미합니다.

  • 머신 러닝 모델은 가능한 입력 공간 안에서 비교적 간단하고, 저차원이며, 매우 구조적인 부분 공간(잠재 매니폴드(latent manifold)만 학습하면 됩니다.
  • 이런 매니폴드 중 하나 안에서 두 입력 사이를 보간(interpolation)하는 것이 항상 가능합니다. 즉, 연속적인 경로를 따라 한 입력에서 다른 입력으로 변형할 때 모든 포인트가 이 매니폴드에 속합니다.

일반화의 원천이 보간

다루는 데이터 포인트를 “보간”할 수 있다면 이전에 본 적 없는 포인트를 해당 매니폴드에서 가까이 놓인 다른 포인트와 연결하여 이해할 수 있습니다. 다른 말로 하면 공간 안의 샘플만 사용해서 공간 전체를 이해할 수 있습니다. 보간을 사용해서 빈 곳을 채울 수 있기 때문입니다.

근사적으로 학습된 데이터 매니폴드에서 보간을 통해 딥러닝의 일반화가 달성되지만 보간이 일반화의 전부라고 가정하는 것은 실수입니다. 이는 빙산의 일각입니다. 보간은 이전에 본 것과 매우 가까운 것을 이해하는데 도움을 줄 수 있을 뿐입니다. 이를 지역 일반화(local generalization)라고 합니다. 하지만 놀랍게도 사람은 항상 극도로 새로운 것을 잘 다루면서 잘 처리합니다. 사람은 앞으로 마주할 모든 상황에 대해 무수히 많은 샘플에서 미리 훈련할 필요가 없습니다.

사람은 보간 이외의 인지 매커니즘으로 궁극 일반화(extreme generalization)를 할 수 있습니다. 인지 메커니즘은 추상화, 세상에 대한 상징적 모델, 추론, 논리, 상식, 일반적으로 이성이라고 부르는 세상에 대한 선천적 능력 등을 말하며 직관이나 패턴 인식과는 다릅니다.

딥러닝이 동작하는 이유

딥러닝 모델이 충분한 표현 능력을 가진다는 일반적인 사실 외에도 잠재 매니폴드를 학습하는 데 특히 잘 맞는 몇 가지 속성이 있습니다.

  • 딥러닝 모델은 입력에서부터 출력으로 매끄럽고 연속적인 매핑을 구현합니다. 필수적으로 미분 가능해야 하기 때문에 매끄럽고 연속적이어야 합니다.(그렇지 않으면 경사 하강법을 사용할 수 없습니다.) 이런 매끄러움은 동일한 속성을 가진 잠재 매니폴드를 근사하는데 도움이 됩니다.
  • 딥러닝 모델은 (모델 구조에 대한 가정을 바탕으로) 훈련 데이터에 있는 정보의 형태를 반영하는 식으로 구조화되는 경향이 있습니다. 특히 이미지 처리 모델(8~9장)과 시퀀스 처리 모델(10장)에서 그렇습니다. 더 일반적으로 심층 신경망은 학습한 표현을 계층적으로 모듈 방식으로 구조화되며 이는 자연적인 데이터가 구성되는 방식을 반영한 것입니다.

가장 중요한 훈련 데이터

딥러닝이 실제로 매니폴드 학습에 잘 맞지만 인반화의 능력은 모델의 어떤 속성 때문이라기 보다 데이터의 자연적인 구조로 인한 결과입니다. 데이터가 보간할 수 있는 매니폴드를 형성하는 경우에만 일반화할 수 있습니다. 특성이 유익하고 잡음이 적을수록 입력 공간이 더 간단하고 구조적이기 때문에, 더 잘 일반화할 수 있습니다. 데이터 큐레이션(data curation)특성 공학(feature engineerin은 일반화에 필수적입니다. 데이터 큐레이션은 데이터를 수집하고 구성하여 유용하고 가치있는 정보로 변환하는 과정

따라서 딥러닝 모델을 향상시키는 가장 좋은 방법 중 하나는 더 좋고, 더 많은 데이터에서 훈련하는 것이라는 점을 항상 기억하세요. (당연히 잡음이 크거나 부정확한 데이터를 추가하면 일반화에 해가 됩니다.)

2. 머신러닝 모델 평가

2.1 훈련, 검증, 테스트 세트

단순 홀드아웃 검증

코드 5-5 홀드아웃 검증 구현 예

num_validation_samples = 10000
np.random.shuffle(data) # 데이터를 섞는 것(셔플링)이 일반적으로 좋습니다.
validation_data = data[:num_validation_samples] # 검증 세트를 만듭니다.
training_data = data[num_validation_samples:] # 훈련 세트를 만듭니다.
model = get_model()
model.fit()
validation_score = model.evaluate(validation_data, ...) 
... # 여기에서 모델을 튜닝, 훈련, 평가하는 과정을 반복합니다.
model = get_model()
model.fit(np.concatenate([training_data, validation]) 
test_score = model.evaluate(text_data, ...)

K-겹 교차 검증

2.3 모델 평가에 유념해야 할 점

  • 대표성 있는 데이터
  • 훈련 세트와 테스트 세트에 대한 대표성이 있어야 합니다.
  • 시간의 방향쉬운 예로, 훈련 세트에 있는 데이터보다 테스트 세트에 있는 모든 데이터가 미래의 것이어야 합니다.
  • 과러로부터 미래를 예측하려고 한다면, 데이터를 분할하기 전에 무작위로 섞어서는 안됩니다.
  • 데이터 중복
  • 한 데이터셋에 어떤 데이터 포인트가 2번 등장하면, 데이터를 섞고 훈련 세트와 검증 세트로 나누었을 때 훈련 세트와 검증 세트에 데이터 포인트가 중복될 수 있습니다.

3. 훈련 성능 향상하기

최적적합 모델을 얻으려면 먼저 과대적합되어야 합니다. 이 경계가 어디인지 미리 알지 못하기 때문에 경계를 찾으려면 넘어가 보아야 합니다. 따라서 문제를 다루기 시작할 때 초기 목표는 약간의 일반화 능력을 보이고 과대적합할 수 있는 모델을 얻는 것입니다.

이런 모델을 얻고 난 후 과대적합과 싸워 일반화 성능을 개선하는 데 초점을 맞춥니다.

이 단계에서 일반적으로 세 가지 문제가 발생합니다.

  • 훈련이 되지 않는다.
  • 훈련은 잘 시작되었지만 모델이 의미 있는 일반화를 달성하지 못한다.
  • 여전히 과소적합으로, 과대적합이 되지 않는다.

3.1 경사 하강법의 핵심 파라미터 튜닝하기

어쨌든 학습이 제대로 진행되지 않는다면, 항상 경사 하강법 과정에 대한 설정에 문제가 있다고 생각해도 무방합니다. 옵티마이저, 모델 가중치의 초깃값 분포, 학습률, 배치 크기 등을 생각할 수 있습니다. 이런 모든 파라미터는 상호 의존적입니다. 일반적으로 나머지 파라미터는 고정하고 학습률과 배치 크기를 튜닝하는 것으로 충분합니다.

코드 5-7 잘못된 높은 학습률로 MNIST 모델 훈련하기

(train_images, train_labels), _ = mnist.load_data()
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype("float32") / 255

model = keras.Sequential([
    layers.Dense(512, activation="relu"),
    layers.Dense(10, activation="softmax")
])
model.compile(optimizer=keras.optimizers.RMSprop(**1.**),
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
model.fit(train_images, train_labels,
          epochs=10,
          batch_size=128,
          validation_split=0.2)

이 모델은 빠르게 정확도 30~40%를 달성하지만, 이를 넘어서지는 못합니다. 조금 더 낮은 1e-2값으로 낮춰보겠습니다.

model = keras.Sequential([
    layers.Dense(512, activation="relu"),
    layers.Dense(10, activation="softmax")
])
model.compile(optimizer=keras.optimizers.RMSprop(**1e-2**),
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
model.fit(train_images, train_labels,
          epochs=10,
          batch_size=128,
          validation_split=0.2)

이제 모델 training이 잘 될 것입니다.

비슷한 상황에 처했다면 다음을 시도해 보세요.

  • 학습률을 낮추거나 높입니다. 너무 높은 학습률은 이전 예제처럼 최적적합을 크게 뛰어넘는 업데이트가 일어날 수 있습니다. 너무 낮은 학습률은 훈련을 너무 느리게 만들거나, local minima를 넘어서지 못할 수도 있습니다.
  • 배치 크기를 증가시킵니다. 배치 샘플을 더 늘리면 유익하고 잡음이 적은(분산이 낮은) 그레디언트가 만들어집니다.

3.2 구조에 대해 더 나은 “가정”을 하기

모델이 훈련이 잘 되지만, validation score가 전혀 나아지지 않는다면, 이게 일반적으로 맞닥뜨릴 수 있는 최악의 머신 러닝 상황일 것입니다. 이는 접근 방식에 근본적으로 잘못된 무언가가 있다는 의미입니다. 그것이 무엇인지 알기는 쉽지 않을 수 있습니다. 몇 가지 팁은 다음과 같습니다.

먼저 단순하게 입력 데이터에 타깃 예측을 위한 정보가 충분하지 않을 수 있습니다. 즉, 현재 방식으로는 문제를 풀 수 없습니다.

또는 현재 사용하는 모델의 종류가 문제에 적합하지 않을 수 있습니다. 예를 들어 10장에서 밀집 연결 신경망을 사용하는 시계열(timeserires) 예측 문제를 볼 것입니다. 이런 구조는 단순한 기준점을 넘어설 수 없습니다. 순환 신경망(recurrent neural network)이 더 적합하며 일반화가 잘됩니다. 일반화 성능을 달성하려면 문제에 대한 올바른 가정을 하는 모델을 사용해야 합니다. 즉, 구조에 대한 올바른 가정을 내려야 합니다.

3.3 모델 용량 늘리기

코드 5-9 MNIST 데이터를 사용한 간단한 로지스틱 회귀 모델

model = keras.Sequential([layers.Dense(10, activation="softmax")])
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
history_small_model = model.fit(
    train_images, train_labels,
    epochs=20,
    batch_size=128,
    validation_split=0.2)
import matplotlib.pyplot as plt
val_loss = history_small_model.history["val_loss"]
epochs = range(1, 21)
plt.plot(epochs, val_loss, "b--",
         label="Validation loss")
plt.title("Effect of insufficient model capacity on validation loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()

항상 “과대적합”은 가능하다는 것을 기억하세요. 과대적합 할 수 없는 것처럼 보인다면, 모델의 표현 능력(representation power)이 부족한 것입니다. 즉, 용량이 더 큰 모델이 필요합니다.

용량이 더 큰 모델로 학습하면 overfitting 현상이 나타나는 것을 확인할 수 있습니다.(2개의 층 96개의 unit)

4. 일반화 성능 향상하기

4.1 데이터셋 큐레이션

딥러닝의 일반화가 데이터의 잠재 구조에서 비롯된다는 것을 배웠습니다. 데이터를 사용하여 샘플 사이를 부드럽게 보간할 수 있다면 일반화 성능을 가진 딥러닝 모델을 훈련할 수 있을 것입니다. 주어진 문제에 지나치게 잡음이 많거나 리스트 정렬처럼 근본적으로 불연속적인 경우 딥러닝은 도움이 되지 않습니다. 딥러닝은 마법이 아니라 일종의 곡선을 맞추는 작업입니다.

따라서 적절한 데이터셋으로 작업하고 있는지 확인하는 것이 중요합니다. 데이터 수집에 노력과 비용을 투자하는 것이 동일한 노력과 비용을 모델 개발에 투자하는 것보다 거의 항상 더 나은 결과를 가져다 줍니다.

  • 데이터가 충분한지 확인합니다. 입력에서 출력을 매핑하는 공간을 조밀하게 샘플링해야 한다는 것을 기억하세요. 데이터가 많을수록 좋은 모델이 만들어집니다. 이따금 처음에는 불가능한 것처럼 보이는 문제가 대용량의 데이터셋으로 해결됩니다.
  • 레이블 할당 에러를 최소화합니다. 입력을 시각화하여 이상치를 확인하고, 레이블을 교정합니다.
  • 데이터를 정제하고 누락된 값을 처리합니다.
  • 많은 특성 중에서 어떤 것이 유용한지 확실하지 않다면 특성 선택을 수행하세요.

데이터의 일반화 가능성을 향상시키는 매우 중요한 방법은 특성 공학(feature engineering)입니다.

4.2 특성 공학(feature engineering)

4.3 조기 종료(Early Stopping) 사용하기

4.4 모델 규제하기

규제(regularization) 기법은 훈련 데이터에 완벽하게 맞추려는 모델의 능력을 적극적으로 방행하는 일련의 모범 사례입니다. 이를 통해 모델의 검증 점수를 향상시키는 것이 목적입니다. 모델을 더 간단하고 더 평범하게, 곡선을 부드럽고 더 일반적으로 만드는 경향을 가지기 때문에 모델을 ‘규제’한다고 말합니다. 따라서 모델이 훈련 세트에 덜 특화되고 데이터의 잠재 매니폴드를 조금 더 가깝게 근사함으로써 일반화 능력을 높일 수 있습니다.

가중치 규제 추가

오캄의 면도날(Occam’s razor) 이론을 알고 있을지 모르겠습니다. 어떤 것에 대한 두 가지의 설명이 있다면 더 적은 가정이 필요한 간단한 설명이 옳을 것이라는 이론입니다. 이 개념은 신경망으로 학습되는 모델에도 적용됩니다. 어떤 훈련 데이터와 네트워크 구조가 주어졌을 때 데이터를 설명할 수 있는 가중치 값의 집합(모델)은 여러 개입니다. 간단한 모델이 복잡한 모델보다 덜 과대적합 될 가능성이 높습니다.

여기에서 간단한 모델은 파라미터 값 분포의 엔트로피가 작은 모델입니다.(또는 앞 절에서 본 것처럼 적은 수의 파라미터를 가진 모델입니다.) 그러므로 과대적합을 완화하기 위한 일반적인 방법은 모델의 복잡도에 제한을 두어 가중치가 작은 값을 가지도록 강제하는 것입니다. 이로 인해 가중치 값의 분포가 더 균일하게 됩니다. 이를 가중치 규제(weight regularization)라고 하며, 모델의 손실 함수에 큰 가중치에 연관된 비용을 추가합니다. 두 가지 형태의 비용이 있습니다.

  • L1 규제 : 가중치의 절댓값에 비례하는 비용이 추가됩니다.
  • L2 규제 : 가중치의 제곱에 비례하는 비용이 추가됩니다.

코드 5-13 모델에 L2 가중치 추가하기

from tensorflow.keras import regularizers
model = keras.Sequential([
    layers.Dense(16,
                 **kernel_regularizer=regularizers.l2(0.002),**
                 activation="relu"),
    layers.Dense(16,
                 **kernel_regularizer=regularizers.l2(0.002),**
                 activation="relu"),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
history_l2_reg = model.fit(
    train_data, train_labels,
    epochs=20, batch_size=512, validation_split=0.4)

앞의 코드에서 l2(0.0002)는 가중치 행렬의 모든 원소를 제곱하고 0.0002 값($\lambda$)를 곱해 모델의 전체 손실에 더해진다는 의미입니다. 이 페널티(penalty)항은 훈련할 때만 추가합니다.

코드 5-14 케라스에서 사용할 수 있는 가중치 규제

from tensorflow.keras import regularizers
regularizers.l1(0.001)
regularizers.l1_l2(l1=0.001, l2=0.001)

드롭아웃 추가

드롭아웃(dropout)은 토론토 대학교의 제프리 힌튼과 그의 학생들이 개발했습니다. 신경망을 위해 사용되는 규제 기법 중에서 가장 효과적이고 널리 사용되는 방법 중 하나입니다. 모델층에 드롭 아웃을 적용하면 훈련하는 동안 무작위로 층의 출력 특성을 일부 제외시킵니다.(0으로 만듭니다)

이 기법이 이상하고 무계획적으로 보일 수 있습니다. 왜 드롭아웃이 과대적합을 줄이는 데 도움이 될까요? 힌튼은 은행에서 사용하는 부정 방지 메커님즘에서 착안했다고 합니다. 그의 말을 빌리면 “은행에 갔을 때 행원들이 바뀌길래 왜 그런지 물었습니다. 자신들도 이유는 모르지만 자주 업무가 바뀐다고 했ㅅㅂ니다. 나는 은행에서 부정 행위를 하려면 직원들 사이의 유대가 필요하기 때문이라고 판단했습니다. 각 샘플에 대해 뉴런의 일부가 무작위하게 제거하면 뉴런의 부정한 협업을 방지하고 결국 과대적합을 감소시킨다는 것을 깨달았습니다” 핵심 아이디어는 층의 출력값에 노이즈를 추가하여 중요하지 않은 우연한 패턴을 깨뜨리는 것입니다. 노이즈가 없다면 모델이 이 패턴을 기억하기 시작할 것입니다.

케라스에서는 층의 출력 바로 뒤에 Dropout 층을 추가하여 모델에 드롭아웃을 적용할 수 있습니다.

model = keras.Sequential([
    layers.Dense(16, activation="relu"),
    layers.Dropout(0.5),
    layers.Dense(16, activation="relu"),
    layers.Dropout(0.5),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
history_dropout = model.fit(
    train_data, train_labels,
    epochs=20, batch_size=512, validation_split=0.4)

정리하면 신경망에서 일반화 성능을 극대화하고, 과대적합을 방지하기 위해 가장 널리 사용하는 방법은 다음과 같습니다.

  • 훈련 데이터를 더 모읍니다. 또는 더 나은 데이터를 모읍니다.
  • 더 나은 특성을 개발합니다.
  • 네트워크의 용량을 감소시킵니다.
  • (작은 가중치를 가진 모델을 만들기 위해) 가중치 규제를 추가합니다.
  • 드롭아웃을 추가합니다.

5. 요약

  • 머신 러닝 모델의 목적은 이전에 본 적 없는 입력에서 정확하게 동작하는 일반화입니다. 이는 보기보다 어렵습니다.
  • 심층 신경망은 훈련 샘플 사이를 성공적으로 보간할 수 있는 모수 모델(parametric model)을 훈련하여 일반화를 달성합니다. 이런 모델은 훈련 데이터의 ‘잠재 매니 폴드’를 학습했다고 말할 수 있습니다. 이것이 딥러닝 모델이 훈련 도중 본 샘플에 매우 가까운 입력만 이해할 수 있는 이유입니다.
    • parametric model : 파라미터 수가 결정된 모델을 의미한다. 파라미터 수가 결정된 이유는 입력 데이터가 어떤 분포를 따른다고 가정했기 때문이다. 따라서 non-parametric 모델과 달리 아무리 입력 데이터 양이 많더라도 학습해야 할 파라미터 수는 변하지 않는다. 이러한 parametric model의 종류는 Linear Regression, Logsitic Regression, CNN, RNN 등이 있다. 모델이 학습해야 할 parameter가 결정되어있기 때문에 non-parametric 방식에 비해 학습 속도가 빠르고 모델의 복잡성이 낮다는 장점이 있다. 반면 단점은 입력 데이터가 어떤 분포를 따른다는 가정이 있으므로 유연성이 낮고, non-parametric model에 비해 복잡한 문제를 해결하기 어렵다.
  • 머신 러닝의 근본적인 문제는 최적화와 일반화 사이의 줄다리기입니다. 일반화를 달성하기 위해 먼저 훈련 데이터에 잘 맞추어야 하지만 훈련 데이터에 대한 성능 향상은 잠시 후 불가피하게 일반화를 저해합니다. 딥러닝의 모든 모범 사례는 이런 긴장 관계를 관리하는 것입니다.
  • 딥러닝 모델의 일반화 능력은 데이터의 잠재 매니폴드를 근사하는 방법을 학습하고 보간을 통해 새로운 입력을 이해할 수 있다는 사실에서 비롯됩니다.
  • 모델을 개발하는 동안 모델의 일반화 능력을 정확하게 평가할 수 있어야 합니다. 간단히 홀드아웃 검증부터 K-fold Cross Validation과 셔플링을 통한 반복 K-Fold Corss Validation까지 다양한 평가 방법을 사용할 수 있습니다. 검증 데이터에서 모델로 정보가 누출될 수 있기 때문에 최종 모델 평가를 위해 완전히 별개의 테스트 세트를 떼어 놓아야 한다는 것을 기억하세요.
  • 모델을 구축하기 시작할 때 먼저 약간의 일반화 능력을 가지고 과대적합할 수 있는 모델을 만드는 것이 목표입니다. 이를 위한 모범 사례는 학습률과 배치 크기를 튜닝하고, 구조에 대해 더 나은 가정을 활용하고, 모델 용량을 늘리고 또는 단순히 더 오래 훈련하는 것입니다.
  • 모델이 과대적합되기 시작할 때 규제를 통해 일반화 성능을 향상시키도록 목표가 바뀝니다. 이를 위해 model capacity을 줄이고, Dropout이나 Weight Regluarization를 추가하고 또는 Early Stopping을 사용할 수 있습니다. 당연히 더 크고 더 좋은 데이터셋이 모델의 일반화를 향상시키는 데 언제나 가장 좋은 방법입니다.