🔄 자동 미분 (auto-grad)
KeraTorch는 자동 미분을 지원한다. 자동 미분이란 함수형 프로그래밍 언어와 같이 어떤 값을 연산할 때 연산 결과뿐만 아니라 연산 과정을 추적하여 자동으로 미분을 해주는 것을 말한다. 이는 딥러닝의 오차 역전파 (backpropagation)에서 필수적이다.
본 프로젝트에서 자동 미분을 위해 구현한 GradArray
클래스와 Grad
클래스에 대해 자세히 살펴보기 전에 역전파 알고리즘이 왜 필요하고 어떤 방식으로 작동하는지 간단히 알아보자.
⏪ 역전파 (backpropagation)
1. 모델 및 오차 정의
필자는 딥러닝을 가능하게 만든 가장 중요한 알고리즘은 역전파라고 생각한다. 오차 역전파는 Geoffrey Hinton이 크게 기여한 알고리즘으로, 신경망의 오차가 계산되었을 때 그 값에 각 파라미터가 기여하는 정도를 미분으로 계산하는 방식을 말한다.
예를 들어 아래와 같은 수식으로 연산되는 퍼셉트론 (perceptron)을 생각해보자.
z(x)=wTx+b=i=1∑nwixi+by^(x)=σ(z(x))
위 모델은 입력 x∈Rn에 대해 스칼라 출력 y^∈R을 만든다. 모델에 비선형성을 주기 위해 비선형 활성화함수 σ를 적용한다.
우리는 이제 모델을 데이터셋 {(x1,y1),⋯(xN,yN)}에 fitting 하고자 한다. 이때, 모델이 만든 출력 y^와 실제 정답 y의 차이의 제곱을 오차로 정의할 수 있을 것이다. 여러 개의 데이터가 학습에 사용되므로 전체 데이터에 대한 오차는 각 데이터에 대한 오차의 평균이다.
L=N1i=1∑N(y^i−yi)2wherey^i=y^(xi)
✅ n은 입력의 차원 (n=dimx), N은 batch의 크기이다.
2. 경사하강법과 오차 역전파
우리는 모델을 L을 줄이는 방향으로 업데이트 하기 위해 경사하강법 (gradient descent) 알고리즘을 이용한다. 경사하강법은 아래의 수식을 이용하여 파라미터를 업데이트한다.
w←w−α∂w∂L
위 식에서 오차 L에 대한 파라미터 w에 대한 편미분은 w에 대해 L이 증가하는 정도를 나타낸다. 즉, L이 Rn에 그리는 면의 w 축에 대한 기울기이다. 경사하강법은 이 방향의 음의 방향으로 파라미터를 조절한다.
이때 역전파 알고리즘이 이용된다. 연쇄 법칙 (chain rule)을 적용한 아래 식을 살펴보자. 간단하게 표현하기 위해 두 출력은 vector 형태로 작성하겠다.
{y^:=[y^1⋯y^N]⊤y:=[y1⋯yN]⊤
∂w∂L=∂y^∂L∂w∂y^=∂y^∂L∂z∂y^∂w∂z
L에 대한 wi의 편미분을 직접 계산하기 복잡하기 때문에 미분의 연쇄 법칙을 이용하여 다른 편미분의 곱으로 계산한다. 우선 첫 번째 항을 계산해보자.
L=N1i=1∑N(y^i−yi)2=N1i=1∑N(y^i2−2y^iyi+yi2)=N1(y^⊤y^+y⊤y−2y^⊤y)
∂y^∂L=N1∂y^∂L(y^⊤y^+y⊤y−2y^⊤y)=N2(y^−y)⊤
두 번째 항 또한 계산해보자.
∂z∂y^=[∂z∂y^1⋯∂z∂y^N]⊤=[∂z∂σ(z(x1))⋯∂z∂σ(z(xN))]⊤=[σ′(z(x1))⋯σ′(z(xN))]⊤
세 번째 항은 아래와 같이 계산된다. 간단한 선형 결합이므로 미분 또한 상수로 표현된다.
∂w∂z=x⊤
최종적으로 파라미터 업데이트를 위해 계산해야 했던 미분식은 아래와 같이 표현된다.
∂w∂L=N2(y^−y)⊤⎣⎢⎢⎡σ′(z(x1))⋮σ′(z(xN))⎦⎥⎥⎤x⊤
이로써 위 미분값을 이용해 파라미터 w를 업데이트 할 수 있게 되었다.
❗️ 역전파 알고리즘의 중요성
하나의 층으로 구성된 퍼셉트론의 예시에서는 오차 역전파가 강력한 도구로 보이지 않지만, 위와 같은 역전파 매커니즘이 깊은 네트워크에도 동일하게 적용된다는 점에서 딥러닝에 역전파 알고리즘은 필수적이다.
🏠 GradArray
클래스
GradArray
클래스는 PyTorch의 torch.Tensor
와 유사한 역할을 하는 클래스로, 실제 array 값과 값이 연산되기 위해 사용된 연산자 정보를 저장한다.
GradArray
가 지니는 중요한 속성을 몇 가지 살펴보겠다.
-
GradArray._array
: numpy.ndarray
타입으로, 실제 array 값을 저장한다.
-
GradArray._grad
: numpy.ndarray
타입으로, 역전파가 실행되었을 때 연산된 미분 값을 저장한다.
-
GradArray._grad_op
: Grad
타입으로, 해당 GradArray
가 생성되기 위해 수행된 연산 정보를 저장한다. 연산되지 않고 값만 할당된 GradArray
의 경우에는 None
으로 설정된다.
위 3가지 속성으로 GradArray
는 역전파를 지원한다. 자세한 역전파 과정과 연산은 다음 포스트에서 살펴보겠다.
⛰️ Grad
클래스
역전파를 지원하기 위해 연산 정보를 저장하는 추상 클래스이다. 연산의 정보를 저장하기 위해 연산에 사용된 입력 GradArray
를 저장하며, 역전파 과정에서 미분값이 입력 GradArray
로 전달된다.
Grad
추상 클래스는 자체로는 아무런 연산 정보를 갖지 않기 때문에 Grad.backward()
는 추장 메소드로 선언되어 있다. Grad
추상 클래스를 상속한 AddGrad
, TransposeGrad
, MatMulGrad
, PowerGrad
등의 클래스는 backward()
를 적절히 정의함으로써 역전파 알고리즘에서 호출될 수 있도록 구현한다.
🔥 KeraTorch는 OOP를 적극적으로 수용한다!
✈️ 결론 및 다음 포스트
이번 포스트에서는 자동 미분 및 오차 역전파와 GradArray
, Grad
클래스의 대략적인 구조와 역할에 알아봤다. 다음 포스트에서는 KeraTorch의 핵심이라고 볼 수 있는 GradArray
와 Grad
클래스의 작동 방식과 연산을 세부적으로 알아보겠다.
공감하며 읽었습니다. 좋은 글 감사드립니다.