Tensorflow 2 NLP(자연어처리)/추가적으로 필요한 개념

Automatic Differentiation이란

Suhd 2022. 10. 23. 15:19

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

 

Automatic differentiation - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Techniques to evaluate the derivative of a function specified by a computer program In mathematics and computer algebra, automatic differentiation (AD), also called algorithmic diffe

en.wikipedia.org

 

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

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

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

그렇다면,

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

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

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

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

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

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

서로 곱해줘야 한다.

재미있는 부분은 우리가

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

각각의 chain의 미분값들은

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

연관을 가진다는 뜻은,

하나의 chain의 미분값이

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

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

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

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

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


Forward accumulation specifies that one traverses the chain rule from inside to outside

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

Forward accumulation이라고 하고,

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

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

Reverse accumulation이라고 한다.

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

이제 각각을

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


 

 

Forward accumulation

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

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

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

을 구해보자.

 


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

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


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

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

A


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

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

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

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


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


Reverse accumulation

 

Reverse accumulation은

Forward와 반대로

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

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


를 가장 바깥쪽 껍질에 해당하는 함수 ( 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 : RnRm with mn

- Reverse accumulation is more efficient than forward accumulation for functions f : RnRm with mn

Forward acuumulation의 경우에는

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

Reverse acuumulation의 경우에는 반대로

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