Mục lục
- Mục tiêu bài học
- Recap: loss function là gì
- Regression trong deep learning
- Notation
- MSE — Mean Squared Error
- Tính chất MSE
- MAE — Mean Absolute Error
- Tính chất MAE
- Huber Loss
- Smooth L1 Loss
- Log-Cosh Loss
- Khi nào dùng cái nào
- MSE = MLE Gaussian
- PyTorch API
- Multi-output regression
- Pitfall thực tế
- Code Python
- Bài tập
- Tóm tắt
Mục tiêu bài học
Sau bài học, bạn sẽ:
- Viết được công thức MSE \( \frac{1}{n}\sum (y_i - \hat{y}_i)^2 \), MAE \( \frac{1}{n}\sum |y_i - \hat{y}_i| \), Huber, Smooth L1, Log-Cosh.
- Tính được gradient \( \partial L / \partial \hat{y}_i \) của từng loss và giải thích vì sao MSE phạt outlier mạnh, MAE robust.
- Chọn được loss phù hợp với dữ liệu: clean, có outlier, hoặc cần balance.
- Chứng minh được MSE tương đương MLE khi giả thiết noise Gaussian.
- Dùng đúng
nn.MSELoss,nn.L1Loss,nn.HuberLoss,nn.SmoothL1Losstrong PyTorch, biết tác dụng củareductionvà shape của input. - Nhận diện được pitfall: scale target chưa normalize, dùng MSE cho classification, reduction sai dẫn đến LR sai.
Bài này tiếp Bài 8 — Softmax và mở đầu chuỗi 2 bài về loss; Bài 10 sẽ nói cross-entropy cho classification.
Recap: loss function là gì
Loss function (còn gọi cost function, objective) đo độ lệch giữa prediction \( \hat{y} \) và ground truth \( y \). Train model = tìm tham số \( \theta \) làm loss nhỏ nhất trên tập train (theo nghĩa kỳ vọng):
\[ \theta^* = \arg\min_\theta \; \frac{1}{N} \sum_{i=1}^{N} L\big( y_i, f_\theta(\mathbf{x}_i) \big) \]
Series 1 (ML cổ điển B26) và Series 2 (B17) đã giới thiệu khái niệm này cho linear / logistic regression. Trong deep learning câu chuyện giống hệt: chỉ thay \( f_\theta \) bằng neural network và tối ưu bằng gradient descent (B17 PyTorch, B11 Backprop).
Lựa chọn \( L \) không trung lập: nó định nghĩa "tốt" nghĩa là gì. Hai bài toán cùng dữ liệu nhưng đổi loss có thể cho model rất khác — đặc biệt khi dữ liệu có outlier hoặc phân phối lệch.
Regression trong deep learning
Regression: output là số thực liên tục (không phải nhãn rời rạc). Vài ví dụ điển hình trong DL:
- Dự đoán nhiệt độ: cho dữ liệu thời tiết → nhiệt độ ngày mai. Scalar output.
- Dự đoán giá nhà: cho feature căn hộ → giá (VND). Scalar.
- Depth estimation: cho ảnh RGB → depth map \( H \times W \) (mỗi pixel là khoảng cách thực). Dense output.
- Age estimation: cho ảnh khuôn mặt → tuổi (năm).
- Bounding box regression: object detection dự đoán \( (x, y, w, h) \) — 4 số thực.
- Pose estimation: dự đoán toạ độ 2D / 3D của khớp.
Output layer cho regression thường không có activation ở đầu ra (logit thẳng), hoặc dùng activation phù hợp range target (vd sigmoid rồi nhân scale nếu target đã chuẩn hoá về \( [0, 1] \)).
Notation
Quy ước dùng xuyên bài:
- \( y_i \in \mathbb{R} \) — ground truth của sample thứ \( i \).
- \( \hat{y}_i \in \mathbb{R} \) — prediction của model.
- \( e_i = y_i - \hat{y}_i \) — error / residual.
- \( n \) — batch size (số sample trong batch).
Với multi-output: \( \mathbf{y}_i, \hat{\mathbf{y}}_i \in \mathbb{R}^D \) trong đó \( D \) là số chiều output (vd 4 cho bounding box).
MSE — Mean Squared Error
MSE là loss phổ biến nhất cho regression — bình phương sai số rồi lấy trung bình:
\[ L_{\text{MSE}} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 \]
Còn gọi L2 loss hoặc quadratic loss. Một số biến thể đáng chú ý:
- SSE (Sum of Squared Errors): không chia \( n \), chỉ tổng. PyTorch
reduction="sum". - RMSE (Root MSE): \( \sqrt{L_{\text{MSE}}} \). Dùng làm metric đánh giá vì cùng đơn vị target, nhưng không khác MSE về điểm tối ưu (đơn điệu).
- Half-MSE: \( \frac{1}{2n} \sum (y - \hat{y})^2 \) — gradient sạch hơn không có hệ số 2. Một số tài liệu (CS231n) dùng dạng này; PyTorch không.
Tính chất MSE
- Convex theo \( \hat{y} \): hàm bậc hai, đạt min duy nhất tại \( \hat{y}_i = y_i \). Lưu ý: convex theo prediction, không convex theo weight của network sâu.
- Smooth, khả vi mọi nơi: thuận tiện cho gradient-based optimization.
- Phạt outlier nặng: error \( e \) đóng góp \( e^2 \). Sample sai 10 đơn vị đóng góp \( 100 \), gấp 100 lần sample sai 1 đơn vị.
- Đơn vị: bình phương đơn vị target. Nếu target là USD thì MSE có đơn vị USD². Khó interpret trực tiếp — thường báo RMSE thay vì MSE khi present.
Gradient theo từng prediction (với reduction "mean"):
\[ \frac{\partial L_{\text{MSE}}}{\partial \hat{y}_i} = \frac{2}{n} (\hat{y}_i - y_i) \]
Tỉ lệ thuận với error \( \hat{y}_i - y_i \): error càng lớn, signal cập nhật càng mạnh. Đây là điểm khiến MSE "adapt" theo magnitude — và cũng là lý do outlier dominate.
MAE — Mean Absolute Error
MAE lấy trị tuyệt đối thay vì bình phương:
\[ L_{\text{MAE}} = \frac{1}{n} \sum_{i=1}^{n} | y_i - \hat{y}_i | \]
Còn gọi L1 loss. Đơn vị giống target (USD ra USD, °C ra °C) — đọc trực tiếp được: "model lệch trung bình 2.3 USD/sample".
Tính chất MAE
- Robust với outlier: error đóng góp \( |e| \) (linear, không bình phương). Sample sai 10 đơn vị đóng góp 10, gấp 10 lần sample sai 1 — không gấp 100 như MSE.
- Cùng đơn vị target: dễ interpret cho stakeholder.
- Không khả vi tại 0: \( |e| \) gãy tại \( e = 0 \). Phải dùng sub-gradient:
\[ \frac{\partial L_{\text{MAE}}}{\partial \hat{y}_i} = \begin{cases} -\frac{1}{n} & \text{nếu } \hat{y}_i < y_i \\ +\frac{1}{n} & \text{nếu } \hat{y}_i > y_i \\ \in [-\frac{1}{n}, +\frac{1}{n}] & \text{nếu } \hat{y}_i = y_i \end{cases} \]
Trong thực tế, framework chọn sub-gradient \( 0 \) tại điểm gãy — không ảnh hưởng kết quả vì điểm này có xác suất 0 trên dữ liệu thực.
Điểm cần để ý: gradient constant theo dấu, không phụ thuộc magnitude của error. Sample sai nhiều và sai ít nhận update cùng độ lớn. Hệ quả: train với MAE thường chậm hội tụ quanh nghiệm tối ưu — gradient không nhỏ dần khi error nhỏ dần, optimizer dao động.
Huber Loss
Huber (1964) đề xuất loss combine ưu điểm của MSE (smooth) và MAE (robust):
\[ L_{\delta}(y, \hat{y}) = \begin{cases} \frac{1}{2}(y - \hat{y})^2 & \text{nếu } |y - \hat{y}| \le \delta \\ \delta \, |y - \hat{y}| - \frac{1}{2}\delta^2 & \text{nếu } |y - \hat{y}| > \delta \end{cases} \]
Ý nghĩa: error nhỏ (\( |e| \le \delta \)) → quadratic như MSE; error lớn → linear như MAE. Hằng \( -\frac{1}{2}\delta^2 \) chỉ để hai nhánh nối liên tục tại \( |e| = \delta \).
- \( \delta \) là hyperparameter: ngưỡng phân biệt "lỗi nhỏ" và "lỗi lớn". Mặc định \( \delta = 1 \). Tăng \( \delta \) → gần MSE hơn; giảm \( \delta \) → gần MAE hơn.
- Khả vi mọi nơi: hai nhánh nối liên tục cả giá trị lẫn đạo hàm tại \( |e| = \delta \).
- Gradient bị chặn: \( |\partial L_\delta / \partial \hat{y}| \le \delta \) (không tính hệ số \( 1/n \)). Outlier cực lớn không thể "phá" gradient.
Gradient:
\[ \frac{\partial L_\delta}{\partial \hat{y}_i} = \begin{cases} -(y_i - \hat{y}_i) & \text{nếu } |y_i - \hat{y}_i| \le \delta \\ -\delta \cdot \text{sign}(y_i - \hat{y}_i) & \text{nếu } |y_i - \hat{y}_i| > \delta \end{cases} \]
Huber thường là lựa chọn default an toàn khi không chắc dữ liệu có outlier không.
Smooth L1 Loss
Smooth L1 là biến thể của Huber dùng trong object detection (xuất hiện trong Fast R-CNN, Girshick 2015). Trong PyTorch nn.SmoothL1Loss(beta=1.0):
\[ L_{\text{smoothL1}}(y, \hat{y}) = \begin{cases} \frac{0.5 (y - \hat{y})^2}{\beta} & \text{nếu } |y - \hat{y}| < \beta \\ |y - \hat{y}| - 0.5 \beta & \text{ngược lại} \end{cases} \]
Khác biệt so với Huber: Smooth L1 chia thêm \( \beta \) ở nhánh quadratic và nhánh linear không có hệ số \( \delta \). Khi \( \beta = 1 \) hai hàm trùng nhau. PyTorch giữ cả nn.HuberLoss(delta=...) và nn.SmoothL1Loss(beta=...) để rõ nghĩa hyperparameter — nội dung cốt lõi giống nhau, chỉ khác hệ số scale.
Log-Cosh Loss
Log-Cosh dùng \( \log \cosh \) của error:
\[ L_{\text{logcosh}} = \frac{1}{n} \sum_{i=1}^{n} \log\big( \cosh(y_i - \hat{y}_i) \big) \]
Tính chất:
- Khi \( |e| \) nhỏ: \( \log \cosh(e) \approx e^2 / 2 \) — gần như nửa MSE.
- Khi \( |e| \) lớn: \( \log \cosh(e) \approx |e| - \log 2 \) — gần như MAE.
- Khả vi mọi nơi: \( \log \cosh \) trơn, không có điểm gãy như Huber tại \( |e| = \delta \).
- Không có hyperparameter ngưỡng — đơn giản hơn Huber.
Đạo hàm: \( \frac{d}{de} \log \cosh(e) = \tanh(e) \), nằm trong \( (-1, 1) \) → gradient tự nhiên bị chặn, giống MAE ở vùng error lớn.
Khi nào dùng cái nào
Quy tắc thực dụng:
- MSE — dùng khi: dữ liệu clean (ít outlier), giả thiết noise Gaussian hợp lý, muốn phạt sai lệch lớn mạnh hơn. Phần lớn benchmark dùng MSE.
- MAE — dùng khi: dữ liệu có outlier rõ rệt và bạn muốn model bỏ qua chúng; quan tâm median của phân phối hơn mean; cần báo cáo error cùng đơn vị target.
- Huber / Smooth L1 — default an toàn cho regression không chắc về outlier. Phổ biến trong bounding box regression của object detection.
- Log-Cosh — gần Huber nhưng không cần chọn \( \delta \), khả vi đẹp hơn. Một lựa chọn khi muốn tránh tinh chỉnh hyperparameter loss.
Lưu ý về median vs mean: với loss \( L(y, \cdot) \) cố định và prediction tối ưu là một hằng số \( c \) trên phân phối \( y \):
- MSE → \( c^* = \mathbb{E}[y] \) (mean).
- MAE → \( c^* = \text{median}(y) \).
Đó là lý do MAE robust với outlier — median không bị kéo bởi vài giá trị cực đoan.
MSE = MLE Gaussian
MSE không phải lựa chọn tuỳ tiện — nó có gốc xác suất rõ ràng. Giả thiết: target \( y \) cho input \( \mathbf{x} \) tuân theo phân phối Gaussian với mean là model prediction và variance \( \sigma^2 \) cố định:
\[ p(y \mid \mathbf{x}, \theta) = \mathcal{N}\big( y \mid \hat{y}_\theta(\mathbf{x}), \sigma^2 \big) = \frac{1}{\sqrt{2\pi}\sigma} \exp\!\left( -\frac{(y - \hat{y}_\theta(\mathbf{x}))^2}{2\sigma^2} \right) \]
Log-likelihood của \( n \) sample i.i.d.:
\[ \log \mathcal{L}(\theta) = \sum_{i=1}^{n} \log p(y_i \mid \mathbf{x}_i, \theta) = -\frac{1}{2\sigma^2} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 - \frac{n}{2} \log(2\pi\sigma^2) \]
Maximize log-likelihood theo \( \theta \) tương đương minimize \( \sum (y_i - \hat{y}_i)^2 \) (số hạng còn lại không phụ thuộc \( \theta \)). Tức là:
\[ \theta_{\text{MLE}} = \arg\min_\theta \; \frac{1}{n}\sum_{i=1}^{n} (y_i - \hat{y}_i)^2 = \arg\min_\theta \; L_{\text{MSE}} \]
Hệ quả: nếu noise không Gaussian, MSE không còn là lựa chọn nguyên lý — nên cân nhắc khác. Tương tự, MAE tương đương MLE khi noise theo phân phối Laplace.
PyTorch API
PyTorch 2.x cung cấp sẵn các loss này dưới dạng nn.Module trong torch.nn:
import torch
import torch.nn as nn
y_true = torch.tensor([3.0, 5.0, 2.0, 7.0])
y_pred = torch.tensor([2.5, 5.5, 2.0, 6.0])
mse = nn.MSELoss()(y_pred, y_true) # 0.1875
mae = nn.L1Loss()(y_pred, y_true) # 0.5
huber = nn.HuberLoss(delta=1.0)(y_pred, y_true)
smooth_l1 = nn.SmoothL1Loss(beta=1.0)(y_pred, y_true)
print(mse.item(), mae.item(), huber.item(), smooth_l1.item())
Tham số quan trọng — reduction (có ở mọi loss):
"mean"(mặc định) — trung bình trên mọi phần tử của tensor input."sum"— chỉ tổng, không chia. Loss scale tuyến tính với batch size."none"— không reduce, trả về tensor cùng shape với input. Hữu ích khi cần loss per-sample (vd weighting).
criterion_none = nn.MSELoss(reduction="none")
per_sample = criterion_none(y_pred, y_true)
# tensor([0.2500, 0.2500, 0.0000, 1.0000])
Quy ước: criterion(y_pred, y_true) — prediction đứng trước. Cả hai phải cùng shape và cùng dtype (thường float32).
Multi-output regression
Khi mỗi sample có \( D \) target liên tục (vd bounding box \( D = 4 \), 2D pose 17 keypoint × 2 = 34, depth map \( H \times W \) flatten), tensor có shape \( (B, D) \). MSE mở rộng tự nhiên:
\[ L_{\text{MSE}} = \frac{1}{nD} \sum_{i=1}^{n} \sum_{j=1}^{D} (y_{ij} - \hat{y}_{ij})^2 \]
nn.MSELoss(reduction="mean") chia cho tổng số phần tử \( n \cdot D \) — đó là lý do giá trị loss không phụ thuộc \( D \). Nếu chỉ muốn chia theo batch (\( n \)), phải reduce thủ công.
Khi các component có scale khác nhau (vd dự đoán \( (x, y, w, h) \) với \( w, h \) lớn hơn \( x, y \)), có thể weight từng component:
weights = torch.tensor([1.0, 1.0, 2.0, 2.0])
diff = (y_pred - y_true) ** 2
loss = (diff * weights).mean()
Hoặc normalize từng component về cùng range trước khi train — thường gọn hơn.
Pitfall thực tế
- Quên
reduction="mean": dùng"sum"mà không tính → loss scale theo batch size. Learning rate phù hợp với batch 32 sẽ không phù hợp với batch 256. Chuẩn: giữ"mean". - Dùng MSE cho classification: technically vẫn chạy nhưng kém hơn cross-entropy rất nhiều — gradient gần 0 khi sigmoid/softmax saturate, model học chậm. Lý do được phân tích kỹ ở B10.
- Target chưa normalize: predict giá nhà 1 tỷ VND → MSE rơi vào \( 10^{18} \). Float32 không hỏng nhưng gradient ban đầu khổng lồ, optimizer khó stable. Cách xử lý: chia target cho hằng (vd \( 10^6 \)) hoặc dùng
(target - mean) / stdrồi nhớ scale ngược lúc inference. - Outlier không clean: dùng MSE với dataset bị nhiễm label sai → model "đu" theo outlier, ignore phần còn lại. Cân nhắc Huber/MAE hoặc clean data trước.
- Shape mismatch im lặng:
y_predshape \( (B, 1) \) còny_trueshape \( (B,) \) → PyTorch broadcast thành \( (B, B) \), MSE tính trên \( B^2 \) phần tử. Bug dễ bị bỏ sót. Luônprint(y_pred.shape, y_true.shape)ở debug đầu. - NaN trong target: làm loss thành NaN, lan ra cả network qua backprop. Mask NaN trước khi tính loss hoặc dùng
torch.nan_to_num.
Code Python
Implement bằng NumPy:
import numpy as np
def mse(y, y_hat):
return np.mean((y - y_hat) ** 2)
def mae(y, y_hat):
return np.mean(np.abs(y - y_hat))
def huber(y, y_hat, delta=1.0):
err = y - y_hat
abs_err = np.abs(err)
quadratic = 0.5 * err ** 2
linear = delta * abs_err - 0.5 * delta ** 2
return np.mean(np.where(abs_err <= delta, quadratic, linear))
y = np.array([3.0, 5.0, 2.0, 7.0])
y_hat = np.array([2.5, 5.5, 2.0, 6.0])
print(f"MSE = {mse(y, y_hat):.4f}") # 0.3125
print(f"MAE = {mae(y, y_hat):.4f}") # 0.5000
print(f"Huber = {huber(y, y_hat, 1.0):.4f}") # 0.1875
Demo outlier dominate với MSE:
np.random.seed(0)
y_clean = np.random.randn(99)
y_hat_clean = y_clean + 0.1 * np.random.randn(99) # error ~ 0.1
# Thêm 1 outlier sai 100 đơn vị
y = np.append(y_clean, 0.0)
y_hat = np.append(y_hat_clean, 100.0)
print(f"MSE = {mse(y, y_hat):.2f}") # ~100.01 — 1 outlier áp đảo
print(f"MAE = {mae(y, y_hat):.2f}") # ~1.08 — robust hơn nhiều
Train MLP đơn giản cho regression:
import torch
import torch.nn as nn
torch.manual_seed(0)
X = torch.randn(256, 4)
y = (X.sum(dim=1, keepdim=True) + 0.1 * torch.randn(256, 1))
model = nn.Sequential(
nn.Linear(4, 32),
nn.ReLU(),
nn.Linear(32, 1),
)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-2)
for epoch in range(200):
y_hat = model(X)
loss = criterion(y_hat, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 50 == 0:
print(f"epoch {epoch:3d} loss = {loss.item():.4f}")
Đổi criterion sang nn.L1Loss() hoặc nn.HuberLoss(delta=1.0) và chạy lại — quan sát curve loss và final loss khác nhau ra sao trên cùng seed.
Bài tập
- Tính tay MSE, MAE và Huber (\( \delta = 1 \)) cho \( y = [3, 5, 2, 7] \), \( \hat{y} = [2.5, 5.5, 2, 6] \). Đối chiếu với output của code mục 17.
- Tạo dataset 100 sample regression, thêm 5 outlier với label sai \( \pm 50 \). Train 3 model (loss = MSE / MAE / Huber) trên cùng seed. So sánh RMSE và MAE trên test set sạch (không có outlier). Loss nào cho model gần ground truth nhất?
- Chứng minh: với \( y \sim p(y) \) cho trước, hằng số \( c \) tối thiểu hoá \( \mathbb{E}[(y - c)^2] \) là \( c^* = \mathbb{E}[y] \).
- Chứng minh: hằng số \( c \) tối thiểu hoá \( \mathbb{E}[|y - c|] \) là \( c^* = \text{median}(y) \). Gợi ý: lấy đạo hàm theo \( c \), chú ý tích phân hai phần \( y < c \) và \( y > c \).
- Suy ra dạng đóng của Huber gradient ở mục 9; kiểm tra liên tục tại \( |e| = \delta \).
- Triển khai loss "Quantile" \( L_\tau(e) = \max(\tau e, (\tau - 1) e) \) với \( \tau \in (0, 1) \) bằng NumPy. Tại \( \tau = 0.5 \) chứng minh nó tỉ lệ với MAE.
- Trong PyTorch, so sánh loss trả về của
nn.MSELoss(reduction="sum")vànn.MSELoss(reduction="mean")trên cùng tensor \( (B, D) \). Tỉ số có đúng bằng \( B \cdot D \) không? Vì sao điều này quan trọng khi tinh chỉnh LR?
Đáp án ngắn
- Errors \( e = (0.5, -0.5, 0, 1.0) \). MSE \( = (0.25 + 0.25 + 0 + 1)/4 = 0.375 \). MAE \( = (0.5+0.5+0+1)/4 = 0.5 \). Huber: \( |e| \le 1 \) cả 4 → \( (0.125+0.125+0+0.5)/4 = 0.1875 \). Lưu ý
nn.MSELosskhông có hệ số \( 1/2 \) nên ra \( 0.375 \), code mục 17 ra \( 0.3125 \) là do dataset khác ví dụ trong bảng tay. - Thường Huber và MAE cho RMSE thấp hơn MSE rõ rệt khi có outlier nặng — MSE "đu" theo outlier.
- \( \frac{d}{dc} \mathbb{E}[(y-c)^2] = -2 \mathbb{E}[y - c] = 0 \Rightarrow c = \mathbb{E}[y] \).
- \( \mathbb{E}[|y - c|] = \int_{-\infty}^c (c-y) p(y) dy + \int_c^{\infty} (y-c) p(y) dy \). Lấy \( d/dc \): \( P(y \le c) - P(y > c) = 0 \Rightarrow P(y \le c) = 1/2 \), tức \( c \) là median.
- Gradient nhánh quadratic: \( -(y - \hat{y}) \). Tại \( |e| = \delta \): nhánh quadratic cho \( -\delta \text{sign}(e) \cdot (-1) \) — khớp với \( -\delta \text{sign}(y - \hat{y}) \) của nhánh linear.
- Với \( \tau = 0.5 \): \( L_{0.5}(e) = \max(0.5 e, -0.5 e) = 0.5 |e| \). Mean \( = 0.5 \cdot \text{MAE} \).
- Đúng \( B \cdot D \). LR phù hợp với
"mean"sẽ phải chia cho \( B \cdot D \) khi chuyển sang"sum"— quên dẫn đến gradient quá lớn, divergence.
Tóm tắt
- Loss function định nghĩa "tốt" cho model; chọn loss = chọn nghiệm tối ưu.
- MSE \( = \frac{1}{n}\sum (y - \hat{y})^2 \): convex, smooth, phạt outlier mạnh, tối ưu \( c^* = \text{mean} \). Gradient \( \frac{2}{n}(\hat{y} - y) \).
- MAE \( = \frac{1}{n}\sum |y - \hat{y}| \): robust, cùng đơn vị target, không khả vi tại 0, gradient \( \pm 1/n \), tối ưu \( c^* = \text{median} \).
- Huber: quadratic khi \( |e| \le \delta \), linear khi \( |e| > \delta \). Khả vi mọi nơi, robust + smooth. Default \( \delta = 1 \).
- Smooth L1 (PyTorch) = Huber có khác hệ số scale; Log-Cosh smooth tự nhiên, không cần \( \delta \).
- MSE = MLE khi noise Gaussian; MAE = MLE khi noise Laplace.
- PyTorch:
nn.MSELoss,nn.L1Loss,nn.HuberLoss,nn.SmoothL1Loss. Chú ýreductionvà shape input/target. - Pitfall: scale target chưa normalize, dùng MSE cho classification, shape mismatch im lặng, NaN trong target.
- Mặc định khởi đầu: MSE nếu data clean, Huber nếu không chắc, MAE khi outlier rõ và muốn robust.
- Wikipedia - Mean squared error
- Wikipedia - Mean absolute error
- Wikipedia - Huber loss
- Huber (1964) - Robust Estimation of a Location Parameter
- Girshick (2015) - Fast R-CNN (Smooth L1 loss)
- Wikipedia - Maximum likelihood estimation
- PyTorch Docs - nn.MSELoss
- PyTorch Docs - nn.L1Loss
- PyTorch Docs - nn.HuberLoss
- PyTorch Docs - nn.SmoothL1Loss
- Goodfellow, Bengio, Courville - Deep Learning Book Ch. 5 (Machine Learning Basics)
- Stanford CS231n - Neural Networks Part 2 (loss functions)
- scikit-learn - Regression metrics
