Bạn chuyển một vector logits thành các giá trị có tổng bằng 1. Công thức nhìn đơn giản nhưng tính exp trực tiếp trên số lớn có thể lỗi trước khi kịp chia cho tổng. Một phép dịch toàn bộ vector giúp tránh vấn đề này mà vẫn giữ ý nghĩa toán học của softmax.
Bài đối chiếu tài liệu SciPy 1.16.2 và PyTorch 2.15 ngày 07/11/2026; không gọi SciPy 1.16.2 là bản mới nhất. Ví dụ chạy Python 3.9.6 thuần, chưa chạy NumPy, SciPy, PyTorch, GPU hoặc model. Helper chỉ xử lý một vector số hữu hạn, không có chiều batch hay attention mask.
Vì sao phép dịch không đổi tỷ lệ?
Softmax lấy exp của từng logit rồi chia cho tổng exp. Nếu cùng trừ một số m khỏi mọi logit, mỗi tử số và mẫu số cùng nhận một hệ số exp(-m). Hệ số chung ấy triệt tiêu trong tỷ lệ.
Chọn m bằng logit lớn nhất khiến mọi hiệu đều không dương. Ít nhất một hiệu bằng 0, có exp bằng 1. Bạn không cần tính exp của logit dương rất lớn nữa; số học máy vẫn có giới hạn nên kết quả được so bằng sai số thay vì yêu cầu bằng tuyệt đối.
1. Tái hiện lỗi rồi viết phiên bản dịch max
Chạy đoạn sau trong file Python riêng. Các logits đều là số do ví dụ tự tạo:
import math
def stable_softmax(logits):
values = list(logits)
if not values or not all(math.isfinite(x) for x in values):
raise ValueError("Can vector huu han, khong rong")
maximum = max(values)
weights = [math.exp(x - maximum) for x in values]
denominator = math.fsum(weights)
return [weight / denominator for weight in weights]
try:
math.exp(1000.0)
except OverflowError:
print("Direct exp overflows in this Python runtime")
else:
raise AssertionError("Expected overflow for this fixture")
small = stable_softmax([0.0, 1.0, 2.0])
large = stable_softmax([1000.0, 1001.0, 1002.0])
assert all(math.isclose(a, b, rel_tol=1e-12)
for a, b in zip(small, large))
assert math.isclose(math.fsum(large), 1.0, abs_tol=1e-12)
assert all(0.0 <= value <= 1.0 for value in large)
print([round(value, 6) for value in large])
Trong runtime đã thử, đoạn cuối cho các giá trị làm tròn 0.090031, 0.244728 và 0.665241. Đây là kết quả của bộ ba số minh họa, không phải confidence thu từ một model thật.
Hai vector chênh nhau cùng 1000 ở mọi vị trí. Assertions xác nhận phân phối gần bằng nhau và tổng gần 1. Chúng không kiểm tra mọi khả năng làm tròn của các dtype hay thiết bị khác nhau.
2. Giữ ca biên trong phép kiểm tra
Nối tiếp file trên để kiểm tra vector một phần tử, các logits bằng nhau và đầu vào không hợp lệ:
assert stable_softmax([7.0]) == [1.0]
assert stable_softmax([5.0, 5.0]) == [0.5, 0.5]
for invalid in [[], [float("nan")], [float("inf")], [-float("inf")]]:
try:
stable_softmax(invalid)
except ValueError:
pass
else:
raise AssertionError(invalid)
Helper cố ý từ chối cả infinity âm. Nhiều pipeline dùng infinity âm để biểu diễn mask, nhưng ca toàn bộ vị trí bị mask cần chính sách riêng. Không bỏ kiểm tra hữu hạn chỉ để helper nhận một định dạng đầu vào mà nó chưa được thiết kế xử lý.
Chuyển hiểu biết này vào thư viện thực tế
Trong code dùng tensor, ưu tiên hàm của thư viện và chọn đúng chiều lớp. Với ma trận nhiều mẫu, chuẩn hóa toàn ma trận khác với chuẩn hóa từng mẫu. Đọc tham số dim hoặc axis, rồi kiểm tra tổng trên đúng chiều bạn định dùng.
Kiểu dữ liệu cũng ảnh hưởng phạm vi và sai số. Kiểm tra dtype đầu vào khi đổi sang mixed precision, thay vì mặc định một fixture Python float chứng minh hành vi float16 trên GPU. Bài không đo tốc độ hoặc chất lượng model khi đổi dtype.
Giới hạn cần nhớ khi đọc kết quả
Trừ max giúp cách tính ổn định hơn về overflow, nhưng không tự xử lý logits NaN, sai thứ tự nhãn hoặc một bộ score chưa được hiệu chỉnh. Có tổng bằng 1 chưa chứng minh xác suất phản ánh đúng tần suất xảy ra trong dữ liệu thật.
Các hiệu âm rất lớn vẫn có thể cho trọng số làm tròn về 0. Đừng dùng helper này làm một triển khai loss hoặc log-probability đầy đủ. Giữ ví dụ để kiểm tra hiểu biết về phép dịch, rồi chọn API chuyên dụng phù hợp với bước tính tiếp theo.

