역전파(Backpropagation)는 손실에서 출발해 계산 순서를 거슬러 올라가며 각 가중치의 기울기를 구하는 방법이다. 기울기는 현재 가중치를 조금 바꿀 때 손실이 어느 방향으로 얼마나 변하는지 나타낸다.
앞 글에서는 은닉층으로 XOR를 표현할 수 있음을 확인했다. 이제는 원하는 출력을 내도록 가중치를 조정하는 데 필요한 기울기를 어떻게 구하는지 살펴본다.
순전파(Forward propagation)는 입력으로부터 은닉층의 값과 예측값을 차례로 계산하는 과정이다. 예측값을 정답과 비교하면 손실을 얻는다. 앞쪽 가중치는 여러 계산을 거쳐 손실에 영향을 주므로, 그 사이의 연결을 따라 미분해야 한다.
이때 사용하는 연쇄 법칙(Chain rule)은 합성함수의 미분을 중간 단계의 미분을 곱해 구하는 규칙이다. 가중치 가 중간값 와 예측값 를 거쳐 손실 에 영향을 주는 하나의 경로라면 다음과 같다.
각 항은 바로 이웃한 계산 사이의 변화율이다. 역전파는 출력 쪽에서 구한 기울기에 현재 단계의 미분을 곱해 앞쪽으로 전달한다. 이미 계산한 기울기를 다시 사용하므로 가중치마다 전체 경로를 처음부터 계산할 필요가 없다.
은닉층의 값 하나가 여러 출력으로 이어진다면 각 경로를 통해 전달된 기울기를 더한다. 예를 들어 은닉값 가 두 중간값 , 로 이어지고, 이 두 경로로만 손실에 영향을 준다면 다음과 같다.
역전파로 기울기를 구한 다음에는 경사 하강법(Gradient descent) 같은 최적화 방법으로 가중치를 갱신한다. 기본 경사 하강법의 갱신식은 다음과 같다.
는 이동 크기를 정하는 학습률이다. 기울기가 양수이면 가중치를 줄이고, 음수이면 늘린다. 한 번의 갱신에 사용할 기울기는 모두 갱신 전의 같은 가중치 상태에서 계산한다. 앞층의 기울기를 구하는 도중에 뒷층의 가중치를 새 값으로 바꾸어 넣으면 안 된다.
PyTorch에서는 이 역할을 다음과 같이 나눈다.
| 호출 | 역할 |
|---|---|
optimizer.zero_grad() | 이전에 쌓인 기울기를 초기화한다. |
loss.backward() | 계산 그래프를 거슬러 기울기를 계산하고 파라미터의 .grad에 누적한다. |
optimizer.step() | 저장된 기울기와 선택한 최적화 규칙에 따라 파라미터를 갱신한다. |
일반적인 학습에서는 매번 기울기를 초기화하고, 새 손실의 역전파를 수행한 뒤 가중치를 갱신한다. backward() 호출만으로 가중치가 바뀌지는 않는다.
계산을 확인하기 위해 입력·은닉 뉴런·출력 뉴런이 각각 하나인 신경망을 구성한다. 편향은 생략하고, 두 뉴런 모두 시그모이드 를 사용한다. 입력은 , 정답은 , 두 가중치는 , 이다.
시그모이드의 미분은 이다. 이를 연쇄 법칙에 대입하면 두 가중치의 기울기를 구할 수 있다.
앞쪽 가중치의 식에는 출력층을 거쳐 은닉층까지 돌아오는 데 필요한 미분이 더 곱해져 있다.
, , , 을 넣으면 다음 값을 얻는다. 수치는 소수점 아래 여섯 자리로 반올림했다.
| 계산 | 값 |
|---|---|
| 은닉값 | 0.500000 |
| 예측값 | 0.622459 |
| 손실 | 0.071268 |
| 기울기 | -0.022181 |
| 기울기 | -0.044362 |
학습률을 0.1로 두면 새 가중치는 각각 약 0.002218, 1.004436이다. 이 값으로 다시 순전파하면 손실은 약 0.071023으로 줄어든다. 이 예시는 한 번의 계산을 확인한 것으로, 학습률이 지나치게 크면 갱신 후 손실이 오히려 커질 수 있다.