실습 · 연습문제 2개
상대오차로 gradient 검증하기 gradient-check
해석적으로 구한(또는 직접 만든 자동미분이 계산한) gradient가 맞는지 중앙차분으로 확인하는 함수 grad_check(f, grad, x, eps=1e-6)를 완성한다.
| 인자 | 설명 |
|---|---|
f |
1차원 배열 (n,)을 받아 스칼라를 돌려주는 함수 |
grad |
검사할 gradient, shape (n,) |
x |
검사할 점, shape (n,) |
eps |
중앙차분 간격 |
반환값은 성분별 상대오차의 최댓값(스칼라)이다. 성분 의 상대오차는
이고, 는 중앙차분이다. 분모의 는 두 값이 모두 0인 성분에서 0으로 나누지 않기 위한 것이다.
요구 사항:
x가 float32 배열이나 정수 배열로 주어져도 float64로 바꿔 계산한다. float32로 차분하면 반올림 오차 때문에 올바른 gradient도 큰 상대오차를 보인다(본문 참고).- 입력
x를 제자리에서 바꾸지 않는다.
테스트는 올바른 gradient에서 상대오차가 미만인지, 상수배가 틀린 gradient와 한 성분의 부호가 틀린 gradient에서 보다 큰지, gradient가 0인 성분에서 nan이 나오지 않는지, float32 입력을 float64로 처리하는지 확인한다.
힌트: x = np.array(x, dtype=np.float64)는 복사본을 만든다.
스칼라 자동미분 엔진 만들기 value-engine
본문의 엔진을 직접 다시 만든다. Value는 스칼라 값 data, 그 값에 대한 출력의 gradient grad, 이 노드를 만든 입력 노드 parents, 각 입력에 대한 국소 미분 local_grads를 가진다. 생성자는 주어져 있다.
다음 네 메서드를 완성한다.
| 메서드 | 순전파 값 | 기록할 국소 미분 |
|---|---|---|
a + b (__add__) |
||
a * b (__mul__) |
||
a.tanh() |
||
out.backward() |
— | 아래 설명 |
backward()는 out.grad = 1로 두고, 그래프의 노드를 위상 순서의 역순(출력에서 입력 쪽)으로 방문하며 각 노드 v의 입력 p에 p.grad += local * v.grad를 더한다.
b가 Value가 아닌 숫자(float, int)여도 a + 2.0, a * 3이 동작해야 한다. 숫자는 Value로 감싼다.
테스트가 확인하는 것:
- 뉴런 하나 의 gradient가 손 유도와 같은가.
- 같은 노드를 여러 번 쓰는 식 에서 인가. gradient를 덮어쓰지 말고 더해야 한다.
- 마름모 모양 그래프 에서 위상 순서가 맞는가. 어떤 노드의 gradient를 그 노드를 쓰는 모든 노드가 처리되기 전에 전달하면 틀린다.
힌트: 위상 정렬은 깊이 우선 탐색으로 만든다. 노드의 모든 입력을 먼저 방문한 뒤 자신을 리스트에 넣으면, 리스트의 역순이 출력에서 입력으로 가는 순서다.