Hồi quy Softmax
Mục tiêu
Phần tiêu đề “Mục tiêu”Sau bài này, bạn sẽ:
- Hiểu vì sao ghép nhiều bộ phân loại nhị phân (one-vs-rest) chưa cho xác suất đúng nghĩa, và hồi quy softmax (softmax regression) giải quyết điều đó thế nào.
- Tính được hàm softmax bằng tay, giải thích được vì sao nó dùng hàm mũ, và cài đặt được bản ổn định số bằng mẹo trừ logit lớn nhất.
- Tự dẫn được hàm mất mát cross-entropy với nhãn one-hot và gradient , rồi huấn luyện mô hình bằng gradient descent.
- Nhận ra ranh giới quyết định (decision boundary) của hồi quy softmax là tuyến tính từng đoạn, và biết khi nào không nên dùng softmax.
Cần biết trước
Phần tiêu đề “Cần biết trước”- Hồi quy Logistic, thuộc phần Học máy (Đã học)
Trực giác
Phần tiêu đề “Trực giác”Bạn có một bông hoa diên vĩ (iris) và đo được cánh hoa (petal) dài 4.9 cm, rộng 1.5 cm. Nó thuộc loài nào trong ba loài: setosa, versicolor hay virginica? Đây là bộ dữ liệu iris, do nhà thống kê Ronald Fisher công bố năm 1936: 150 bông hoa, mỗi loài 50 bông. Bài này chỉ dùng hai số đo cánh hoa, để vẽ được lên mặt phẳng. Bông đầu tiên của mỗi loài trong bộ dữ liệu trông như sau:
| Loài | Dài cánh hoa (cm) | Rộng cánh hoa (cm) |
|---|---|---|
| setosa | 1.4 | 0.2 |
| versicolor | 4.7 | 1.4 |
| virginica | 6.0 | 2.5 |
Bông hoa của bạn nằm giữa versicolor và virginica, nên câu trả lời tốt không chỉ là một tên loài, mà là ba xác suất cộng lại bằng 1, ví dụ “64% versicolor, 35% virginica”.
Cách thứ nhất: ghép ba bộ phân loại nhị phân
Phần tiêu đề “Cách thứ nhất: ghép ba bộ phân loại nhị phân”Bạn đã biết hồi quy logistic cho hai lớp. Cách đơn giản nhất là huấn luyện ba mô hình riêng, mỗi mô hình trả lời một câu hỏi có/không: “có phải setosa không?”, “có phải versicolor không?”, “có phải virginica không?”. Cách này gọi là one-vs-rest (OvR, một lớp với phần còn lại). Huấn luyện ba mô hình đó bằng LogisticRegression trên 105 bông hoa (70% dữ liệu, đã chuẩn hóa), rồi hỏi về bông hoa của bạn:
| Câu hỏi | Xác suất “có” |
|---|---|
| Có phải setosa? | 0.008 |
| Có phải versicolor? | 0.425 |
| Có phải virginica? | 0.350 |
| Tổng | 0.783 |
Hai điều không ổn:
- Tổng không bằng 1. Mỗi mô hình được huấn luyện riêng, không mô hình nào biết hai mô hình kia nói gì. Trên cả 150 bông của bộ dữ liệu, tổng này dao động từ 0.405 tới 1.539.
- Cả ba mô hình đều nói “không”, vì không xác suất nào vượt 0.5. Lấy lớp có xác suất lớn nhất vẫn ra versicolor, nhưng mô hình “có phải versicolor?” gặp khó thật sự: versicolor nằm giữa hai loài kia, nên một đường thẳng không tách được nó khỏi “phần còn lại”.
Cách thứ hai: cho mỗi loài một điểm
Phần tiêu đề “Cách thứ hai: cho mỗi loài một điểm”Thay vì ba câu hỏi rời, hãy cho một mô hình chấm cho mỗi loài một điểm, rồi so các điểm với nhau. Giả sử mô hình chấm cho bông hoa của bạn ba điểm, gọi là logit: setosa , versicolor , virginica . Điểm càng cao, loài đó càng hợp.
Đổi ba điểm này thành xác suất thế nào? Chia mỗi điểm cho tổng thì không được: có điểm âm, và tổng lại bằng đúng 0. Cách làm của softmax là lấy mũ từng điểm trước (kết quả luôn dương), rồi mới chia cho tổng:
| Loài | Logit | Xác suất | |
|---|---|---|---|
| setosa | −3.0 | 0.0498 | 0.0053 |
| versicolor | 1.8 | 6.0496 | 0.6422 |
| virginica | 1.2 | 3.3201 | 0.3525 |
| Tổng | 9.4195 | 1.0000 |
Ví dụ . Ba xác suất cộng lại bằng 1, giữ đúng thứ tự của các điểm, và versicolor thắng.
Bài toán của bài này là: cho mỗi lớp một vectơ trọng số để chấm điểm, đổi các điểm thành xác suất cộng lại bằng 1, rồi học các trọng số sao cho lớp đúng của mỗi mẫu nhận xác suất cao.
Lý thuyết
Phần tiêu đề “Lý thuyết”Phát biểu bài toán
Phần tiêu đề “Phát biểu bài toán”Có lớp, đánh số (với iris, ). Mỗi mẫu có đặc trưng và một nhãn là một trong lớp. Đây là phân loại nhiều lớp (multiclass classification): mỗi mẫu thuộc đúng một lớp.
Hồi quy softmax cho mỗi lớp một vectơ trọng số (có phần tử) và một hệ số tự do . Điểm của lớp là logit:
Mỗi logit là một mô hình tuyến tính như ở bài Hồi quy tuyến tính, chỉ khác là có mô hình chạy song song trên cùng một . Với iris dùng 2 đặc trưng, mô hình có trọng số và 3 hệ số tự do. Gom logit thành vectơ .
Hàm softmax
Phần tiêu đề “Hàm softmax”Softmax đổi vectơ logit thành vectơ xác suất :
Tử số là mũ của logit lớp ; mẫu số là tổng mũ của mọi logit, giống nhau cho mọi lớp. Đọc là “xác suất mô hình gán cho lớp ”. Lớp dự đoán là lớp có lớn nhất.
Vì sao lại là hàm mũ? Vì nó cho đúng ba tính chất cần có:
- Luôn dương. với mọi , kể cả âm, nên mọi xác suất đều dương, và chia cho tổng là ra các số cộng lại bằng 1.
- Giữ thứ tự. đồng biến: logit lớn hơn thì xác suất lớn hơn. Lớp có xác suất lớn nhất cũng chính là lớp có logit lớn nhất.
- Khuếch đại khác biệt. Chia hai xác suất cho nhau thì mẫu số triệt tiêu, rồi dùng :
Hai logit chênh nhau 1 thì xác suất chênh nhau lần; chênh nhau 2 thì lần. Trong ví dụ hoa iris, versicolor hơn virginica điểm, nên .
Cái tên “softmax” đến từ chỗ nó là một bản “mềm” của việc chọn giá trị lớn nhất (max, hay đúng hơn là argmax): lớp có logit lớn nhất nhận phần lớn xác suất, nhưng các lớp khác vẫn được một phần, và phần đó thay đổi trơn khi logit thay đổi. Tính trơn này là thứ cho phép lấy đạo hàm để huấn luyện.
Cộng hằng số không đổi gì, và mẹo trừ max
Phần tiêu đề “Cộng hằng số không đổi gì, và mẹo trừ max”Công thức tỉ số ở trên cho thấy chỉ hiệu giữa các logit là quan trọng. Kiểm tra trực tiếp: cộng cùng một số vào mọi logit, rồi tách :
Dòng thứ hai đặt ra ngoài tổng ở mẫu số, rồi giản ước với ở tử số.
Tính chất này cứu máy tính khỏi tràn số (overflow). Số thực 64 bit lớn nhất khoảng , tức chỉ chứa được khi . Nếu logit là , máy tính ra vô cực, rồi vô cực chia vô cực ra nan (not a number). Mẹo: trừ logit lớn nhất khỏi mọi logit trước khi lấy mũ. Logit thành , mũ lớn nhất là , không thể tràn, và theo đẳng thức trên, kết quả vẫn y hệt: đó cũng chính là logit của bông hoa iris cộng thêm 1000, nên xác suất vẫn là . Mọi thư viện đều cài softmax theo cách này. Ô code thứ nhất thử cả hai cách.
Với hai lớp, softmax chính là sigmoid
Phần tiêu đề “Với hai lớp, softmax chính là sigmoid”Đặt . Chia cả tử và mẫu của cho :
Vậy hồi quy softmax hai lớp là hồi quy logistic với điểm , tức và . Ví dụ, logit cho . Hồi quy logistic là trường hợp riêng của hồi quy softmax, nên tên chính thức của hồi quy softmax là hồi quy logistic đa thức (multinomial logistic regression).
Phép trừ cũng cho thấy một điều: hai bộ tham số khác nhau có thể cho cùng một mô hình. Cộng cùng một vectơ vào và thì hiệu không đổi. Mục huấn luyện ở dưới sẽ quay lại điểm này.
Nhãn one-hot và cross-entropy
Phần tiêu đề “Nhãn one-hot và cross-entropy”Để so với nhãn thật, viết nhãn cũng thành một vectơ phần tử: phần tử của lớp đúng bằng 1, còn lại bằng 0. Cách viết này gọi là mã hóa one-hot (one-hot encoding). Với iris:
| Nhãn | |
|---|---|
| setosa | |
| versicolor | |
| virginica |
Không dùng thẳng nhãn số 0, 1, 2, vì như vậy là ngầm nói virginica “lớn hơn” versicolor và “xa” setosa hơn, điều không có nghĩa với tên loài.
Hàm mất mát của một mẫu là cross-entropy:
Ở đây là logarit tự nhiên. Vì là one-hot, mọi số hạng có đều biến mất, chỉ còn số hạng của lớp đúng. Gọi lớp đúng là :
Hàm mất mát chỉ đơn giản là trừ logarit của xác suất mà mô hình gán cho lớp đúng. Với bông hoa iris là versicolor: . Nếu nó thật ra là virginica thì , còn nếu là setosa thì : gán xác suất gần 0 cho lớp đúng bị phạt rất nặng. Với , công thức này chính là log loss của hồi quy logistic, viết gọn lại.
Trên mẫu huấn luyện, hàm mất mát là trung bình:
Vì sao chọn cross-entropy mà không chọn MSE? Cũng như log loss, làm nhỏ tương đương với làm lớn xác suất mà mô hình gán cho toàn bộ nhãn của tập huấn luyện (cực đại likelihood), và nó cho gradient rất gọn, như mục dưới.
Một mốc để nhớ: lúc mọi tham số bằng 0, mọi logit bằng 0, softmax chia đều cho mỗi lớp, nên . Với 3 lớp, đó là . Mô hình đã học được gì đó thì phải nhỏ hơn số này.
Cần đạo hàm của theo từng logit . Cách gọn nhất là viết thẳng theo logit.
Bước 1: viết theo . Thay định nghĩa softmax vào , rồi dùng và :
Bước 2: lấy đạo hàm theo . Số hạng đầu có đạo hàm nếu , và 0 nếu . Đó chính là , vì đúng khi . Số hạng thứ hai có dạng với . Đạo hàm của là nhân đạo hàm của , và trong tổng chỉ số hạng phụ thuộc :
Bước 3: cộng lại.
Đọc bằng lời: gradient theo logit là xác suất dự đoán trừ nhãn one-hot. Với bông hoa iris (lớp đúng versicolor): . Gradient descent đi ngược gradient, nên nó tăng logit của lớp đúng và giảm logit của các lớp sai, lớp sai nào đang được nhiều xác suất (virginica) thì bị giảm mạnh hơn. Các thành phần luôn cộng lại bằng 0, vì cả lẫn đều cộng lại bằng 1.
Bước 4: đi tiếp tới trọng số. Logit thay đổi theo với tốc độ , và theo với tốc độ 1. Theo quy tắc hàm hợp (chain rule), nhân gradient theo logit với hai tốc độ này:
Đúng dạng của hồi quy logistic, nay lặp lại cho mỗi lớp.
Huấn luyện bằng gradient descent
Phần tiêu đề “Huấn luyện bằng gradient descent”Viết cho cả tập huấn luyện. Trong bài này, chỉ gồm các đặc trưng ( hàng, cột, không có cột số 1), còn hệ số tự do viết riêng. Xếp các thành các cột của ma trận ( hàng, cột) và các thành vectơ . Khi đó:
- là ma trận logit, hàng cột: hàng là . Số hạng chỉ có nghĩa là cộng vào mọi hàng.
- là softmax của từng hàng của ; là ma trận nhãn one-hot, cùng kích thước.
Lấy trung bình gradient của mẫu (mỗi mẫu là một hàng của , nhân với ) được:
So với MSE ở bài Gradient Descent, : cùng hình dạng “đặc trưng nhân sai lệch”. Quy tắc cập nhật vẫn là , . Ô code thứ hai cài đặt đúng hai dòng này.
Ba điều cần biết khi huấn luyện:
- Không có công thức nghiệm, như hồi quy logistic, nên phải lặp. Tin tốt: là hàm lồi theo , không có hố phụ.
- Nghiệm không duy nhất. Cộng cùng một vectơ vào mọi (và cùng một số vào mọi ) thì mọi logit cộng thêm , mà softmax bất biến với việc cộng cùng một số. Đáy của là cả một “rãnh” chứ không phải một điểm. Regularization (bài Ridge, Lasso, Elastic Net) chọn ra điểm có trọng số nhỏ nhất trong rãnh;
LogisticRegressioncủa scikit-learn có phạt L2 bật sẵn (C=1.0). - Lớp tách được hoàn toàn thì trọng số phình mãi. Setosa tách hẳn khỏi hai loài kia bằng một đường thẳng. Không có regularization, mô hình có thể làm xác suất của setosa gần 1 hơn nữa bằng cách tăng trọng số, nên cứ giảm chậm mãi mà không dừng. Ô code thứ hai cho thấy điều này.
Từ 3 lớp trở lên, LogisticRegression của scikit-learn (bộ giải mặc định lbfgs) huấn luyện đúng mô hình softmax này. Tham số multi_class trong các hướng dẫn cũ đã bị bỏ ở các bản scikit-learn mới, đừng truyền nó.
Ranh giới quyết định
Phần tiêu đề “Ranh giới quyết định”Mô hình dự đoán lớp có lớn nhất, tức lớp có logit lớn nhất (softmax giữ thứ tự). Ranh giới giữa lớp và lớp là nơi hai logit bằng nhau:
Đây là một phương trình tuyến tính theo : với 2 đặc trưng, nó là một đường thẳng. Vùng của mỗi lớp là nơi logit của nó thắng mọi logit khác, tức giao của các nửa mặt phẳng, nên là một vùng lồi. Ghép các vùng lại, ranh giới giữa chúng là tuyến tính từng đoạn (piecewise linear): các đoạn thẳng gặp nhau tại những điểm mà ba logit bằng nhau. Ô code thứ ba vẽ ranh giới này cho iris.
Softmax trong mạng nơ-ron và LLM
Phần tiêu đề “Softmax trong mạng nơ-ron và LLM”Lớp cuối của hầu hết mạng nơ-ron phân loại chính là một hồi quy softmax: các lớp phía trước biến đổi thành đặc trưng mới, còn lớp cuối tính logit, áp softmax, và huấn luyện bằng cross-entropy với gradient như trên. Mô hình ngôn ngữ lớn cũng vậy, với là số token trong từ vựng (hàng chục nghìn): mỗi bước, nó cho một logit cho mỗi token rồi softmax chọn token kế tiếp. Tham số temperature mà bạn chỉnh khi gọi API chỉ là chia mọi logit cho một số trước softmax, như bài Sử dụng API văn bản. Mục Minh họa cho thấy việc co giãn logit làm gì.
Giới hạn
Phần tiêu đề “Giới hạn”- Ranh giới luôn tuyến tính từng đoạn. Lớp có hình dạng phức tạp (ví dụ một lớp nằm trong vòng tròn của lớp khác) cần đặc trưng mới, hoặc mô hình khác như bài Decision Tree và Random Forest hay mạng nơ-ron.
- Mỗi mẫu đúng một lớp. Bài toán một mẫu có nhiều nhãn cùng lúc không dùng softmax (hộp thứ hai ở mục Lỗi hay gặp).
- Xác suất chưa chắc đáng tin. Hai mô hình có cùng độ chính xác vẫn có thể cho xác suất khác nhau khá xa (hộp thứ ba ở mục Lỗi hay gặp).
Minh họa
Phần tiêu đề “Minh họa”Bảng dưới lấy logit của bông hoa iris, , nhân cả ba với cùng một số , rồi tính softmax. Nhân với cũng là chia cho nhiệt độ .
| Logit dùng | setosa | versicolor | virginica |
|---|---|---|---|
| 0.3333 | 0.3333 | 0.3333 | |
| 0.0495 | 0.5460 | 0.4045 | |
| (gốc) | 0.0053 | 0.6422 | 0.3525 |
| 0.0053 | 0.6422 | 0.3525 | |
| 0.0001 | 0.7685 | 0.2315 | |
| 0.0000 | 0.9975 | 0.0025 |
Đọc bảng từ trên xuống:
- Logit bằng nhau thì xác suất chia đều. Hàng đầu là mô hình lúc chưa học gì: mỗi lớp , và cross-entropy là .
- Cộng thêm một hằng số không đổi gì. Hàng giống hệt hàng gốc: đây là tính chất cho phép mẹo trừ max.
- Nhân với số lớn làm phân phối nhọn. Thứ tự ba lớp không bao giờ đổi, nhưng với , versicolor nhận gần hết xác suất: softmax tiến tới argmax, chọn hẳn một lớp. Nhân với số nhỏ thì ngược lại, phân phối phẳng dần về .
Điều này cũng giải thích vì sao trọng số phình to làm mô hình “tự tin” hơn: nhân mọi , với 2 thì mọi logit nhân với 2, ranh giới không đổi chỗ, nhưng xác suất bị đẩy về gần 0 và 1.
Ví dụ code
Phần tiêu đề “Ví dụ code”Ba ô dưới đây chạy độc lập. Ô thứ nhất chỉ dùng NumPy. Ô thứ hai và thứ ba lần đầu chạy lâu hơn, vì trình duyệt phải tải thêm scikit-learn (và Matplotlib cho ô thứ ba).
Ô đầu tiên cài đặt softmax theo hai cách, thử với logit của bông hoa iris, với logit cộng thêm 1000, và kiểm tra trường hợp .
Softmax ổn định số bằng NumPy
import numpy as np
def softmax_naive(z): # Cách ngây thơ: lấy mũ thẳng từng logit. e = np.exp(z) return e / e.sum()
def softmax(z): # Trừ logit lớn nhất trước: kết quả không đổi, mũ lớn nhất là e^0 = 1. e = np.exp(z - z.max()) return e / e.sum()
# Ba logit của một bông hoa: setosa, versicolor, virginica.z = np.array([-3.0, 1.8, 1.2])p = softmax(z)print("p =", p.round(4), f" sum = {p.sum():.4f}")
# Cộng cùng một hằng số vào mọi logit: xác suất giữ nguyên.print("z + 5 =", softmax(z + 5).round(4))
# Logit lớn: e^1001.8 vượt quá số thực lớn nhất (khoảng 1.8e308).big = z + 1000with np.errstate(over="ignore", invalid="ignore"): print("naive =", softmax_naive(big))print("stable =", softmax(big).round(4))
# K = 2: softmax của (z1, z2) bằng sigmoid của z1 - z2.z2 = np.array([1.8, 1.2])sigmoid = 1 / (1 + np.exp(-(z2[0] - z2[1])))print("K=2 =", softmax(z2).round(4), f" sigmoid = {sigmoid:.4f}")Lần chạy đầu cần tải Python, khoảng 10 MB.
- Logit cho , tổng bằng 1, đúng như bảng ở mục Trực giác. Cộng 5 vào mọi logit không đổi gì.
- Cộng 1000: cách ngây thơ cho
[nan nan nan]vì tràn thành vô cực. Cách trừ max cho đúng xác suất cũ. - Dòng cuối: softmax của cho lớp đầu , đúng bằng .
Ô thứ hai huấn luyện hồi quy softmax bằng batch gradient descent trên iris với hai đặc trưng cánh hoa. Dữ liệu được chia 105 bông để huấn luyện, 45 bông để kiểm tra (stratify=y giữ mỗi loài 15 bông trong tập test), rồi chuẩn hóa z-score bằng StandardScaler học từ tập train. Mô hình xuất phát từ , , , chạy 1000 epoch, rồi so với LogisticRegression của scikit-learn.
Hồi quy softmax bằng gradient descent
import numpy as npfrom sklearn.datasets import load_irisfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import train_test_splitfrom sklearn.preprocessing import StandardScaler
X, y = load_iris(return_X_y=True)X = X[:, 2:] # chiều dài và chiều rộng cánh hoa (cm)X_tr, X_te, y_tr, y_te = train_test_split( X, y, test_size=0.3, random_state=0, stratify=y)scaler = StandardScaler().fit(X_tr) # chỉ học từ tập trainA_tr, A_te = scaler.transform(X_tr), scaler.transform(X_te)m, K = len(y_tr), 3Y = np.eye(K)[y_tr] # nhãn one-hot: m hàng, K cột
def softmax(Z): E = np.exp(Z - Z.max(axis=1, keepdims=True)) # trừ max của từng hàng return E / E.sum(axis=1, keepdims=True)
# Mỗi cột của W là vectơ trọng số w_k của một lớp.W, b, eta = np.zeros((2, K)), np.zeros(K), 0.5for epoch in range(1001): P = softmax(A_tr @ W + b) if epoch in (0, 1, 10, 100, 1000): loss = -np.mean(np.log(P[np.arange(m), y_tr])) print(f"epoch {epoch:4d}: loss = {loss:.4f}") G = P - Y # gradient theo logit: y_hat - y W -= eta * A_tr.T @ G / m b -= eta * G.mean(axis=0)
acc = np.mean(np.argmax(A_te @ W + b, axis=1) == y_te)print(f"GD test acc = {acc:.4f}")# Từ 3 lớp trở lên, LogisticRegression mặc định dùng softmax.clf = LogisticRegression().fit(A_tr, y_tr)print(f"sklearn test acc = {clf.score(A_te, y_te):.4f}")flower = scaler.transform([[4.9, 1.5]]) # cánh hoa 4.9 cm x 1.5 cmprint("GD p =", softmax(flower @ W + b)[0].round(3))print("sklearn p =", clf.predict_proba(flower)[0].round(3))Lần chạy đầu cần tải Python, khoảng 10 MB.
- Epoch 0, loss là 1.0986, đúng : mọi lớp đang được . Sau 10 epoch còn 0.4657, sau 100 epoch 0.1836, sau 1000 epoch 0.0976.
- Loss vẫn đang giảm ở epoch 1000. Nếu cho chạy tới epoch 5000 (sửa cả
range(1001)lẫn danh sách epoch được in), nó chỉ xuống 0.0891, còn trọng số thì tiếp tục lớn dần. Đây là hiện tượng setosa tách được hoàn toàn đã nói ở mục Lý thuyết. - Hai mô hình có cùng độ chính xác trên tập test, 0.9778, tức 44 trên 45 bông.
- Với bông hoa 4.9 cm × 1.5 cm, scikit-learn cho , rất gần bảng ở mục Trực giác: logit chưa làm tròn của nó là . Mô hình GD tự viết cho versicolor 0.771, tự tin hơn hẳn, vì nó không có phạt L2 nên trọng số lớn hơn.
Ô thứ ba dùng LogisticRegression (sau StandardScaler, trong một pipeline) để tô màu mặt phẳng theo lớp dự đoán, rồi đánh giá trên tập test bằng ma trận nhầm lẫn (confusion matrix) và classification_report.
Ranh giới quyết định và đánh giá trên tập test
import matplotlib.pyplot as pltimport numpy as npfrom sklearn.datasets import load_irisfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import classification_report, confusion_matrixfrom sklearn.model_selection import train_test_splitfrom sklearn.pipeline import make_pipelinefrom sklearn.preprocessing import StandardScaler
iris = load_iris()X, y = iris.data[:, 2:], iris.target # hai đặc trưng cánh hoa (cm)X_tr, X_te, y_tr, y_te = train_test_split( X, y, test_size=0.3, random_state=0, stratify=y)model = make_pipeline(StandardScaler(), LogisticRegression())model.fit(X_tr, y_tr)
# Tô màu mỗi điểm của lưới theo lớp có xác suất lớn nhất.g1, g2 = np.meshgrid(np.linspace(0.5, 7.5, 300), np.linspace(0, 2.8, 300))grid = np.c_[g1.ravel(), g2.ravel()]region = model.predict(grid).reshape(g1.shape)fig, ax = plt.subplots(figsize=(6, 4.5))ax.contourf(g1, g2, region, levels=[-0.5, 0.5, 1.5, 2.5], colors=["#e8d5b7", "#c9d9c3", "#c7cfe0"])for k, marker in enumerate(["o", "s", "^"]): pts = X_tr[y_tr == k] ax.scatter(pts[:, 0], pts[:, 1], marker=marker, edgecolor="k", facecolor="white", label=iris.target_names[k])ax.set_xlabel("petal length (cm)")ax.set_ylabel("petal width (cm)")ax.legend(loc="upper left")plt.show()
# Đánh giá trên tập test: hàng là lớp thật, cột là lớp dự đoán.y_pred = model.predict(X_te)print(confusion_matrix(y_te, y_pred))print(classification_report(y_te, y_pred, digits=3, target_names=iris.target_names))Lần chạy đầu cần tải Python, khoảng 10 MB.
Hình cho thấy ranh giới tuyến tính từng đoạn: hai đoạn thẳng chia mặt phẳng thành ba vùng. Ba đường , , gặp nhau ở một điểm nằm ngoài khung hình (chiều dài cánh hoa âm), nên trong khung bạn chỉ thấy hai đoạn. Ranh giới setosa nằm giữa khoảng trống rộng, còn ranh giới versicolor–virginica phải đi qua chỗ hai nhóm chồng lên nhau.
Ma trận nhầm lẫn (hàng là lớp thật, cột là lớp dự đoán) cho thấy lỗi duy nhất: một bông virginica bị đoán là versicolor. Đó là bông có cánh hoa 5.6 cm × 1.4 cm, hẹp như versicolor; mô hình cho nó versicolor 0.593, virginica 0.405. Báo cáo có precision, recall và F1 cho từng lớp, rồi hai dòng gộp: macro avg lấy trung bình cộng của ba lớp, mỗi lớp nặng như nhau, còn weighted avg lấy trung bình theo số mẫu của mỗi lớp. Ở đây mỗi lớp có đúng 15 mẫu nên hai dòng bằng nhau: precision 0.979, recall và F1 0.978. Ý nghĩa của các chỉ số này và khi nào chọn cách gộp nào nằm ở bài Đánh giá mô hình.
Lỗi hay gặp
Phần tiêu đề “Lỗi hay gặp”Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Tóm tắt và đọc thêm
Phần tiêu đề “Tóm tắt và đọc thêm”Ý chính:
- Hồi quy softmax cho mỗi lớp một logit , rồi . Khác ba bộ phân loại one-vs-rest rời nhau, các xác suất luôn dương, giữ thứ tự của logit và cộng lại bằng 1.
- Softmax chỉ phụ thuộc hiệu giữa các logit: cộng cùng một hằng số không đổi gì, nên trừ logit lớn nhất trước khi lấy mũ để tránh tràn số. Với , softmax là , tức hồi quy logistic.
- Với nhãn one-hot, cross-entropy thu về , bắt đầu từ khi mô hình chưa học gì. Gradient theo logit là , nên , và huấn luyện bằng gradient descent.
- Ranh giới quyết định là tuyến tính từng đoạn. Softmax cũng là lớp cuối của mạng nơ-ron phân loại và của LLM; nó chỉ dùng cho bài toán mỗi mẫu đúng một lớp.
Đọc thêm:
- Vũ Hữu Tiệp (2017). Machine Learning cơ bản, Bài 13: Softmax Regression. Tiếng Việt, đi từ one-vs-rest tới softmax, có mục ổn định số và code NumPy. Ký hiệu khác: là số lớp, là số mẫu, hệ số tự do gộp vào bằng cách thêm số 1 vào đầu .
- Zhang, A., Lipton, Z. C., Li, M., Smola, A. J. (2023). Dive into Deep Learning, mục 4.1: Softmax Regression. One-hot, softmax, cross-entropy theo góc nhìn likelihood và lý thuyết thông tin, dẫn gradient theo logit, có bài tập về nhiệt độ.
- scikit-learn developers (2007–2026). scikit-learn 1.8 User Guide, mục 1.1.11.2: Multinomial Case. Hàm mục tiêu thật của
LogisticRegressionnhiều lớp, và ghi chú vì sao dùng vectơ trọng số dù là đủ. - Fisher, R. A. (1936). The Use of Multiple Measurements in Taxonomic Problems. Annals of Eugenics 7(2), 179–188. Bài công bố bộ dữ liệu iris dùng trong bài này.
- Bridle, J. S. (1990). Probabilistic Interpretation of Feedforward Classification Network Outputs, with Relationships to Statistical Pattern Recognition. Trong Neurocomputing, Springer, 227–236. Bài thường được dẫn là nơi đặt tên “softmax” cho lớp đầu ra của mạng nơ-ron.
Trình duyệt đang chặn lưu dữ liệu. Tiến độ sẽ mất khi bạn tải lại trang.
Nội dung theo giấy phép CC BY-NC-SA 4.0. Mã nguồn theo giấy phép MIT.Giới thiệu