Overfitting vs Underfitting
Overfitting vs Underfitting: Cân bằng nghệ thuật trong Machine Learning
Một trong những thách thức lớn nhất khi xây dựng mô hình machine learning là tìm được điểm cân bằng tối ưu giữa hai hiện tượng đối lập: overfitting (quá khớp) và underfitting (kém khớp). Bài viết này sẽ giải thích chi tiết về hai hiện tượng này, nguyên nhân cơ bản đằng sau chúng thông qua bias-variance tradeoff, cách nhận diện qua learning curves, và các kỹ thuật regularization để đạt được mô hình cân bằng.
1. Overfitting và Underfitting: Định nghĩa và nhận diện
Overfitting (Quá khớp)
Overfitting xảy ra khi mô hình học quá kỹ từ dữ liệu huấn luyện, đến mức "học thuộc lòng" cả nhiễu (noise) thay vì chỉ học các mẫu tổng quát. Mô hình overfitting có đặc điểm:
Hiệu suất rất tốt trên tập huấn luyện (training set)
Hiệu suất kém trên tập kiểm thử (test set) hoặc dữ liệu mới
Mô hình phức tạp với nhiều tham số
Có xu hướng "uốn cong" để phù hợp với từng điểm dữ liệu
Tưởng tượng một học sinh học thuộc lòng tất cả các bài tập và câu hỏi đã được giải trong sách, nhưng lại không hiểu nguyên tắc cơ bản để áp dụng cho các bài toán mới trong kỳ thi.
Underfitting (Kém khớp)
Underfitting xảy ra khi mô hình quá đơn giản và không thể nắm bắt được mối quan hệ cơ bản trong dữ liệu. Mô hình underfitting có đặc điểm:
Hiệu suất kém ngay cả trên tập huấn luyện
Hiệu suất kém trên tập kiểm thử
Mô hình quá đơn giản
Không thể nắm bắt được các mẫu và xu hướng phức tạp
Tương tự như một học sinh chỉ học qua loa về các khái niệm cơ bản mà không đi sâu vào chi tiết, dẫn đến không thể giải được các bài tập căn bản.
2. Bias-Variance Tradeoff: Cốt lõi của vấn đề
Để hiểu sâu hơn về nguyên nhân dẫn đến overfitting và underfitting, chúng ta cần tìm hiểu về khái niệm bias-variance tradeoff - một trong những nguyên lý cơ bản nhất trong machine learning.
Bias (Độ chệch)
Bias là sai số hệ thống của mô hình, phản ánh mức độ đơn giản hóa của mô hình so với mối quan hệ thực tế trong dữ liệu.
High bias: Mô hình quá đơn giản, bỏ qua nhiều mối quan hệ quan trọng trong dữ liệu → dẫn đến underfitting
Low bias: Mô hình phức tạp, có khả năng nắm bắt được các mối quan hệ phức tạp
Variance (Độ phương sai)
Variance thể hiện độ nhạy cảm của mô hình đối với sự thay đổi nhỏ trong dữ liệu huấn luyện. Nó đo lường mức độ mà mô hình thay đổi khi được huấn luyện trên các tập dữ liệu khác nhau.
High variance: Mô hình quá nhạy cảm với dữ liệu huấn luyện, không tổng quát hóa tốt → dẫn đến overfitting
Low variance: Mô hình ổn định, ít thay đổi giữa các tập dữ liệu huấn luyện khác nhau
Tổng lỗi và Tradeoff
Tổng lỗi (total error) của một mô hình có thể được phân tích thành tổng của ba thành phần:
Total Error = Bias² + Variance + Irreducible ErrorTrong đó, irreducible error (lỗi không khử được) là nhiễu cố hữu trong dữ liệu mà không mô hình nào có thể giải quyết.
Cốt lõi của bias-variance tradeoff là khi chúng ta giảm bias (bằng cách làm mô hình phức tạp hơn), variance thường tăng lên, và ngược lại. Nghệ thuật của machine learning là tìm được điểm cân bằng tối ưu giữa bias và variance.
Visualizing the Tradeoff
Mô hình đơn giản (ví dụ: hồi quy tuyến tính): High bias, Low variance
Mô hình phức tạp (ví dụ: cây quyết định sâu): Low bias, High variance
Mô hình cân bằng (ví dụ: các mô hình với regularization phù hợp): Moderate bias, Moderate variance
3. Learning Curves: Công cụ chẩn đoán
Learning curves là công cụ trực quan và mạnh mẽ để chẩn đoán overfitting, underfitting, và xác định xem mô hình có thể được cải thiện bằng cách nào.
Cách đọc Learning Curves
Learning curves biểu diễn mối quan hệ giữa lỗi huấn luyện (training error) và lỗi kiểm thử (validation error) khi kích thước tập huấn luyện tăng dần.
Mẫu Learning Curves của mô hình Underfitting:
Training error: Cao và không giảm nhiều khi tăng dữ liệu
Validation error: Cao, gần với training error
Khoảng cách: Nhỏ giữa hai đường
Đặc điểm: Cả hai đường đều hội tụ ở mức lỗi cao
Mẫu Learning Curves của mô hình Overfitting:
Training error: Thấp và tiếp tục giảm khi tăng dữ liệu
Validation error: Ban đầu giảm, sau đó tăng lên hoặc dao động
Khoảng cách: Lớn giữa hai đường
Đặc điểm: Training error thấp hơn nhiều so với validation error
Mẫu Learning Curves của mô hình Cân bằng:
Training error: Tương đối thấp
Validation error: Tiếp tục giảm và tiến gần đến training error khi có thêm dữ liệu
Khoảng cách: Hẹp và tiếp tục thu nhỏ
Đặc điểm: Cả hai đường hội tụ ở mức lỗi thấp
Ứng dụng thực tế của Learning Curves
Chẩn đoán hiện tượng: Xác định nhanh chóng mô hình đang underfitting hay overfitting
Đánh giá lợi ích của dữ liệu: Xác định xem việc thu thập thêm dữ liệu có giúp cải thiện mô hình không
Điều chỉnh độ phức tạp: Hướng dẫn việc tăng/giảm độ phức tạp của mô hình
4. Regularization: Kỹ thuật chống Overfitting
Regularization là nhóm kỹ thuật được thiết kế để chống overfitting bằng cách thêm vào hàm mất mát (loss function) các ràng buộc làm "đơn giản hóa" mô hình, khuyến khích các trọng số nhỏ hơn hoặc các mô hình đơn giản hơn.
L1 Regularization (Lasso)
L1 Regularization thêm vào hàm mất mát một số hạng tỷ lệ với tổng giá trị tuyệt đối của các trọng số:
Loss = Original Loss + λ * Σ|w_i|Đặc điểm:
Thúc đẩy các trọng số bằng không (sparse models)
Tự động thực hiện feature selection
Phù hợp khi nghi ngờ một số features không liên quan
Hiệu quả trong không gian nhiều chiều thưa thớt (sparse)
L2 Regularization (Ridge)
L2 Regularization thêm vào hàm mất mát một số hạng tỷ lệ với tổng bình phương các trọng số:
Loss = Original Loss + λ * Σ(w_i²)Đặc điểm:
Khuyến khích các trọng số nhỏ nhưng không nhất thiết bằng không
Xử lý tốt vấn đề đa cộng tuyến (multicollinearity)
Phân phối ảnh hưởng đều giữa các features
Phổ biến hơn trong các mô hình neural network (weight decay)
Elastic Net
Elastic Net kết hợp cả L1 và L2 regularization:
Loss = Original Loss + λ1 * Σ|w_i| + λ2 * Σ(w_i²)Đặc điểm:
Kết hợp ưu điểm của cả L1 và L2
Linh hoạt hơn, có thể điều chỉnh cân bằng giữa feature selection và shrinkage
Hiệu quả khi số lượng features lớn hơn số lượng mẫu
Dropout (cho Neural Networks)
Dropout là kỹ thuật regularization đặc biệt cho neural networks, hoạt động bằng cách ngẫu nhiên "tắt" một tỷ lệ các neuron trong quá trình huấn luyện:
Đặc điểm:
Buộc mạng học các biểu diễn mạnh mẽ hơn
Tương tự như huấn luyện nhiều mạng lưới và lấy trung bình (ensemble)
Đơn giản để triển khai và hiệu quả trong thực tế
Tỷ lệ dropout (thường 0.2-0.5) là hyperparameter cần điều chỉnh
Early Stopping
Early Stopping không phải là regularization theo nghĩa truyền thống, nhưng có tác dụng tương tự:
Đặc điểm:
Dừng huấn luyện khi validation error bắt đầu tăng
Ngăn mô hình học quá mức từ dữ liệu huấn luyện
Đơn giản, hiệu quả và không tốn thêm chi phí tính toán
Yêu cầu một tập validation riêng biệt
5. Các Chiến lược Thực tiễn để Cân bằng Bias-Variance
Khi gặp Underfitting:
Tăng độ phức tạp của mô hình:
Thêm các features/tính năng mới
Tăng độ sâu/rộng của mô hình (ví dụ: thêm hidden layers trong neural network)
Sử dụng mô hình phức tạp hơn (ví dụ: từ linear models đến polynomial hay non-linear models)
Giảm regularization:
Giảm giá trị λ trong L1/L2 regularization
Giảm tỷ lệ dropout
Feature engineering:
Tạo các tính năng kết hợp, tương tác
Khám phá các biến đổi phi tuyến của features
Khi gặp Overfitting:
Thu thập thêm dữ liệu:
Dữ liệu huấn luyện nhiều hơn giúp mô hình tổng quát hóa tốt hơn
Data augmentation (cho computer vision, NLP, v.v.)
Giảm độ phức tạp của mô hình:
Giảm số lượng layers/units trong neural networks
Giảm độ sâu của cây quyết định
Chọn mô hình đơn giản hơn
Tăng regularization:
Tăng giá trị λ trong các kỹ thuật regularization
Tăng tỷ lệ dropout
Áp dụng batch normalization
Feature selection:
Loại bỏ các features ít quan trọng hoặc nhiễu
Sử dụng PCA hoặc các kỹ thuật giảm chiều khác
Cross-validation:
Sử dụng k-fold cross-validation để đánh giá mô hình một cách mạnh mẽ hơn
Giúp chọn hyperparameters phù hợp
6. Ví dụ thực tế và Mã Python
Visualizing Overfitting và Underfitting
Để hiểu trực quan về overfitting và underfitting, hãy xem xét ví dụ hồi quy đa thức với độ phức tạp tăng dần:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error
# Tạo dữ liệu mẫu
np.random.seed(0)
X = np.sort(np.random.rand(30) * 2 - 1)
X = X.reshape(-1, 1)
y = np.sin(2 * np.pi * X).ravel() + np.random.randn(30) * 0.1
# Tạo các mô hình với độ phức tạp tăng dần
degrees = [1, 3, 15] # Bậc của đa thức
plt.figure(figsize=(14, 4))
X_test = np.linspace(-1, 1, 100).reshape(-1, 1)
for i, degree in enumerate(degrees):
ax = plt.subplot(1, 3, i + 1)
# Tạo pipeline cho mô hình đa thức
model = Pipeline([
('poly', PolynomialFeatures(degree=degree)),
('linear', LinearRegression())
])
# Huấn luyện mô hình
model.fit(X, y)
# Dự đoán và tính toán lỗi
y_pred_train = model.predict(X)
y_pred_test = model.predict(X_test)
mse_train = mean_squared_error(y, y_pred_train)
# Vẽ đồ thị
ax.plot(X_test, np.sin(2 * np.pi * X_test), label="True function", color='green')
ax.scatter(X, y, label="Samples", color='black', s=20)
ax.plot(X_test, y_pred_test, label=f"Model (degree={degree})", color='red')
ax.set_ylim((-2, 2))
ax.set_title(f"Degree {degree}\nMSE = {mse_train:.4f}")
ax.legend()
if i == 0:
plt.annotate("Underfitting", xy=(0.05, 0.85), xycoords='axes fraction',
fontsize=14, color='blue')
elif i == 2:
plt.annotate("Overfitting", xy=(0.05, 0.85), xycoords='axes fraction',
fontsize=14, color='blue')
else:
plt.annotate("Good balance", xy=(0.05, 0.85), xycoords='axes fraction',
fontsize=14, color='blue')
plt.tight_layout()
plt.show()Plotting Learning Curves
from sklearn.model_selection import learning_curve
def plot_learning_curve(estimator, X, y, cv=5, train_sizes=np.linspace(0.1, 1.0, 10)):
train_sizes, train_scores, val_scores = learning_curve(
estimator, X, y, cv=cv, train_sizes=train_sizes, scoring='neg_mean_squared_error')
# Chuyển đổi sang MSE
train_scores_mean = -np.mean(train_scores, axis=1)
val_scores_mean = -np.mean(val_scores, axis=1)
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_scores_mean, 'o-', color='blue', label='Training error')
plt.plot(train_sizes, val_scores_mean, 'o-', color='red', label='Validation error')
plt.xlabel('Training Set Size')
plt.ylabel('Mean Squared Error')
plt.title('Learning Curve')
plt.legend(loc='best')
plt.grid(True)
# Ghi chú dựa trên hình dạng của learning curve
gap = val_scores_mean[-1] - train_scores_mean[-1]
level = val_scores_mean[-1]
if gap > 0.1 and train_scores_mean[-1] < 0.1:
plt.annotate("Likely Overfitting", xy=(0.7, 0.9), xycoords='axes fraction',
fontsize=14, color='blue')
elif level > 0.2 and gap < 0.1:
plt.annotate("Likely Underfitting", xy=(0.7, 0.9), xycoords='axes fraction',
fontsize=14, color='blue')
else:
plt.annotate("Good Balance", xy=(0.7, 0.9), xycoords='axes fraction',
fontsize=14, color='blue')
plt.show()
# Sử dụng cho các mô hình với độ phức tạp khác nhau
for degree in [1, 3, 15]:
model = Pipeline([
('poly', PolynomialFeatures(degree=degree)),
('linear', LinearRegression())
])
plot_learning_curve(model, X, y)Comparing Regularization Techniques
from sklearn.linear_model import Ridge, Lasso, ElasticNet
# Tạo dữ liệu mẫu với nhiều features
np.random.seed(42)
X_multi = np.random.randn(100, 20)
true_weights = np.zeros(20)
true_weights[:5] = [1.0, -2.0, 3.0, -4.0, 5.0] # Chỉ 5 features đầu tiên thực sự quan trọng
y_multi = X_multi @ true_weights + np.random.randn(100) * 0.5
# Chia dữ liệu
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_multi, y_multi, test_size=0.3, random_state=42)
# Huấn luyện và so sánh các mô hình với các kỹ thuật regularization khác nhau
models = {
"Linear Regression": LinearRegression(),
"Ridge (L2)": Ridge(alpha=1.0),
"Lasso (L1)": Lasso(alpha=0.1),
"ElasticNet": ElasticNet(alpha=0.1, l1_ratio=0.5)
}
plt.figure(figsize=(14, 10))
for i, (name, model) in enumerate(models.items()):
model.fit(X_train, y_train)
# So sánh trọng số thực với trọng số được học
ax = plt.subplot(2, 2, i + 1)
plt.bar(range(20), model.coef_, alpha=0.7, label='Predicted weights')
plt.bar(range(20), true_weights, alpha=0.5, color='red', label='True weights')
plt.axhline(y=0, color='gray', linestyle='-', alpha=0.3)
plt.title(f"{name}\nTest Score: {model.score(X_test, y_test):.4f}")
plt.xlabel("Feature Index")
plt.ylabel("Weight Value")
plt.legend()
# Chỉ hiển thị nhãn trục x cho một số điểm
ax.set_xticks(range(0, 20, 4))
plt.tight_layout()
plt.show()Kết luận
Overfitting và underfitting là hai thái cực trong machine learning. Hiểu được bias-variance tradeoff, biết cách phân tích learning curves, và sử dụng các kỹ thuật regularization phù hợp là những kỹ năng thiết yếu để xây dựng các mô hình cân bằng, có khả năng tổng quát hóa tốt.
Nghệ thuật xây dựng mô hình machine learning không chỉ nằm ở việc chọn thuật toán phù hợp, mà còn ở việc điều chỉnh độ phức tạp của mô hình để cân bằng giữa bias và variance. Đây là quá trình lặp đi lặp lại, đòi hỏi sự kết hợp giữa kiến thức lý thuyết, kinh nghiệm thực tế, và thử nghiệm có hệ thống.
Bằng cách áp dụng các nguyên tắc và kỹ thuật trong bài viết này, bạn sẽ có khả năng xây dựng các mô hình machine learning mạnh mẽ, có khả năng dự đoán chính xác trên dữ liệu mới, không chỉ "học thuộc" dữ liệu huấn luyện.
Last updated