수학

MATH / 중급 33번

연쇄법칙: 층을 통과하며 곱해지는 비율

층 20개 뒤에 있는 가중치 하나가 손실을 얼마나 흔드는가. 합성함수의 미분을 «비율의 곱»으로 다시 읽고, 갈림길이 있을 때 경로마다 곱하고 경로끼리 더하는 다변수 연쇄법칙을 세운 뒤, 계산 그래프 하나를 손으로 끝까지 따라갑니다.

PALDYN Team32 MIN READ

20층짜리 신경망의 첫 번째 층에 있는 가중치 하나를 생각해 봅시다. 그 수를 0.001만큼 키우면 손실이 얼마나 변할까요.

그 답이 p.grad에 들어갑니다. 그런데 그 가중치와 손실 사이에는 행렬곱 스무 번과 활성함수 스무 번이 끼어 있습니다. 가중치가 흔들리면 첫 층의 출력이 흔들리고, 그것이 둘째 층의 입력이 되어 다시 흔들리고, 그렇게 스무 번을 거친 끝에 손실이 흔들립니다. 이 긴 사슬을 한 번에 미분하는 방법이 있어야 합니다.

지난 글에서 그래디언트를 「손잡이마다의 민감도를 모은 벡터」로 읽었습니다. 이 글은 그 민감도를 실제로 어떻게 구하는가에 답하는 법칙 하나를 세웁니다. 법칙은 하나뿐이고, 역전파는 그것을 순서대로 적용하는 것 이상이 아닙니다.

이어진 두 손잡이

xx 가 변하면 yy 가 변하고, yy 가 변하면 zz 가 변하는 상황입니다. 기호로는 z=f(y)z = f(y), y=g(x)y = g(x) 이고 이런 겹침을 합성함수(composite function)라고 부릅니다.

초급의 도함수 규칙 글에서 이 경우의 계산법을 「겉을 미분하고 속을 미분해 곱한다」로 익혔습니다. 여기서는 왜 곱인지를 지난 글의 선형근사로 확인합니다.

지난 글의 읽기를 그대로 씁니다. 미분 가능하다는 것은 작은 hh 에 대해

g(a+h)≈g(a)+g′(a) hg(a + h) \approx g(a) + g'(a)\,h

가 성립한다는 뜻이었습니다. 입력의 흔들림 hh 가 출력의 흔들림 g′(a)hg'(a)h 로 바뀐다는 말이고, g′(a)g'(a) 는 그 환율입니다. 이제 그 결과를 ff 에 넣습니다. ff 는 자기 입력이 g′(a)hg'(a)h 만큼 흔들렸다고 보고

f(g(a)+g′(a)h)≈f(g(a))+f′(g(a))⋅g′(a) hf\big(g(a) + g'(a)h\big) \approx f(g(a)) + f'(g(a)) \cdot g'(a)\,h

를 내놓습니다. 처음의 hh 와 마지막 흔들림을 맞대면 환율이 두 번 걸린 것이 그대로 보입니다.

연쇄법칙(chain rule). z=f(g(x))z = f(g(x)) 일 때 dzdx=dzdy⋅dydx=f′(g(x)) g′(x)\frac{dz}{dx} = \frac{dz}{dy} \cdot \frac{dy}{dx} = f'(g(x))\, g'(x) 이다. 미분은 「입력 흔들림 → 출력 흔들림」의 환율이고, 환율은 이어 붙이면 곱해진다.

환율이 두 번 걸리면 값은 두 비율의 곱만큼 흔들린다

수로 확인합니다. y=2xy = 2x, z=y2z = y^2 를 x=3x = 3 에서 봅니다. y=6y = 6, z=36z = 36 이고

dydx=2,dzdy=2y=12\frac{dy}{dx} = 2, \qquad \frac{dz}{dy} = 2y = 12

이므로 연쇄법칙은 dz/dx=12×2=24dz/dx = 12 \times 2 = 24 라고 말합니다. 직접 합성해 보면 z=(2x)2=4x2z = (2x)^2 = 4x^2 이고 dz/dx=8x=24dz/dx = 8x = 24 입니다. 같습니다.

앞쪽 값이 있어야 뒤쪽 비율이 나온다

위 계산에서 dz/dy=12dz/dy = 12 를 구할 때 y=6y = 6 이라는 값이 필요했습니다. 환율은 상수가 아니라 「그 지점에서의」 환율이라, 뒤쪽 비율을 구하려면 앞쪽에서 계산된 값을 알고 있어야 합니다.

이 한 줄이 역전파의 메모리 사용량을 통째로 설명합니다. 순전파를 돌 때 각 층의 중간 출력을 버리지 않고 붙들고 있어야 하고, 그래서 배치가 커지거나 층이 깊어지면 메모리가 파라미터 수가 아니라 중간값의 총량으로 결정됩니다. 그래디언트 체크포인팅처럼 중간값 일부를 버렸다가 역전파 때 다시 계산하는 기법이 있는 것도 여기서 나옵니다 — 버릴 수 있는 것은 값이지 법칙이 아닙니다.

셋 이상 이어질 때

손잡이가 셋 이어져도 규칙은 그대로입니다. x→y→z→wx \to y \to z \to w 라면 환율이 셋 곱해집니다.

dwdx=dwdz⋅dzdy⋅dydx\frac{dw}{dx} = \frac{dw}{dz} \cdot \frac{dz}{dy} \cdot \frac{dy}{dx}

수로 봅니다. y=x+1y = x + 1, z=y2z = y^2, w=3zw = 3z 를 x=1x = 1 에서 잡으면 y=2y = 2, z=4z = 4, w=12w = 12 이고 세 환율은 각각 11, 2y=42y = 4, 33 입니다. 곱하면 1212 입니다. 합성해서 직접 미분해도 w=3(x+1)2w = 3(x+1)^2 이므로 dw/dx=6(x+1)=12dw/dx = 6(x+1) = 12 로 같습니다.

합성해서 직접 미분하는 길이 이 예에서는 더 짧아 보입니다. 그런데 층이 스무 개가 되면 합성한 식을 적는 것 자체가 불가능해집니다. 연쇄법칙의 값어치는 전체 식을 한 번도 안 보고 각 자리의 국소 비율만으로 답을 내는 데 있습니다. 자동미분 프레임워크가 모델 전체의 수식을 들고 있지 않은 것도 그래서입니다 — 들고 있는 것은 연산 하나하나의 국소 미분 규칙과, 그것들이 어떤 순서로 이어졌는가 하는 그래프뿐입니다.

층이 20개면 이 곱이 20개라는 것이 이 글의 뒷부분을 지배합니다. 곱의 개수가 층 수만큼 늘어난다는 사실 하나에서 기울기 소실과 폭주가 전부 따라 나옵니다.

갈림길이 있으면

신경망의 계산은 일직선이 아닙니다. 한 값이 여러 곳으로 갈라져 들어가고, 그 갈래들이 다시 만나 손실 하나가 됩니다. 이럴 때 법칙이 어떻게 늘어나는지가 이 절입니다.

tt 하나가 uu 와 vv 를 만들고, 둘이 함께 zz 를 만드는 경우를 봅니다.

u=u(t),v=v(t),z=f(u,v)u = u(t), \quad v = v(t), \quad z = f(u, v)

tt 를 hh 만큼 흔들면 uu 는 u′(t)hu'(t)h 만큼, vv 는 v′(t)hv'(t)h 만큼 흔들립니다. 그리고 지난 글의 다변수 선형근사가 두 흔들림이 더해진다고 말합니다.

Δz≈∂z∂u (u′(t)h)+∂z∂v (v′(t)h)\Delta z \approx \frac{\partial z}{\partial u}\,\big(u'(t)h\big) + \frac{\partial z}{\partial v}\,\big(v'(t)h\big)

양변을 hh 로 나누면 그대로 법칙입니다.

다변수 연쇄법칙. dzdt=∂z∂ududt+∂z∂vdvdt\dfrac{dz}{dt} = \dfrac{\partial z}{\partial u}\dfrac{du}{dt} + \dfrac{\partial z}{\partial v}\dfrac{dv}{dt}

한 문장으로 줄이면 경로마다 곱하고 경로끼리 더한다입니다. tt 에서 zz 로 가는 길이 둘이니 각 길에서 환율을 곱해 두고, 두 길의 기여를 합칩니다.

t에서 z로 가는 경로가 둘이면 각 경로의 곱을 더한다

한 경로만 세면 답이 아니다

수로 확인합니다. u=t2u = t^2, v=3tv = 3t, z=uvz = uv 를 t=2t = 2 에서 봅니다. u=4u = 4, v=6v = 6 이고

∂z∂u=v=6,∂z∂v=u=4,dudt=2t=4,dvdt=3\frac{\partial z}{\partial u} = v = 6, \quad \frac{\partial z}{\partial v} = u = 4, \quad \frac{du}{dt} = 2t = 4, \quad \frac{dv}{dt} = 3

이므로

dzdt=6×4+4×3=24+12=36\frac{dz}{dt} = 6 \times 4 + 4 \times 3 = 24 + 12 = 36

입니다. 합성해서 직접 미분하면 z=t2⋅3t=3t3z = t^2 \cdot 3t = 3t^3 이고 dz/dt=9t2=36dz/dt = 9t^2 = 36 입니다. 두 경로를 더한 값이 맞습니다.

여기서 한 경로만 세면 24나 12가 나옵니다. 둘 다 답의 일부일 뿐 답이 아니고, 둘 중 어느 것도 답에 가깝지조차 않습니다. 갈래를 빠뜨리는 것이 손으로 역전파를 유도할 때 가장 흔한 실수이고, 아래에서 볼 가중치 감쇠가 정확히 그 자리입니다.

이 실수가 특히 위험한 이유는 틀린 값도 그럴듯해 보인다는 것입니다. 부호도 맞고 자릿수도 맞으니 눈으로는 안 걸립니다. 걸러 내는 방법은 하나뿐이라 아래에서 유한차분으로 맞대 봅니다.

합의 범위만 늘어난다

중간 변수가 여럿이고 입력도 여럿이면 새 규칙이 생기는 것이 아니라 합의 범위만 늘어납니다.

∂z∂tj=∑i∂z∂ui∂ui∂tj\frac{\partial z}{\partial t_j} = \sum_{i} \frac{\partial z}{\partial u_i} \frac{\partial u_i}{\partial t_j}

ii 는 tjt_j 가 직접 닿는 중간 변수 전부를 훑습니다. 경로가 셋이면 항이 셋, 열이면 열이지요. 이 한 줄이 이 글의 전부입니다 — 남은 것은 이것을 실제 그래프에 적용하는 연습입니다.

계산 그래프 위에서 손으로 끝까지

이제 아주 작은 신경망 하나를 세우고 모든 편도함수를 손으로 구합니다. 층이 둘, 파라미터가 셋인 모델입니다.

a=w1x+b,h=a2,y=w2h,L=(y−t)2+λw12a = w_1 x + b, \qquad h = a^2, \qquad y = w_2 h, \qquad L = (y - t)^2 + \lambda w_1^2

마지막 항 λw12\lambda w_1^2 은 가중치 감쇠(weight decay)입니다. 가중치가 커지는 것 자체에 벌점을 매겨 손실에 더하는 항이고, 여기서는 w1w_1 이 손실에 닿는 두 번째 경로를 만들어 주는 역할을 합니다.

값은 x=1x = 1, w1=2w_1 = 2, b=−1b = -1, w2=3w_2 = 3, 정답 t=1t = 1, λ=0.5\lambda = 0.5 로 잡습니다.

순전파로 값을 채우고 역방향으로 미분을 채운다

순전파로 값 채우기

먼저 앞에서 뒤로 한 줄씩 값을 채웁니다. 앞 절에서 본 대로 이 값들이 있어야 뒤쪽 비율을 구할 수 있으므로, 역전파를 시작하기 전에 표를 다 채워 두는 것이 순서입니다.

단계 식 값
aa 2×1+(−1)2 \times 1 + (-1) 1
hh 121^2 1
yy 3×13 \times 1 3
오차항 (3−1)2(3 - 1)^2 4
벌점항 0.5×220.5 \times 2^2 2
LL 4+24 + 2 6

표의 마지막 줄이 손실입니다. 여기까지가 forward 한 번이고, 아직 미분은 하나도 구하지 않았습니다.

역방향으로 비율 곱하기

이제 뒤에서 앞으로 갑니다. 출발점은 자기 자신에 대한 미분이라 언제나 1입니다.

∂L∂L=1\frac{\partial L}{\partial L} = 1

한 걸음씩 뒤로 갑니다. 각 줄에서 하는 일은 「바로 앞에서 받은 값 × 이 자리의 국소 비율」 곱셈 하나뿐입니다.

∂L∂y=2(y−t)=2(3−1)=4\frac{\partial L}{\partial y} = 2(y - t) = 2(3-1) = 4

∂L∂w2=∂L∂y⋅∂y∂w2=4×h=4×1=4\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial w_2} = 4 \times h = 4 \times 1 = 4

∂L∂h=∂L∂y⋅∂y∂h=4×w2=4×3=12\frac{\partial L}{\partial h} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial h} = 4 \times w_2 = 4 \times 3 = 12

∂L∂a=∂L∂h⋅∂h∂a=12×2a=12×2=24\frac{\partial L}{\partial a} = \frac{\partial L}{\partial h} \cdot \frac{\partial h}{\partial a} = 12 \times 2a = 12 \times 2 = 24

∂L∂b=∂L∂a⋅1=24\frac{\partial L}{\partial b} = \frac{\partial L}{\partial a} \cdot 1 = 24

다섯 줄 모두 모양이 같습니다. 받은 값이 있고, 그 자리의 국소 비율이 있고, 둘을 곱해 다음 줄로 넘깁니다. 여기까지는 그래프가 일직선이라 곱셈만 있었습니다.

같은 노드가 두 번 쓰이면 더한다

w1w_1 에서 갈래가 생깁니다. w1w_1 은 aa 를 통해 손실에 닿고, 벌점항을 통해 한 번 더 닿습니다.

∂L∂w1=∂L∂a⋅∂a∂w1⏟신경망 경로+2λw1⏟벌점 경로=24×1+2(0.5)(2)=24+2=26\frac{\partial L}{\partial w_1} = \underbrace{\frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial w_1}}_{\text{신경망 경로}} + \underbrace{2\lambda w_1}_{\text{벌점 경로}} = 24 \times 1 + 2(0.5)(2) = 24 + 2 = 26

26이지 24가 아닙니다. 그리고 두 경로가 서로를 모른 채 각자 곱해 온 값을 마지막에 더했을 뿐입니다.

숫자로 검산해 봅니다. w1w_1 만 2.0012.001 로 바꾸면 a=1.001a = 1.001, h=1.002001h = 1.002001, y=3.006003y = 3.006003 이고

L=(2.006003)2+0.5(2.001)2=4.024048+2.002001=6.026049L = (2.006003)^2 + 0.5(2.001)^2 = 4.024048 + 2.002001 = 6.026049

입니다. 변화량은 0.0260490.026049 이고 0.0010.001 로 나누면 26.0526.05 — 손으로 구한 26과 맞습니다.

이 「더하기」가 자동미분 구현의 핵심이기도 합니다. 프레임워크가 grad 를 대입이 아니라 누적으로 두는 이유가 이것이고, 그래서 배치를 나눠 여러 번 backward() 를 부르면 그래디언트가 더해진 채로 남습니다. zero_grad() 를 깜빡했을 때 학습이 이상해지는 것이 같은 규칙의 뒷면입니다.

왜 역방향으로 도는가

연쇄법칙 자체는 방향을 정해 주지 않습니다. 앞에서 뒤로 적용해도 똑같이 맞습니다. 그런데도 역전파가 굳이 뒤에서 앞으로 도는 데는 이유가 있습니다.

순방향은 입력마다, 역방향은 출력마다 한 번씩 훑는다

순방향으로 돌면 입력 하나를 정해 두고 그래프를 따라 내려오며 「그 입력에 대한 미분」을 노드마다 들고 갑니다. 한 번 훑으면 입력 하나에 대한 모든 출력의 미분이 나옵니다. 역방향은 반대로 출력 하나를 정해 두고 거슬러 오르며 「그 출력의 미분」을 들고 가므로, 한 번 훑으면 출력 하나에 대한 모든 입력의 미분이 나옵니다.

방향 한 번 훑어 얻는 것 필요한 훑기 수
순방향 입력 하나에 대한 모든 출력의 미분 입력 수만큼
역방향 출력 하나에 대한 모든 입력의 미분 출력 수만큼

신경망 학습은 출력이 손실 하나이고 입력이 파라미터 수십억인 모양입니다. 순방향으로 돌면 파라미터마다 한 번씩 수십억 번 훑어야 하고, 역방향은 한 번이면 끝납니다. 비용 차이가 열 배나 백 배가 아니라 파라미터 수만큼이지요.

수로 재 보면 차이가 분명합니다. 파라미터가 1억 개인 모델에서 순방향으로 모든 그래디언트를 구하려면 그래프를 1억 번 훑어야 하고, 역방향은 손실이 하나뿐이라 한 번이면 끝납니다. 한 번 훑는 데 1초가 걸린다고 치면 한쪽은 3년이 넘고 다른 쪽은 1초입니다. 역전파가 선택지가 아니라 사실상 유일한 길인 이유가 이 표에 다 적혀 있습니다.

반대 모양이면 반대 답이 나옵니다 — 입력이 하나이고 출력이 많으면 순방향이 쌉니다. 두 방향을 같은 틀에서 적고 비용을 수로 비교하는 것은 35번 · VJP와 JVP의 몫입니다.

곱이 길어지면 값이 무너진다

법칙이 곱이라는 사실에는 대가가 따릅니다. 층이 LL 개면 입력까지 내려오는 미분은 국소 비율 LL 개의 곱입니다.

∂L∂x=rL⋅rL−1⋯r2⋅r1\frac{\partial \mathcal{L}}{\partial x} = r_L \cdot r_{L-1} \cdots r_2 \cdot r_1

지수가 하는 일

비율들이 대체로 비슷한 크기 rr 이라면 전체는 rLr^L 입니다. LL 이 지수에 올라앉아 있습니다.

rr L=10L = 10 L=30L = 30 L=50L = 50
0.5 9.8×10−49.8 \times 10^{-4} 9.3×10−109.3 \times 10^{-10} 8.9×10−168.9 \times 10^{-16}
0.9 0.349 0.042 0.005
1.0 1 1 1
1.1 2.59 17.4 117.4
1.5 57.7 1.9×1051.9 \times 10^{5} 6.4×1086.4 \times 10^{8}

층 수가 늘면 비율의 곱은 지수적으로 벌어진다

비율을 전부 같은 rr 로 두는 것이 거친 가정처럼 보이지만, 깊은 신경망은 대개 같은 모양의 층을 되풀이해 쌓아 만들기 때문에 층마다의 국소 비율이 비슷한 크기에 몰립니다. 값이 정확히 같지 않더라도 곱의 크기는 평균적인 비율 하나로 대표해 읽으면 자릿수가 맞습니다 — 한두 층이 유별나게 크거나 작아도 나머지 열여덟 층이 방향을 정하기 때문입니다.

표의 가로 방향을 읽으면 층이 늘 때 값이 어떻게 벌어지는지가 보이고, 세로 방향을 읽으면 비율이 0.1만 달라져도 50층에서 자릿수가 통째로 갈리는 것이 보입니다.

소실과 폭주는 같은 식의 양쪽 끝

r=0.9r = 0.9 는 「한 층에서 10%만 줄어든다」는 아주 온순한 값인데도 50층을 지나면 0.0050.005 로 200분의 1이 됩니다. 앞쪽 층의 그래디언트가 사실상 0이 되어 갱신이 멈추는 이 현상을 기울기 소실(vanishing gradient)이라고 부릅니다. 반대로 r=1.1r = 1.1 이면 50층에서 117배로 불어나 갱신 한 번에 파라미터가 날아가는데, 이쪽이 기울기 폭주(exploding gradient)입니다.

둘은 별개의 고장이 아닙니다. rLr^L 이라는 같은 식에서 rr 이 1보다 작냐 크냐로만 갈립니다. r=1r = 1 이라는 하나의 값에서만 곱이 안정하고, 그 언저리를 벗어나면 어느 쪽이든 지수적으로 벌어집니다. 그 사이에 완만한 중간 지대는 없습니다.

그래서 무엇으로 막는가

깊은 신경망의 설계가 대부분 이 곱을 1 근처에 붙들어 두려는 시도입니다. 이름이 붙은 장치 셋이 각각 곱의 어디에 개입하는지만 적어 둡니다.

장치 곱의 어디에 개입하나
잔차 연결 곱해지는 값 자체에 1을 심는다 — ∂(x+F(x))/∂x=1+∂F/∂x\partial(x + F(x))/\partial x = 1 + \partial F/\partial x
정규화 층 각 층 출력의 크기를 고정해 rr 이 커지지 않게 잡는다
기울기 클리핑 이미 커진 곱을 사후에 잘라 낸다

앞의 둘은 rr 을 1 근처로 만드는 장치이고, 마지막 하나는 rr 을 손대지 않고 결과만 자르는 사후 처방입니다. 그래서 클리핑은 폭주에는 듣지만 소실에는 아무것도 못 합니다 — 0에 가까워진 곱을 잘라 봐야 여전히 0이니까요. 셋이 각각 어떤 구조로 구현되는지는 이 글의 범위 밖이고, 여기서는 셋 다 같은 곱을 겨냥하고 있다는 것까지만 봅니다.

코드로 확인하기

손 유도와 유한차분 맞대기

x, t, lam = 1.0, 1.0, 0.5

def forward(w1, b, w2):
    a = w1 * x + b
    h = a ** 2
    y = w2 * h
    return a, h, y, (y - t) ** 2 + lam * w1 ** 2

w1, b, w2 = 2.0, -1.0, 3.0
a, h, y, L = forward(w1, b, w2)
print(a, h, y, L)                     # 1.0 1.0 3.0 6.0

# ① 손으로 유도한 역전파 — 각 줄이 「받은 값 × 국소 비율」 하나다
dL_dy = 2 * (y - t)                   # 4.0
dL_dw2 = dL_dy * h                    # 4.0
dL_dh = dL_dy * w2                    # 12.0
dL_da = dL_dh * 2 * a                 # 24.0
dL_db = dL_da * 1                     # 24.0
dL_dw1 = dL_da * x + 2 * lam * w1     # 24 + 2 = 26.0   ← 경로 둘을 더한다
print(dL_dw1, dL_db, dL_dw2)          # 26.0 24.0 4.0

# ② 중심차분으로 검산
eps = 1e-6
def num(i):
    p, m = [w1, b, w2], [w1, b, w2]
    p[i] += eps; m[i] -= eps
    return (forward(*p)[3] - forward(*m)[3]) / (2 * eps)
print([round(num(i), 6) for i in range(3)])   # [26.0, 24.0, 4.0]

# ③ 갈래를 빠뜨리면 얼마나 틀리는가
print(dL_da * x)                      # 24.0  — 벌점 경로를 뺀 값

②가 이 글의 유도를 기계로 확인한 것입니다. 손으로 구한 셋과 유한차분 셋이 소수점 여섯 자리까지 같습니다. ③은 갈래 하나를 빠뜨렸을 때의 값인데, 26 대신 24라 비율로는 8% 어긋난 값이 부호도 자릿수도 멀쩡하게 나옵니다. 이런 오차는 학습을 멈추게 하지 않고 조금씩 엉뚱한 곳으로 끌고 가므로 눈으로는 영영 안 걸립니다. ②를 한 번 돌려 보는 것이 유일한 방어입니다.

곱이 길어질 때

# ④ 곱이 길어질 때 — 지수가 하는 일
for r in [0.5, 0.9, 1.0, 1.1, 1.5]:
    print(r, [f"{r ** L:.3g}" for L in (10, 30, 50)])
# 0.5 ['0.000977', '9.31e-10', '8.88e-16']
# 0.9 ['0.349',    '0.0424',   '0.00515']
# 1.0 ['1',        '1',        '1']
# 1.1 ['2.59',     '17.4',     '117']
# 1.5 ['57.7',     '1.92e+05', '6.38e+08']

# ⑤ 잔차 연결은 곱해지는 값에 1을 심는다
from math import prod
r = 0.9                                    # 곁가지 F 의 국소 비율
print(f"{prod([r] * 50):.3g}")             # 0.00515   그냥 쌓으면 200분의 1
print(f"{prod([1 + r] * 50):.3g}")         # 8.66e+13  1 위에 그대로 얹으면 반대로 터진다
print(f"{prod([1 + 0.02 * r] * 50):.3g}")  # 2.44      곁가지를 눌러 두면 1 근처

⑤는 잔차 연결이 만능이 아니라는 것도 함께 보여 줍니다 — 심어 둔 1에 곁가지가 그대로 더해지면 이번에는 반대쪽으로 터지므로, 실제 구조는 FF 의 출력 크기를 함께 눌러 둡니다. 위 표에서 정규화 층이 하는 일이 바로 그 「눌러 두기」입니다.

연습 문제

손으로 구한 뒤 반드시 합성해서 직접 미분한 값과 맞대 보세요. 두 값이 갈리면 경로를 빠뜨렸거나 앞쪽 값을 잘못 넣은 것입니다.

연습 1 — 셋 이어진 사슬

각 사슬에서 환율 셋을 따로 적고 곱한 뒤, 합성해서 직접 미분한 값과 비교하세요.

  1. y=3xy = 3x, z=y3z = y^3, w=z+2w = z + 2 를 x=1x = 1 에서
    y=3y=3, z=27z=27 입니다. 환율은 dy/dx=3dy/dx = 3, dz/dy=3y2=27dz/dy = 3y^2 = 27, dw/dz=1dw/dz = 1 이므로 곱은 8181. 합성하면 w=27x3+2w = 27x^3 + 2 이고 dw/dx=81x2=81dw/dx = 81x^2 = 81 로 같습니다.
  2. u=x2u = x^2, v=1/uv = 1/u, s=5vs = 5v 를 x=2x = 2 에서
    u=4u=4, v=0.25v=0.25 입니다. 환율은 du/dx=2x=4du/dx = 2x = 4, dv/du=−1/u2=−1/16dv/du = -1/u^2 = -1/16, ds/dv=5ds/dv = 5 이므로 곱은 5×(−1/16)×4=−1.255 \times (-1/16) \times 4 = -1.25. 합성하면 s=5/x2s = 5/x^2 이고 ds/dx=−10/x3=−1.25ds/dx = -10/x^3 = -1.25 로 같습니다.
  3. a=x−1a = x - 1, b=a2b = a^2, c=4bc = 4b 를 x=3x = 3 에서
    a=2a=2, b=4b=4 입니다. 환율은 11, 2a=42a = 4, 44 이므로 곱은 1616. 합성하면 c=4(x−1)2c = 4(x-1)^2 이고 dc/dx=8(x−1)=16dc/dx = 8(x-1) = 16 로 같습니다.

연습 2 — 갈림길

경로마다의 곱을 따로 적고 나서 더하세요. 한 경로만 적고 끝내면 안 됩니다.

  1. u=t3u = t^3, v=2tv = 2t, z=u+v2z = u + v^2 를 t=1t = 1 에서
    u=1u=1, v=2v=2 입니다. uu 경로는 (∂z/∂u)(du/dt)=1×3t2=3(\partial z/\partial u)(du/dt) = 1 \times 3t^2 = 3 이고 vv 경로는 (∂z/∂v)(dv/dt)=2v×2=8(\partial z/\partial v)(dv/dt) = 2v \times 2 = 8 이므로 합은 1111. 합성하면 z=t3+4t2z = t^3 + 4t^2 이고 dz/dt=3t2+8t=11dz/dt = 3t^2 + 8t = 11 로 같습니다.
  2. p=t+1p = t + 1, q=t2q = t^2, z=pqz = pq 를 t=2t = 2 에서
    p=3p=3, q=4q=4 입니다. pp 경로는 q×1=4q \times 1 = 4 이고 qq 경로는 p×2t=3×4=12p \times 2t = 3 \times 4 = 12 이므로 합은 1616. 합성하면 z=t3+t2z = t^3 + t^2 이고 dz/dt=3t2+2t=16dz/dt = 3t^2 + 2t = 16 로 같습니다.

연습 3 — 곱이 길어질 때

계산기를 써서 값을 구하고, 처음의 몇 배 또는 몇 분의 일인지까지 적으세요.

  1. 한 층의 국소 비율이 0.80.8 로 같을 때 40층을 지난 곱
    0.840≈1.33×10−40.8^{40} \approx 1.33 \times 10^{-4} 로 약 7,500분의 1입니다. 한 층에서 20%만 줄어드는데도 40층이면 그래디언트가 사실상 사라집니다.
  2. 한 층의 국소 비율이 1.21.2 로 같을 때 40층을 지난 곱
    1.240≈14701.2^{40} \approx 1470 으로 약 1,470배입니다. 1과의 거리가 두 문제 모두 0.20.2 로 같은데 한쪽은 7,500분의 1이 되고 다른 쪽은 1,470배가 됩니다 — 곱이라 대칭이 아니기 때문입니다.

정리

  • 연쇄법칙은 환율의 곱이다. 미분이 「입력 흔들림 → 출력 흔들림」의 비율이므로, 함수를 이어 붙이면 비율이 곱해진다.
  • 뒤쪽 비율을 구하려면 앞쪽에서 계산된 값이 필요하다. 역전파가 순전파의 중간값을 메모리에 붙들고 있는 이유다.
  • 갈림길이 있으면 경로마다 곱하고 경로끼리 더한다. 일반형은 ∂z/∂tj=∑i(∂z/∂ui)(∂ui/∂tj)\partial z/\partial t_j = \sum_i (\partial z/\partial u_i)(\partial u_i/\partial t_j) 한 줄이다.
  • 역전파의 한 걸음은 「받은 값 × 이 자리의 국소 비율」 곱셈 하나다. 그 이상의 규칙은 없다.
  • 갈래를 빠뜨리는 것이 손 유도의 가장 흔한 실수다. 예제에서 26이어야 할 값이 24가 됐고, 부호도 자릿수도 멀쩡해 눈으로는 안 걸린다.
  • 역방향으로 도는 것은 법칙이 시켜서가 아니라 출력이 하나고 입력이 수십억이기 때문이다. 훑는 횟수가 출력 수만큼이면 되기 때문이다.
  • 곱이 LL 개면 크기는 rLr^L 이라 LL 이 지수에 올라간다. r=0.9r = 0.9 로도 50층이면 200분의 1이 된다.
  • 그래서 기울기 소실과 폭주는 같은 식의 양쪽 끝이고, 잔차 연결·정규화·클리핑은 전부 밑을 1 근처에 두려는 장치다.

처음의 물음으로 돌아갑니다. 20층 뒤의 가중치 하나가 손실을 얼마나 흔드는지는, 그 가중치에서 손실까지 가는 길들을 따라 국소 비율을 곱하고 길끼리 더하면 나옵니다. loss.backward()가 하는 일이 정확히 그것이고, 층이 20층이든 100층이든 규칙은 늘지 않습니다 — 곱셈 한 번을 몇 번 더 하느냐만 달라집니다.

다만 지금까지의 예제에서 각 자리의 「국소 비율」은 전부 수 하나였습니다. 실제 층은 벡터를 받아 벡터를 내놓으므로, 그 자리의 미분은 수가 아니라 표 하나가 됩니다. 다음 글이 그 표를 세웁니다.


읽어주셔서 감사합니다. 😊

LATEST

수학의 최신 글

수학2026.09.07

양자화 오차: 격자 사상, 오차 분산, 이상치 채널

실수를 2^b개 격자에 사상할 때 오차의 분산이 왜 Δ²/12인지 유도하고, 그것이 비트당 6.02dB라는 SNR로 번역되는 과정을 실측과 대조했습니다. 이상치 하나가 나머지 값의 유효 비트를 어떻게 먹는지, 그리고 int4에서 성능이 무너지는 지점을 오차 예산으로 미리 계산하는 법까지.

중급18 MIN
수학2026.09.07

수치적으로 안정한 계산 패턴 모음

최댓값 빼기, 로그 공간, log1p·expm1, 분산의 두 공식, 정규화의 ε, fp32 누산, 역행렬 대신 solve — 프레임워크가 몰래 해 주는 일곱 가지를 하나씩 꺼내 각각 어떤 고장을 막는지 직접 재 봤습니다. 수식을 그대로 옮긴 코드가 왜 라이브러리보다 나쁜지에 대한 목록입니다.

중급22 MIN
수학2026.09.07

부동소수점은 어디서 새는가: 반올림, 상쇄, 더하는 순서

0.1 + 0.2가 0.3이 아닌 이유부터 시작해 머신 엡실론을 유도하고, 같은 16비트인데 fp16과 bf16이 서로 다른 지점에서 터지는 이유, 비슷한 수를 뺄 때 유효자리가 사라지는 파괴적 상쇄, 그리고 1,000만 개를 순서만 바꿔 더했을 때 오차가 백만 배 갈리는 실험까지 직접 재 봤습니다.

중급23 MIN