개인 공부 공간/딥러닝
밑바닥부터 시작하는 딥러닝3 - STEP 6
Hoon Kang
2021. 3. 10. 23:02
Variable 클래스 추가 구현
역전파에 대응하는 Variable 클래스 구현 코드는 다음과 같다.
class Variable:
def __init__(self, data):
self.data = data
self.grad = None
grad
라는 인스턴스 변수를 추가한 후 None으로 초기화해 놓은 후에 실제로 나중에 역전파를 하면 미분값을 계산하여 대입한다.
Function 클래스 추가 구현
기존 Function
클래스에 다음 두 기능을 추가.
- 미분을 계산하는 역전파(
backward
메서드) forward
메서드 호출 시 건네받은Variable
인스턴스 유지
class Function:
def __call__(self, input):
x = input.data
y = self.forward(x)
output = Variable(y)
self.input = input # 입력 변수를 기억(보관)한다.
return output
def forward(self, x):
raise NotImplementedError()
def backward(self, gy):
raise NotImplementedError()
__call__
메서드에서 입력된 input을 self.input
에 저장후 나중에 역전파 과정에서 필요할 시 가져와 사용할 수 있다.
Square와 Exp 클래스 추가 구현
class Square(Function):
def forward(self, x):
y = x ** 2
return y
def backward(self, gy):
x = self.input.data
gx = 2 * x * gy
return gx
class Exp(Function):
def forward(self, x):
y = np.exp(x)
return y
def backward(self, gy):
x = self.input.data
gx = np.exp(x) * gy
return gx
backward
의 인수 gy
는 출력 쪽에서 전해지는 미분값을 전달하는 역할을 한다.
역전파 구현
위와 같은 계산 그래프를 순전파 하는 코드는 다음과 같다.
A = Square()
B = Exp()
C = Square()
x = Variable(np.array(0.5))
a = A(x)
b = B(a)
y = C(b)
이를 역전파로 y를 미분하는 과정의 계산 그래프와 코드는 다음과 같다.
y.grad = np.array(1.0)
b.grad = C.backward(y.grad)
a.grad = B.backward(b.grad)
x.grad = A.backward(a.grad)
print(x.grad)
실행 결과
3.297442541400256
역전파는 $dy/dy = 1$ 에서 시작하기 때문에 출력 $y$의 미분값인 y.grad
를 np.array(1.0)
로 설정해야 한다. 수동으로 역전파를 구현하는 방법은 배웠지만 매번 역전파 순서에 맞춰 코드를 작성한다는 점과 초기 미분값을 자동으로 설정해줄 수 있다면 더욱 편리할 것 같다는 생각이 들었다.
출처: 사이토 고키, 『밑바닥부터 시작하는 딥러닝3』, 개앞맵시, 한빛미디어(2020)