Skip to content

Latest commit

 

History

History
607 lines (466 loc) · 27.3 KB

calculus_vn.md

File metadata and controls

607 lines (466 loc) · 27.3 KB

Giải tích

🏷️sec_calculus

Tìm diện tích của một đa giác vẫn là một bí ẩn cho tới ít nhất $2.500$ năm trước, khi người Hy Lạp cổ đại chia đa giác thành các tam giác và cộng diện tích của chúng lại. Để tìm diện tích của các hình cong, như hình tròn, người Hy Lạp cổ đại đặt các đa giác nội tiếp bên trong các hình cong đó. Như trong :numref:fig_circle_area, một đa giác nội tiếp với càng nhiều cạnh bằng nhau thì càng xấp xỉ đúng hình tròn. Quy trình này còn được biết đến như phương pháp vét kiệt.

Tìm diện tích hình tròn bằng phương pháp vét kiệt. 🏷️fig_circle_area

Phương pháp vét kiệt chính là khởi nguồn của giải tích tích phân (sẽ được miêu tả trong :numref:sec_integral_calculus). Hơn $2.000$ năm sau, nhánh còn lại của giải tích, giải tích vi phân, ra đời. Trong những ứng dụng quan trọng nhất của giải tích vi phân, các bài toán tối ưu hoá sẽ tìm cách tốt nhất để thực hiện một công việc nào đó. Như đã bàn đến trong :numref:subsec_norms_and_objectives, các bài toán như vậy vô cùng phổ biến trong học sâu.

Trong học sâu, chúng ta huấn luyện các mô hình, cập nhật chúng liên tục để chúng ngày càng tốt hơn khi học với nhiều dữ liệu hơn. Thông thường, trở nên tốt hơn tương đương với cực tiểu hoá một hàm mất mát, một điểm số sẽ trả lời câu hỏi "mô hình của ta đang tệ tới mức nào?" Câu hỏi này lắt léo hơn ta tưởng nhiều. Mục đích cuối cùng mà ta muốn là mô hình sẽ hoạt động tốt trên dữ liệu mà nó chưa từng nhìn thấy. Nhưng chúng ta chỉ có thể khớp mô hình trên dữ liệu mà ta đang có thể thấy. Do đó ta có thể chia việc huấn luyện mô hình thành hai vấn đề chính: i) tối ưu hoá: quy trình huấn luyện mô hình trên dữ liệu đã thấy. ii) tổng quát hoá: dựa trên các nguyên tắc toán học và sự uyên thâm của người huấn luyện để tạo ra các mô hình mà tính hiệu quả của nó vượt ra khỏi tập dữ liệu huấn luyện.

Để giúp bạn hiểu các bài toán tối ưu hóa và các phương pháp tối ưu hóa trong các chương sau, ở đây chúng tôi sẽ cung cấp một chương ngắn vỡ lòng về các kĩ thuật giải tích vi phân thông dụng trong học sâu.

Đạo hàm và Vi phân

Chúng ta bắt đầu bằng việc đề cập tới khái niệm đạo hàm, một bước quan trọng của hầu hết các thuật toán tối ưu trong học sâu. Trong học sâu, ta thường chọn những hàm mất mát khả vi theo các tham số của mô hình. Nói đơn giản, với mỗi tham số, ta có thể xác định hàm mất mát tăng hoặc giảm nhanh như thế nào khi tham số đó tăng hoặc giảm chỉ một lượng cực nhỏ.

Giả sử ta có một hàm $f: \mathbb{R} \rightarrow \mathbb{R}$ có đầu vào và đầu ra đều là số vô hướng. Đạo hàm của $f$ được định nghĩa là

$$f'(x) = \lim_{h \rightarrow 0} \frac{f(x+h) - f(x)}{h},$$ :eqlabel:eq_derivative

nếu giới hạn này tồn tại. Nếu $f'(a)$ tồn tại, $f$ được gọi là khả vi (differentiable) tại $a$. Nếu $f$ khả vi tại mọi điểm trong một khoảng, thì hàm này được gọi là khả vi trong khoảng đó. Ta có thể giải nghĩa đạo hàm $f'(x)$ trong :eqref:eq_derivative như là tốc độ thay đổi tức thời của hàm $f$ theo biến $x$. Cái gọi là tốc độ thay đổi tức thời được dựa trên độ biến thiên $h$ trong $x$ khi $h$ tiến về $0$.

Để minh họa cho khái niệm đạo hàm, hãy thử với một ví dụ. Định nghĩa $u = f(x) = 3x^2-4x$.

%matplotlib inline
from d2l import mxnet as d2l
from IPython import display
from mxnet import np, npx
npx.set_np()

def f(x):
    return 3 * x ** 2 - 4 * x

Cho $x=1$$h$ tiến về $0$, kết quả của phương trình $\frac{f(x+h) - f(x)}{h}$ trong :eqref:eq_derivative tiến về $2$. Dù thử nghiệm này không phải là một dạng chứng minh toán học, lát nữa ta sẽ thấy rằng quả thật đạo hàm của $u'$$2$ khi $x=1$.

def numerical_lim(f, x, h):
    return (f(x + h) - f(x)) / h

h = 0.1
for i in range(5):
    print('h=%.5f, numerical limit=%.5f' % (h, numerical_lim(f, 1, h)))
    h *= 0.1

Hãy làm quen với một vài ký hiệu cùng được dùng để biểu diễn đạo hàm. Cho $y = f(x)$ với $x$$y$ lần lượt là biến độc lập và biến phụ thuộc của hàm $f$. Những biểu diễn sau đây là tương đương nhau:

$$f'(x) = y' = \frac{dy}{dx} = \frac{df}{dx} = \frac{d}{dx} f(x) = Df(x) = D_x f(x),$$

với ký hiệu $\frac{d}{dx}$$D$ là các toán tử vi phân (differentiation operator) để chỉ các phép toán vi phân. Ta có thể sử dụng các quy tắc lấy đạo hàm của các hàm thông dụng sau đây:

  • $DC = 0$ ($C$ là một hằng số),
  • $Dx^n = nx^{n-1}$ (quy tắc số mũ, $n$ là số thực bất kỳ),
  • $De^x = e^x$,
  • $D\ln(x) = 1/x.$

Để lấy đạo hàm của một hàm được tạo từ vài hàm đơn giản hơn, ví dụ như từ những hàm thông dụng ở trên, có thể dùng các quy tắc hữu dụng dưới đây. Giả sử hàm $f$$g$ đều khả vi và $C$ là một hằng số, ta có quy tắc nhân hằng số

$$\frac{d}{dx} [Cf(x)] = C \frac{d}{dx} f(x),$$

quy tắc tổng

$$\frac{d}{dx} [f(x) + g(x)] = \frac{d}{dx} f(x) + \frac{d}{dx} g(x),$$

quy tắc nhân

$$\frac{d}{dx} [f(x)g(x)] = f(x) \frac{d}{dx} [g(x)] + g(x) \frac{d}{dx} [f(x)],$$

quy tắc đạo hàm phân thức

$$\frac{d}{dx} \left[\frac{f(x)}{g(x)}\right] = \frac{g(x) \frac{d}{dx} [f(x)] - f(x) \frac{d}{dx} [g(x)]}{[g(x)]^2}.$$

Bây giờ ta có thể áp dụng các quy tắc ở trên để tìm đạo hàm $u' = f'(x) = 3 \frac{d}{dx} x^2-4\frac{d}{dx}x = 6x-4$. Vậy nên, với $x = 1$, ta có $u' = 2$: điều này đã được kiểm chứng với thử nghiệm lúc trước ở mục này khi kết quả có được cũng tiến tới $2$. Giá trị đạo hàm này cũng đồng thời là độ dốc của đường tiếp tuyến với đường cong $u = f(x)$ tại $x = 1$.

Để minh họa cách hiểu này của đạo hàm, ta sẽ dùng matplotlib, một thư viện vẽ biểu đồ thông dụng trong Python. Ta cần định nghĩa một số hàm để cấu hình thuộc tính của các biểu đồ được tạo ra bởi matplotlib. Trong đoạn mã sau, hàm use_svg_display chỉ định matplotlib tạo các biểu đồ ở dạng svg để có được chất lượng ảnh sắc nét hơn.

# Saved in the d2l package for later use
def use_svg_display():
    """Use the svg format to display a plot in Jupyter."""
    display.set_matplotlib_formats('svg')

Ta định nghĩa hàm set_figsize để chỉ định kích thước của biểu đồ. Lưu ý rằng ở đây ta đang dùng trực tiếp d2l.plt do câu lệnh from matplotlib import pyplot as plt đã được đánh dấu để lưu vào gói d2l trong phần Lời nói đầu.

# Saved in the d2l package for later use
def set_figsize(figsize=(3.5, 2.5)):
    """Set the figure size for matplotlib."""
    use_svg_display()
    d2l.plt.rcParams['figure.figsize'] = figsize

Hàm set_axes sau cấu hình thuộc tính của các trục biểu đồ tạo bởi matplotlib.

# Saved in the d2l package for later use
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """Set the axes for matplotlib."""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()

Với ba hàm cấu hình biểu đồ trên, ta định nghĩa hàm plot để vẽ nhiều đồ thị một cách nhanh chóng vì ta sẽ cần minh họa khá nhiều đồ thị xuyên suốt cuốn sách.

# Saved in the d2l package for later use
def plot(X, Y=None, xlabel=None, ylabel=None, legend=[], xlim=None,
         ylim=None, xscale='linear', yscale='linear',
         fmts=['-', 'm--', 'g-.', 'r:'], figsize=(3.5, 2.5), axes=None):
    """Plot data points."""
    d2l.set_figsize(figsize)
    axes = axes if axes else d2l.plt.gca()

    # Return True if X (ndarray or list) has 1 axis
    def has_one_axis(X):
        return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
                and not hasattr(X[0], "__len__"))

    if has_one_axis(X):
        X = [X]
    if Y is None:
        X, Y = [[]] * len(X), X
    elif has_one_axis(Y):
        Y = [Y]
    if len(X) != len(Y):
        X = X * len(Y)
    axes.cla()
    for x, y, fmt in zip(X, Y, fmts):
        if len(x):
            axes.plot(x, y, fmt)
        else:
            axes.plot(y, fmt)
    set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)

Giờ ta có thể vẽ đồ thị của hàm số $u = f(x)$ và đường tiếp tuyến của nó $y = 2x - 3$ tại $x=1$, với hệ số $2$ là độ dốc của tiếp tuyến.

x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])

Đạo hàm riêng

Cho tới giờ, ta đã làm việc với đạo hàm của các hàm một biến. Trong học sâu, các hàm lại thường phụ thuộc vào nhiều biến. Do đó, ta cần mở rộng ý tưởng của đạo hàm cho các hàm nhiều biến đó.

Cho $y = f(x_1, x_2, \ldots, x_n)$ là một hàm với $n$ biến. Đạo hàm riêng của $y$ theo tham số thứ $i$, $x_i$, là

$$ \frac{\partial y}{\partial x_i} = \lim_{h \rightarrow 0} \frac{f(x_1, \ldots, x_{i-1}, x_i+h, x_{i+1}, \ldots, x_n) - f(x_1, \ldots, x_i, \ldots, x_n)}{h}.$$

Để tính $\frac{\partial y}{\partial x_i}$, ta chỉ cần coi $x_1, \ldots, x_{i-1}, x_{i+1}, \ldots, x_n$ là các hằng số và tính đạo hàm của $y$ theo $x_i$. Để biểu diễn đạo hàm riêng, các ký hiệu sau đây đều có ý nghĩa tương đương:

$$\frac{\partial y}{\partial x_i} = \frac{\partial f}{\partial x_i} = f_{x_i} = f_i = D_i f = D_{x_i} f.$$

Gradient

Chúng ta có thể ghép các đạo hàm riêng của mọi biến trong một hàm nhiều biến để thu được vector gradient của hàm số đó. Giả sử rằng đầu vào của hàm $f: \mathbb{R}^n \rightarrow \mathbb{R}$ là một vector $n$ chiều $\mathbf{x} = [x_1, x_2, \ldots, x_n]^\top$ và đầu ra là một số vô hướng. Gradient của hàm $f(\mathbf{x})$ theo $\mathbf{x}$ là một vector gồm $n$ đạo hàm riêng đó:

$$\nabla_{\mathbf{x}} f(\mathbf{x}) = \bigg[\frac{\partial f(\mathbf{x})}{\partial x_1}, \frac{\partial f(\mathbf{x})}{\partial x_2}, \ldots, \frac{\partial f(\mathbf{x})}{\partial x_n}\bigg]^\top.$$

Biểu thức $\nabla_{\mathbf{x}} f(\mathbf{x})$ thường được viết gọn thành $\nabla f(\mathbf{x})$ trong trường hợp không sợ nhầm lẫn.

Cho $\mathbf{x}$ là một vector $n$-chiều, các quy tắc sau thường được dùng khi tính vi phân hàm đa biến:

  • Với mọi $\mathbf{A} \in \mathbb{R}^{m \times n}$, $\nabla_{\mathbf{x}} \mathbf{A} \mathbf{x} = \mathbf{A}^\top$,
  • Với mọi $\mathbf{A} \in \mathbb{R}^{n \times m}$, $\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} = \mathbf{A}$,
  • Với mọi $\mathbf{A} \in \mathbb{R}^{n \times n}$, $\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} \mathbf{x} = (\mathbf{A} + \mathbf{A}^\top)\mathbf{x}$,
  • $\nabla_{\mathbf{x}} |\mathbf{x} |^2 = \nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{x} = 2\mathbf{x}$.

Tương tự, với bất kỳ ma trận $\mathbf{X}$ nào, ta đều có $\nabla_{\mathbf{X}} |\mathbf{X} |_F^2 = 2\mathbf{X}$. Sau này ta sẽ thấy, gradient sẽ rất hữu ích khi thiết kế thuật toán tối ưu trong học sâu.

Quy tắc dây chuyền

Tuy nhiên, những gradient như thế có thể khó để tính toán. Đó là bởi vì các hàm nhiều biến trong học sâu đa phần là những hàm hợp, nên ta không thể áp dụng các quy tắc đề cập ở trên để lấy vi phân cho những hàm này. May mắn thay, quy tắc dây chuyền cho phép chúng ta lấy vi phân của các hàm hợp.

Trước tiên, chúng ta hãy xem xét các hàm một biến. Giả sử hai hàm $y=f(u)$$u=g(x)$ đều khả vi, quy tắc dây chuyền được mô tả như sau

$$\frac{dy}{dx} = \frac{dy}{du} \frac{du}{dx}.$$

Giờ ta sẽ xét trường hợp tổng quát hơn đối với các hàm nhiều biến. Giả sử một hàm khả vi $y$ có các biến số $u_1, u_2, \ldots, u_m$, trong đó mỗi biến $u_i$ là một hàm khả vi của các biến $x_1, x_2, \ldots, x_n$. Lưu ý rằng $y$ cũng là hàm của các biến $x_1, x_2, \ldots, x_n$. Quy tắc dây chuyền cho ta

$$\frac{dy}{dx_i} = \frac{dy}{du_1} \frac{du_1}{dx_i} + \frac{dy}{du_2} \frac{du_2}{dx_i} + \cdots + \frac{dy}{du_m} \frac{du_m}{dx_i}$$

cho mỗi $i = 1, 2, \ldots, n$.

Tóm tắt

  • Vi phân và tích phân là hai nhánh con của giải tích, trong đó vi phân được ứng dụng rộng rãi trong các bài toán tối ưu hóa của học sâu.
  • Đạo hàm có thể được hiểu như là tốc độ thay đổi tức thì của một hàm số đối với các biến số. Nó cũng là độ dốc của đường tiếp tuyến với đường cong của hàm.
  • Gradient là một vector có các phần tử là đạo hàm riêng của một hàm nhiều biến theo tất cả các biến số của nó.
  • Quy tắc dây chuyền cho phép chúng ta lấy vi phân của các hàm hợp.

Bài tập

dịch đoạn phía trên

  1. Vẽ đồ thị của hàm số $y = f(x) = x^3 - \frac{1}{x}$ và đường tiếp tuyến của nó tại $x = 1$.
  2. Tìm gradient của hàm số $f(\mathbf{x}) = 3x_1^2 + 5e^{x_2}$.
  3. Gradient của hàm $f(\mathbf{x}) = |\mathbf{x}|_2$ là gì?
  4. Có thể dùng quy tắc dây chuyền cho trường hợp sau đây không: $u = f(x, y, z)$, với $x = x(a, b)$, $y = y(a, b)$$z = z(a, b)$?

Thảo luận

Những người thực hiện

Bản dịch trong trang này được thực hiện bởi:

  • Đoàn Võ Duy Thanh
  • Lê Khắc Hồng Phúc
  • Phạm Hồng Vinh
  • Vũ Hữu Tiệp
  • Nguyễn Cảnh Thướng
  • Phạm Minh Đức
  • Tạ H. Duy Nguyên