Xấp xỉ hàm¶
Xấp xỉ hàm thay thế các hàm phức tạp bằng các hàm đơn giản hơn nhưng đủ gần để hữu ích. Tài liệu này bao quát tuyến tính hóa, chuỗi Taylor, xấp xỉ đa thức, chuỗi Fourier, và định lý xấp xỉ phổ quát — nền tảng lý thuyết của lý do mạng nơ-ron có thể học các ánh xạ tùy ý.
-
Nhiều hàm chúng ta gặp quá phức tạp để làm việc trực tiếp. Tính \(e^{0.1}\) trên giấy, dự đoán quỹ đạo vệ tinh, v.v. đều liên quan đến các hàm không có đáp án dạng đóng đơn giản.
-
Xấp xỉ hàm thay thế một hàm phức tạp bằng một hàm đơn giản hơn mà "đủ gần" trên vùng chúng ta quan tâm.
-
Xấp xỉ tự nhiên nhất là một đa thức. Đa thức chỉ là tổng các lũy thừa của \(x\) với các hệ số, và chúng dễ dàng để đánh giá, vi phân, và tích phân.
-
Nhưng tại sao đa thức hoạt động tốt đến vậy với vai trò là xấp xỉ? Hãy xem xét mỗi lũy thừa của \(x\) đóng góp gì.
- Số hạng hằng \(a_0\) đặt giá trị nền tảng.
- Số hạng \(a_1 x\) thêm một độ dốc.
- Số hạng \(a_2 x^2\) thêm độ cong.
- Mỗi lũy thừa càng cao càng nắm bắt chi tiết tinh tế hơn về hình dạng của hàm.
-
Bằng cách chọn các hệ số phù hợp, ta có thể khớp giá trị, độ dốc, độ cong và hành vi bậc cao hơn của hàm tại một điểm, từng mảnh một.
-
Với đủ số hạng, đa thức có thể bắt chước hầu hết mọi hàm trơn.
-
Câu hỏi trở thành: làm thế nào để tìm ra đúng các hệ số?
-
Tuyến tính hóa (linearisation) là xấp xỉ đơn giản nhất. Gần một điểm \(x = a\), ta thay thế hàm bằng đường tiếp tuyến của nó:
-
Đây là xấp xỉ Taylor bậc nhất. Nó nói: bắt đầu từ giá trị đã biết \(f(a)\), sau đó điều chỉnh bằng độ dốc nhân với khoảng cách từ \(a\).
-
Ví dụ, tuyến tính hóa \(\sin(x)\) tại \(x = 0\): \(f(0) = 0\), \(f'(0) = \cos(0) = 1\), nên \(L(x) = x\). Gần 0, \(\sin(x) \approx x\). Hãy thử: \(\sin(0.1) = 0.0998\ldots \approx 0.1\).
-
Nhưng tuyến tính hóa chỉ tốt ở rất gần \(a\). Di chuyển xa hơn và xấp xỉ hỏng. Để làm tốt hơn, ta đưa vào các số hạng bậc cao hơn.
-
Chuỗi Taylor biểu diễn một hàm như một tổng vô hạn của các số hạng đa thức, mỗi số hạng nắm bắt chi tiết tinh tế hơn về hành vi của hàm gần một điểm \(a\):
-
Mỗi số hạng kế tiếp thêm một hiệu chỉnh. Số hạng đầu khớp giá trị, số hạng thứ hai khớp độ dốc, số hạng thứ ba khớp độ cong, và cứ thế. Càng bao gồm nhiều số hạng, vùng xấp xỉ chính xác càng lớn.
-
Ký hiệu \(n!\) ở mẫu số không phải tùy tiện. Khi bạn vi phân \((x - a)^n\) chính xác \(n\) lần, bạn được \(n!\). Giai thừa triệt tiêu điều này, đảm bảo rằng đạo hàm bậc \(n\) của đa thức Taylor bằng đạo hàm bậc \(n\) của hàm gốc tại \(x = a\).
-
Chuỗi Maclaurin đơn giản là chuỗi Taylor có tâm tại \(a = 0\):
- Một số chuỗi Maclaurin nổi tiếng:
-
Chú ý rằng \(\sin x\) chỉ có các lũy thừa lẻ (nó là một hàm lẻ) và \(\cos x\) chỉ có các lũy thừa chẵn (nó là một hàm chẵn). Các dấu hiệu đan xen khiến xấp xỉ dao động quanh giá trị thực, hội tụ từ cả hai phía.
-
Hãy xấp xỉ \(e^{0.5}\) bằng bốn số hạng: \(1 + 0.5 + \frac{0.25}{2} + \frac{0.125}{6} = 1 + 0.5 + 0.125 + 0.02083 \approx 1.6458\). Giá trị thực là \(1.6487\ldots\), vậy bốn số hạng đã cho ta ba chữ số thập phân chính xác.
-
Không phải chuỗi Taylor nào cũng hội tụ ở mọi nơi. Bán kính hội tụ (radius of convergence) cho ta biết xa tâm \(a\) bao nhiêu thì chuỗi vẫn cho kết quả hợp lệ. Trong bán kính đó, xấp xỉ đa thức có thể được làm chính xác tùy ý bằng cách thêm nhiều số hạng. Bên ngoài nó, chuỗi phân kỳ.
-
Chuỗi lũy thừa (power series) có dạng tổng quát: \(\sum_{n=0}^{\infty} a_n (x - c)^n\). Chuỗi Taylor là chuỗi lũy thừa nơi các hệ số được xác định bởi đạo hàm. Các chuỗi lũy thừa khác được xác định bởi một số quy tắc khác. Kiểm tra tỉ lệ (ratio test) xác định sự hội tụ: tính \(\lim_{n \to \infty} \left|\frac{a_{n+1}}{a_n}\right|\). Nếu giới hạn này là \(L\), bán kính hội tụ là \(R = 1/L\).
-
Khi ta cắt bớt chuỗi Taylor sau \(n\) số hạng, ta mắc phải một sai số. Phần dư Lagrange (Lagrange remainder) chặn sai số này:
-
Ở đây \(c\) là một điểm nào đó chưa biết giữa \(a\) và \(x\). Ta không biết chính xác \(c\), nhưng ta thường có thể chặn \(|f^{(n+1)}(c)|\) để có một ước lượng sai số trong trường hợp xấu nhất. \((n+1)!\) ở mẫu số tăng cực kỳ nhanh, nên sai số co lại nhanh chóng khi ta thêm nhiều số hạng (đối với các hàm nằm trong bán kính hội tụ).
-
Với hàm nhiều biến, khai triển Taylor bao gồm các đạo hàm riêng hỗn hợp. Xấp xỉ bậc hai của \(f(\mathbf{x})\) quanh một điểm \(\mathbf{a}\) là:
-
Số hạng đầu là giá trị, số hạng thứ hai sử dụng gradient (một vector, như ta đã thấy ở giải tích đa biến), và số hạng thứ ba sử dụng ma trận Hessian (nắm bắt độ cong). Điều này kết nối chương ma trận của ta trực tiếp với giải tích: ma trận Hessian là một ma trận các đạo hàm bậc hai mô tả hình dạng của mặt cong hàm số.
-
Xấp xỉ bậc hai đa biến này là nền tảng của phương pháp Newton và các kỹ thuật tối ưu hóa bậc hai khác, mà ta sẽ thấy trong tài liệu tiếp theo.
-
Ngoài đa thức, còn có những phương pháp xấp xỉ khác đáng biết:
- Nội suy spline (spline interpolation): thay vì một đa thức bậc cao, dùng nhiều đa thức bậc thấp ghép nối trơn tru. Điều này tránh các dao động dữ dội mà đa thức bậc cao có thể tạo ra.
- Chuỗi Fourier: xấp xỉ các hàm tuần hoàn như tổng của các hàm sin và cos. Thiết yếu trong xử lý tín hiệu và âm thanh.
- Mạng nơ-ron: bộ xấp xỉ hàm phổ quát. Với đủ nơ-ron, chúng có thể xấp xỉ bất kỳ hàm liên tục nào đến độ chính xác tùy ý. Đây là biện minh lý thuyết cho học sâu.
-
Một hàm được gọi là "cư xử tốt" nếu nó có các tính chất khiến cho việc xấp xỉ trở nên đáng tin cậy: liên tục (không nhảy), khả vi (không có góc nhọn), trơn (đạo hàm mọi cấp đều tồn tại), và bị chặn (đầu ra hữu hạn).
-
Đa thức, hàm mũ, và hàm lượng giác đều là những hàm cư xử tốt. Hàm càng cư xử tốt, bạn càng cần ít số hạng Taylor để có một xấp xỉ tốt.
Bài tập lập trình (dùng CoLab hoặc notebook)¶
-
Xấp xỉ \(e^x\) bằng cách sử dụng số lượng số hạng Taylor tăng dần và trực quan hóa sự cải thiện của xấp xỉ.
import jax.numpy as jnp import matplotlib.pyplot as plt x = jnp.linspace(-2, 3, 300) plt.plot(x, jnp.exp(x), "k-", linewidth=2, label="eˣ (exact)") colors = ["#e74c3c", "#3498db", "#27ae60", "#9b59b6"] for n, color in zip([1, 2, 4, 8], colors): approx = sum(x**k / jnp.array(float(jnp.prod(jnp.arange(1, k+1)) if k > 0 else 1)) for k in range(n+1)) plt.plot(x, approx, color=color, linestyle="--", label=f"{n} terms") plt.ylim(-2, 15) plt.legend() plt.title("Taylor approximation of eˣ") plt.show() -
Tính phần dư Lagrange để chặn sai số của việc xấp xỉ \(\sin(1)\) với các số lượng số hạng Taylor khác nhau.
import jax.numpy as jnp x = 1.0 exact = jnp.sin(x) taylor = 0.0 for n in range(8): sign = (-1)**n factorial = float(jnp.prod(jnp.arange(1, 2*n+2))) taylor += sign * x**(2*n+1) / factorial error = abs(exact - taylor) bound = x**(2*n+3) / float(jnp.prod(jnp.arange(1, 2*n+4))) print(f"terms={n+1} approx={taylor:.10f} error={error:.2e} bound={bound:.2e}") -
So sánh xấp xỉ Taylor tuyến tính và bậc hai của \(\cos(x)\) gần \(x = 0\). Vẽ cả hai xấp xỉ cùng với hàm thực và quan sát phạm vi độ chính xác của mỗi xấp xỉ.
import jax.numpy as jnp import matplotlib.pyplot as plt x = jnp.linspace(-3, 3, 300) plt.plot(x, jnp.cos(x), "k-", linewidth=2, label="cos(x)") plt.plot(x, jnp.ones_like(x), "--", color="#e74c3c", label="linear: 1") plt.plot(x, 1 - x**2/2, "--", color="#3498db", label="quadratic: 1 - x²/2") plt.plot(x, 1 - x**2/2 + x**4/24, "--", color="#27ae60", label="4th order") plt.ylim(-2, 2) plt.legend() plt.title("Taylor approximations of cos(x)") plt.show()