학습 곡선 해석하기
훈련 데이터에 있는 정보를 크게 두 가지로 나눌 수 있습니다: 신호(signal)와 노이즈(noise)입니다. 신호는 모델이 새로운 데이터에서 예측할 때 도움이 되는 부분이며, 일반화될 수 있는 정보입니다. 반면, 노이즈는 훈련 데이터에서만 나타나는 우연한 변동이나 의미 없는 패턴을 포함하고 있으며, 실제로는 예측에 도움이 되지 않는 정보입니다.
모델을 훈련할 때, 우리는 훈련 세트의 손실(loss)을 최소화하는 가중치 또는 파라미터를 선택합니다. 그러나 모델의 성능을 정확하게 평가하려면 새로운 데이터 세트, 즉 검증 데이터(validation data)에서 평가해야 합니다.
훈련할 때, 우리는 각 에포크마다 훈련 세트의 손실을 그래프로 그립니다. 여기에 검증 데이터의 손실도 추가로 플로팅합니다. 이러한 그래프를 학습 곡선(learning curves)이라고 합니다. 딥러닝 모델을 효과적으로 훈련시키기 위해서는 이 학습 곡선을 해석할 수 있어야 합니다.
훈련 손실은 모델이 신호를 배우거나 노이즈를 배울 때 모두 감소할 수 있습니다. 하지만 검증 손실은 모델이 신호를 배울 때만 감소합니다. (훈련 세트에서 배운 노이즈는 새로운 데이터로 일반화되지 않습니다.) 따라서 모델이 신호를 배우면 두 곡선이 모두 내려가지만, 노이즈를 배우면 곡선 사이에 격차(gap)가 생깁니다. 이 격차의 크기는 모델이 얼마나 많은 노이즈를 배웠는지를 나타냅니다.
이상적으로는 모든 신호를 배우고 노이즈는 전혀 배우지 않는 모델을 만들고 싶겠지만, 실제로는 신호와 노이즈 간의 균형을 맞추는 트레이드오프가 존재합니다. 일정 지점 이후에는 노이즈를 배우는 비용이 신호를 배우는 이익을 초과하게 되고, 검증 손실이 다시 증가하기 시작합니다.
모델 용량
모델의 용량(capacity)은 학습할 수 있는 패턴의 크기와 복잡도를 나타냅니다. 신경망의 경우, 이는 주로 뉴런의 수와 연결 방식에 의해 결정됩니다. 데이터에 대한 모델의 언더피팅이 의심되는 경우, 모델의 용량을 늘려보세요.
모델의 용량을 늘리는 방법에는 모델을 넓게(레이어에 더 많은 유닛을 추가) 만드는 것과 깊게(레이어를 더 추가) 만드는 것이 있습니다. 넓은 네트워크는 더 선형적인 관계를 배우기 쉽고, 깊은 네트워크는 비선형적인 관계를 선호합니다.
model = keras.Sequential([
layers.Dense(16, activation='relu'),
layers.Dense(1),
])
wider = keras.Sequential([
layers.Dense(32, activation='relu'),
layers.Dense(1),
])
deeper = keras.Sequential([
layers.Dense(16, activation='relu'),
layers.Dense(16, activation='relu'),
layers.Dense(1),
])
조기 종료(Early Stopping)
모델이 노이즈를 학습하면서 검증 손실이 증가하기 시작하면 훈련을 멈출 수 있습니다. 이를 조기 종료(Early Stopping)라고 합니다. 조기 종료는 모델이 신호를 충분히 학습하지 못한 상황을 방지하고, 훈련을 너무 오래 진행하여 오버피팅하는 것도 방지합니다. 이를 위해 많은 에포크를 설정하고 조기 종료를 사용하여 적절한 시점에 훈련을 중지하도록 합니다.
from tensorflow.keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(
min_delta=0.001, # 최소한의 개선을 나타내는 값
patience=20, # 개선이 없을 때 대기할 에포크 수
restore_best_weights=True,
)
예시 - 조기 종료를 사용한 모델 훈련
네트워크의 용량을 늘리고 조기 종료 콜백을 추가하여 오버피팅을 방지합니다.
import pandas as pd
from tensorflow import keras
from tensorflow.keras import layers, callbacks
# 데이터 준비
red_wine = pd.read_csv('../input/dl-course-data/red-wine.csv')
df_train = red_wine.sample(frac=0.7, random_state=0)
df_valid = red_wine.drop(df_train.index)
# 특성과 목표 분리
X_train = df_train.drop('quality', axis=1)
X_valid = df_valid.drop('quality', axis=1)
y_train = df_train['quality']
y_valid = df_valid['quality']
# 모델 정의
model = keras.Sequential([
layers.Dense(512, activation='relu', input_shape=[11]),
layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(1),
])
model.compile(optimizer='adam', loss='mae')
# 조기 종료 콜백 추가
early_stopping = callbacks.EarlyStopping(
min_delta=0.001,
patience=20,
restore_best_weights=True,
)
# 모델 훈련
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=256,
epochs=500,
callbacks=[early_stopping],
verbose=0,
)
# 결과 확인
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot()
print("Minimum validation loss: {}".format(history_df['val_loss'].min()))
이 예제에서는 모델의 용량을 크게 늘렸지만, 조기 종료를 통해 검증 손실이 증가하기 시작할 때 훈련을 중지하여 오버피팅을 방지합니다.
'컴퓨터공학 > 인공지능' 카테고리의 다른 글
이진 분류 Binary Classification (82) | 2024.08.03 |
---|---|
딥러닝 모델 성능 향상을 위한 Dropout과 Batch Normalization (94) | 2024.08.02 |
Stochastic Gradient Descent 경사하강법 (83) | 2024.07.31 |
딥뉴럴 네트워크 Deep Neural Networks (79) | 2024.07.30 |
딥러닝과 뉴런, 파이썬 케라스 코드 (83) | 2024.07.29 |