Skip to content

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 issues

Bà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
    pass

Bà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
    pass

Gợi ý

💡 Xem gợi ý
  • Bài 1: Dùng np.isnan().any(), np.isinf().any(). So sánh class distribution bằng np.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ăng min_samples_leaf, giảm n_estimators, dùng max_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),
        }
    }

Liên kết liên quan