역전파
고친 사람 github-actions[bot]
역전파는 신경망 안의 숫자마다 어느 쪽으로 얼마나 고칠지를 한 번에 구해 줍니다. 신경망이 답을 낸 계산과 그 답이 틀린 정도를 넣으면 숫자마다 고칠 방향이 나옵니다. 답을 낸 계산을 끝에서부터 거꾸로 되짚어 구하므로 역전파라고 부릅니다. 신경망은 이 결과로 숫자들을 조금씩 고치며 학습합니다.
쉽고 빠른 이해
신경망의 숫자 하나하나가 틀린 답에 얼마나 책임이 있는지 계산해 줍니다. 고양이 사진을 보고 0.3 이라고 답했다고 해 봅니다. 정답은 1 입니다. 그러면 숫자마다 키울지 줄일지와 그 정도가 나옵니다.
숫자가 수백만 개면 하나씩 살짝 바꿔 가며 다시 재는 방법은 끝나지 않습니다. 역전파는 답을 한 번 낸 계산을 거꾸로 한 번 훑어서 전부 구합니다.
- 입력을 넣어 답을 냅니다. 중간 계산값은 모두 적어 둡니다.
- 답이 정답과 얼마나 다른지 숫자 하나로 잽니다.
- 끝 쪽부터 앞쪽으로 계산을 되짚습니다. 뒤에서 구한 값을 앞 단계에 넘겨 가며 숫자마다 책임을 구합니다.
대가는 메모리입니다. 되짚을 때 쓰려고 중간 계산값을 다 들고 있어야 합니다. 계산이 길게 이어지면 뒤에서 넘어온 값이 점점 작아지거나 커져서 앞쪽 숫자가 잘 안 고쳐지기도 합니다.
쓰려면 계산의 단계마다 값을 조금 움직였을 때 결과가 얼마나 변하는지 구할 수 있어야 합니다. 「크면 왼쪽」 같은 갈림으로 답하는 모델에는 못 씁니다.
상세
이 절은 역전파가 무엇을 받아 무엇을 내놓는지부터 봅니다. 그다음 가중치 두 개짜리 작은 계산을 손으로 따라가며 절차를 보입니다. 끝으로 대가와 쓰는 때를 가립니다.
신경망은 입력에 숫자를 곱하고 더하기를 여러 번 되풀이해 답을 냅니다. 이때 곱하는 숫자를 가중치라고 부릅니다. 곱하고 더하는 한 단계는 레이어라고 합니다.
입력이 첫 레이어에서 마지막 레이어로 흘러가며 답이 되는 계산을 순전파라고 합니다. 앞에서 뒤로만 가는 계산입니다. 역전파라는 이름은 이 방향을 뒤집는다는 데서 왔습니다.
답이 틀린 정도는 손실 함수가 숫자 하나로 바꿉니다. 이 숫자를 손실이라고 부릅니다. 정답이 1 인데 0.3 을 냈다면 차이 0.7 을 제곱한 0.49 를 손실로 쓰는 식입니다. 학습은 손실이 작아지도록 가중치를 고치는 일입니다.
가중치를 어느 쪽으로 고칠지는 기울기가 알려 줍니다. 기울기는 가중치를 아주 조금 움직였을 때 손실이 그 움직인 양의 몇 배만큼 변하는지를 나타내는 비율입니다. 기울기가 3 이면 가중치를 0.01 키울 때 손실이 0.03 쯤 커집니다. 이렇게 기울기가 양수면 그 가중치를 줄여야 손실이 작아집니다.
이런 변화 비율을 구하는 계산을 미분이라고 합니다. 기울기를 구한다는 말은 손실을 가중치로 미분한다는 말과 같습니다.
역전파는 손실에 대한 모든 가중치의 기울기를 구하는 절차입니다. 받는 것은 순전파의 계산 과정과 계산 도중에 나온 중간값, 그리고 손실입니다. 내놓는 것은 가중치마다 하나씩인 기울기 목록입니다. 가중치가 백만 개면 기울기도 백만 개가 나옵니다.
구한 기울기로 가중치를 고치는 일은 역전파가 하지 않습니다. 그 일은 경사 하강법이 맡습니다. 학습은 예시 한 묶음마다 순전파, 손실 계산, 역전파, 경사 하강법을 차례로 돕니다. 이 바퀴를 수없이 되풀이합니다.
아래 그림은 이 바퀴에서 단계마다 다음 단계로 넘기는 것을 보입니다.
flowchart TD
F["순전파"] -->|"답과 중간값"| C["손실 계산"]
C -->|"손실"| B["역전파"]
B -->|"가중치마다 기울기"| G["경사 하강법"]
G -->|"고친 가중치로 다음 묶음"| F
기울기를 받아 가중치를 얼마나 옮길지 정하는 방법을 옵티마이저라고 부릅니다. 경사 하강법은 그 가장 단순한 꼴입니다. 어느 옵티마이저를 골라도 기울기는 역전파가 구합니다. 옵티마이저가 바꾸는 것은 그 기울기로 가중치를 얼마나 옮기느냐입니다.
가중치마다 따로 재는 방법
역전파가 왜 필요한지는 가장 단순한 방법과 견주면 보입니다. 그 방법은 가중치를 하나씩 살짝 움직여 보는 것입니다.
가중치 하나를 조금 키우고 순전파를 다시 돌려 손실이 얼마나 변했는지 잽니다. 이 변화를 움직인 양으로 나누면 그 가중치의 기울기가 나옵니다. 이 방법을 수치 미분이라고 부릅니다.
문제는 횟수입니다. 가중치가 백만 개면 기울기를 한 벌 구하는 데 순전파를 백만 번 넘게 돌려야 합니다. 학습은 기울기를 수없이 다시 구하므로 이 방법으로는 끝나지 않습니다.
역전파는 순전파 한 번과 거꾸로 훑는 계산 한 번으로 기울기를 전부 구합니다. 거꾸로 훑는 계산은 순전파와 비슷한 분량이라서 대개 순전파 한 번의 몇 배 안쪽으로 끝납니다. 가중치가 늘어도 이 비율은 크게 변하지 않습니다.
연쇄 법칙
역전파가 기대는 수학 규칙은 하나입니다. 계산이 여러 단계로 이어질 때 앞 단계의 변화가 끝까지 얼마나 크게 전해지는지를 정하는 규칙입니다.
x 를 두 배 한 값을 a 라고 해 봅니다. a 를 제곱한 값은 L 입니다.
x 가 조금 변하면 a 가 변합니다. a 가 변하면 L 이 변합니다. 궁금한 것은 x 의 변화가 L 까지 몇 배로 전해지는가입니다.
답은 단계마다의 변화 비율을 곱하면 나옵니다. 이 규칙을 연쇄 법칙이라고 부릅니다. 첫 단계에서 a 는 x 의 두 배로 변합니다. 둘째 단계에서 a² 을 미분하면 2a 이므로, L 은 a 의 변화에 지금 a 값의 두 배를 곱한 만큼 변합니다.
아래는 x 가 3 일 때를 계산한 코드입니다. 이름 dL_da 는 a 가 변할 때 L 이 몇 배로 변하는지를 담는다는 뜻입니다. 앞 세 줄은 순전파입니다. 뒤 세 줄이 변화 비율입니다.
x = 3.0
a = 2 * x # 6.0
L = a ** 2 # 36.0
dL_da = 2 * a # 12.0
da_dx = 2.0
dL_dx = dL_da * da_dx # 24.0
dL_dx 가 24 라는 것은 x 를 아주 조금 키우면 L 이 키운 양의 24 배만큼 커진다는 뜻입니다. 식을 한 번에 풀어서 맞춰 볼 수 있습니다. L 은 4x² 입니다. 이것을 미분한 8x 에 3 을 넣으면 24 입니다.
끝에서부터 되짚는 순서
연쇄 법칙만 있으면 어느 방향으로 곱해도 답은 같습니다. 이 소절은 왜 끝에서부터 곱하는지를 가중치 두 개짜리 신경망으로 봅니다.
입력 x 에 가중치 w1 을 곱해 중간값 h 를 만듭니다. h 에 가중치 w2 를 곱해 답 y 를 냅니다. 손실은 답과 정답 t 의 차이를 제곱한 값입니다.
실제 신경망은 곱한 값을 활성화 함수에 한 번 더 통과시킵니다. 곱셈만 이어 붙이면 아무리 쌓아도 곱셈 한 번과 같아지기 때문입니다. 아래 예는 계산을 짧게 하려고 이 함수를 뺐습니다.
x, t = 1.0, 5.0 # 입력, 정답
w1, w2 = 2.0, 3.0 # 가중치 둘
h = w1 * x # 2.0
y = w2 * h # 6.0
L = (y - t) ** 2 # 1.0
dy = 2 * (y - t) # 2.0
dw2 = dy * h # 4.0
dh = dy * w2 # 6.0
dw1 = dh * x # 6.0
가운데 세 줄이 순전파입니다. 손실은 1 입니다. 아래 네 줄이 역전파입니다. 끝에 있는 손실에서 출발해 앞으로 거슬러 갑니다.
같은 계산을 그림으로 그리면 아래와 같습니다. 실선은 순전파로 값이 나아가는 길입니다. 점선과 굵은 선은 역전파로 기울기가 돌아오는 길입니다.
flowchart TD
X["x = 1"] --> M1(("×"))
W1["w1 = 2"] --> M1
M1 --> H["h = 2"]
H --> M2(("×"))
W2["w2 = 3"] --> M2
M2 --> Y["y = 6"]
Y --> D(("차이 제곱"))
T["t = 5"] --> D
D --> L["L = 1"]
L -.->|"dy = 2"| Y
Y -.->|"dw2 = dy × h = 4"| W2
Y -.->|"dh = dy × w2 = 6"| H
H ==>|"dw1 = dh × x = 6"| W1
dy 는 y 가 변할 때 손실이 몇 배로 변하는지를 담습니다. (y − t)² 을 미분하면 2(y − t) 라서 2 가 나옵니다. w2 의 기울기 dw2 는 여기에 w2 와 곱해졌던 h 를 곱한 4 입니다.
눈여겨볼 값은 dh 입니다. dh 는 중간값 h 가 변할 때 손실이 몇 배로 변하는지를 담습니다. h 는 w2 와 곱해져 y 가 됐습니다. 그래서 dy 에 w2 를 곱한 6 이 dh 입니다.
w1 의 기울기는 이 dh 에 x 를 곱하기만 하면 나옵니다. 손실에서 h 까지의 계산을 다시 따라갈 필요가 없습니다. 그림의 굵은 선이 이 곱셈입니다.
레이어가 백 개여도 같은 방식으로 돕니다. 각 레이어는 뒤에서 받은 값으로 곱셈을 두 번 합니다. 자기 가중치의 기울기는 받은 값에 그 레이어의 입력을 곱해 얻습니다. 예제의 dw2 = dy × h 가 이것입니다.
앞 레이어로 넘길 값은 받은 값에 그 레이어의 비율을 곱해 얻습니다. 레이어의 비율은 레이어에 들어온 값이 변할 때 나가는 값이 몇 배로 변하는지입니다. 예제에서 h 가 들어와 y 가 나가는 레이어는 비율이 w2 입니다. 그래서 dh = dy × w2 입니다.
아래 그림은 레이어 셋에서 이 넘겨주기가 어떻게 이어지는지 보입니다.
flowchart TD
L["손실"] -->|"넘긴다"| R3["레이어 3 이 받은 값"]
R3 -->|"× 레이어 3 의 입력"| G3["레이어 3 가중치의 기울기"]
R3 -->|"× 레이어 3 의 비율"| R2["레이어 2 가 받은 값"]
R2 -->|"× 레이어 2 의 입력"| G2["레이어 2 가중치의 기울기"]
R2 -->|"× 레이어 2 의 비율"| R1["레이어 1 이 받은 값"]
R1 -->|"× 레이어 1 의 입력"| G1["레이어 1 가중치의 기울기"]
예제의 dh 가 이 넘기는 값입니다. 뒤에서 한 번 구한 값을 앞 레이어 전부가 이어받아 쓰므로 한 번 훑기로 끝납니다.
앞에서부터 곱하면 사정이 다릅니다. 같은 예에서 w1 쪽부터 출발해 봅니다. w1 이 변할 때 h 가 몇 배로 변하는지 먼저 구합니다. 이어서 y 가, 끝으로 손실이 몇 배로 변하는지를 차례로 곱해 dw1 을 얻습니다.
그런데 이 곱셈 사슬은 w1 하나를 위한 것입니다. w2 의 기울기를 구하려면 w2 에서 다시 출발해야 합니다. 가중치가 수백만 개면 이 일을 수백만 번 합니다.
손실은 숫자 하나입니다. 가중치는 수백만 개입니다. 그래서 숫자 하나인 손실 쪽에서 출발해야 한 번에 끝납니다.
중간값을 들고 있는 대가
역전파는 계산을 아끼는 대신 메모리를 씁니다. 이 소절은 그 메모리가 어디서 오는지를 봅니다.
앞 예에서 dw2 를 구하려면 순전파 때 나온 h 가 있어야 했습니다. 레이어마다 이런 중간값이 있습니다. 이 값은 거꾸로 훑을 때까지 버릴 수 없습니다. 그래서 순전파가 끝나도 모든 레이어의 중간값을 메모리에 들고 있습니다.
이 메모리는 레이어 수에 비례해 늘어납니다. 한 번에 넣는 예시 수에도 비례합니다.
학습을 마친 신경망으로 답만 내는 일은 추론이라고 합니다. 추론은 순전파만 하므로 지나온 레이어의 중간값을 바로 버려도 됩니다. 같은 신경망이라도 학습이 추론보다 메모리를 훨씬 많이 쓰는 까닭이 이것입니다.
레이어 1, 2, 3 이 낸 중간값을 h1, h2, h3 이라고 하면 두 경우는 아래처럼 갈립니다.
flowchart TD
subgraph TRAIN["학습"]
A1["순전파 · h1, h2, h3 을 차례로 낸다"] --> A2["메모리에 h1, h2, h3 이 모두 남는다"]
A2 --> A3["역전파 · h3, h2, h1 순으로 쓰고 버린다"]
end
subgraph INFER["추론"]
B1["레이어 1 · h1 을 낸다"] --> B2["레이어 2 · h2 를 내고 h1 을 버린다"]
B2 --> B3["레이어 3 · h3 을 내고 h2 를 버린다"]
end
A3 ~~~ B1
메모리가 모자라면 중간값 일부만 적어 두기도 합니다. 나머지는 거꾸로 훑을 때 다시 계산합니다. 계산을 더 하는 대신 메모리를 아끼는 맞바꿈입니다.
이 방법을 그래디언트 체크포인팅이라고 부릅니다. 그래디언트는 기울기의 영어 이름입니다.
두 방법의 비용을 계산과 메모리로 나눠 적으면 아래와 같습니다.
| 역전파 | 수치 미분 | |
|---|---|---|
| 계산 | 순전파 한 번 + 그 몇 배 안쪽 | 순전파를 가중치 수 + 1 번 |
| 메모리 | 모든 레이어의 중간값 | 순전파 한 번 분량 |
역전파는 계산 횟수를 가중치 수와 떼어 냅니다. 그 대가로 메모리를 내줍니다.
기울기 소실과 기울기 폭발
곱셈을 길게 이어 붙이는 데서 오는 문제가 하나 있습니다. 이 소절은 레이어가 깊어질 때 넘기는 값이 어떻게 변하는지를 봅니다.
역전파는 레이어를 지날 때마다 그 레이어의 비율을 곱합니다. 비율이 1 보다 작은 레이어가 이어지면 앞쪽에 닿는 값은 0 에 가까워집니다. 0.5 를 열 번 곱하면 0.001 쯤입니다.
그러면 입력 쪽 가중치는 기울기가 거의 0 이라서 잘 고쳐지지 않습니다. 이 현상을 기울기 소실이라고 합니다. 반대로 비율이 1 보다 크면 값이 레이어마다 불어나 감당하지 못할 만큼 커집니다. 이쪽은 기울기 폭발입니다.
아래 그림은 레이어 열 개에서 비율이 0.5 일 때와 2 일 때 넘어가는 값을 보입니다.
flowchart TD
subgraph VAN["비율이 0.5 일 때"]
V0["손실에서 출발 · 1"] --> V1["레이어 10 · 0.5"]
V1 --> V2["레이어 9 · 0.25"]
V2 --> V3["레이어 8 에서 2 까지 · 일곱 번 더 곱한다"]
V3 --> V4["레이어 1 · 약 0.001"]
end
subgraph EXP["비율이 2 일 때"]
E0["손실에서 출발 · 1"] --> E1["레이어 10 · 2"]
E1 --> E2["레이어 9 · 4"]
E2 --> E3["레이어 8 에서 2 까지 · 일곱 번 더 곱한다"]
E3 --> E4["레이어 1 · 약 1000"]
end
V4 ~~~ E0
깊은 신경망을 학습하려면 이 둘을 막는 장치가 따로 필요합니다. 비율이 1 근처에 머무는 활성화 함수를 고르거나, 레이어를 건너뛰어 값을 넘기는 잔차 연결을 두는 방법이 쓰입니다.
쓰는 때와 못 쓰는 때
역전파가 쓰이는 범위는 조건 하나가 가릅니다. 계산의 단계마다 변화 비율을 구할 수 있어야 합니다.
| 상황 | 역전파 | 까닭 |
|---|---|---|
| 신경망 학습 | 쓴다 | 곱셈 · 덧셈 · 활성화 함수 모두 변화 비율을 구할 수 있다 |
| 학습을 마친 신경망으로 답만 내기 | 안 쓴다 | 가중치를 고칠 일이 없다 |
| 결정 트리 학습 | 안 쓴다 | 「크면 왼쪽」 같은 갈림은 값을 조금 움직이면 결과가 안 변하거나 뚝 바뀐다 |
| 계산 중간에 정수로 반올림하는 단계 | 그 단계에서 끊긴다 | 거의 모든 값에서 변화 비율이 0 이다 |
기준은 모델의 이름이 아니라 계산의 모양입니다. 단계마다 비율을 구할 수 있는 계산이면 신경망이 아니어도 역전파로 기울기를 구할 수 있습니다.
프레임워크의 자동 미분
실무에서 역전파 코드를 손으로 짜는 일은 드뭅니다. 이 소절은 그 일을 누가 대신하는지를 봅니다.
딥러닝 프레임워크는 신경망을 짜고 학습시키는 데 쓰는 라이브러리입니다. 개발자는 순전파 코드만 적습니다. 역전파는 프레임워크가 대신 돌립니다.
프레임워크는 순전파 코드를 실행하면서 어떤 계산을 어떤 순서로 했는지 기록합니다. 이 기록을 계산 그래프라고 부릅니다. 앞에서 x, w1, h, w2, y, L 을 이어 그린 그림이 바로 이런 기록입니다. 손실을 구한 뒤 역전파를 요청하면 프레임워크가 이 그래프를 거꾸로 훑어 기울기를 채웁니다.
계산 기록에서 미분을 자동으로 구하는 기법을 자동 미분이라고 합니다. 사람이 식을 손으로 미분하지 않아도 기울기가 나옵니다.
자동 미분에는 끝에서부터 훑는 방식과 앞에서부터 훑는 방식이 있습니다. 앞에서부터 훑는 방식은 「끝에서부터 되짚는 순서」에서 본 대로 가중치마다 따로 출발해야 합니다. 역전파는 끝에서부터 훑는 방식을 신경망 학습에 쓴 것입니다.
관련 항목
역전파가 속하는 상위 분류
역전파가 기대는 수학 규칙
연쇄 법칙 · 편미분 · 기울기 · 야코비 행렬 · 계산 그래프
역전파 앞뒤에 서는 학습 단계
순전파 · 손실 함수 · 경사 하강법 · 확률적 경사 하강법 · 옵티마이저 · 학습률 · 미니배치 · 에포크
역전파가 기울기를 구하는 대상
가중치 · 편향 · 파라미터 · 레이어 · 활성화 함수
역전파의 기울기 소실·폭발과 그 대책
기울기 소실 · 기울기 폭발 · 그래디언트 클리핑 · ReLU · 시그모이드 · 배치 정규화 · 잔차 연결
역전파의 메모리 부담을 덜어 주는 기법
그래디언트 체크포인팅 · 혼합 정밀도 학습 · 그래디언트 누적
역전파와 맞세워지는 기울기 계산 방법
수치 미분 · 기호 미분 · 순방향 자동 미분 · 역방향 자동 미분
역전파를 계산해 주는 프레임워크
딥러닝 프레임워크 · PyTorch · TensorFlow · JAX
역전파로 학습하는 신경망과 그 변형
다층 퍼셉트론 · 합성곱 신경망 · 순환 신경망 · 트랜스포머 · 시간 역전파
다른 이름: backpropagation · backprop · 오차 역전파 · 오차 역전파법 · 역전파법 · 백프로파게이션 · 역전파 알고리즘