8.1 현재의 Variable 클래스

빨간 표시를 한 부분이 입력방향으로 하나 앞 변수의 backward 메서드를 호출하는데, 호출된 backward 메서드에서 또 호출하는 방식이고 self.creator가 None이 변수를 찾을 때까지 계속됨
f: <__main__.Square object at 0x000001F79713E410>
x: 1.2840254166877414
x.grad: 2.568050833375483
f: <__main__.Exp object at 0x000001F79713FCD0>
x: 0.25
x.grad: 3.297442541400256
f: <__main__.Square object at 0x000001F79713EFE0>
x: 0.5
x.grad: 3.297442541400256
f: None
f: None
x.backward() None
# f, x.backward 가 None 값 나와서 끝남
# 바로 앞 변수 시작함
f: <__main__.Square object at 0x000001F79713EFE0>
x: 0.5
x.grad: 3.297442541400256
f: None
f: None
x.backward() None
x.backward() None
# f, x.backward 가 None 값 나와서 끝남
f: <__main__.Exp object at 0x000001F79713FCD0>
x: 0.25
x.grad: 3.297442541400256
f: <__main__.Square object at 0x000001F79713EFE0>
x: 0.5
x.grad: 3.297442541400256
f: None
f: None
x.backward() None
# f, x.backward 가 None 값 나와서 끝남
f: <__main__.Square object at 0x000001F79713EFE0>
x: 0.5
x.grad: 3.297442541400256
f: None
f: None
x.backward() None
x.backward() None
x.backward() None
# 완전히 끝!
8.2 반복문을 통한 구현
재귀를 사용한 방식이 비효율 적이여서 반복문을 이용한 구현으로 수정
class Variable:
def __init__(self, data):
if data is not None:
if not isinstance(data, np.ndarray):
raise TypeError('{}은(는) 지원하지 않습니다.'.format(type(data)))
self.data = data # 통상값
self.grad = None # 미분값
self.creator = None # 함수와의 관계
def set_creator(self, func):
self.creator = func
def backward(self):
if self.grad is None:
self.grad = np.ones_like(self.data) # dy/dy = 1
funcs = [self.creator]
while funcs:
f = funcs.pop() # 함수를 가져온다
x, y = f.input, f.output # 함수의 입력과 출력을 가져온다
x.grad = f.backward(y.grad) # backward 메서드를 호출
if x.creator is not None:
funcs.append(x.creator) # 하나 앞의 함수를 리스트에 추가함
여기서 주목할 점은 funcs = [처리해야할 함수들]을 funcs에 차례로 넣고 while 블록 안에서 funcs.pop()을 호출하여 처리할 함수 f를 꺼내고, f의 backward메서드를 호출함
이때, f.input, f.output에서 함수 f의 입력과 출력 변수를 얻음으로써 f.backward()의 인수와 반환값을 올바르게 설정함
8.3 동작 확인
A = Square()
B = Exp()
C = Square()
x = Variable(np.array(0.5))
a = A(x)
b = B(a)
y = C(b)
# 역전파
y.grad = np.array(1.0)
y.backward()
print(x.grad)

- 함수 진행 순서에 따라서 실제 값들이 진행되는 걸 형광펜 색으로 표시했는데, 확실히 전의 재귀함수를 사용했을때보다 훨씬 더 쉽고 빠르게 진행되는 걸 알수 있음
- 재귀 방식이 함수를 재귀적으로 호출할 때마다 중간 결과를 메모리에 유지하면서(스택에 쌓으면서) 처리를 이어감
- 일반적으로 반복문 방식의 효율이 더 좋을 수 밖에 없음
'Study 공부할레나' 카테고리의 다른 글
| [스터디/밑시딥3] 제 1고지 미분 자동 계산_10. 테스트 (0) | 2023.08.15 |
|---|---|
| [스터디/밑시딥3] 제 1고지 미분 자동 계산_9. 함수를 더 편리하게 (0) | 2023.08.15 |
| [스터디/밑시딥3] 제 1고지 미분 자동 계산_7.역전파 자동화 (0) | 2023.08.13 |
| [스터디/밑시딥3] 제 1고지 미분 자동 계산_6.수동 역전파 (0) | 2023.08.13 |
| [스터디/밑시딥3] 제 1고지 미분 자동 계산_5.역전파 이론 (0) | 2023.08.13 |