Skip to content

행렬 미분 · 야코비와 헤시안 ​

기말 범위 12주차 요약. 입력·출력이 스칼라·벡터·행렬인 함수들의 도함수 표기법과, 그 대표인 야코비 행렬·헤시안, 그리고 자주 쓰는 행렬 미분 항등식을 정리한다.

함수 종류별 도함수의 모양 ​

미분의 대상이 스칼라냐 벡터냐 행렬이냐에 따라 도함수의 모양(스칼라·벡터·행렬)이 달라진다.

스칼라 인수 벡터 함수 ​

  • 스칼라를 받아 벡터를 돌려주는 함수 f(x):R↦Rm를 벡터값 함수vector-valued function라 한다. 그 예가 매개변수 곡선parametric curve이다.
f(t)=tcos⁡(t)x^+tsin⁡(t)y^+tz^
  • 이 함수의 도함수를 접벡터tangent vector라 하며, 각 성분을 미분한 열벡터이다.
∂f∂x=[∂f0/∂x∂f1/∂x⋮∂fn−1/∂x]

벡터 인수 스칼라 함수 ​

  • 벡터를 받아 스칼라를 돌려주는 스칼라장 f:Rm↦R의 도함수는 그래디언트이며, 행렬 미분 표기법에서는 행벡터로 쓴다.
∂f∂x=[∂f∂x0∂f∂x1⋯∂f∂xm−1]

도함수의 모양 정리

  • 스칼라 인수 벡터 함수의 도함수는 열벡터(접벡터).
  • 벡터 인수 스칼라 함수의 도함수는 행벡터(그래디언트).
  • 벡터 인수 벡터 함수 f:Rm↦Rn의 도함수는 행렬(야코비 행렬).

벡터 인수 벡터 함수와 행렬 함수 ​

  • 벡터 인수 벡터 함수의 도함수는 행렬이며, 각 행이 성분 함수의 그래디언트이다.
∂f∂x=[∂f0∂x0⋯∂f0∂xm−1⋮⋱⋮∂fn−1∂x0⋯∂fn−1∂xm−1]=[∇f0(x)⊤⋮∇fn−1(x)⊤]
  • 스칼라를 받아 행렬을 돌려주는 함수 F:R↦Rn×m의 도함수(각 성분을 미분)를 접행렬tangent matrix이라 하고, 행렬을 받아 스칼라를 돌려주는 함수 f(X):Rn×m↦R의 도함수를 기울기 행렬gradient matrix이라 한다.

야코비 행렬 ​

야코비 행렬

야코비 행렬Jacobian matrix은 벡터 인수 벡터 함수 f:Rm↦Rn의 도함수로, (i,j) 성분이 ∂fi/∂xj인 n×m 행렬이다.

Jx=∂f∂x=[∂f0∂x0∂f0∂x1⋯∂f0∂xm−1∂f1∂x0∂f1∂x1⋯∂f1∂xm−1⋮⋮⋱⋮∂fn−1∂x0∂fn−1∂x1⋯∂fn−1∂xm−1]

기계학습의 역전파에서 쓰이는 손실 함수loss function의 도함수가 바로 이런 벡터 인수 벡터 함수의 도함수이다.

python
import numpy as np

# 유한 차분으로 야코비 행렬 계산: J[i,j] = ∂f_i/∂x_j
def jacobian(f, x, h=1e-6):
    x = np.asarray(x, dtype=float)
    f0 = np.asarray(f(x), dtype=float)
    J = np.zeros((f0.size, x.size))
    for j in range(x.size):
        e = np.zeros_like(x); e[j] = h
        J[:, j] = (f(x + e) - f(x - e)) / (2 * h)
    return J

# f(x,y) = [ x^2 * y , 5x + sin(y) ]
f = lambda v: np.array([v[0]**2 * v[1], 5*v[0] + np.sin(v[1])])
p = np.array([2.0, 1.0])

J = jacobian(f, p)
exact = np.array([[2*p[0]*p[1], p[0]**2],   # [2xy, x^2]
                  [5.0,         np.cos(p[1])]])  # [5, cos y]
print("점 (2,1)에서 수치 야코비 =")
print(np.round(J, 4))
print("해석 야코비 =")
print(np.round(exact, 4))
print("일치:", np.allclose(J, exact))

헤시안 행렬 ​

  • 스칼라장 f(x)의 그래디언트 ∇f는 다시 벡터 인수 벡터 함수이므로, 그 야코비 행렬을 취하면 헤시안 행렬Hessian matrix이 된다. 헤시안은 이계 편미분들을 성분으로 갖는다.
H=∂∂x(∂f∂x)⊤,Hij=∂2f∂xi∂xj
  • 혼합 편미분의 순서가 무관하므로(∂2f/∂xi∂xj=∂2f/∂xj∂xi) 헤시안은 대칭행렬이다. 정류점에서 헤시안이 양의 정부호이면 극소, 음의 정부호이면 극대, 부호가 섞이면 안장점이다.
python
import numpy as np

# 유한 차분 헤시안: H[i,j] = ∂²f / ∂x_i∂x_j
def hessian(f, x, h=1e-4):
    x = np.asarray(x, dtype=float); n = x.size
    H = np.zeros((n, n))
    for i in range(n):
        for j in range(n):
            ei = np.zeros(n); ei[i] = h
            ej = np.zeros(n); ej[j] = h
            H[i, j] = (f(x+ei+ej) - f(x+ei-ej) - f(x-ei+ej) + f(x-ei-ej)) / (4*h*h)
    return H

# f(x,y) = x^2 + y^2 + 3xy  ->  H = [[2,3],[3,2]] (상수)
f = lambda v: v[0]**2 + v[1]**2 + 3*v[0]*v[1]
H = hessian(f, np.array([1.0, 1.0]))
print("헤시안 H =")
print(np.round(H, 3))
print("대칭 여부:", np.allclose(H, H.T))
print("고윳값:", np.round(np.linalg.eigvalsh(H), 3),
      "-> 부호 혼재이면 안장점")

행렬 미분 항등식 ​

  • f, g를 벡터 x를 받아 스칼라를 돌려주는 함수, a를 x에 무관한 스칼라라 하면 기본 항등식은 다음과 같다.
∂∂x(af)=a∂f∂x,∂∂x(f+g)=∂f∂x+∂g∂x∂∂x(fg)=f∂g∂x+g∂f∂x,∂∂x(f∘g)=∂f∂g∂g∂x
  • x에 무관한 상수 벡터 a에 대해 선형형식의 미분과, 벡터값 함수의 곱셈 항등식이 성립한다.
∂∂x(a⊤x)=a⊤,∂∂x(f⊤g)=f⊤∂g∂x+g⊤∂f∂x

역전파의 핵심 — 벡터 함수의 연쇄법칙

스칼라 인수 벡터 함수와 벡터 인수 벡터 함수 모두에 대해 상수배·상수행렬배·합·연쇄법칙이 성립한다.

∂∂x(Af)=A∂f∂x,∂∂x(f∘g)=∂f∂g∂g∂x

마지막 연쇄법칙(야코비의 곱)이 신경망 역전파의 수학적 뼈대이다.

성분별 연산의 도함수 ​

  • 두 벡터의 덧셈 f=a+b의 야코비는 ∂f/∂a=I, ∂f/∂b=I이다. 뺄셈이면 ∂f/∂b=−I이다.
  • 성분별 곱셈 fi=aibi의 야코비는 대각행렬이 된다(비대각 성분은 서로 무관하므로 0).
∂f∂a=diag(b0,…,bn−1),∂f∂b=diag(a0,…,an−1)
PDF