Giao diện
Thực hành: Model Debugging
🎯 Mục tiêu
🎯 Sau bài thực hành này, bạn sẽ:
- Chẩn đoán common training failures từ symptoms
- Implement sanity checks trước và trong khi training
- Xử lý overfitting, underfitting, và gradient issues
Mô tả bài tập
Bạn nhận được các đoạn code training có vấn đề. Nhiệm vụ là tìm ra bugs, giải thích nguyên nhân, và sửa chúng.
Yêu cầu
Bài 1: Training Sanity Checks
Implement các sanity checks cơ bản trước khi bắt đầu training.
python
import numpy as np
def run_sanity_checks(X_train, y_train, X_val, y_val):
"""Chạy sanity checks và trả về list các issues phát hiện.
Checks:
1. NaN/Inf trong data
2. Class distribution giữa train và val
3. Feature scale (có features nào quá lớn/nhỏ?)
4. Data leakage (overlap giữa train và val)
"""
issues = []
# TODO: Implement
return issuesBài 2: Diagnose Training Logs
Phân tích training logs để chẩn đoán vấn đề.
python
training_logs = [
# Scenario A
{'epoch': [1,2,3,4,5,10,20,50],
'train_loss': [2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3],
'val_loss': [2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3]},
# Scenario B
{'epoch': [1,2,3,4,5,10,20,50],
'train_loss': [2.3, 1.5, 0.8, 0.3, 0.05, 0.001, 0.0001, 0.00001],
'val_loss': [2.3, 1.6, 1.2, 1.1, 1.3, 1.8, 2.5, 3.2]},
# Scenario C
{'epoch': [1,2,3,4,5],
'train_loss': [2.3, 15.7, 892.3, float('nan'), float('nan')],
'val_loss': [2.3, 18.2, 1024.1, float('nan'), float('nan')]},
]
def diagnose_training(logs):
"""Cho mỗi scenario, trả về:
- diagnosis: tên vấn đề
- explanation: giải thích
- fix: cách sửa
"""
# TODO: Implement
passBài 3: Fix Overfitting
Model đang overfit nghiêm trọng. Implement các kỹ thuật giảm overfitting.
python
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import numpy as np
def diagnose_and_fix_overfitting(X_train, y_train):
"""
1. Train model mặc định, đo train vs val gap
2. Apply regularization techniques
3. So sánh trước và sau
Return: dict với before/after metrics
"""
# TODO: Implement
passGợi ý
💡 Xem gợi ý
- Bài 1: Dùng
np.isnan().any(),np.isinf().any(). So sánh class distribution bằngnp.unique(return_counts=True). Check overlap bằng set intersection. - Bài 2: A = loss không đổi (learning rate quá nhỏ hoặc model broken). B = overfitting (train giảm, val tăng). C = gradient explosion (loss bùng nổ rồi NaN).
- Bài 3: RandomForest: giảm
max_depth, tăngmin_samples_leaf, giảmn_estimators, dùngmax_features='sqrt'.
Lời giải
✅ Xem lời giải
python
# Bài 1
def run_sanity_checks(X_train, y_train, X_val, y_val):
issues = []
if np.isnan(X_train).any() or np.isnan(X_val).any():
issues.append('NaN values detected in features')
if np.isinf(X_train).any() or np.isinf(X_val).any():
issues.append('Inf values detected in features')
_, train_counts = np.unique(y_train, return_counts=True)
_, val_counts = np.unique(y_val, return_counts=True)
train_dist = train_counts / len(y_train)
val_dist = val_counts / len(y_val)
if np.abs(train_dist - val_dist).max() > 0.1:
issues.append(f'Class distribution mismatch: train={train_dist}, val={val_dist}')
feature_range = X_train.max(axis=0) - X_train.min(axis=0)
if (feature_range > 1000).any():
issues.append('Some features have very large range — consider scaling')
train_set = set(map(tuple, X_train))
val_set = set(map(tuple, X_val))
overlap = train_set & val_set
if overlap:
issues.append(f'Data leakage: {len(overlap)} samples appear in both train and val')
return issues
# Bài 2
def diagnose_training(logs):
results = []
# Scenario A: flat loss
results.append({
'diagnosis': 'Training không hội tụ (no convergence)',
'explanation': 'Loss không giảm suốt quá trình training. Có thể do learning rate quá nhỏ, bug trong model (gradient bị block), hoặc data không có signal.',
'fix': 'Tăng learning rate, verify model architecture (check gradient flow), overfit-on-one-batch test.'
})
# Scenario B: overfitting
results.append({
'diagnosis': 'Overfitting nghiêm trọng',
'explanation': 'Train loss giảm liên tục nhưng val loss bắt đầu tăng từ epoch 5. Model memorize training data thay vì generalize.',
'fix': 'Early stopping tại epoch 4-5, tăng regularization (dropout, weight decay), data augmentation, giảm model capacity.'
})
# Scenario C: gradient explosion
results.append({
'diagnosis': 'Gradient explosion',
'explanation': 'Loss tăng vọt rồi thành NaN. Gradients quá lớn khiến weights update bùng nổ.',
'fix': 'Gradient clipping, giảm learning rate, kiểm tra data normalization, dùng batch normalization.'
})
return results
# Bài 3
def diagnose_and_fix_overfitting(X_train, y_train):
# Before: default parameters
model_before = RandomForestClassifier(n_estimators=500, random_state=42)
scores_before = cross_val_score(model_before, X_train, y_train, cv=5, scoring='f1')
model_before.fit(X_train, y_train)
train_score_before = model_before.score(X_train, y_train)
# After: regularized
model_after = RandomForestClassifier(
n_estimators=200,
max_depth=10,
min_samples_leaf=5,
max_features='sqrt',
random_state=42
)
scores_after = cross_val_score(model_after, X_train, y_train, cv=5, scoring='f1')
model_after.fit(X_train, y_train)
train_score_after = model_after.score(X_train, y_train)
return {
'before': {
'train_score': round(train_score_before, 4),
'cv_mean': round(scores_before.mean(), 4),
'gap': round(train_score_before - scores_before.mean(), 4),
},
'after': {
'train_score': round(train_score_after, 4),
'cv_mean': round(scores_after.mean(), 4),
'gap': round(train_score_after - scores_after.mean(), 4),
}
}