🔬 Bài 27: Hàm số, Độ dốc và Đạo hàm — Cách máy biết đi hướng nào
Chặng 7 · Toán & Tư duy ML (Bài 26 → 30) · đây là bài 2/5 của chặng.
🎯 Mục tiêu: hiểu hàm số là gì, tính được độ dốc, và nắm được đạo hàm chính là độ dốc tại một điểm — con số quyết định việc máy học được hay không.
👥 Đối tượng: học sinh cấp 2–3, sinh viên, người mới học Python. Cần biết trước: hàm def (Bài 11) và NumPy cơ bản (Bài 21, 26).
📖 Cách đọc 3 lớp: mỗi phần có ba khối màu song song — 🟢 Lớp A trực giác, 🔵 Lớp B cơ chế, 🟣 Lớp C nghiên cứu. Cứ đọc hết Lớp A trước rồi quay lại B và C sau cũng được.
Sau bài này bạn sẽ:
- Giải thích được hàm số như một cỗ máy: đưa số vào, nhận đúng một số ra.
- Tính được độ dốc giữa hai điểm và hiểu nó nói lên điều gì.
- Viết được hàm tính đạo hàm bằng số, không cần thuộc công thức nào.
- Trả lời được: vì sao muốn máy học thì bắt buộc phải có đạo hàm.
Bài 26 dạy máy biểu diễn dữ liệu: mọi thứ đều thành vector và ma trận. Bài này dạy máy một việc khác hẳn và quan trọng hơn — biết đi hướng nào để tốt lên. Khi một mô hình đang đoán sai, nó phải trả lời được câu hỏi: chỉnh tham số lên hay xuống thì sai số giảm? Câu trả lời nằm gọn trong một khái niệm: đạo hàm.
Hình 1 — Hàm số nhận một số và trả về đúng một số. Vẽ tất cả các cặp (vào, ra) lên mặt phẳng thì được đồ thị.
1. Hàm số — cỗ máy vào một số, ra một số
Hãy tưởng tượng một chiếc máy xay: bỏ vào 3 quả cam thì ra một cốc nước cam. Bỏ vào đúng 3 quả cam ấy lần nữa thì vẫn ra đúng cốc nước ấy, không bao giờ ra ly cà phê.
Hàm số làm y hệt vậy, chỉ khác là nó xay số. Đưa vào 3, máy 2x + 1 trả về 7. Lần nào đưa 3 vào cũng ra 7.
Điều kiện duy nhất để được gọi là hàm: một đầu vào chỉ cho đúng một đầu ra. Nếu cùng một số mà lúc ra thế này lúc ra thế kia thì đó không phải hàm.
Trong Python, hàm toán học viết bằng def y như mọi hàm khác. Điểm đáng giá: nếu đưa vào một mảng NumPy, hàm sẽ tính cho toàn bộ mảng cùng lúc mà không cần vòng lặp.
import numpy as np def f(x): return 2*x + 1 print(f(0), f(1), f(5)) # 1 3 11 xs = np.linspace(-3, 3, 7) # [-3 -2 -1 0 1 2 3] print(f(xs)) # [-5 -3 -1 1 3 5 7] - tinh ca mang mot luot
Đó chính là lý do bài trước phải học vector: nhờ nó, một dòng lệnh xử lý được cả nghìn điểm dữ liệu.
Trong Machine Learning, bản thân mô hình chính là một hàm. Hồi quy tuyến tính là hàm f(x) = w·x + b. Một mạng nơ-ron sâu cũng chỉ là một hàm, chỉ có điều nó được ghép từ hàng triệu hàm nhỏ.
Khác biệt duy nhất so với hàm ở lớp phổ thông: w và b không cho sẵn. Chúng là những núm vặn mà máy phải tự dò ra. Toàn bộ phần còn lại của chặng này là câu chuyện máy vặn núm thế nào cho đúng.
2. Độ dốc — đi ngang một bước thì lên được bao nhiêu
Bạn đang leo một con dốc. Đi ngang 1 mét mà lên cao 2 mét thì dốc đứng; đi ngang 1 mét chỉ lên 0,1 mét thì gần như bằng phẳng.
Độ dốc = lên bao nhiêu chia cho đi ngang bao nhiêu. Nó trả lời câu hỏi: nhích x sang phải một chút thì y thay đổi thế nào?
Dốc dương là đang lên, dốc âm là đang xuống, dốc bằng 0 là đang đi trên mặt phẳng.
Giữa hai điểm bất kỳ, độ dốc tính bằng (y₂ − y₁) / (x₂ − x₁). Với đường thẳng, con số này giống nhau ở mọi chỗ. Với đường cong thì không.
def do_doc(f, x1, x2): return (f(x2) - f(x1)) / (x2 - x1) # Duong thang: doc o dau cung nhu nhau print(do_doc(f, 0, 1)) # 2.0 print(do_doc(f, 10, 20)) # 2.0 def g(x): return x**2 # Duong cong: doc thay doi tuy cho, va tuy khoang cach print(do_doc(g, 1, 3)) # 4.0 print(do_doc(g, 1, 1.1)) # 2.1 print(do_doc(g, 1, 1.001)) # 2.001
Hãy nhìn kỹ ba dòng cuối. Hai điểm càng xích lại gần nhau, con số càng bám về 2. Đó không phải trùng hợp — đó là cả nội dung của phần 3.
Trong ML, thứ ta muốn đo độ dốc không phải là y theo x, mà là sai số theo tham số. Câu hỏi thật sự là: tăng trọng số w lên một chút thì mô hình sai nhiều hơn hay ít hơn?
Nếu trả lời được câu đó cho mọi tham số, ta biết ngay phải chỉnh chúng theo hướng nào. Đây chính là cơ chế duy nhất khiến việc “học” của máy trở nên khả thi — thay vì dò ngẫu nhiên hàng tỉ khả năng.
3. Đạo hàm — độ dốc tại đúng một điểm
Trên một đường cong, hỏi “độ dốc giữa hai điểm” thì dễ. Nhưng hỏi độ dốc ngay tại một điểm thì lạ: chỉ có một điểm, lấy đâu ra hai chỗ để so?
Cách giải quyết rất đẹp: lấy điểm thứ hai rồi kéo nó lại gần dần. Càng gần, con số càng ổn định về một giá trị. Giá trị đó gọi là đạo hàm.
Hình dung dễ nhất: đặt một cây thước thẳng sao cho nó chỉ chạm vào đường cong đúng tại điểm đó. Độ dốc của cây thước ấy chính là đạo hàm. Cây thước đó gọi là tiếp tuyến.
Ta không cần thuộc bảng công thức nào. Chỉ cần lấy một khoảng h thật nhỏ rồi đo độ dốc quanh điểm đó. Cách lấy hai bên (trái và phải) cho kết quả chính xác hơn hẳn cách lấy một bên.
def dao_ham(f, x, h=1e-6): return (f(x + h) - f(x - h)) / (2*h) print(dao_ham(g, 1)) # 2.0 -> khop voi 2x = 2 print(dao_ham(g, 3)) # 6.0 -> khop voi 2x = 6 print(dao_ham(g, -2)) # -4.0 -> dang di xuong
Thử với g(x) = x² ở nhiều chỗ, bạn sẽ thấy đạo hàm luôn đúng bằng 2x. Đó là quy luật mà môn Toán chứng minh bằng giới hạn; ở đây ta phát hiện lại nó bằng máy tính.
Khi hàm có nhiều biến đầu vào — và mô hình ML nào cũng vậy — ta lấy đạo hàm theo từng biến một. Gom tất cả lại thành một vector thì được gradient. Nghe lạ tai nhưng nó chỉ là “danh sách các độ dốc”, đúng cái vector của Bài 26.
Gradient nói cho ta hai điều cùng lúc: hướng nào làm sai số tăng nhanh nhất, và tăng mạnh cỡ nào. Muốn giảm sai số thì đi ngược lại. Đó là toàn bộ ý tưởng của gradient descent — thuật toán ở Bài 29, và cũng là thuật toán huấn luyện gần như mọi mô hình hiện nay.
Trong thực tế người ta không tính đạo hàm bằng số như ở Lớp B, vì với hàng triệu tham số thì quá chậm. Thư viện như PyTorch dùng autograd: vừa tính vừa ghi lại đường đi, rồi suy ngược ra đạo hàm chính xác. Nhưng ý nghĩa thì vẫn đúng y như những gì bạn vừa làm.
Hình 2 — Đường cong y = x². Điểm thứ hai càng tiến gần x = 1, đường nối càng gần trùng với tiếp tuyến, và độ dốc càng bám về đúng 2.
⚠️ Chọn h thế nào cho đúng: nhiều người nghĩ h càng nhỏ càng chính xác, nhưng không phải. Nhỏ quá — ví dụ 1e-15 — thì hai giá trị f(x+h) và f(x−h) gần bằng nhau tới mức máy tính làm tròn mất phần khác biệt, kết quả sai bét. Lớn quá thì lại không còn là “tại một điểm”. Khoảng 1e-6 đến 1e-8 là vùng an toàn.
📝 Bảng ghi nhớ
| Khái niệm | Ý nghĩa | Trong Python |
|---|---|---|
| Hàm số | Vào một số, ra đúng một số | def f(x): return 2*x + 1 |
| Tính cho cả mảng | Một dòng xử lý nghìn điểm | f(np.linspace(-3, 3, 7)) |
| Độ dốc giữa hai điểm | Đi ngang bao nhiêu thì lên bấy nhiêu | (f(x2) - f(x1)) / (x2 - x1) |
| Đạo hàm | Độ dốc tại đúng một điểm | (f(x+h) - f(x-h)) / (2*h) |
| Tiếp tuyến | Đường thẳng chạm đường cong tại điểm đó | y = f(a) + m*(x - a) |
| Đạo hàm dương | Đang đi lên → muốn giảm thì lùi lại | dao_ham(g, 3) = 6 |
| Đạo hàm âm | Đang đi xuống → muốn giảm thì tiến tới | dao_ham(g, -2) = -4 |
| Đạo hàm bằng 0 | Đang ở đáy hoặc đỉnh, không dốc về bên nào | dao_ham(g, 0) = 0 |
| Gradient | Vector gồm đạo hàm theo từng tham số | sẽ gặp ở Bài 29 |
✎ Kiểm tra nhanh
Câu 1. Với f(x) = 3x − 2, giá trị f(4) bằng bao nhiêu?
- 10
- 12
- 14
- 5
3×4 − 2 = 12 − 2 = 10. Hàm chỉ là một quy trình tính, cứ thay số vào rồi làm theo đúng thứ tự.Câu 2. Đường thẳng y = 5x + 7 có độ dốc bằng bao nhiêu?
- 7
- 5
- 12
- 35
y = ax + b thì a chính là độ dốc, còn b chỉ quyết định đường thẳng cắt trục dọc ở đâu. Đi ngang 1 đơn vị thì lên 5 đơn vị, ở mọi chỗ đều vậy.Câu 3. Với g(x) = x², độ dốc giữa x = 2 và x = 2,001 gần bằng:
- 2
- 4
- 8
- 0,001
x = 2. Đạo hàm của x² là 2x, nên tại x = 2 ta được 4. Tính tay cũng ra: (2,001² − 2²) / 0,001 = 4,001.Câu 4. Đạo hàm của x² tại x = −3 bằng:
- 9
- 6
- −6
- −3
x² là 2x, nên tại x = −3 ta có 2×(−3) = −6. Dấu âm cho biết ở phía bên trái parabol, đường cong đang đi xuống khi ta tiến sang phải.Câu 5. Trong Machine Learning, đạo hàm cho ta biết điều gì?
- Giá trị nhỏ nhất của sai số là bao nhiêu
- Nên chỉnh tham số theo hướng nào và mạnh cỡ nào để sai số giảm
- Cần thu thập thêm bao nhiêu dữ liệu
- Mô hình đã học xong hay chưa
💻 Thực hành: nhìn thấy đạo hàm bằng mắt
▶ Cách dùng: bấm Khởi động Python một lần (lần đầu mất khoảng 10–20 giây vì phải tải NumPy và Matplotlib), đợi báo sẵn sàng rồi bấm Chạy code. Sửa thoải mái trong ô đen và chạy lại bao nhiêu lần tùy thích.
💡 Thử thách (làm được cả ba là bạn đã nắm chắc bài):
- Đổi
a = 1thànha = -1,5rồi chạy lại. Tiếp tuyến nghiêng về phía nào? Con số độ dốc mang dấu gì, và điều đó nói lên điều gì về đường cong ở chỗ đó? - Đổi hàm thành
def f(x): return x**3 - 3*x. Tìm bằng cách thử xem đạo hàm bằng 0 ở những giá trịxnào. Nhìn đồ thị, hai chỗ đó có gì đặc biệt? - Trong hàm
dao_ham, đổih = 1e-6thànhh = 1e-15rồi chạy lại. Kết quả có còn đúng bằng2xnữa không? Hộp cảnh báo phía trên giải thích vì sao.
Bài tiếp theo: ta đã biết cách đo độ dốc của một hàm bất kỳ. Bài 28 sẽ dựng ra hàm mất mát — một hàm đặc biệt đo xem mô hình đang sai nhiều hay ít. Rồi Bài 29 ghép hai thứ lại: lấy đạo hàm của hàm mất mát để biết đường đi, và cho máy tự bước từng bước xuống chỗ thấp nhất.