什麼是雅可比矩陣(Jacobian Matrix)?

什麼是雅可比矩陣(Jacobian Matrix)?配圖

你有沒有想過,谷歌地圖是如何確定到達你所在位置的最短路線的?或者當你轉動方向盤時,自動移動方向盤會對車輛的運動產生怎樣的影響?那麼,這一切都可以歸結為雅可比矩陣。雅可比矩陣是向量函式偏導數的矩陣。雅可比球面座標變換是雅可比最常用的地方。它涉及微分中雅可比球面座標變換的思想。在本文中,我們將討論雅可比矩陣的數學概念、公式、行列式以及我們在日常生活中如何使用它。

什麼是雅可比矩陣?

雅可比矩陣及其行列式是為變數數相同的有限個函式定義的,被稱為 “雅可比”。它告訴我們在不同空間之間對映的函式中,一組變數的變化如何影響另一組變數。

在這種情況下,我們可以在每一行中找到關於變數的同一函式的第一次偏導數。矩陣可以是行列數相等的正方形矩陣,也可以是行列數不相等的矩形矩陣。

舉例說明 在山路顛倒的山中跋涉時,通常會有一個方向和陡峭程度。無論你在山上的哪個位置,雅可比矩陣就像你的嚮導,告訴你攀登的陡度和方向。

什麼是雅可比矩陣?

雅可比矩陣是一個由偏導陣列成的矩陣,它顯示了一個函式將輸入向量轉化為輸出向量的過程。它解釋了每個輸出如何隨每個輸入變數而變化。對於函式 f:ℝⁿ → ℝᵐ,共有 m 個分量和 n 個變數,雅可比公式可表示為:

符號雅可比矩陣:Matrix([[2*x, -1], [2*y, 2*x]])

點 (2, 3) 的雅可比矩陣:Matrix([[4, -1], [6, 4]])

雅可比的行列式(符號):4*x**2 + 2*y

點 (2, 3) 的行列式:22

點 (2, 3) 處的雅可比數:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
[[ 4.000001 -1. ]
[ 6. 4. ]]
[[ 4.000001 -1. ] [ 6. 4. ]]
[[ 4.000001 -1.      ]  
[ 6.        4.      ]]

在這裡,雅可比公式將給出一個函式在某一點周圍的區域性線性近似值,並解釋該函式是如何拉伸、旋轉和變換空間的。

雅可比矩陣的數學基礎

為了充分理解雅可比矩陣,我們將討論不同的數學基礎:

1. 向量值函式與多元微積分

它基本上是指將點從一個空間對映到另一個空間的函式。這些函式具有與多個輸入相對應的多個輸出。這些函式是流體動力學等現實系統的基礎結構。

雅可比比結合了線性代數和多變數微積分。標量導數告訴我們單變數函式的變化率。它還解釋了以矩陣格式呈現的具有多個輸入和輸出的函式的變化率。

2. 符號與維度

雅可比矩陣的結構和格式解釋了有關變換表示的重要資訊。對於函式 f: ℝⁿ into ℝᵐ,其中“n”代表輸入,“m”代表輸出,雅可比矩陣就是一個“m”乘“n”的矩陣。雅可比矩陣的條目表示 Jᵢⱼ=∂fᵢ/∂xⱼ,第 i 個輸出函式的表示隨第 j 個輸入變數的變化而變化。

因此,矩陣的維數會影響變換。從三維空間到二維空間,雅可比矩陣的行等於輸出,列等於輸入,從而形成 2*3 矩陣。

3. 幾何解釋

雅可比矩陣的函式行為也解釋了代數定義的直觀見解。下面的解釋有助於我們確定雅可比矩陣如何從幾何角度描述函式的區域性行為。

雅可比矩陣的函式行為

  • 區域性線性變換:雅可比函式給出了函式在點鄰域的最線性近似值。它解釋了輸入點附近無限小的區域如何對映到輸出點。
  • 切線近似:雅可比函式將切線向量從輸入空間轉換到輸出空間,反之亦然。將其視為曲面時,它給出了這些曲面如何相互轉向的區域性描述。

4. 雅可比函式的可逆性

雅可比函式與可逆性之間的關係是必要的資訊。它提供了在特定點上函式區域性行為的洞察力。

雅可比函式的可逆性

  • |J| > 0:函式保留區域性方向。
  • |J| < 0:區域性方向被函式反轉。
  • |J| = 0:在特定臨界點失去可逆性

只要雅可比函式的行列式不等於零,它在鄰域內就是可逆的。那麼與該點重合,我們就有了反函式定理。但只要雅可比行列式變為零,輸出域就會發生摺疊、壓縮或區域性化。

雅可比的性質

現在,讓我們來了解雅可比的性質。

  1. 鏈式法則:對於複合函式,可以透過雅可比乘法得到複合函式的雅可比。
  2. 方向導數:雅可比可以用來計算任意方向的方向導數。
  3. 線性近似:任意點附近函式的近似值為 f(x + Δx) ≈ f(x) + J(x) – Δx。

計算雅可比矩陣

現在,我們將看到計算雅可比矩陣和雅可比球面座標變換的三種不同方法–分析推導法、數值逼近法和自動微分法。

雅可比矩陣的分析推導

這是一種經典方法,依靠直接計算偏導數得出雅可比矩陣,從而深入瞭解變換結構。它是透過系統微分每個分量函式與每個輸入變數的關係來實現的。

讓我們考慮這樣一個例子:向量函式 f: ℝ → ℝᵐ 的分量為 f₁、f₂、…、fₘ,變數為 x₁、x₂、…、xₙ,在每個 j=1,2,….n 時,計算偏導數 ∂fi/∂xj。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
J(x) = [
∂f₁/∂x₁ ∂f₁/∂x₂ ... ∂f₁/∂xₙ
∂f₂/∂x₁ ∂f₂/∂x₂ ... ∂f₂/∂xₙ
... ... ... ...
∂fₘ/∂x₁ ∂fₘ/∂x₂ ... ∂fₘ/∂xₙ
]
Example: f(x,y) = (x²-y, 2xy), the partial derivatives evaluated are:
∂f₁/∂x = 2x
∂f₁/∂y = -1
∂f₂/∂x = 2y
∂f₂/∂y = 2x
And by this we can say that the Jacobian matrix observed is:
J(x,y) = [2x -1
2y 2x]
J(x) = [ ∂f₁/∂x₁ ∂f₁/∂x₂ ... ∂f₁/∂xₙ ∂f₂/∂x₁ ∂f₂/∂x₂ ... ∂f₂/∂xₙ ... ... ... ... ∂fₘ/∂x₁ ∂fₘ/∂x₂ ... ∂fₘ/∂xₙ ] Example: f(x,y) = (x²-y, 2xy), the partial derivatives evaluated are: ∂f₁/∂x = 2x ∂f₁/∂y = -1 ∂f₂/∂x = 2y ∂f₂/∂y = 2x And by this we can say that the Jacobian matrix observed is: J(x,y) = [2x -1 2y 2x]
J(x) = [
∂f₁/∂x₁  ∂f₁/∂x₂  ...  ∂f₁/∂xₙ
∂f₂/∂x₁  ∂f₂/∂x₂  ...  ∂f₂/∂xₙ
...      ...      ...  ...
∂fₘ/∂x₁  ∂fₘ/∂x₂  ...  ∂fₘ/∂xₙ
]

Example: f(x,y) = (x²-y, 2xy), the partial derivatives evaluated are:

∂f₁/∂x = 2x
∂f₁/∂y = -1
∂f₂/∂x = 2y
∂f₂/∂y = 2x

And by this we can say that the Jacobian matrix observed is:

J(x,y) = [2x  -1
2y  2x]

透過這種方法,我們可以看到精確的結果。然而,在同時處理多個變數或複雜函式時,情況會變得複雜,無法進行計算。

雅可比矩陣的數值逼近法

當分析推導過於繁瑣或函式缺乏形式表達時,數值方法提供了實用的替代解決方案,即使用有限差分法計算偏導數。兩種主要的有限差分法是

  1. 正向差分法:
∂fi/∂xⱼ ≈ [f(x₁,...,xⱼ+h,...,xₙ) - f(x₁,...,xⱼ,...,xₙ)]/h
  1. 中心差值精度更高
∂fi/∂xⱼ ≈ [f(x₁,...,xⱼ+h,...,xₙ) - f(x₁,...,xⱼ-h,...,xₙ)]/(2h)

這裡,h = 小步,對於雙精度來說,通常是 10-⁶ 的數量級。

關鍵在於選擇合適的步長。步長過大會帶來近似誤差,而步長過小則會因浮點數限制而導致數值不穩定。使用自適應步長或理查德森外推法的先進技術可以進一步提高精度。

雅可比矩陣的自動微分

自動微分結合了分析精度和計算自動化,在列表中名列前茅。它與數值方法的不同之處在於,自動微分計算的是精確導數而不是近似導數,從而避免了離散化誤差。自動微分的基本原理如下

  1. 應用鏈式法則:它系統地應用鏈式法則進行構成函式的基本運算。
  2. 計算圖的表示:在已知導數的基本運算中,將函式分解為尖圖。
  3. 正向和反向節點:正向模式將導數從輸入傳播到輸出,而反向模式則將導數從輸出傳播回輸入。

雅可比矩陣的自動微分

Source: Automatic Differentiation

這使得自動微分對於 TensorFlow、PyTorch、JAX 等現代軟體框架來說非常容易使用且高效。他們更喜歡用它來計算機器學習中的雅可比矩陣和科學最佳化問題。

使用 Python 計算雅可比矩陣和行列式

讓我們看看如何使用 Python 實現雅可比矩陣和雅可比球面座標。我們將分別使用 SymPy 和 NumPy 進行符號計算和數值逼近。

步驟 1:設定環境

匯入執行函式所需的路徑。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
import numpy as np import sympy as sp import matplotlib.pyplot as plt from matplotlib.patches import Ellipse
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

步驟 2:執行符號計算

使用 SymPy 編寫符號計算函式。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def symbolic_jacobian():
x, y = sp.symbols('x y')
f1 = x**2 - y
f2 = 2*x*y
# Define the function vector
f = sp.Matrix([f1, f2])
X = sp.Matrix([x, y])
# Calculate the Jacobian matrix
J = f.jacobian(X)
print("Symbolic Jacobian matrix:")
print(J)
# Calculate the Jacobian at point (2, 3)
J_at_point = J.subs([(x, 2), (y, 3)])
print("\nJacobian at point (2, 3):")
print(J_at_point)
# Calculate the determinant
det_J = J.det()
print("\nDeterminant of Jacobian (symbolic):")
print(det_J)
print("\nDeterminant at point (2, 3):")
print(det_J.subs([(x, 2), (y, 3)]))
return J, det_J
def symbolic_jacobian(): x, y = sp.symbols('x y') f1 = x**2 - y f2 = 2*x*y # Define the function vector f = sp.Matrix([f1, f2]) X = sp.Matrix([x, y]) # Calculate the Jacobian matrix J = f.jacobian(X) print("Symbolic Jacobian matrix:") print(J) # Calculate the Jacobian at point (2, 3) J_at_point = J.subs([(x, 2), (y, 3)]) print("\nJacobian at point (2, 3):") print(J_at_point) # Calculate the determinant det_J = J.det() print("\nDeterminant of Jacobian (symbolic):") print(det_J) print("\nDeterminant at point (2, 3):") print(det_J.subs([(x, 2), (y, 3)])) return J, det_J
def symbolic_jacobian():
x, y = sp.symbols('x y')
f1 = x**2 - y
f2 = 2*x*y
# Define the function vector
f = sp.Matrix([f1, f2])
X = sp.Matrix([x, y])
# Calculate the Jacobian matrix
J = f.jacobian(X)
print("Symbolic Jacobian matrix:")
print(J)
# Calculate the Jacobian at point (2, 3)
J_at_point = J.subs([(x, 2), (y, 3)])
print("\nJacobian at point (2, 3):")
print(J_at_point)
# Calculate the determinant
det_J = J.det()
print("\nDeterminant of Jacobian (symbolic):")
print(det_J)
print("\nDeterminant at point (2, 3):")
print(det_J.subs([(x, 2), (y, 3)]))
return J, det_J

步驟 3:新增數值近似值

使用 NumPy 編寫數值逼近函式。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def numerical_jacobian(func, x, epsilon=1e-6):
n = len(x) # Number of input variables
m = len(func(x)) # Number of output variables
jacobian = np.zeros((m, n))
for i in range(n):
x_plus = x.copy()
x_plus[i] += epsilon
jacobian[:, i] = (func(x_plus) - func(x)) / epsilon
return jacobian
def numerical_jacobian(func, x, epsilon=1e-6): n = len(x) # Number of input variables m = len(func(x)) # Number of output variables jacobian = np.zeros((m, n)) for i in range(n): x_plus = x.copy() x_plus[i] += epsilon jacobian[:, i] = (func(x_plus) - func(x)) / epsilon return jacobian
def numerical_jacobian(func, x, epsilon=1e-6):
n = len(x)  # Number of input variables
m = len(func(x))  # Number of output variables
jacobian = np.zeros((m, n))
for i in range(n):
x_plus = x.copy()
x_plus[i] += epsilon
jacobian[:, i] = (func(x_plus) - func(x)) / epsilon
return jacobian

步驟 4:編寫執行函式

編寫執行上述函式和視覺化轉換的主函式。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def f(x):
return np.array([x[0]**2 - x[1], 2*x[0]*x[1]])
# Visualize the transformation
def visualize_transformation():
# Create a grid of points
x = np.linspace(-3, 3, 20)
y = np.linspace(-3, 3, 20)
X, Y = np.meshgrid(x, y)
# Calculate transformed points
U = X**2 - Y
V = 2*X*Y
# Plot original and transformed grid
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
# Original grid
ax1.set_title('Original Space')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.grid(True)
ax1.plot(X, Y, 'k.', markersize=2)
# Add a unit circle
circle = plt.Circle((0, 0), 1, fill=False, color='red', linewidth=2)
ax1.add_artist(circle)
ax1.set_xlim(-3, 3)
ax1.set_ylim(-3, 3)
ax1.set_aspect('equal')
# Transformed grid
ax2.set_title('Transformed Space')
ax2.set_xlabel('u')
ax2.set_ylabel('v')
ax2.grid(True)
ax2.plot(U, V, 'k.', markersize=2)
# Calculate the transformation of the unit circle
theta = np.linspace(0, 2*np.pi, 100)
x_circle = np.cos(theta)
y_circle = np.sin(theta)
u_circle = x_circle**2 - y_circle
v_circle = 2*x_circle*y_circle
ax2.plot(u_circle, v_circle, 'r-', linewidth=2)
# Show the local linear approximation at point (1, 0)
point = np.array([1, 0])
J = numerical_jacobian(f, point)
# Calculate how the Jacobian transforms a small circle at our point
scale = 0.5
transformed_points = []
for t in theta:
delta = scale * np.array([np.cos(t), np.sin(t)])
transformed_delta = J @ delta
transformed_points.append(transformed_delta)
transformed_points = np.array(transformed_points)
# Plot the approximation
base_point_transformed = f(point)
ax2.plot(base_point_transformed[0] + transformed_points[:, 0],
base_point_transformed[1] + transformed_points[:, 1],
'g-', linewidth=2, label='Linear Approximation')
ax2.legend()
plt.tight_layout()
plt.show()
# Execute the functions
symbolic_result = symbolic_jacobian()
point = np.array([2.0, 3.0])
numerical_result = numerical_jacobian(f, point)
print("\nNumerical Jacobian at point (2, 3):")
print(numerical_result)
# Visualize the transformation
visualize_transformation()
def f(x): return np.array([x[0]**2 - x[1], 2*x[0]*x[1]]) # Visualize the transformation def visualize_transformation(): # Create a grid of points x = np.linspace(-3, 3, 20) y = np.linspace(-3, 3, 20) X, Y = np.meshgrid(x, y) # Calculate transformed points U = X**2 - Y V = 2*X*Y # Plot original and transformed grid fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6)) # Original grid ax1.set_title('Original Space') ax1.set_xlabel('x') ax1.set_ylabel('y') ax1.grid(True) ax1.plot(X, Y, 'k.', markersize=2) # Add a unit circle circle = plt.Circle((0, 0), 1, fill=False, color='red', linewidth=2) ax1.add_artist(circle) ax1.set_xlim(-3, 3) ax1.set_ylim(-3, 3) ax1.set_aspect('equal') # Transformed grid ax2.set_title('Transformed Space') ax2.set_xlabel('u') ax2.set_ylabel('v') ax2.grid(True) ax2.plot(U, V, 'k.', markersize=2) # Calculate the transformation of the unit circle theta = np.linspace(0, 2*np.pi, 100) x_circle = np.cos(theta) y_circle = np.sin(theta) u_circle = x_circle**2 - y_circle v_circle = 2*x_circle*y_circle ax2.plot(u_circle, v_circle, 'r-', linewidth=2) # Show the local linear approximation at point (1, 0) point = np.array([1, 0]) J = numerical_jacobian(f, point) # Calculate how the Jacobian transforms a small circle at our point scale = 0.5 transformed_points = [] for t in theta: delta = scale * np.array([np.cos(t), np.sin(t)]) transformed_delta = J @ delta transformed_points.append(transformed_delta) transformed_points = np.array(transformed_points) # Plot the approximation base_point_transformed = f(point) ax2.plot(base_point_transformed[0] + transformed_points[:, 0], base_point_transformed[1] + transformed_points[:, 1], 'g-', linewidth=2, label='Linear Approximation') ax2.legend() plt.tight_layout() plt.show() # Execute the functions symbolic_result = symbolic_jacobian() point = np.array([2.0, 3.0]) numerical_result = numerical_jacobian(f, point) print("\nNumerical Jacobian at point (2, 3):") print(numerical_result) # Visualize the transformation visualize_transformation()
def f(x):
return np.array([x[0]**2 - x[1], 2*x[0]*x[1]])
# Visualize the transformation
def visualize_transformation():
# Create a grid of points
x = np.linspace(-3, 3, 20)
y = np.linspace(-3, 3, 20)
X, Y = np.meshgrid(x, y)
# Calculate transformed points
U = X**2 - Y
V = 2*X*Y
# Plot original and transformed grid
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
# Original grid
ax1.set_title('Original Space')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.grid(True)
ax1.plot(X, Y, 'k.', markersize=2)
# Add a unit circle
circle = plt.Circle((0, 0), 1, fill=False, color='red', linewidth=2)
ax1.add_artist(circle)
ax1.set_xlim(-3, 3)
ax1.set_ylim(-3, 3)
ax1.set_aspect('equal')
# Transformed grid
ax2.set_title('Transformed Space')
ax2.set_xlabel('u')
ax2.set_ylabel('v')
ax2.grid(True)
ax2.plot(U, V, 'k.', markersize=2)
# Calculate the transformation of the unit circle
theta = np.linspace(0, 2*np.pi, 100)
x_circle = np.cos(theta)
y_circle = np.sin(theta)
u_circle = x_circle**2 - y_circle
v_circle = 2*x_circle*y_circle
ax2.plot(u_circle, v_circle, 'r-', linewidth=2)
# Show the local linear approximation at point (1, 0)
point = np.array([1, 0])
J = numerical_jacobian(f, point)
# Calculate how the Jacobian transforms a small circle at our point
scale = 0.5
transformed_points = []
for t in theta:
delta = scale * np.array([np.cos(t), np.sin(t)])
transformed_delta = J @ delta
transformed_points.append(transformed_delta)
transformed_points = np.array(transformed_points)
# Plot the approximation
base_point_transformed = f(point)
ax2.plot(base_point_transformed[0] + transformed_points[:, 0],
base_point_transformed[1] + transformed_points[:, 1],
'g-', linewidth=2, label='Linear Approximation')
ax2.legend()
plt.tight_layout()
plt.show()
# Execute the functions
symbolic_result = symbolic_jacobian()
point = np.array([2.0, 3.0])
numerical_result = numerical_jacobian(f, point)
print("\nNumerical Jacobian at point (2, 3):")
print(numerical_result)
# Visualize the transformation
visualize_transformation()

輸出:

編寫執行上述函式和視覺化轉換的主函式 編寫執行上述函式和視覺化轉換的主函式

輸出點評:

提出了非線性對映 f(x,y) = (x²-y, 2xy),並強調了雅可位元性。左圖為原始空間,包含一個均勻網格和一個單位圓,右圖為變換後的空間,其中圓變形為八字形。

雅可比矩陣是透過符號(Matrix([[2x, -1],[2y, 2*x]])和數值點(2,3)計算得出的。) 結果顯示行列式等於 22。這意味著區域性區域有很大的延伸。因此,這一分析提供了變換如何扭曲面積的數學檢視。線性化(綠色曲線)代表了這種非線性對映的區域性結構。

雅可比矩陣的應用

最新的 ML 框架包含自動微分工具,可為我們計算雅可比矩陣。這改變了複雜應用的遊戲規則,例如

  1. 機械臂速度控制:在雅可比矩陣的幫助下,我們可以指出應用程式的角關節速度與末端執行器速度之間的關聯,從而實現精確的運動路徑。
  2. 動態系統穩定性分析:系統的穩定性將決定其與特徵值運動的一致性,在特徵值運動中可以找到平衡點。
  3. 蛇形機器人障礙導航:這些研究利用雅可比比將關節速度與頭部速度聯絡起來,並在狹小空間內製定運動策略。
  4. 機械手運動規劃:雅可比比計算達到所需末端執行器位置所需的關節軌跡,這對自動化中的取放操作至關重要。
  5. 機器人技術中的力矩變換:這意味著將末端執行器的力,如抓取力,轉換為力敏感應用中所需的等效扭矩。

小結

微積分、微分幾何和線性代數都是雅可比矩陣串聯起來並應用於現實世界的數學學科。從先進的手術機器人到 GPS 定位,雅可比矩陣在提高技術響應速度方面發揮了巨大作用。這是數學如何既能描述我們的宇宙,又能幫助我們更有效、更高效地與之互動的一個例子。

評論留言