5.1 일반화 : 머신러닝의 목표
5.2 머신 러닝 모델평가
5.3 훈련 성능 향상하기
5.4 일반화 성능 향상하기
5.5 요약
이 장에서는 정확한 모델 평가의 중요성 및 훈련 과 일반화 사이의 균형을 강조하면서 머신러닝에 대한 새로운 직관을 확고한 개념으로 정립하겠습니다.
기존 데이터의 784차원에 백색 잡음인 784개 의 차원을 연결하여 새로운 훈련 세트를 만듭니다. 따라서 데이터의 절반은 잡음입니다. 비교를 위해 모두 0인 784개의 차원을 연결하여 동일한 데이터셋을 만듭니다. 의미 없는 특성의 연결은 데이터의 기존 정보에 전혀 영향을 미치지 않습니다.
즉, 무언가 추가만 한 것입니다. 사람의 분류 정확도는 이런 변환에 전혀 영향을 받지 않습니다.
# 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()
잡음 특성은 필연적으로 과대적합을 유발시킵니다.
따라서 특성이 모델에 유익한지 또는 모델을 혼란스럽게 만드는지 확실하지 않다면 훈련 전에 특성 선택을 수행하는 것이 일반적입니다. 예를 들어 IMDB 데이터를 가장 자주 등장하는 최상위 1만 개 단어로 제한하는 것은 세련되지 않은 특성 선택 방법입니다.
즉, 특성과 레이블 사이의 상호 의존 정보 처럼 작업에 대해 특성이 얼마나 유익한지 측정합니다. 그 다음은 일정 임계 값을 넘긴 특성만 사용합니다. 이렇게 하면 앞선 예제에서 백색 잡음이 걸러질 수 있다.
딥러닝 모델에 곤한 놀라운 사실은 표현 능력이 충분하다면 어떤 것에도 맞추도록 훈련할 수 있다는 것이다.
입력과 뒤섞은 레이블 사이에 아무런 관계가 없지만 비교적 작은 모델에서도 훈련 손실이 잘 감소합니다. 당연히 이런 상황에서 가능한 일반화가 없기 때문에 검증 손실은 시간이 지남에 따라 향상되지 않습니다.
# 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)
따라서 딥러닝 모델을 향상시키는 가장 좋은 방법은 더 좋고, 더 많은 데이터에서 훈련하는 것이라는 점을 항상 기억하세요.
이 절에서 머신 러닝 모델을 평가할 수 있는 여러 가지 방법을 소개합니다. 이 중 대부분은 이전 장에서 이미 보았습니다.
모델 평가의 핵심은 가용한 데이터를 항상 훈련,검증,테스트 3개의 세트로 나누는 것입니다. 훈련 세트에서 모델을 훈련하고 검증세트에서 모델을 평가합니다. 모델을 출시할 준비가 되면 테스트 세트에서 최종적으로 딱 한번 모델을 테스트 합니다. 테스트 데이터는 가능한 제품 환경의 데이터와 비슷해야 합니다. 그 다음 모델을 제품환경에 배포합니다.
층이나 층의 유닛 개수를 선택합니다. (이런 파라미터를 네트워크의 가중치와 구분하기 위해 하이퍼파라미터라고 부릅니다.) 검증 세트에서 모델의 성능을 평가하여 이런 튜닝을 수행합니다.
본질적으로 이런 튜닝도 어떤 파라미터 공간에서 좋은 설정을 찾는 학습입니다.
셜국 검증 세트의 성능을 기반으로 모델의 설정을 튜닝하면 검증 세트로 모델을 직접 훈련하지 않더라도 빠르게 검증 세트에 과대적합될 수 있습니다.
이 현상의 핵심은 정보누설 개념이 있습니다. 검증세트의 모델 성능에 기반하여 모델의 하이퍼파라미터를 조정할 떄마다 검증 데이터에 관한 정보가 모델로 새는 것입니다.
하나의 파라미터에 개해 단 한 번만 튜닝한다면 아주 적은 정보가 누설됩니다. 한 번 튜닝하고 나서 검증 세트에 평가한 결과를 가지고 다시 모델을 평가할 만합니다.
데이터 훈련,검증,테스트 세트로 나누는 것은 간단해 보일 수 있지만 데이터가 적을 떄는 몇가지 고급 기법을 사용하면 도움이됩니다. 대표적으로
또한, 상식 수준의 기준 모델을 사용해서 훈련이 잘 진행되는지 확인하는 방법을 설명하겠다.
단순 홀드아웃 검증 p194
데이터의 일정량을 테스트 세트로 뗴어 놓습니다. 남은 데이터에서 훈련하고 테스트 세트로 평가합니다. 앞 절에서 설명했듯이 정보 누설을 막기 위해 테스트 세트를 사용하여 모델을 튜닝해서는 안됩니다. 이런 이유로 검증 세트도 따로 떼어 놓아야 합니다.
평가 방법은 단순해서 한가지 단점이 있다. 데이터가 적을 떄는 검증 세트와 테스트 세트의 샘플이 너무 적어 주어진 전체 데이터를 통계적으로 대표하지 못할 수 있습니다. 쉽게 이를 확인할 수 있습니다. 다른 난수 초깃값으로 셔플링해서 데이터를 나누었을 때 모델의 성능이 매우 달라지면 바로 이 문제입니다. 다음에 이야기할 k-겹 교차 검증과 반복 k-겹 교차 검증이 이 문제를 해결할 수 있습니다.
K-겹 교차 검증
이 방식에서는 데이터를 동일한 크기를 가진 k개의 분할로 나눕니다. 각 분할 i에 대해 남은 k-1개의 분할로 모델을 훈련하고 분할 i에서 모델을 평가합니다. 최종 점수는 이렇게 얻은 k개의 점수를 평균합니다. 이 방법은 모델의 성능이 데이터 분할에 따라 편차가 클 때 도움이 됩니다. 홀드 아웃 검증처럼 이 방법은 모델의 튜닝에 별개의 검증 세트를 사용하게 됩니다.
셔플링을 사용한 반복 K-겹 교차 검증
이 방법은 비교적 가용 데이터가 적고 가능한 정확하게 모델을 평가하고자 할 때 사용합니다. 캐글 경연에서는 이 방법이 아주 크게 도움이 됩니다. 이 방법은 k-겹 교차 검증을 여러번 적용하되 k개의 분할로 나누기 전에 매번 데이터를 무작위로 섞습니다. 최종 점수는 모든 k-겹 교차 검증을 실행해서 얻은 점수의 평균이 됩니다. 결국 P*K개(P는 반복횟수)의 모델을 훈련하고 평가하므로 비용이 매우 많이 듭니다.
평가 방식을 선택할 떄 다음 사항을 유의해야합니다.
최적적합 모델을 얻으려면 먼저 과대적합되어야 합니다. 따라서 문제를 다루기 시작할떄 초기 목표는 약간의 일반화 능력을 보이고 과대적합할 수 있는 모델을 얻는 것입니다. 이런 모델을 얻고 난 후 과대 적합과 싸워 일반화 성능을 개선하는 데 초점을 맞춥니다.
이런 이슈를 해결하여 머신 러닝 프로젝트의 첫 번째 큰 이정표(상식 수준의 기준점을 넘을 수 있어 약간의 일반화 능력이 있고 과대적합하 수 있는 모델을 얻는 것)를 달성하는 방법을 알아보겠습니다.
항상 경사하강법 과정에 대한 설정에 문제가 있습니다. 옵티마이저 선택, 모델 가중치의 초깃값 분포, 학습률, 배치 크기입니다. 이 모든 파라미터는 상호 의존적 입니다.
일반적으로 나머지 파라미터는 고정하고 학습률과 배치 크기를 튜닝하는 것으로 충분합니다.
모델이 훈련되지만 일반화 되지 않습니다. 아마 최악의 머신러닝 상황일것이다. 이는 접근 방식에 근본적으로 잘못된 무엇간가 있다는 의미이다. 먼저 단순하게 입력 데이터에 타깃 예측을 위한 정보가 충분하지 않을 수 있습니다.
또는 현재 사용하는 모델의 종류가 문제에 적합하지 않을 수 있습니다.
첫번째 모델을 과대적합 시켜야 한다.
훈련손실이 줄어들지 않는 문제와 마찬가지로 이런 문제는 항상 해결할 수 있다. 과대적합할 수 없는 것처럼 보인다면 모델의 표현능력이 부족한것이다. 용량이 더 큰 모델이 필요하다. 더 많은 정보를 저장할 수 있는 모델입니다. 층을 추가하거나(더 많은 가중치를 가지도록) 층 크기를 늘리거나, 현재 문제에 더 적합한 종류의 층(구조에 대해 더 나은 가정)을 사용할 수 있습니다.
모델이 어느 정도 일반화 성능을 갖조 과대적합할 수 있다면 이제 일반화를 극대화하는데 초점을 맞춤 차례입니다.
딥러닝의 일반화가 데이터의 잠재 구조에서 비롯된다는 것을 배웠습니다. 데이터를 사용하여 샘플 사이를 부드럽게 보간할 수 있다면 일반화 성능을 가진 딥러닝 모델을 훈련할 수 있을 것입니다. 주어진 문제에 지나치게 잡음이 많거나 리스트 정렬처럼 근본적으로 불연속적인 경우 딥러닝은 도움이 되지 않습니다. 딥러닝은 일종의 곡선을 맞추는 작업입니다.
따라서 적절한 데이터셋으로 작업하고 있는지 확인하는 것이 중요합니다.
데이터의 일반화 가능성을 향상시키는 매우 중요한 한 방법은 특성공학입니다. 대부분의 머신 러닝 문제에서 특성 공학은 성공을 위한 핵심 요소입니다.
특성 공학은 데이터와 머신러닝 알고리즘(여기에서는 신경망)에 관한 지식을 사용하는 단계입니다. 모델에 데이터를 주입하기 전에 (학습이 아닌) 하드코딩된 변환을 적용하여 알고리즘이 더 잘 수행되도록 만들어 줍니다.
이해하기 위해서 쉬운 예를 하나 들겠다.
시계 이미지를 입력으로 받고 하루의 시간을 출력하는 모델을 개발한다고 가정합시다.
이미지의 원본 픽셀을 입력으로 사용한다면 어려운 머신러닝 문제가 될 것입니다. 이를 해결하려면 합성곱 신경망이 필요할 것이고 이 네트워크를 훈련하기 위해 많은 컴퓨팅 자원도 필요합니다.
고수준에서 이 문제를 이해하고 있다면 (우리는 시계에서 시간을 읽는 방법을 알고 있습니다.) 머신 러닝 알고리즘을 위해 훨씬 더 좋은 입력 특성을 만들 수 있습니다.
이것이 특성 공학의 핵심입니다. 특성을 더 간단한 방식으로 표현하여 문제를 쉽게 만듭니다.
딥러닝 이전에는 특성 공학이 먼신 러닝 워크플로에서 가장 중요한 부분이였습니다.