개발일기

기초 수학 - 편미분(Partial Derivative) 본문

AI/기초 수학

기초 수학 - 편미분(Partial Derivative)

Flashback 2024. 6. 29. 21:04
728x90
반응형

편미분(Partial Derivative)에 대한 정의

지금껏 봐온 함수는 $ \frac{\mathrm{d} y}{\mathrm{d} x} = x^2 - 3x + 6 $ 와 같이 $ x $ 라는 변수 하나로 y의 미분값이 결정되는 일변수 함수였다. 하지만 머신 러닝에서 주로 사용되는 함수는 다변수 함수이다. 다변수 함수는 $ z = x^2y^2 + 7xy - 3x + 6 $와 같이 여러 개의 독립 변수를 가지고 있는 함수를 의미한다. 이와같이 $ x $, $ y $ 라는 여러 개의 독립 변수를 가진 다변수 함수를 미분하기 위해 편미분을 사용한다.

 

3D그래프로 확인하기

$ z = x^2 - y^2 $ 라는 다변수 함수는 $ x $, $ y $라는 변수를 가지고 있으며 이 변수들은 결과값 z에 영향을 주는 변수이다.

https://www.geogebra.org/3d 이 사이트로 이동해 3D그래프로 확인하면 편미분에 대한 이해를 더 쉽게 할 수 있다.

 

$ z = x^2 - y^2 $

시각화할 방정식 $ z = x^2 - y^2 $ 를 써넣으면 위와 같은 그래프가 나타나게 된다. 그래프를 돌려 확인하면 z >0 부분은 아래로 볼록한 포물선, z< 0 부분은 위로 볼록한 포물선이 있다.

 

y축 고정 그래프

이 그래프를 돌려 y를 0으로 고정하면 다음과 같은 모양이 나타난다.

y축 고정

y값을 고정시키면 온전히 그래프는 x에 따른 z의 변화를 확인할 수 있다. 즉, z에 대한 x의 경사를 구할 수 있다. y값을 고정시켰으니 y값을 상수로 취급한다. 상수로 취급하는 이유는 y는 0으로 고정되어있고 x와 z간의 변화에 따른 값을 구하기 때문이다. $ x^2 - y^2 $ 을 미분하면 $ y^2 $ 는 상수로 취급되어 0이 된다. 즉 y를 고정시킨 상태에서 $ z = x^2 - y^2 $ 의 도함수는 $ \frac{\partial z}{\partial x} = 2x $ 가 된다. 부호를 보면 $ \partial $ 가 사용됬는데 편미분을 표기할 대는 $ \partial $ 를 사용한다.

 

z축 고정 그래프

이와 반대로 x값을 고정하면 y에 따른 z의 변화를 확인할 수 있다.

x축 고정

x가 고정된 상태에서 편미분을 하면 $ x^2 $ 을 상수 취급하여 $ \frac{\partial z}{\partial y} = -2y $ 로 도함수가 구해진다.

Pytorch에는 편미분을 바로 출력하는 함수는 없으며 기존의 자동 미분을 응용하여 편미분 값을 구할 수 있다.

 

Pytorch 편미분

# Pytorch Partial Derivative
import torch

x = torch.tensor(2.0, requires_grad=True)
y = torch.tensor(3.0, requires_grad=True)

def f(x, y):
  return x**2 - y**2

z = f(x, y).backward() # 역전파

print(x.grad) # x에 대한 편미분
print(y.grad) # y에 대한 편미분

# tensor(4.)
# tensor(-6.)

$ x^2 - y^2 $ 를 z에 할당하고 backward() 함수를 호출하여 자동 미분을 수행한다. z에는 x와 y라는 서로 다른 두 텐서를 들어가 있으며 각 텐서를 grad함수로 호출하면 해당 텐서의 편미분값을 확인할 수 있다.

또 다른 방법이 있는데 이는 torch.autograd.grad를 사용하는 방법이다.

 

import torch

def f(x, y):
    return x**2 - y**2

x = torch.tensor(2.0, requires_grad=True)
y = torch.tensor(3.0, requires_grad=True)

z = f(x, y) # 함수 f(x, y) 생성

grad_x, grad_y = torch.autograd.grad(z, [x, y]) # z에 대한 x, y의 편미분값

print(grad_x) # x에 대한 편미분
print(grad_y) # y에 대한 편미분

# tensor(4.)
# tensor(-6.)

torch.autograd.grad()에 첫번째 파라미터에는 미분할 함수인 z를 입력한다. 두번째 파라미터에는 미분할 변수들을 리스트에 추가한다. 여기선 x와 y이므로 [x, y]를 입력한다.

각 변수에 대한 미분값이 계산된 grad_x와 grad_y를 출력하면 해당 변수에 따른 편미분 값을 확인할 수 있다.

Tensorflow에서도 Pytorch와 비슷한 방식으로 편미분 값을 확인할 수 있다.

 

Tensorflow 편미분

import tensorflow as tf

x = tf.Variable(2.0)
y = tf.Variable(3.0)

with tf.GradientTape(persistent=True) as t:
  z = x**2 - y**2

grad_x = t.gradient(z, x) # z에 대한 x의 편미분 값
print(grad_x)

grad_y = t.gradient(z, y) # z에 대한 y의 편미분 값
print(grad_y)

del t

# tf.Tensor(4.0, shape=(), dtype=float32)
# tf.Tensor(-6.0, shape=(), dtype=float32)

persistent: 미분을 여러번 하기 위해 사용한다. GraidentTape는 한 번 호출하면 보유한 리소스가 해제된다. 동일한 방정식에 대해 여러번 미분하려면 persistent를 True로 설정해야 한다. persistent를 False로 설정하면 한 번의 미분만 가능하다.

del: GradientTape 객체를 삭제하여 메모리를 해제한다. persistent를 True로 설정하면 자동으로 메모리가 해제되지 않고 여러번 미분 연산을 위해 지속된다. 그렇기 때문에 del을 써서 미분 연산을 한 후 메모리를 해제한다.

위의 코드에서 persistent를 False로 설정하면 에러가 발생한다.

# Tensorflow Partial Derivative
import tensorflow as tf

x = tf.Variable(2.0)
y = tf.Variable(3.0)

with tf.GradientTape(persistent=False) as t:
  z = x**2 - y**2

grad_x = t.gradient(z, x)
print(grad_x)

grad_y = t.gradient(z, y)
print(grad_y)

"""
tf.Tensor(4.0, shape=(), dtype=float32)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-12-869e77d93169> in <cell line: 13>()
     11 print(grad_x)
     12 
---> 13 grad_y = t.gradient(z, y)
     14 print(grad_y)

/usr/local/lib/python3.10/dist-packages/tensorflow/python/eager/backprop.py in gradient(self, target, sources, output_gradients, unconnected_gradients)
   1003     """
   1004     if self._tape is None:
-> 1005       raise RuntimeError("A non-persistent GradientTape can only be used to "
   1006                          "compute one set of gradients (or jacobians)")
   1007     if self._recording:

RuntimeError: A non-persistent GradientTape can only be used to compute one set of gradients (or jacobians)
"""

persistent=False로 인해 한 번 미분을 진행한 후, 메모리가 해제됬는데 미분 연산을 재호출했기 때문에 위와 같은 에러가 발생한다. True로 설정하면 에러없이 실행할 수 있다.

 


참고 사이트:

https://www.geogebra.org/3d

 

3차원 계산기 - GeoGebra

 

www.geogebra.org

 

https://colab.research.google.com/drive/10MzjbCA6_5PxZS7IXbdCePjV2D6Eqwk4?usp=sharing

 

편미분.ipynb

Colab notebook

colab.research.google.com

 

 

 

728x90
반응형
Comments