Python - Bài 27: Hàm số, Độ dốc và Đạo hàm (Khoa học Dữ liệu & ML)

 

🔬 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àm số là một cỗ máy: vào một số, ra một số vào x = 3 cỗ máy f 2*x + 1 ra y = 7 Mỗi số đưa vào cho đúng một số đi ra. Không bao giờ hai kết quả khác nhau. đồ thị của f

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ố

🟢 Lớp A · Trực giác

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.

🔵 Lớp B · Cơ chế

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.

🟣 Lớp C · Nghiên cứ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: wb 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

🟢 Lớp A · Trực giác

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.

🔵 Lớp B · Cơ chế

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.

🟣 Lớp C · Nghiên cứu

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

🟢 Lớp A · Trực giác

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.

🔵 Lớp B · Cơ chế

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.

🟣 Lớp C · Nghiên cứu

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.

Kéo hai điểm lại gần nhau, ta được tiếp tuyến 0 1 2 độ dốc 3 độ dốc 2,5 x = 1 tiếp tuyến Khi điểm thứ hai tiến về x = 1 tới x = 3 → 4,0 tới x = 2 → 3,0 tới x = 1,5 → 2,5 tới x = 1,001 → 2,001 đạo hàm tại x = 1 là 2

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)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ĩaTrong 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ảngMột dòng xử lý nghìn điểmf(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ạidao_ham(g, 3) = 6
Đạo hàm âmĐang đi xuống → muốn giảm thì tiến tớidao_ham(g, -2) = -4
Đạo hàm bằng 0Đang ở đáy hoặc đỉnh, không dốc về bên nàodao_ham(g, 0) = 0
GradientVector 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
Thay 4 vào chỗ của x: 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
Với đường thẳng dạng 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 = 2x = 2,001 gần bằng:

  • 2
  • 4
  • 8
  • 0,001
Hai điểm rất sát nhau nên độ dốc gần bằng đạo hàm tại x = 2. Đạo hàm của 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 tại x = −3 bằng:

  • 9
  • 6
  • −6
  • −3
Đạo hàm của 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
Đạo hàm không cho biết đáp án cuối cùng nằm ở đâu — nó chỉ cho biết ngay tại chỗ đang đứng thì nên bước về hướng nào. Máy cứ lặp lại việc đó nhiều lần và dần dần đi tới chỗ sai số thấp. Bài 29 sẽ dựng đúng thuật toán này.

💻 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):

  1. Đổi a = 1 thành a = -1,5 rồ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ỗ đó?
  2. Đổ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ị x nào. Nhìn đồ thị, hai chỗ đó có gì đặc biệt?
  3. Trong hàm dao_ham, đổi h = 1e-6 thành h = 1e-15 rồi chạy lại. Kết quả có còn đúng bằng 2x nữ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.