Auto Differentiation(자동미분) 이란?

Donghae Suh·2022년 10월 23일

pytroch

목록 보기
1/1

PyTorch가 dynamic auto differentiation(autodif)를 지원한다고 하기에

이 Auto differentiation이 무엇인지 한번 알아보려고 한다.

​

우리는 Gradient Descent를 이용해

손실함수의 최솟값을 쫓아가면서

가중치들을 업데이트한다.

​

이때, 가중치를 업데이트 하는 방법은 아래와 같다.

​

현재 가중치에

Loss를 현재 업데이트하려는 가중치로 편미분한값을

스케일조정(a)해서

빼주는 방식으로 업데이트 한다.

​

Gradient Descent에 대해서는 잘 설명된 글이 넘쳐나기 때문에

이 정도에서 마무리하고

​

이때, 저 미분값을 컴퓨터가 어떻게 계산할 것인지에 대해 다뤄보고자 한다.


Finite Differencing

​

가장 먼저, 도함수의 정의를 이용해 미분값을 구하는 방식이다.

​

하지만 h가 0에 아주 가까이 접근함으로써

h가 너무 작게 되면, 컴퓨터에서 처리할 수 있는

음의 실수 범위를 벗어나게 된다.

이럴 경우, 표현할 수 있는 부분까지 표현하고

나머지를 그냥 잘라내거나(truncate), 반올림(round)하면서 잘라낸다.

-> 이때 생기는 오차가 h가 더욱 작아질 수록 커진다.

-> 이때 생기는 오차를 각각 Truncation Errors, Round-off Errors라고 한다.

​

​

그러자고 h를 키우면,

그에 따른 오차가 생긴다.


Symbolic Differentiation

​

​

우리가 계산하는 미분 법칙을 적용해서 ( ex) x2의 미분 = 2x : 지수를 계수로 내리고 지수에서 1을 뺀다.)

코드로 구현한다음에, 각 변수들에 값을 대입하는 방식이다.

​

​

-> 특정 함수의 경우, 매우 길어지고 복잡해질 수 있다.

(합성함수의 미분법만 생각해도 계수가 높아질 수록 그 식이 매우 길어짐을 볼 수 있다.)

​


Automatic Differentiation

​

어떤 함수든지 간에

​

가장 작은 단위들의 함수들의 합성으로 나타낼 수 있다.

즉, 여러가지 연산으로 이루어져 있는 함수를 합성함수 형태로 바꾸고

​

이에 따른 미분을 chain rule을 이용해 쉽게 계산하는 것이다.

​

이때 Forward accumulation 방법과, Reverse accumulation 방법이 있다.

​

예를 들면서 이해를 해보자.

​

위키피디아의 내용을 정리해보았다.

https://en.wikipedia.org/wiki/Automatic_differentiation#Reverse_accumulation

​

가장먼저, y를 여러 합성함수의 형태로 나타낸 다음에,

가장 안의 껍질부터 하나씩 벗기면서

각각 새로운 변수로 치환을 해준다.

​

그렇다면,

가장 바깥 껍질에 해당하는 y와

가장 안의 껍질에 해당하는 x간의 미분을 구한다면,

위와 같은 치환된 변수에 대한 chain rule을 적용시켜

최종적인 미분을 구할 수 있다.

​

이때, 이 미분을 구하기 위해서는

각각 chain들의 미분값들을 알아낸다음

서로 곱해줘야 한다.

​

재미있는 부분은 우리가

껍질을 하나하나씩 벗겨가면서 치환한 덕분에

각각의 chain의 미분값들은

서로 연관을 가진다는 사실을 발견할 수 있다.

​

연관을 가진다는 뜻은,

하나의 chain의 미분값이

그 다음이나, 그 이전 chain의 미분값을 구하는데

사용된다는 뜻이다...!

​

그래서 하나의 chain의 미분값을 알면

그 다음의 chain의 미분값을 앞선 chain의 미분값과 앞선 chain의 정보들을 가지고 구할 수 있다.

​

이때 어떤 방향으로 미분값을 구해나가는지에 따라 2가지로 나뉜다.

​


​

​

​

껍질 가장 안쪽에서 껍질 바깥쪽으로 chain을 따라 가면서 미분값들을 구하는 방식을

Forward accumulation이라고 하고,

( 변수에서 -> 함수 y 로 흘러가는 정방향(Forward) )

​

​

​

껍질 가장 바깥쪽에서 껍질 안쪽으로 chain을 따라가며 미분값들을 구하는 방식을

​

Reverse accumulation이라고 한다.

( 함수 y -> 변수 로 흘러가는 역방향(reverse) )

​

​


​

이제 각각을

실제 예를 들어가며 이해해보자.

​


Forward accumulation

​

​

가장먼저, x1 , x2라는 독립변수에 대하여,

​

위와같은 함수가 있다고 하자,

​

이 함수의 변수 x1에 대한 편미분

을 구해보자.


​

가장 안쪽 껍질부터 하나하나씩 치환해나가서

최종적으로 단 하나의 변수가 되도록 치환한다.


그 이유는 x1과 x2는 서로 독립적이기 때문에

각각을 서로 편미분 할 경우 0이 되기 때문이다.


이 값을 이용해서 더욱 바깥껍질의 미분

w˙3 , w˙4 ,w˙5 를 구할 수 있다.\dot{w}_3\ ,\ \dot{w}_4\ ,\dot{w}_5\ 를\ 구할\ 수\ 있다.
˙


바깥 껍질에 해당하는 값의 미분값은

이전 껍질의 미분값들과 이전 껍질들의 값들을 조합하여(재사용)

구할 수 있음을 확인할 수 있다.

​


위 함수와 과정을 computational graph(계산 그래프)로 그려보았다.


Reverse accumulation

​

Reverse accumulation은

Forward와 반대로

​
가장 바깥쪽 껍질부터 하나씩 까내면서

미분을 구해나가는 것이다.
​

w̄ 를 가장 바깥쪽 껍질에 해당하는 함수 ( f(x1,x2) = y ) 에 대한

w의 편미분이라 정의하자.

그리고 우리가 구하고자 하는 dy/dx는

chain rule에 의해 아래와 같이 나타낼 수 있다.


이제 바깥쪽 껍질부터 하나하나씩

미분을 구해나가면 된다.

​

주의해야 할 점은, w5의 경우 2개의 합으로 나타내어 지고,

각각의 항에 w1이 존재하기 때문에

w1에 대한 편미분을 구할 때에는

두 항에 대한 편미분을 각각 구한다음 더해줘야 한다.


이는 놓치기 쉽기 때문에

아래와 같이 계산 그래프(computational graph)를 그려서

하나씩 구해나가는 것이 좋다.


​

무엇을 사용해야 할까?

​

Forward accumulation is more efficient than reverse accumulation for functions f : Rn → Rm with m ≫ n

Reverse accumulation is more efficient than forward accumulation for functions f : Rn → Rm with m ≪ n

​

  • Forward acuumulation의 경우에는

입력 차원이 출력차원보다 매우 작은 경우 효율적이라고 하고

​

  • Reverse acuumulation의 경우에는 반대로

출력차원이 입력차원보다 매우 작은 경우 효율적이라고 한다.

0개의 댓글