실제 프로젝트에서 딥러닝 모델을 개발할 때 필요한 실전 지식
1. 하이퍼파라미터 튜닝
하이퍼파라미터 중요도 순서
1순위 (가장 중요):
- 🥇 학습률 (Learning Rate)
- 🥈 배치 크기 (Batch Size)
2순위:
- 은닉층 개수
- 은닉층 뉴런 수
- Dropout 비율
3순위:
- 옵티마이저 선택
- 활성화 함수
- 가중치 감쇠
1.1 학습률 찾기
방법: Learning Rate Finder
# 작은 학습률부터 시작하여 지수적으로 증가시키며 손실 관찰
lrs = []
losses = []
for lr in [1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1]:
model = create_model()
optimizer = keras.optimizers.Adam(learning_rate=lr)
# 몇 에포크 학습
history = model.fit(X_train, y_train, epochs=3, verbose=0)
lrs.append(lr)
losses.append(history.history['loss'][-1])
# 시각화
import matplotlib.pyplot as plt
plt.plot(lrs, losses)
plt.xscale('log')
plt.xlabel('Learning Rate')
plt.ylabel('Loss')
plt.show()
# 손실이 가장 빠르게 감소하는 학습률 선택
경험적 값:
- Adam: 0.001 (기본값)
- SGD: 0.01 ~ 0.1
- AdamW: 0.0001 ~ 0.001
1.2 배치 크기 선택
배치 크기 | 장점 | 단점 | 사용 시기 |
---|---|---|---|
작음 (16-32) | 일반화 성능 좋음 메모리 적음 | 느림 불안정 | 데이터 적음 메모리 제약 |
중간 (64-128) | 균형 잡힘 | - | 일반적인 경우 |
큼 (256-512+) | 빠름 안정적 | 일반화 성능 저하 메모리 많이 필요 | 대규모 데이터 강력한 GPU |
추천: 32 or 64로 시작
1.3 은닉층 구조
경험 법칙:
- 입력층 → 점점 감소 → 출력층
- 예: 784 → 512 → 256 → 128 → 10
깊이 vs 너비:
깊은 모델 | 넓은 모델 | |
---|---|---|
층 수 | 많음 (5+) | 적음 (2-3) |
뉴런 수 | 적음-중간 | 많음 |
표현력 | 복잡한 패턴 | 단순한 패턴 |
과적합 위험 | 높음 | 중간 |
학습 속도 | 느림 | 빠름 |
시작점:
- 2-3개 은닉층
- 128-512 뉴런
- 과소적합이면 층/뉴런 추가
- 과적합이면 층/뉴런 감소 또는 정규화
1.4 Dropout 비율
위치 | 추천 비율 |
---|---|
입력층 | 0.1 ~ 0.2 |
은닉층 (FC) | 0.3 ~ 0.5 |
CNN | 0.1 ~ 0.2 |
RNN | 0.2 ~ 0.5 |
조정 방법:
- 과적합 심하면 → 증가 (0.5 → 0.6)
- 과소적합이면 → 감소 (0.5 → 0.3)
2. 일반적인 문제와 해결책
문제 1: 과적합 (Overfitting) 🔥
증상:
- 훈련 손실 < 검증 손실
- 훈련 정확도 >> 검증 정확도
- 학습 곡선이 갈라짐
시각화:
Loss
|
| Train ----___
| \___
| Val ________/----
| /
+------------------- Epoch
해결책 (우선순위):
- 🥇 더 많은 데이터 수집 (가장 효과적)
- 🥈 Dropout 추가/증가 (0.3 → 0.5)
- 🥉 L2 정규화 추가 (weight_decay=0.0001)
- 모델 단순화 (층/뉴런 감소)
- 조기 종료 (Early Stopping)
- 데이터 증강 (이미지/텍스트)
- Batch Normalization 추가
코드 예시:
# 과적합 방지 조합
model = keras.Sequential([
Dense(256, kernel_regularizer=l2(0.001)), # L2 정규화
BatchNormalization(),
Activation('relu'),
Dropout(0.5), # Dropout 증가
Dense(128, kernel_regularizer=l2(0.001)),
BatchNormalization(),
Activation('relu'),
Dropout(0.4),
Dense(10, activation='softmax')
])
# Early Stopping
early_stop = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)
model.fit(X, y, validation_split=0.2, callbacks=[early_stop])
문제 2: 과소적합 (Underfitting)
증상:
- 훈련 손실도 높음
- 훈련 정확도도 낮음
- 검증 성능도 낮음
시각화:
Loss
|
| Train --------
| \______
| Val --------
| \______
+------------------- Epoch
해결책:
- 🥇 모델 복잡도 증가 (층/뉴런 추가)
- 🥈 더 오래 학습 (에포크 증가)
- 🥉 정규화 감소 (Dropout 낮춤)
- 더 나은 특징 엔지니어링
- 다른 모델 아키텍처 시도
- 학습률 조정 (너무 낮거나 높음)
코드 예시:
# 모델 복잡도 증가
model = keras.Sequential([
Dense(512, activation='relu'), # 뉴런 수 증가
Dense(256, activation='relu'), # 층 추가
Dense(128, activation='relu'),
Dense(10, activation='softmax')
])
# 더 오래 학습
model.fit(X, y, epochs=100) # 에포크 증가
문제 3: 학습이 안 됨
증상:
- 손실이 감소하지 않음
- 정확도가 랜덤 수준
- 손실이 NaN
원인과 해결책:
원인 | 해결책 |
---|---|
학습률이 너무 큼 | 학습률 감소 (0.001 → 0.0001) |
학습률이 너무 작음 | 학습률 증가 (0.0001 → 0.001) |
잘못된 가중치 초기화 | He/Xavier 초기화 사용 |
데이터 전처리 안 함 | 정규화/표준화 적용 |
기울기 소실/폭발 | Batch Norm, ReLU 사용 |
잘못된 손실 함수 | 문제 유형에 맞는 손실 선택 |
체크리스트:
# 1. 데이터 정규화 확인
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_val = scaler.transform(X_val)
# 2. 가중치 초기화 확인
Dense(128, kernel_initializer='he_normal')
# 3. 학습률 조정
optimizer = Adam(learning_rate=0.001)
# 4. Batch Normalization 추가
model.add(BatchNormalization())
# 5. 작은 모델로 시작
model = keras.Sequential([
Dense(64, activation='relu'),
Dense(32, activation='relu'),
Dense(10, activation='softmax')
])
문제 4: 기울기 소실/폭발
증상:
- 초기 층의 가중치가 거의 업데이트 안 됨
- NaN 손실 발생
- 학습이 매우 느림
해결책:
기울기 소실:
# 1. ReLU 활성화 함수 사용
Dense(128, activation='relu')
# 2. Batch Normalization
model.add(BatchNormalization())
# 3. He 초기화
Dense(128, kernel_initializer='he_normal', activation='relu')
# 4. 잔차 연결 (ResNet)
# 고급 주제 - 별도 학습 필요
기울기 폭발:
# 1. 기울기 클리핑
optimizer = Adam(clipnorm=1.0)
# 또는 PyTorch
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# 2. 낮은 학습률
optimizer = Adam(learning_rate=0.0001)
# 3. Batch Normalization
model.add(BatchNormalization())
문제 5: 학습이 너무 느림
해결책:
-
배치 크기 증가
model.fit(X, y, batch_size=128) # 32 → 128
-
GPU 사용
# PyTorch device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = model.to(device)
-
더 빠른 옵티마이저
optimizer = Adam(learning_rate=0.001) # SGD보다 빠름
-
학습률 증가
optimizer = Adam(learning_rate=0.01) # 0.001 → 0.01
-
모델 단순화
# 층이나 뉴런 수 감소
3. 딥러닝 워크플로우
3.1 데이터 준비
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 1. 데이터 분할 (60% 훈련, 20% 검증, 20% 테스트)
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
# 2. 정규화 (훈련 데이터 기준으로 fit)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_val = scaler.transform(X_val)
X_test = scaler.transform(X_test)
print(f"Train: {X_train.shape}, Val: {X_val.shape}, Test: {X_test.shape}")
3.2 모델 구축
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Input(shape=(input_dim,)),
# 첫 번째 블록
layers.Dense(256, kernel_initializer='he_normal'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Dropout(0.3),
# 두 번째 블록
layers.Dense(128, kernel_initializer='he_normal'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Dropout(0.3),
# 세 번째 블록
layers.Dense(64, kernel_initializer='he_normal'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Dropout(0.2),
# 출력층
layers.Dense(num_classes, activation='softmax')
])
model.summary()
3.3 모델 컴파일
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.001),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
3.4 콜백 설정
callbacks = [
# 조기 종료
keras.callbacks.EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True,
verbose=1
),
# 학습률 감소
keras.callbacks.ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=5,
min_lr=1e-7,
verbose=1
),
# 모델 저장
keras.callbacks.ModelCheckpoint(
'best_model.keras',
monitor='val_accuracy',
save_best_only=True,
verbose=1
)
]
3.5 모델 학습
history = model.fit(
X_train, y_train,
batch_size=32,
epochs=100,
validation_data=(X_val, y_val),
callbacks=callbacks,
verbose=1
)
3.6 학습 곡선 시각화
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 4))
# 손실 곡선
plt.subplot(1, 2, 1)
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Val Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.title('Loss Curves')
plt.grid(True)
# 정확도 곡선
plt.subplot(1, 2, 2)
plt.plot(history.history['accuracy'], label='Train Acc')
plt.plot(history.history['val_accuracy'], label='Val Acc')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.title('Accuracy Curves')
plt.grid(True)
plt.tight_layout()
plt.show()
3.7 모델 평가
# 테스트 세트 평가
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f'Test Loss: {test_loss:.4f}')
print(f'Test Accuracy: {test_acc:.4f}')
# 예측
y_pred = model.predict(X_test)
y_pred_classes = y_pred.argmax(axis=1)
# 혼동 행렬
from sklearn.metrics import confusion_matrix, classification_report
print("Confusion Matrix:")
print(confusion_matrix(y_test, y_pred_classes))
print("\nClassification Report:")
print(classification_report(y_test, y_pred_classes))
4. 체크리스트
데이터 전처리
- 데이터 정규화/표준화
- Train/Val/Test 분할 (60/20/20)
- 클래스 불균형 확인
- 결측치 처리
- 데이터 증강 (필요시)
모델 설계
- 적절한 활성화 함수 (은닉층: ReLU)
- 출력층 활성화 (분류: Softmax/Sigmoid, 회귀: None)
- 적절한 손실 함수
- He/Xavier 초기화
정규화
- Dropout 추가 (0.2-0.5)
- L2 정규화 (weight_decay=0.0001)
- Batch Normalization (선택)
학습 설정
- Adam 옵티마이저 (lr=0.001)
- 적절한 배치 크기 (32-128)
- Early Stopping 설정
- ReduceLROnPlateau (선택)
평가
- 검증 세트로 성능 모니터링
- 학습 곡선 시각화
- 테스트 세트로 최종 평가
- 혼동 행렬 확인
5. 디버깅 플로우차트
학습이 잘 안 되나요?
|
├─ 손실이 감소 안 함?
| ├─ 데이터 정규화 확인
| ├─ 학습률 조정
| └─ Batch Norm 추가
|
├─ 과적합?
| ├─ Dropout 증가
| ├─ Weight Decay 추가
| ├─ 더 많은 데이터
| └─ Early Stopping
|
├─ 과소적합?
| ├─ 모델 복잡도 증가
| ├─ 정규화 감소
| └─ 더 오래 학습
|
└─ 학습이 느림?
├─ 배치 크기 증가
├─ GPU 사용
└─ Adam 옵티마이저
6. 모범 사례 (Best Practices)
시작하기
-
간단한 모델로 시작
- 2-3층, 64-128 뉴런
- 과소적합이면 복잡도 증가
-
기본 설정 사용
- Adam 옵티마이저 (lr=0.001)
- Batch size = 32
- ReLU 활성화
-
반드시 검증 세트 사용
- 과적합 모니터링
- Early Stopping
-
학습 곡선 시각화
- 문제 진단
- 하이퍼파라미터 조정 방향 결정
개선하기
-
과적합이면:
- Dropout 추가/증가
- Weight Decay
- 데이터 증강
-
과소적합이면:
- 층/뉴런 추가
- 정규화 감소
- 더 오래 학습
-
학습률 튜닝
- Learning Rate Finder 사용
- ReduceLROnPlateau 사용
7. 자주 하는 실수
❌ 하지 말아야 할 것
-
테스트 세트로 하이퍼파라미터 튜닝
- → 검증 세트 사용
-
데이터 정규화 안 함
- → StandardScaler 사용
-
모든 가중치를 0으로 초기화
- → He/Xavier 초기화
-
검증 세트 없이 학습
- → Train/Val/Test 분할
-
과적합을 무시하고 계속 학습
- → Early Stopping
-
학습 곡선을 안 봄
- → 반드시 시각화
핵심 요약
기본 설정
- 🎯 Adam(lr=0.001) + Batch=32
- 🎯 ReLU + He 초기화
- 🎯 Dropout(0.3-0.5) + Weight Decay(0.0001)
- 🎯 Early Stopping + ReduceLROnPlateau
문제 해결
- 🔥 과적합 → Dropout↑, 데이터↑
- 🔥 과소적합 → 모델 복잡도↑
- 🔥 학습 안 됨 → 학습률, 데이터 정규화
- 🔥 느림 → 배치 크기↑, GPU
기억할 것
- ✅ 항상 검증 세트 사용
- ✅ 학습 곡선 시각화
- ✅ 간단한 모델부터 시작
- ✅ 체계적으로 디버깅
다음 학습
- 딥러닝_코드_실습 - 실제 프로젝트로 실습
- 컴퓨터 비전 (CNN) - 이미지 처리 학습
← 딥러닝 기초