페이지

2022년 8월 6일 토요일

4.2 수치 미분 구현

 그럼 미분을 정의한 [식4.1]에 따라 미분을 계산하는 코드를 구현해봅시다. 그런데 컴퓨터는 극한을 취급할 수 없으니 h를 극한과 비슷한 값으로 대체하겠습니다. 예를 들어 h = 0.0001(=1e-4)과 같은 매우 작은 값을 이용하여 [식 4.1]을 계산합니다. 이런 미세한 차이를 이용하여 함수의 변화량을 구하는 방법을 수치미분(numerical diffierentiation)이라고 합니다.

수치 미분은 작은 값을 사용하여 '진정한 미분'을 근사합니다. 따라서 값에 어쩔 수 없이 오차가 포함되는데, 이 근사 오차를 줄이는 방법으로는 '중아차분centered difference'이라는 게 있습니다.

중앙차분은 f(x)와 f(x + h)의 차이를 구하는 대신 f(x-h)와 f(x+h)의 차이를 구합니다. 그름으로 나타내면 [그림 4-2]의 파란 선에 해당하죠.


[그림 4-2]에서 보듯 x와 x + h지정에서의 기울기를 구하는 방법을 '전진차분(forward difference'이라 하고, x - h와 x + h에서의 기울기를 구하는 방법을 '중앙차분'이라 하는데, 중앙차분쪽이 상대적으로 오차가 작습니다. 책에 증명까지는 싣지 않았지만 직관적으로는 [그림4-2]에서 직선들의 기울기를 비교해보면 알 수 있습니다. 참고로 중앙차분에서 직선의 기울기는 (f(x+h) - f(x-h))/2h입니다(분모가 2h인 점에 주의하세요).

전진차분보다 중앙차분이 진정한 미분값이 가깝다는 사실은 테일러 급수(Tayler series)를 이용해 증명할 수 있습니다.


그러면 중앙차분을 이용하여 수치 미분을 계산하는 함수를 numerical_diff(f, x, eps=1e-4)라는 이름으로 구현해봅시다. 첫 번째 인수 f는 미분의 대상이 되는 함수이며, 앞에서 구현한 Function의 인스턴스입니다. 두 번째 인수 x는 미분을 계산하는 변수로, Variable인스턴스입니다. 마지막의 eps는 작은 값을 나타내며, 기본값은 1e-4입니다. 수치 미분은 다음과 같이 구현할 수 있습니다.

def numerical_diff(fxeps=1e-4):
  x0 = Variable(x.data - eps)
  x1 = Variable(x.data + eps)
  y0 = f(x0)
  y1 = f(x1)
  return (y1.data - y0.data)/(2 * eps)


실제 데이터는 Variable의 인스턴스 변수인 data에 들어 있다는 것만 주의하면 특별히 조심할 점은 없어 보입니다. 그러면 3단계에서 구현한 Square 클래스를 대상으로 미분해 보겠습니다.

f = Square()
x = Variable(np.array(2.0))
dy = numerical_diff(f, x)
print(dy)

4.000000000004

이렇게 함수 y = x ** 2에서 x = 2.0일때 수치 미분한 결과를 구했습니다. 오차가 없었다면 4.0이 나왔어야 하니, 이 결과는 거의 올바른 값이라고 할 수 있겠네요

댓글 없음: