Chuyển tới nội dung chính

Giải tích ma trận

Phần nay ta chủ yếu ôn lại cách tính và kiểm tra đạo hàm.

1. Đạo hàm của hàm trả về một số vô hướng

Đạo hàm bậc nhất (first-order gradient) hay viết gọn là đạo hàm (gradient) của một hàm số f(x):RnRf(\mathbf{x}): \mathbb{R}^n \to \mathbb{R} theo x\mathbf{x} được định nghĩa là:

xf(x)[f(x)x1f(x)x2f(x)xn]Rn\nabla_{\mathbf{x}} f(\mathbf{x}) \triangleq \begin{bmatrix} \frac{\partial f(\mathbf{x})}{\partial x_1} \\ \frac{\partial f(\mathbf{x})}{\partial x_2} \\ \vdots \\ \frac{\partial f(\mathbf{x})}{\partial x_n} \end{bmatrix} \in \mathbb{R}^n

trong đó f(x)xi\frac{\partial f(\mathbf{x})}{\partial x_i}đạo hàm riêng của hàm số theo thành phần thứ ii của vector x\mathbf{x}. Đạo hàm này được lấy khi tất cả các biến(ngoài xix_{i}) được giả sử là hằng số.

Đạo hàm của hàm số này là một vector có cùng chiều với vector đang được lấy đạo hàm. Tức là nếu vector được viết ở dạng cột thì đạo hàm cũng phải được viết ở dạng cột.

Đạo hàm bậc hai (second-order gradient) của hàm số trên còn được gọi là Hessian được định nghĩa như sau:

2f(x)[2f(x)x122f(x)x1x22f(x)x1xn2f(x)x2x12f(x)x222f(x)x2xn2f(x)xnx12f(x)xnx22f(x)xn2]Sn\nabla^2 f(\mathbf{x}) \triangleq \begin{bmatrix} \frac{\partial^2 f(\mathbf{x})}{\partial x_1^2} & \frac{\partial^2 f(\mathbf{x})}{\partial x_1 \partial x_2} & \cdots & \frac{\partial^2 f(\mathbf{x})}{\partial x_1 \partial x_n} \\ \frac{\partial^2 f(\mathbf{x})}{\partial x_2 \partial x_1} & \frac{\partial^2 f(\mathbf{x})}{\partial x_2^2} & \cdots & \frac{\partial^2 f(\mathbf{x})}{\partial x_2 \partial x_n} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{\partial^2 f(\mathbf{x})}{\partial x_n \partial x_1} & \frac{\partial^2 f(\mathbf{x})}{\partial x_n \partial x_2} & \cdots & \frac{\partial^2 f(\mathbf{x})}{\partial x_n^2} \end{bmatrix} \in \mathbb{S}^n

Đạo hàm cấp một hàm số f(X):Rn×mRf(X) : \mathbb{R}^{n \times m} \rightarrow \mathbb{R} theo ma trận X\mathbf{X} được định nghĩa là:

f(X)=[f(X)x11f(X)x12f(X)x1mf(X)x21f(X)x22f(X)x2mf(X)xn1f(X)xn2f(X)xnm]Rn×m\nabla f(X) = \begin{bmatrix} \frac{\partial f(X)}{\partial x_{11}} & \frac{\partial f(X)}{\partial x_{12}} & \cdots & \frac{\partial f(X)}{\partial x_{1m}} \\ \frac{\partial f(X)}{\partial x_{21}} & \frac{\partial f(X)}{\partial x_{22}} & \cdots & \frac{\partial f(X)}{\partial x_{2m}} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{\partial f(X)}{\partial x_{n1}} & \frac{\partial f(X)}{\partial x_{n2}} & \cdots & \frac{\partial f(X)}{\partial x_{nm}} \end{bmatrix} \in \mathbb{R}^{n \times m}

là một ma trận trong Rn×m\mathbb{R}^{n \times m}.

Cụ thể để tính đạo hàm của hàm này thì ta tính đạo hàm riêng của hàm số đó theo từng thành phần của ma trận khi toàn bộ các thành phần khác được giả sử là hằng số. Tiếp theo, ta sắp xếp các đạo hàm riêng tính được theo đúng thứ tự trong ma trận.

Ví dụ: Xét hàm số f:R2Rf: \mathbb{R}^2 \to \mathbb{R}, f(x)=x12+2x1x2+sin(x1)+2f(\mathbf{x}) = x_{1}^2 + 2x_1x_2 + \sin({x_1}) + 2

Đạo hàm bậc nhất theo x\mathbf{x} của hàm số đó là

f(x)=[f(x)x1f(x)x2]=[2x1+2x2+cos(x1)2x1]\nabla f(x) = \begin{bmatrix} \frac{\partial f(x)}{\partial x_1} \\ \frac{\partial f(x)}{\partial x_2} \end{bmatrix} = \begin{bmatrix} 2x_1 + 2x_2 + \cos(x_1) \\ 2x_1 \end{bmatrix}

Đạo hàm bậc hai theo x\mathbf{x}, hay Hessian

2f(x)=[2f(x)x122f(x)x1x22f(x)x2x12f(x)x22]=[2sin(x1)220]\nabla^2 f(x) = \begin{bmatrix} \frac{\partial^2 f(x)}{\partial x_1^2} & \frac{\partial^2 f(x)}{\partial x_1 \partial x_2} \\ \frac{\partial^2 f(x)}{\partial x_2 \partial x_1} & \frac{\partial^2 f(x)}{\partial x_2^2} \end{bmatrix} = \begin{bmatrix} 2 - \sin(x_1) & 2 \\ 2 & 0 \end{bmatrix}

Chú ý rằng Hessian luôn là một ma trận đối xứng.

2. Đạo hàm của hàm trả về một vector

Xét một hàm trả về vector với đầu vào là một số thực v(x):RRnv(x): \mathbb{R} \rightarrow \mathbb{R}^n:

Đạo hàm của hàm số này theo xx là một vector hàng như sau:

v(x)[v1(x)xv2(x)xvn(x)x]\nabla v(x) \triangleq \left[ \frac{\partial v_1(x)}{\partial x} \quad \frac{\partial v_2(x)}{\partial x} \quad \ldots \quad \frac{\partial v_n(x)}{\partial x} \right]

Đạo hàm bậc hai của hàm số này có dạng:

2v(x)[2v1(x)x22v2(x)x22vn(x)x2]\nabla^2 v(x) \triangleq \left[ \frac{\partial^2 v_1(x)}{\partial x^2} \quad \frac{\partial^2 v_2(x)}{\partial x^2} \quad \ldots \quad \frac{\partial^2 v_n(x)}{\partial x^2} \right]

Ví dụ: Cho một vector aRn\mathbf{a} \in \mathbb{R}^n và một hàm số vector-valued v(x)=xav(x) = x\mathbf{a}, đạo hàm bậc nhất và Hessian của nó lần lượt là

v(x)=aT,2v(x)=0Rn×n\begin{align} \nabla v(x) = \mathbf{a}^T, \quad \nabla^2 v(x) = 0 \in \mathbb{R}^{n \times n} \end{align}

Xét một hàm trả về vector với đầu vào là một vector h(x):RkRnh(x) : \mathbb{R}^k \rightarrow \mathbb{R}^n, đạo hàm bậc nhất của nó là

h(x)[h1(x)x1h2(x)x1hn(x)x1h1(x)x2h2(x)x2hn(x)x2h1(x)xkh2(x)xkhn(x)xk]=[h1(x) h2(x)  hn(x)]Rk×n\begin{align} \nabla h(x) \triangleq \begin{bmatrix} \frac{\partial h_1(x)}{\partial x_1} & \frac{\partial h_2(x)}{\partial x_1} & \cdots & \frac{\partial h_n(x)}{\partial x_1} \\ \frac{\partial h_1(x)}{\partial x_2} & \frac{\partial h_2(x)}{\partial x_2} & \cdots & \frac{\partial h_n(x)}{\partial x_2} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{\partial h_1(x)}{\partial x_k} & \frac{\partial h_2(x)}{\partial x_k} & \cdots & \frac{\partial h_n(x)}{\partial x_k} \end{bmatrix} = \left[ \nabla h_1(x) \space \nabla h_2(x) \space \cdots \space \nabla h_n(x) \right] \in \mathbb{R}^{k \times n} \end{align}

Nếu một hàm số g:RmRng : \mathbb{R}^m \rightarrow \mathbb{R}^n, thì đạo hàm của nó là một ma trận thuộc Rm×n\mathbb{R}^{m \times n}

Đạo hàm bậc hai của hàm số trên là một mảng ba chiều, chúng ta sẽ không nhắc đến ở đây.

Trường hợp đặc biệt đạo hàm của hàm số thường gặp, chúng ta cần biết hai tính chất quan trọng khác thường liên quan đến đạo hàm của một biến.

3. Tính chất quan trọng của đạo hàm

3.1. Quy tắc tích (Product rule)

Đề cho tổng quát, ta giả sử biến đầu vào là một ma trận. Giả sử rằng các hàm số có chiều phù hợp để các phép nhân ma trận thực hiện được. Ta có:

(f(X)Tg(X))=(f(X))g(X)+(g(X))f(X)\nabla (f(X)^T g(X)) = (\nabla f(X)) g(X) + (\nabla g(X)) f(X)

Biểu thức nâng niu hơn thực chứng ta đã quen thuộc:

(f(x)g(x))T=fT(x)g(x)+gT(x)f(x)(f(x) g(x))^T = f^T(x) g(x) + g^T(x) f(x)

Chú ý rằng tích của vector và ma trận, ta không được sử dụng tính chất giao hoán.

3.2. Quy tắc chuỗi (Chain rule)

Khi có các hàm hợp thì

Xg(f(X))=(Xf)T(fg)\nabla_{X}g(f(X)) = (\nabla_X f)^T (\nabla_{f}g)

Quy tắc này cũng giống với quy tắc trong hàm một biến:

(g(f(x)))=f(x)g(f)(g(f(x)))' = f'(x) g'(f)

Một lưu ý nhỏ nhưng quan trọng khi làm việc với tích các ma trận là sự phù hợp về kích thước của các ma trận trong tích.

4. Đạo hàm của các hàm số thường gặp

f(x)f(x)f(x)\nabla f(x)f(X)f(X)Xf(X)\nabla_X f(X)
x\mathbf{x}I\mathbf{I}trace(X)\operatorname{trace}(\mathbf{X})I\mathbf{I}
aTx\mathbf{a^Tx}a\mathbf{a}trace(ATX)\operatorname{trace}(\mathbf{A^TX})A\mathbf{A}
xTAx\mathbf{x^TAx}(A+AT)x\mathbf{(A+A^T)x}trace(XTAX)\operatorname{trace}(\mathbf{X^TAX})(A+AT)X\mathbf{(A+A^T)X}
xTx=x22\mathbf{x^Tx=\|\|x\|\|^2_{2}}2x\mathbf{2x}trace(XTX=XF2)\operatorname{trace}(\mathbf{X^TX=\|X\|^2_F})2X\mathbf{2X}
Axb22\mathbf{\|Ax - b\|^2_2}2AT(Axb)\mathbf{2A^T (Ax - b)}trace(AXBF2)\operatorname{trace}(\mathbf{\|AX - B\|^2_F})2AT(AXB)\mathbf{2A^T (AX - B)}
aTxxTb\mathbf{a^T x x^T b}(abT+baT)x\mathbf{(ab^T + ba^T) x}trace(ATXB)\operatorname{trace}(\mathbf{A^T X B})ABT\mathbf{AB^T}

5. Kiểm tra đạo hàm

5.1. Xấp xỉ đạo hàm của hàm một biến

Theo định nghĩa,

f(x)=limϵ0f(x+ϵ)f(x)ϵf'(x) = \lim_{\epsilon \to 0} \frac{f(x + \epsilon) - f(x)}{\epsilon}

Một cách thường được sử dụng là lấy một giá trị ϵ\epsilon rất nhỏ, ví dụ 10610^{-6}, và sử dụng công thức:

f(x)f(x+ϵ)f(xϵ)2ϵf'(x) \approx \frac{f(x + \epsilon) - f(x - \epsilon)}{2\epsilon}

Cách tính này được gọi là numerical gradient\textit{numerical gradient}. Có hai cách giải thích cho công thức này, hãy xem sách của a Tiệp để hiểu hơn.

5.2. Kiểm tra đạo hàm với python

from __future__ import print_function
import numpy as np

def check_grad(fn, gr, X):
X_flat = X.reshape(-1) # convert X to an 1d array -> 1 for loop needed
shape_X = X.shape # original shape of X
num_grad = np.zeros_like(X) # numerical grad, shape = shape of X
grad_flat = np.zeros_like(X_flat) # 1d version of grad
eps = 1e-6 # a small number, 1e-10 -> 1e-6 is usually good
numElems = X_flat.shape[0] # number of elements in X

# calculate numerical gradient
for i in range(numElems): # iterate over all elements of X
Xp_flat = X_flat.copy()
Xn_flat = X_flat.copy()
Xp_flat[i] += eps
Xn_flat[i] -= eps
Xp = Xp_flat.reshape(shape_X)
Xn = Xn_flat.reshape(shape_X)
grad_flat[i] = (fn(Xp) - fn(Xn))/(2*eps)

num_grad = grad_flat.reshape(shape_X)

diff = np.linalg.norm(num_grad - gr(X))
print(’Difference between two methods should be small:, diff)

# ==== check if grad(trace(A*X)) == A^T ====
m, n = 10, 20
A = np.random.rand(m, n)
X = np.random.rand(n, m)

def fn1(X):
return np.trace(A.dot(X))

def gr1(X):
return A.T

check_grad(fn1, gr1, X)
# ==== check if grad(x^T*A*x) == (A + A^T)*x ====
A = np.random.rand(m, m)
x = np.random.rand(m, 1)

def fn2(x):
return x.T.dot(A).dot(x)

def gr2(x):
return (A + A.T).dot(x)

check_grad(fn2, gr2, x)

Kết quả:

Difference between two methods should be small: 2.02303323394e-08
Difference between two methods should be small: 2.10853872281e-09