Stage 02 — 연쇄 법칙을 코드로: 역방향 자동미분
국소 미분값을 역순으로 합성하고, 공유 노드 누적·중앙 차분·실패 원자성으로 reverse-mode 자동미분을 검증한다.
GPT 학습에서 역전파는 “미분 공식을 안다”는 말만으로 구현되지 않는다. 각 연산의 국소 미분값을 어느 간선에 저장하고, 출력에서 입력 방향으로 어떤 순서로 이동하며, 같은 노드로 돌아온 값들을 어떻게 합칠지 코드로 결정해야 한다.
테스트: Stage 02 테스트
이번 단계가 답할 질문
각 연산의 국소 미분값만 알고 있을 때, 계산 그래프 전체의 미분값을 정확하고 안전하게 구할 수 있는가?
이번 Stage의 범위는 덧셈과 곱셈의 국소 미분, 재귀를 쓰지 않는 위상 정렬, 역방향 전파, 공유 노드 gradient 합산, 중앙 차분 대조, 실패 시 원자적 반영이다. 거듭제곱,지수,로그,tensor,신경망 layer,optimizer는 아직 넣지 않는다.
계산할 함수
z = x*y + x*x
x = 2, y = -3
순전파 값은 product = -6, square = 4, z = -2다. 해석적으로는 다음과 같다.
dz/dx = y + 2x = -3 + 4 = 1
dz/dy = x = 2
국소 미분값을 간선에 기록하기
덧셈 a + b의 국소 미분값은 (1, 1), 곱셈 a * b는 (b, a)다. 결과 노드는 parent와 같은 순서로 국소 미분값을 저장한다.
node.parents = (a, b)
node.local_grads = (dnode/da, dnode/db)
수식은 평범한 산술처럼 읽히지만, 역전파의 위험 경계인 parent와 국소 미분값은 직접 검사할 수 있다. 복잡함을 숨기는 것이 아니라 gradient가 흐르는 간선을 읽을 수 있게 만든 추상화다.
역방향 순회와 연쇄 법칙
위상 정렬은 모든 parent를 consumer보다 먼저 배치한다. 그 목록을 뒤집어 출력부터 처리하고, 출력 gradient를 1로 둔다.
dL/dparent += dL/dnode * dnode/dparent
여기서 +=가 핵심이다. x는 x*y와 x*x 두 경로에 동시에 참여한다. 두 기여도를 합치지 않고 덮어쓰면 마지막 경로 하나만 남는다.
직접 실행한 결과
Windows PowerShell에서 다음 명령을 실행했다.
python .\stages\stage_02_reverse_autodiff.py
python -m unittest tests.test_stage_02_reverse_autodiff -v관찰 결과는 다음과 같다.
- 순전파:
product = -6,square = 4,z = -2 - 역전파:
dz/dx = 1,dz/dy = 2 - 중앙 차분:
dx = 1.00000000,dy = 2.00000000 - Stage 02 테스트 7개 통과
- 전체 테스트 22개 통과
- sanity check:
PASS
순전파, 역전파, 중앙 차분 결과

통제 실험 1: 공유 노드의 gradient
z = x*x + x, x = 3으로 바꾸면 해석 미분은 2x + 1 = 7이다. 직접 실행한 결과도 z = 12, dz/dx = 7이었다. 이는 역순 순회만이 아니라 같은 노드로 들어오는 gradient의 합산이 필요하다는 가설을 검증한다.

통제 실험 2: 실패가 상태를 오염시키는가
순전파 값이 유한해도 역전파 도중 overflow가 생길 수 있다. 전파 중 실제 grad를 즉시 바꾸면 실패 이전의 노드만 갱신되어 그래프가 반쯤 변경된다.
backward()는 모든 결과를 임시 pending_grads에서 계산하고, 전부 유한한 경우에만 실제 상태에 반영한다. 파괴적 실험에서 x.grad = 7, y.grad = 8을 먼저 넣고 overflow를 유도했다. FloatingPointError가 발생한 뒤에도 두 값은 그대로 유지됐다.

이 방어선은 실패 범위를 backward() 호출 하나로 제한한다. optimizer가 일부만 갱신된 gradient를 읽는 연쇄 실패도 막는다.
중앙 차분이 필요한 이유
그럴듯한 gradient는 증명이 아니다. 중앙 차분은 함수값만 사용해 독립적으로 기울기를 근사한다.
f'(x) ≈ (f(x+h) - f(x-h)) / 2h
자동미분 구현과 다른 계산 방법이 같은 결과를 내는지 확인한다. step은 유한한 양수만 허용해 잘못된 실험을 시작 경계에서 거부한다.
비용과 Blast Radius
- 노드 수
V, 간선 수E일 때 위상 정렬과 역전파는O(V + E) - 위상 정렬과 임시 gradient는 각각
O(V)보조 메모리 - 원자적 반영은 메모리를 더 쓰지만 부분 갱신의 실패 범위를 그래프 전체에서 호출 하나로 축소
- 기본 1,000노드 제한으로 잘못 만든 거대 그래프의 CPU·메모리 사용을 조기 차단
- GPU·NPU는 사용하지 않으며 모든 연산은 Python 스칼라 계산과 객체 접근 이 코드는 성능 기준이 아니라 계산 비용과 실패 경계를 관찰하기 위한 기준 구현이다.
이번 Stage가 증명한 것
Stage 02는 국소 미분값과 위상 정렬로 연쇄 법칙을 그래프 전체에 적용할 수 있음을 증명했다. 공유 노드의 합산, 수치 미분과의 일치, 실패 시 상태 보존을 서로 다른 통제 실험으로 확인했다.
다음 Stage에서는 GPT의 loss와 layer에 필요한 거듭제곱, 지수, 로그, ReLU를 추가하고 각 연산을 수치 미분으로 독립 검증한다.