Mở đầu: câu hỏi không phải "bao nhiêu" mà là "có hay không"

Bài 1 dạy model đoán một con số (giá nhà, điểm thi). Bài 2 dạy nó tự học con số đó bằng cách lăn xuống loss landscape. Nhưng phần lớn quyết định quan trọng nhất trong đời sống lẫn công nghiệp không hỏi "bao nhiêu" — chúng hỏi "có hay không": email này có phải spam? khối u trên phim chụp có ác tính? giao dịch thẻ này có gian lận? Đưa thẳng bài toán này vào cỗ máy hồi quy tuyến tính của Bài 1 nghe hợp lý — cứ fit một đường thẳng qua điểm 0/1, rồi cắt ở 0,5. Bài này sẽ chứng minh bằng số rằng cách làm ngây thơ đó vỡ trận ngay khi có 1 điểm dữ liệu hơi lệch, và xây lại từ đầu công thức đúng: sigmoid nén đầu ra về xác suất, cross-entropy làm hàm mất mát, và một bộ thước đo khác hẳn MSE để biết model tốt tới đâu.

Cuối bài là bộ phân loại 2D kéo-thả tương tác — bạn tự tay đặt điểm đỏ/xanh, xem đường ranh giới quyết định (decision boundary) tự uốn theo, và thấy confusion matrix cùng precision/recall đổi số ngay khi kéo ngưỡng quyết định. Đây cũng là bài đầu tiên bạn tự hỏi "model chính xác 99%" có phải luôn là tin tốt hay không — câu trả lời sẽ khiến bạn nhìn mọi con số accuracy sau này bằng con mắt khác.


📚 Điều kiện tiên quyết
Bắt buộc: Bài 1 (model–loss–data, MSE, nghiệm giải tích) và Bài 2 (gradient descent, quy tắc cập nhật $w \leftarrow w - \eta \nabla L$) — bài này tái sử dụng trực tiếp cả hai, chỉ đổi model và loss. Tài nguyên ngoài: Google ML Crash Course — Logistic Regression, 3Blue1Brown — Neural Networks.

1. Vì sao đường thẳng + ngưỡng 0,5 thất bại

Thử cách ngây thơ trước: coi nhãn 0/1 (rớt/đậu) như một con số $y$, fit đường hồi quy tuyến tính $y = wx + b$ của Bài 1, rồi dự đoán lớp $1$ nếu $wx + b \geq 0{,}5$. Với 7 điểm "số giờ học" ($x$) → "đậu/rớt" ($y$) tách biệt rõ ràng:

Giờ học $x$ 1 2 3 6 7 8 9
Nhãn $y$ 0 0 0 1 1 1 1

Nghiệm giải tích (công thức Bài 1) cho $w \approx 0{,}160$, $b \approx -0{,}252$ — đường cắt $0{,}5$ tại $x \approx 4{,}70$, đúng giữa khoảng trống $3$–$6$, phân loại đúng cả 7/7 điểm. Có vẻ ổn. Giờ thêm đúng một điểm THẬT (không nhập sai gì cả): một người học $x = 50$ giờ và vẫn đậu ($y=1$) — một outlier về độ lớn, không phải outlier về nhãn:

threshold_fail.js (chạy đúng trong self-test file tải về)
// Them 1 diem THAT (x=50, y=1) - khong sai nhan, chi o rat xa
const withOutlier = [...clean, { x: 50, y: 1 }];
const fit = fitLeastSquares(withOutlier); // ham y het Bai 1
// w ~ 0.0144, b ~ 0.470 -> nguong cat 0.5 tai x ~ 2.09 (!)
// x=3 (nhan that: RỚT) gio du doan: 0.0144*3 + 0.470 = 0.513 >= 0.5 -> "DAU" — SAI

Một điểm $x=50$ duy nhất kéo hệ số $w$ từ $0{,}160$ xuống còn $0{,}0144$ (giảm hơn 10 lần, vì đường phải "vươn" ra xa để đi qua điểm mới) và đẩy ngưỡng cắt $0{,}5$ từ $x \approx 4{,}70$ về $x \approx 2{,}09$ — lùi sâu vào giữa vùng đáng lẽ toàn là "rớt". Hệ quả: điểm $x=3$ (nhãn thật là $0$ — rớt) giờ được dự đoán $0{,}513 \geq 0{,}5$, tức bị đoán nhầm thành "đậu". Không có gì sai về mặt thuật toán — least-squares vẫn tối ưu đúng MSE của nó — nhưng bản thân việc dùng MSE + ngưỡng cứng cho bài toán 0/1 là sai công cụ.

Vấn đề gốc rễ: đường thẳng $wx+b$ không có giới hạn trên/dưới — nó có thể vọt lên $50$ hay xuống $-30$, trong khi nhãn chỉ có $0$ hoặc $1$. Cần một hàm nén mọi giá trị thực về khoảng $(0, 1)$ để đầu ra đọc được như xác suất. Hàm đó là sigmoid:

$$\sigma(z) = \frac{1}{1 + e^{-z}}$$

Giải nghĩa: $z$ (gọi là logit) là đầu ra tuyến tính thô $wx+b$, có thể là số thực bất kỳ. Sigmoid nén nó về $(0,1)$: $z \to +\infty$ thì $\sigma \to 1$; $z \to -\infty$ thì $\sigma \to 0$; và đẹp nhất, $\sigma(0) = 0{,}5$ — đúng điểm cân bằng. Vài mốc đáng nhớ (tính tay, khớp self-test): $\sigma(2) \approx 0{,}881$, $\sigma(-2) \approx 0{,}119$ — càng xa $0$ theo hướng nào, sigmoid càng bão hoà sát $1$ hoặc $0$ theo hướng đó, không bao giờ chạm hẳn biên. Model logistic bây giờ là $\hat{y} = \sigma(wx+b)$ — và $\hat{y}$ đọc được đúng nghĩa: "xác suất model tin điểm này thuộc lớp 1".

2. Cross-entropy: hàm mất mát phạt theo độ tự tin sai

Sigmoid giải quyết vế "đầu ra là xác suất". Vế còn lại: nếu vẫn dùng MSE $(\hat{y} - y)^2$ của Bài 1 để train, chuyện gì xảy ra? Hàm mất mát đúng cho phân loại là binary cross-entropy (BCE):

$$L = -\big[y \log(\hat{y}) + (1-y)\log(1-\hat{y})\big]$$

Giải nghĩa: với mỗi điểm, đúng một trong hai số hạng "sống" tuỳ nhãn thật — nếu $y=1$, số hạng thứ hai triệt tiêu ($1-y=0$), loss chỉ còn $-\log(\hat{y})$; nếu $y=0$, chỉ còn $-\log(1-\hat{y})$. Trực giác: loss = "phạt theo độ tự tin SAI". Bảng dưới tính $-\log(\hat{y})$ khi nhãn thật là $1$ (đối xứng cho nhãn $0$):

Xác suất model đoán $\hat{y}$ (nhãn thật $y=1$) Cross-entropy loss Diễn giải
$0{,}99$ $0{,}0101$ Tự tin ĐÚNG — phạt gần như 0
$0{,}5$ $0{,}6931$ Không chắc gì cả — phạt vừa
$0{,}1$ $2{,}3026$ Nghiêng sai — phạt tăng rõ
$0{,}01$ $4{,}6052$ Tự tin SAI — phạt nặng
$0{,}001$ $6{,}9078$ Cực kỳ tự tin SAI — phạt cực nặng

Cùng một "khoảng cách" tới đáp án đúng ($1 - \hat{y}$ giảm dần đều: $0{,}01 \to 0{,}5 \to 0{,}9 \to 0{,}99 \to 0{,}999$) nhưng loss KHÔNG tăng đều — nó tăng vọt phi tuyến khi model càng tự tin mà càng sai. Đây chính xác là hành vi ta muốn: một model tự tin $99\%$ nhưng sai phải bị phạt nặng hơn nhiều một model lưỡng lự $50/50$.

Vì sao không dùng MSE cho phân loại? Lý do sâu hơn "công thức khác nhau" — nó nằm ở gradient. Đạo hàm loss theo $z$ (logit, trước sigmoid) của hai hàm mất mát:

$$\frac{dL_{MSE}}{dz} = 2(\sigma(z)-y)\cdot\sigma'(z) \qquad \frac{dL_{CE}}{dz} = \sigma(z) - y$$

Cross-entropy cho một kết quả đẹp đến bất ngờ: gradient của nó theo $z$ chính là "lỗi dự đoán" ($\hat{y} - y$) — không hề đi qua $\sigma'(z)$. MSE thì khác: gradient của nó nhân thêm $\sigma'(z) = \sigma(z)(1-\sigma(z))$, và số hạng này tự triệt tiêu khi $\sigma(z)$ tiến gần $0$ hoặc $1$ (bão hoà). Số liệu cụ thể tại $z=-6$ (model rất tự tin lớp $0$) khi nhãn thật là $y=1$ (tự tin SAI — đúng lúc cần gradient lớn nhất để sửa):

Hàm mất mát Gradient $dL/dz$ tại $z=-6$, $y=1$ Ý nghĩa
MSE $-0{,}00492$ Gần như $0$ — gradient tiêu biến đúng lúc cần sửa gấp nhất
Cross-entropy $-0{,}99753$ Lớn, đúng dấu — cập nhật mạnh về phía đúng

Chênh lệch hơn 200 lần. Dùng MSE cho phân loại, model tự tin sai gần như đứng im — không ai "sửa" nó nữa vì gradient quá nhỏ. Đây là lý do kỹ thuật thật sự, không phải quy ước tuỳ tiện, khiến cross-entropy là lựa chọn bắt buộc cho phân loại, không phải MSE.

⚠️ Cạm bẫy: $\log(0)$ — hai kiểu hỏng khác nhau, cả hai đều có thật

Cross-entropy có $\log(\hat{y})$ và $\log(1-\hat{y})$ — cả hai đều nổ nếu tham số chạm đúng $0$ hoặc $1$. Số dấu phẩy động (float64) khiến chuyện này KHÔNG chỉ là lý thuyết:

  • Tự tin SAI cực độ ($z=-750$, $y=1$): $\sigma(z)$ làm tròn về đúng $0{,}0$ (không còn số thực nào biểu diễn được nhỏ hơn) → $-\log(0) = \texttt{Infinity}$.
  • Tự tin ĐÚNG cực độ ($z=40$, $y=1$): $\sigma(z)$ làm tròn về đúng $1{,}0$ → số hạng lẽ ra vô hại $(1-y)\log(1-\hat{y}) = 0 \times \log(0) = 0 \times \texttt{-Infinity} =$ NaN trong số học dấu phẩy động — dù dự đoán hoàn toàn chính xác.

Cách khắc phục chuẩn công nghiệp: clip $\hat{y}$ vào khoảng $[\epsilon, 1-\epsilon]$ (thường $\epsilon = 10^{-12}$) trước khi lấy log. Với $z=-750$, sau clip loss $= 27{,}63$ — một số lớn nhưng hữu hạn, gradient descent vẫn cập nhật được bình thường thay vì nhận Infinity/NaN rồi phá hỏng mọi tham số phía sau (mọi phép cộng với NaN đều cho NaN).

3. Decision boundary tuyến tính & phân loại đa lớp

Với 2 đặc trưng $x_1, x_2$ (dữ liệu 2 chiều), model là $\hat{y} = \sigma(w_1x_1 + w_2x_2 + b)$. Model dự đoán lớp $1$ khi $\hat{y} \geq 0{,}5$ — mà $\sigma(0)=0{,}5$ đúng, nên điều kiện đó tương đương $w_1x_1+w_2x_2+b \geq 0$. Đường ranh giới (decision boundary) — nơi model "phân vân đúng 50/50" — là đường thẳng:

$$w_1x_1 + w_2x_2 + b = 0$$

Đây là sự thật hay bị bỏ qua: logistic regression luôn cho ranh giới là một đường/mặt phẳng THẲNG, bất kể sigmoid nghe "phi tuyến" thế nào — độ cong chỉ nằm ở cách xác suất chuyển tiếp mượt qua ranh giới đó (xa ranh giới thì $\hat{y}$ áp sát $0$ hoặc $1$; gần ranh giới thì lưỡng lự quanh $0{,}5$), bản thân đường biên vẫn thẳng tuyệt đối. Dữ liệu không tách được bằng 1 đường thẳng (ví dụ hình xoắn ốc) là bài toán logistic regression thuần không giải nổi — cần mạng neural nhiều lớp (Bài 6).

Với nhiều hơn 2 lớp (ví dụ 10 chữ số của MNIST — Bài 10), sigmoid không dùng được trực tiếp vì các xác suất phải cộng lại đúng bằng $1$. Hàm tổng quát hoá là softmax:

$$\text{softmax}(z)_i = \frac{e^{z_i}}{\sum_j e^{z_j}}$$

Mỗi lớp có một logit riêng, softmax biến cả vector logit thành một phân bố xác suất hợp lệ (mọi số $\geq 0$, tổng $=1$), rồi lấy lớp có xác suất cao nhất (argmax) làm dự đoán cuối. Ví dụ tính tay (khớp self-test), 3 lớp với logit $[2{,}0,\ 1{,}0,\ 0{,}1]$:

softmax.js (nếm trước — dùng thật ở Bài 10 MNIST)
function softmax(logits) {
  const m = Math.max(...logits);           // tru max truoc de tranh e^lon tran so
  const exps = logits.map(z => Math.exp(z - m));
  const s = exps.reduce((a, b) => a + b, 0);
  return exps.map(e => e / s);
}
softmax([2.0, 1.0, 0.1]);
// -> [0.6590, 0.2424, 0.0986]  (tong = 1.000000, dung sai < 1e-9)
// argmax = lop 0 — logit lon nhat luon thanh xac suat lon nhat

Chú ý dòng trừ m: không phải trang trí, mà là kỹ thuật ổn định số học — nếu một logit lớn (vd $1000$), $e^{1000}$ tràn số thành Infinity ngay lập tức; trừ đi max trước khi lấy mũ giữ mọi số hạng $\leq e^0 = 1$ mà không đổi kết quả cuối (tính chất toán học của softmax: cộng/trừ hằng số vào mọi logit không đổi output).

🔢 Con số thật: bỏ dòng trừ m thì hỏng ngay ở logit nào?
Thử chạy đúng công thức softmax nhưng KHÔNG trừ max, với logit $[1000,\ 1,\ 0{,}1]$ (đã kiểm chứng): $e^{1000}$ vượt quá số thực lớn nhất mà số dấu phẩy động 64-bit biểu diễn được ($\approx 1{,}8 \times 10^{308}$) → tràn số ngay lập tức, hệ số $s$ (tổng mẫu số) cũng thành Infinity, và phép chia Infinity / Infinity cho ra NaN cho cả 3 lớp — dù bài toán logit $1000$ so với $1$ hoàn toàn không phải trường hợp cực đoan bất thường (một mạng neural huấn luyện dở có thể dễ dàng sinh ra logit cỡ đó). Sau khi trừ max ($m=1000$): softmax trả về đúng $[1{,}0,\ 0{,}0,\ 0{,}0]$ — lớp có logit vượt trội gần như tuyệt đối chiếm hết xác suất, không còn NaN nào.

4. Đo model đúng cách: accuracy có thể nói dối

Bài toán phân loại có bộ thước đo riêng, khác hẳn $R^2$ của Bài 1. Thước đo quen thuộc nhất — accuracy (tỉ lệ đoán đúng) — lại là cái dễ đánh lừa nhất khi dữ liệu lệch (một lớp áp đảo lớp kia). Ví dụ cụ thể: tầm soát một bệnh hiếm, $100$ người thì $99$ người âm tính, $1$ người dương tính. Một model "ngu" nhất có thể — luôn luôn đoán âm tính, không nhìn dữ liệu đầu vào — đạt:

Chỉ số Giá trị
Accuracy $99\%$
Số ca dương tính thật phát hiện được (Recall) $0\%$ — bỏ sót người bệnh duy nhất

$99\%$ nghe như một model xuất sắc — nó chỉ đơn giản phản ánh dữ liệu lệch, không nói gì về khả năng phát hiện bệnh. Cần thước đo tách riêng từng loại đúng/sai. Confusion matrix gọi tên chính xác 4 khả năng khi so dự đoán với nhãn thật:

  Dự đoán: Dương tính Dự đoán: Âm tính
Thật: Dương tính TP FNbỏ sót
Thật: Âm tính FPbáo động giả TN

Từ 4 con số đó, ba thước đo quan trọng nhất:

$$\text{Precision} = \frac{TP}{TP+FP} \qquad \text{Recall} = \frac{TP}{TP+FN} \qquad F_1 = \frac{2 \cdot \text{Precision} \cdot \text{Recall}}{\text{Precision}+\text{Recall}}$$

Giải nghĩa: Precision — trong các ca model báo dương tính, bao nhiêu phần trăm dương tính thật (đo "báo động giả có nhiều không"). Recall — trong các ca dương tính thật, model bắt được bao nhiêu phần trăm (đo "bỏ sót có nhiều không"). F1 là trung bình điều hoà của hai số trên — chỉ cao khi cả hai đều khá, không thể "ăn gian" bằng cách đẩy một số lên cực đoan. Hai thước đo này luôn đánh đổi nhau qua ngưỡng quyết định (mặc định $0{,}5$, nhưng chỉnh được): ngưỡng càng cao, model càng "kén" khi báo dương tính (precision tăng, recall giảm); ngưỡng càng thấp, model càng "rộng rãi" (recall tăng, precision giảm). Số liệu cụ thể trên cùng 1 bộ dự đoán (self-test đối chiếu):

Ngưỡng quyết định Precision Recall F1
$0{,}3$ (rộng rãi) $0{,}700$ $1{,}000$ $0{,}824$
$0{,}5$ (mặc định) $0{,}857$ $0{,}857$ $0{,}857$
$0{,}7$ (kén chọn) $1{,}000$ $0{,}571$ $0{,}727$

Precision tăng đơn điệu, recall giảm đơn điệu khi ngưỡng tăng — đúng như dự đoán; F1 đạt đỉnh ở ngưỡng giữa vì nó phạt cả hai cực đoan. Demo Mục 5 cho bạn tự kéo ngưỡng và nhìn 3 con số này đổi trực tiếp.

🧠 Vì sao F1 dùng trung bình ĐIỀU HOÀ chứ không phải trung bình cộng?
Thử một model "ăn gian" cực đoan: chỉ báo dương tính đúng 1 lần duy nhất khi cực kỳ chắc chắn, còn lại luôn im lặng — đạt $\text{Precision} = 1{,}0$ (mọi lần báo đều đúng) nhưng $\text{Recall} = 0{,}01$ (bỏ sót gần như toàn bộ ca dương tính thật). Đã tính xác minh:
  • Nếu dùng trung bình cộng $(P+R)/2 = (1{,}0 + 0{,}01)/2 = 0{,}505$ — nghe vẫn "được một nửa điểm", che giấu hoàn toàn việc model gần như vô dụng.
  • Trung bình điều hoà (F1 thật): $2 \times 1{,}0 \times 0{,}01 / (1{,}0 + 0{,}01) \approx 0{,}0198$ — sụp xuống gần $0$, phản ánh đúng thực tế: một con số cực thấp đủ để kéo sập toàn bộ điểm số, bất kể con số còn lại đẹp cỡ nào.
Đây chính xác là lý do chọn trung bình điều hoà thay vì trung bình cộng: nó buộc model phải khá ở cả hai mặt trận cùng lúc, không thể lách bằng cách tối đa hoá một chỉ số rồi bỏ mặc chỉ số còn lại.
⚠️ Cạm bẫy: chọn nhầm thước đo có thể trả giá bằng mạng sống
Quay lại ví dụ tầm soát bệnh: nếu đội phát triển tối ưu hoá theo accuracy, model "luôn đoán âm tính" ở trên là lựa chọn tốt nhất có thể ($99\%$!) — và nó bỏ sót $100\%$ người bệnh. Với bài toán mà bỏ sót (FN) đắt hơn nhiều báo động giả (FP) — tầm soát ung thư, phát hiện gian lận nghiêm trọng, cảnh báo cháy — thước đo đúng là recall, chấp nhận nhiều FP hơn (kiểm tra thêm cũng chỉ tốn thời gian) để đổi lấy ít FN nhất có thể (bỏ sót có thể không cứu được). Ngược lại, hệ thống lọc spam thì FP (email quan trọng bị chặn nhầm) đắt hơn FN (vài email rác lọt qua) — ưu tiên precision. Không có thước đo "đúng" phổ quát — câu hỏi luôn phải là "trong bài toán CỤ THỂ này, sai kiểu nào đắt hơn?" trước khi chọn ngưỡng.

5. Thực hành: bộ phân loại 2D — kéo điểm, xem ranh giới & confusion matrix đổi live

Toàn bộ phần "học" của model 2D chỉ là gradient descent (Bài 2) áp dụng đúng gradient đẹp $\hat{y}-y$ của Mục 2 cho từng trọng số — không có gì bí ẩn hơn vòng lặp dưới đây, chạy full-batch trên cả tập điểm mỗi bước:

train_logistic.js (đúng vòng lặp demo dưới đây gọi, self-test đối chiếu)
function trainLogistic(points, lr, epochs) {
  let w1 = 0, w2 = 0, b = 0;           // khoi tao 0 — khong ngau nhien, tai lap duoc
  const n = points.length;
  for (let e = 0; e < epochs; e++) {
    let g1 = 0, g2 = 0, gb = 0;
    for (const p of points) {
      const err = sigmoid(w1*p.x + w2*p.y + b) - p.label;  // = dL/dz (Muc 2)
      g1 += err * p.x; g2 += err * p.y; gb += err;
    }
    w1 -= lr * g1 / n; w2 -= lr * g2 / n; b -= lr * gb / n;  // w = w - eta*grad
  }
  return { w1, w2, b };
}
// trainLogistic(12 diem mac dinh, lr=0.15, 400 buoc) -> 12/12 dung, w1~0.998 w2~-0.041 b~-4.572

Bấm vào khung để thêm điểm lớp đang chọn, kéo điểm có sẵn để di chuyển. Sau mỗi thay đổi, model huấn luyện lại từ đầu bằng đúng hàm trên (không ngẫu nhiên — tái lập được), vẽ lại đường ranh giới, và cập nhật confusion matrix theo ngưỡng đang chọn:

🎯 Demo — phân loại 2D: kéo điểm, xem boundary & metrics đổi live
Đang tải…
  Đoán: Lớp 1 Đoán: Lớp 0
Thật: Lớp 1
Thật: Lớp 0

Kéo một điểm xanh (lớp 1) sang bên trái đường ranh giới để tạo ra 1 False Negative, rồi kéo thanh trượt ngưỡng xuống thấp — xem model "rộng rãi" hơn kéo nó về đúng lớp và Recall tăng trở lại.

Đối chiếu công nghiệp: PyTorch không dùng sigmoid() + cross-entropy tách rời như bài viết — nó gộp hai bước thành BCEWithLogitsLoss, nhận thẳng logit $z$ (chưa qua sigmoid). Lý do là ổn định số học: tính $\sigma(z)$ trước rồi mới $\log$ có thể mất chính xác hoặc tràn số ở $z$ cực trị (đúng cạm bẫy Mục 2) — công thức gộp dùng biến thể log-sum-exp tính trực tiếp từ $z$, tránh hoàn toàn bước trung gian nguy hiểm:

logistic_regression.py (chạy ngoài browser — cần cài PyTorch)
# Doi chieu 1-1 voi demo 2D — cai dat: pytorch.org/get-started/locally
import torch

X = torch.tensor([[2.,2.],[2.,4.],[3.,3.],[4.,2.],[3.,5.],[4.,6.],
                   [7.,6.],[8.,7.],[6.,8.],[8.,5.],[7.,8.],[9.,6.]])
y = torch.tensor([0.,0.,0.,0.,0.,0., 1.,1.,1.,1.,1.,1.])

w = torch.zeros(2, requires_grad=True)
b = torch.zeros(1, requires_grad=True)
opt = torch.optim.SGD([w, b], lr=0.15)
loss_fn = torch.nn.BCEWithLogitsLoss()   # nhan LOGIT tho, tu lo sigmoid + log on dinh

for epoch in range(400):
    opt.zero_grad()
    z = X @ w + b                        # logit tho — KHONG goi sigmoid() truoc
    loss = loss_fn(z, y)                 # gop sigmoid + cross-entropy, on dinh so hoc
    loss.backward()
    opt.step()

print(torch.sigmoid(X @ w + b))          # xac suat cuoi — khop demo 2D tren trang

Tóm lược

  • Hồi quy + ngưỡng cứng vỡ trận khi có outlier về độ lớn: 1 điểm $x=50$ kéo ngưỡng cắt từ $x\approx4{,}70$ về $x\approx2{,}09$, làm $x=3$ bị đoán nhầm — cần hàm nén về xác suất, không phải đường thẳng vô hạn.
  • Sigmoid $\sigma(z)=1/(1+e^{-z})$ nén mọi số thực về $(0,1)$, $\sigma(0)=0{,}5$ — model logistic là $\hat{y}=\sigma(wx+b)$.
  • Cross-entropy phạt theo độ tự tin sai (tăng phi tuyến, không tuyến tính); gradient của nó $= \hat{y}-y$ KHÔNG tiêu biến, còn gradient MSE nhân thêm $\sigma'(z)$ có thể nhỏ hơn 200 lần ở vùng bão hoà — lý do kỹ thuật thật sự để không dùng MSE cho phân loại.
  • $\log(0)$ có 2 kiểu hỏng: tự tin sai cực độ → Infinity; tự tin ĐÚNG cực độ → NaN từ số hạng thừa $0 \times \log(0)$ — clip xác suất vào $[\epsilon, 1-\epsilon]$ để tránh cả hai.
  • Decision boundary logistic luôn là đường thẳng; đa lớp dùng softmax (tổng luôn $=1$) + argmax.
  • Accuracy đánh lừa trên dữ liệu lệch — model "luôn đoán âm tính" đạt $99\%$ accuracy mà bỏ sót $100\%$ ca dương tính; precision/recall/F1 và lựa chọn ngưỡng mới phản ánh đúng loại sai nào đắt giá hơn trong bài toán cụ thể.

Tải file code thực hành minh họa bài học

File JavaScript gồm sigmoid, cross-entropy, softmax, confusion matrix và logistic regression 2D của demo, với self-test đối chiếu đúng mọi con số trích dẫn trong bài (chạy node logistic_regression.js):

Tải về logistic_regression.js

📖 Tài liệu tham khảo

Bài viết liên quan trong series

Bài 2: Gradient Descent & đạo hàm Bài 4: Học không giám sát: K-means & PCA Quay lại Lộ trình Series Trí Tuệ Nhân Tạo

Bình luận