단원 홈
2단원 · 14차시

층을 하나 더
직선으로 안 되던 것을 넘는 법

13차시의 퍼셉트론은 XOR 네 점 앞에서 끝내 멈춰 섰습니다. 가중치 조합 15,625가지를 다 뒤졌는데 네 점을 모두 맞히는 것이 0가지였지요. 오늘은 입력과 출력 사이에 노드 두 개를 끼웁니다. 그것만으로 벽이 무너집니다.

성취기준 12인기02-05
은닉층시그모이드역전파 지역 최솟값학습률딥러닝의 세 조건
🎯 학습 목표
  • 은닉층이 하는 일이 입력 공간을 다시 그리는 것임을 알고, 학습이 끝난 XOR 신경망의 은닉 좌표 네 쌍을 읽어 그 좌표에서는 직선 하나로 나뉜다는 것을 확인할 수 있다.
  • 계단 함수 대신 시그모이드를 쓰는 까닭을 기울기로 설명하고, 역전파가 오차를 뒤로 흘려 가중치마다 책임을 나눠 주는 절차임을 코드에서 짚을 수 있다.
  • 같은 코드가 시작점에 따라 다섯에 하나꼴로 실패하는 것을 직접 만들어 보고, 그 실패가 '나쁜 씨앗' 때문이 아니라 시작점과 걸음 크기의 짝에서 온다는 것을 설명할 수 있다.
🤔

여는 장면 — 어제 우리는 네 점 앞에서 졌다

13차시에서 여러분은 슬라이더를 밀어 가며 퍼셉트론의 경계선을 직접 그었습니다. AND도 되고 OR도 되고 NAND도 됐지요. 그런데 XOR 하나가 끝내 안 됐습니다. 기억을 되살려 봅시다. 그때 확인한 것이 넷이었어요.

  • 손으로 아무리 잘 골라도 가장 잘해야 네 점 중 셋(75%)이었다.
  • 가중치 w1·w2·b를 −3.00에서 +3.00까지 0.25 간격으로 15,625가지 전부 시켜 봤는데, 네 점을 다 맞히는 조합은 0가지였다. AND는 286가지, OR은 650가지, NAND는 364가지가 있었는데 XOR만 없었다.
  • 학습 규칙에 맡겨 2,000에폭을 돌렸더니 가중치를 7,989번 고치고도 한 번도 안 멈췄다. 8에폭째의 (w1, w2, b) = (−0.18, −0.03, +0.07)이 9에폭에서 글자 그대로 다시 나왔다. 주기 1에폭짜리 완전한 제자리걸음이었다.
  • 시작점을 바꿔 봐도 소용없었다. 씨앗 20개 중 0개가 멈췄다.

이것은 운이 나빴던 것이 아닙니다. 직선 하나로는 원리적으로 안 되는 문제였어요. 아래 네 점을 다시 보세요. 어떤 자로 어떻게 그어도 파란 둘과 주황 둘을 갈라 놓을 수 없습니다.

x₁ x₂ 0 1 1 (0,0)→0 (1,0)→1 (0,1)→1 (1,1)→0 직선 하나로는 — 안 된다 같은 색끼리 마주 보고 있다 파란 두 점은 대각선으로 마주 보고, 주황 두 점도 대각선으로 마주 본다. 직선은 평면을 두 조각으로만 자르므로 마주 본 두 점을 같은 조각에 넣으려면 나머지 둘도 딸려 들어온다. 전수 조사 15,625가지 → 4/4는 0가지 가장 잘해야 3/4 (75%)
13차시에서 실제로 재 본 결과를 그림으로 옮긴 것이다. 빨간 점선 셋은 예시일 뿐이고, 0.25 간격으로 만든 15,625가지 직선을 전부 시켜도 네 점을 다 맞히는 것은 하나도 없었다.

그러면 여기서 끝일까요? 만약 끝이라면 인공신경망이라는 말은 진작 사라졌을 겁니다. 실제로 1969년에 이 한계가 책으로 정리되어 나온 뒤 인공신경망 연구는 크게 위축됐습니다. 그런데 답은 이미 그 책 안에 적혀 있었어요. "층을 여러 개 쌓으면 풀 수 있다. 다만 여러 층을 학습시키는 방법을 모른다."

오늘 배울 것이 바로 그 모르던 방법입니다. 이름은 역전파(backpropagation)예요. 그리고 오늘 여러분이 쓸 코드는 40줄 남짓입니다.

💭 오늘의 물음

직선 하나로는 절대 안 되던 문제가, 노드 두 개를 사이에 끼우면 왜 되는가? 그 두 노드는 도대체 무엇을 하고 있는가?

미리 한 가지 밝혀 둡니다. 오늘 코드는 언제나 성공하지 않습니다. 시작 가중치를 정하는 씨앗을 바꾸면 다섯에 하나꼴로 실패해요. 그것을 감추고 성공한 화면만 보여 주는 것은 정직하지 않습니다. 그래서 이 차시에는 실패를 일부러 만들어 보는 자리가 따로 있습니다. 실패하는 까닭을 아는 것이 성공한 결과를 보는 것보다 배울 것이 많아요.

1

사이에 한 층을 끼운다 — 무엇이 늘어나는가

13차시의 퍼셉트론은 이렇게 생겼습니다. 입력 x₁·x₂에 가중치를 곱해 더하고 편향을 보탠 뒤, 그 값이 0 이상이면 1을 냅니다. 배우는 수는 셋이었어요 — w1, w2, b.

오늘 만들 것은 그 사이에 노드 둘을 세워 둡니다. 입력 둘이 먼저 은닉층의 두 노드로 들어가고, 그 두 노드가 낸 값이 다시 출력 노드로 들어갑니다. 은닉층(hidden layer)이라는 이름은 우리가 그 층의 정답을 알려 주지 않기 때문에 붙었습니다. 입력도 아니고 출력도 아니라 바깥에서는 보이지 않는 층이라는 뜻이에요.

입력층 은닉층 (오늘 새로 생긴 것) 출력층 x₁ x₂ h₁ h₂ o 가중치 W1 — 4개 편향 b1 — 2개 가중치 W2 — 2개 편향 b2 — 1개 배우는 수 모두 9개 13차시 퍼셉트론은 3개
입력 2 → 은닉 2 → 출력 1. 은닉 노드가 h개면 배우는 수는 4h + 1개다 — 은닉 1개면 5개, 2개면 9개, 3개면 13개, 5개면 21개. 퍼셉트론(3개)보다 세 배 많아졌을 뿐인데 할 수 있는 일이 달라진다.

여기서 한 가지가 반드시 필요합니다. 노드마다 값을 눌러 주는 함수예요. 만약 그 함수가 없다면, 즉 은닉 노드가 받은 값을 그대로 흘려보낸다면 어떻게 될까요?

그러면 층을 아무리 쌓아도 소용이 없습니다. 곱하고 더하는 일을 두 번 한 것은 결국 한 번 곱하고 더한 것으로 다시 쓸 수 있거든요. 2를 곱하고 3을 곱하면 6을 곱한 것과 같은 것과 마찬가지입니다. 층 사이마다 '곧게 펴지지 않는' 함수가 하나씩 들어가야 층을 쌓는 뜻이 생깁니다. 13차시에서 쓰던 계단 함수가 바로 그런 함수였어요. 그런데 오늘은 계단을 쓰지 않습니다. 왜 그런지는 3절에서 다룹니다.

ℹ️ 용어 정리

이 책에서는 층과 노드라는 말을 씁니다. 13차시에서 '인공 뉴런'이라고 부른 그 하나하나가 오늘 그림의 동그라미, 곧 노드예요. '레이어'·'뉴런'이라는 말을 더 자주 들었을 수도 있는데, 앞에 '인공'을 붙이지 않고 그냥 '뉴런'이라고만 하면 이 책에서는 생물의 신경세포를 가리킵니다. 사람 머릿속의 뉴런과 여기 동그라미는 비슷한 데가 있지만 같은 것이 아니에요. 이름을 갈라 두면 헷갈릴 일이 줄어듭니다.

2

은닉층은 좌표계를 다시 그린다

이 절이 오늘의 핵심입니다. 결론부터 말하면 이렇습니다.

🔑 핵심 문장

은닉층은 네 점을 직선으로 나누기 좋은 새 좌표로 옮겨 놓는다. 출력 노드는 그 새 좌표 위에서 13차시의 퍼셉트론을 그대로 한다.

말로만 들으면 어렵습니다. 그런데 이것은 눈으로 확인할 수 있는 사실이에요. 학습이 끝난 뒤 은닉 노드 둘이 내는 값 (h₁, h₂)를 좌표로 보고 네 점을 찍어 보면 됩니다. 뒤에서 여러분이 직접 돌려 볼 코드가 그 값을 찍어 줍니다. 미리 답을 보면 이렇습니다.

은닉 2개 · 학습률 0.5 · 씨앗 1 · 8,000회 학습한 결과. 은닉값은 소수 셋째 자리까지 봐야 한다 — 0.000처럼 보이는 값은 진짜 0이 아니라 0.0001보다 작은 값이다.
입력 (x₁, x₂)정답은닉 좌표 (h₁, h₂) 출력층 가중합선의 어느 쪽최종 출력
(0, 0)0(0.035, 0.041) −3.813아래쪽 → 00.022
(0, 1)1(0.932, 0.000) +3.969위쪽 → 10.981
(1, 0)1(0.000, 0.924) +3.962위쪽 → 10.981
(1, 1)0(0.031, 0.034) −3.928아래쪽 → 00.019

첫째 줄과 넷째 줄을 나란히 보세요. (0, 0)의 은닉 좌표가 (0.035, 0.041)이고 (1, 1)의 은닉 좌표가 (0.031, 0.034)입니다. 거의 같은 자리예요. 입력 평면에서는 정반대 구석에 있던 두 점이, 은닉 좌표에서는 원점 근처에 나란히 포개져 있습니다.

이것이 '공간을 다시 그렸다'는 말의 정체입니다. 은닉층은 네 점을 세 무리로 접어 버렸어요 — 원점 근처에 정답 0인 두 점, 오른쪽에 (0,1), 위쪽에 (1,0). 그러면 대각선 하나만 그으면 갈립니다.

입력 좌표 (x₁, x₂) 은닉 좌표 (h₁, h₂) 직선으로 못 나눈다 같은 색이 대각선으로 마주 본다 은닉층 이 옮긴다 h₁ h₂ h₂ = −0.993·h₁ + 0.492 (0,0)과 (1,1)이 겹쳤다 (0,1) (1,0) 직선 하나로 나뉜다 출력 노드가 그은 그 선이다
왼쪽 네 점의 자리는 우리가 정한 것이고, 오른쪽 네 점의 자리는 신경망이 스스로 정한 것이다. 오른쪽 초록 선을 그은 것이 출력 노드인데, 그 노드는 13차시의 퍼셉트론과 똑같은 물건이다 — 달라진 것은 발밑의 좌표뿐이다.

그 두 노드는 각각 무엇을 배웠나

더 깊이 들어가 봅시다. 학습이 끝난 뒤 1층 가중치는 이렇습니다.

# 학습이 끝난 1층 (은닉 2 · lr 0.5 · 씨앗 1 · 8000회) W1 = [[-6.075, 5.923], [5.645, -5.862]] b1 = [-3.306, -3.142]

은닉 노드 1은 x₁에 −6.075를, x₂에 +5.923을 곱합니다. x₂가 켜지면 크게 밀어 올리고 x₁이 켜지면 크게 끌어내린다는 뜻이에요. 실제로 네 점을 넣어 보면 이렇게 나옵니다.

# 은닉 노드 1 이 네 점에 내는 값 (0,0) → 0.035 (0,1) → 0.932 (1,0) → 0.000 (1,1) → 0.031 # x₂만 1일 때 켜진다 # 은닉 노드 2 가 네 점에 내는 값 (0,0) → 0.041 (0,1) → 0.000 (1,0) → 0.924 (1,1) → 0.034 # x₁만 1일 때 켜진다

노드 1은 "x₂만 1일 때" 켜지고, 노드 2는 "x₁만 1일 때" 켜집니다. 아무도 그렇게 하라고 시키지 않았는데 둘이 일을 나눠 가졌어요. 그리고 XOR이란 "둘 중 하나만 1일 때 1"입니다. 그러니 둘 중 하나만 켜지면 1이라고 하면 되고, 그것은 h₁ + h₂가 어느 값을 넘느냐만 보면 되는 일 — 직선 하나로 되는 일입니다.

한 점만 손으로 따라가 봅시다. 입력 (0, 1)을 넣습니다.

z₁ = -6.075×0 + 5.923×1 + (-3.306) = +2.617 → h₁ = 시그모이드(+2.617) = 0.932 z₂ = 5.645×0 + (-5.862)×1 + (-3.142) = -9.004 → h₂ = 시그모이드(-9.004) = 0.000 z = 9.102×0.932 + 9.169×0.000 + (-4.514) = +3.969 → o = 시그모이드(+3.969) = 0.981 # 정답 1

계산기로 따라 해 보세요. 표의 값과 맞습니다 — 프로그램도 +3.969를 찍습니다. (다만 h₂를 0.000이라고 적었을 뿐 진짜 0은 아니라 0.00012쯤입니다. 그 몫까지 넣으면 +3.970이 돼요. 손으로 하는 계산은 마지막 한 자리가 늘 조금 흔들립니다 — 반올림한 값으로 계산하기 때문이에요. 프로그램은 반올림하지 않은 값을 씁니다.)

⚠️ 오해하기 쉬운 것 — 은닉층이 배우는 것은 '정해진 개념'이 아니다

"은닉 노드 1은 x₂이면서 x₁이 아님을 배웠다"고 딱 잘라 말하고 싶어집니다. 씨앗 1에서는 그 설명이 잘 맞아요. 하지만 씨앗을 바꾸면 두 노드가 나눠 갖는 일도 달라집니다. 실제로 재 보면 이렇습니다.

씨앗은닉 노드 1이 배운 것은닉 노드 2가 배운 것
1x₂이면서 x₁이 아님x₁이면서 x₂가 아님
2ORNAND
5ANDOR
7NORNAND

씨앗 2를 보세요. 13차시에 퍼셉트론 하나로 각각 만들어 봤던 OR과 NAND가 나란히 나왔습니다. 두 개가 함께 켜지는 자리가 정확히 XOR이에요 — XOR = OR 이면서 NAND. 아무도 그렇게 하라고 시키지 않았는데 이 분해를 스스로 찾아낸 겁니다. 하지만 씨앗 1은 전혀 다른 방식으로 같은 답에 닿았어요. 은닉층이 배우는 것은 사람이 미리 정해 준 개념이 아니라 정답을 맞히기에 편한 어떤 좌표입니다. 길은 여러 갈래예요. 시뮬레이터에서 씨앗을 바꿔 가며 은닉값이 어떻게 달라지는지 꼭 확인해 보세요.

3

계단을 버리고 시그모이드를 쓰는 까닭

13차시의 퍼셉트론은 계단 함수를 썼습니다. 가중합이 0 이상이면 1, 아니면 0. 딱 떨어지고 이해하기 쉬웠지요. 그런데 오늘 코드에는 계단이 없습니다. 대신 이렇게 생긴 함수를 씁니다.

def sig(z): return 1 / (1 + math.exp(-z)) # 시그모이드(sigmoid)

시그모이드는 계단을 매끄럽게 편 것입니다. 아주 작은 값을 넣으면 0에 가깝고, 아주 큰 값을 넣으면 1에 가깝고, 0을 넣으면 정확히 0.5가 나와요. 모양은 계단과 비슷한데 모서리가 없습니다.

계단 함수 — 13차시 시그모이드 — 오늘 z 1 0 기울기 0 기울기 0 기울기 없음 어디로 얼마나 밀지 알 수 없다 z 1 0 여기 기울기 0.25 작지만 0은 아니다 어느 자리에서나 기울기를 잴 수 있다
계단은 z = 0 한 자리에서만 값이 바뀌고, 나머지 어디에서나 평평하다. 평평하다는 것은 가중치를 조금 움직여도 출력이 안 바뀐다는 뜻이고, 그러면 어느 쪽으로 얼마나 밀어야 할지 계산할 방법이 없다.

왜 이것이 중요할까요? 9차시에서 경사하강법을 배울 때를 떠올려 보세요. 우리는 기울기를 보고 "이쪽으로 이만큼 내려가면 손실이 준다"고 정했습니다. 기울기가 곧 어느 쪽으로 얼마나 밀지를 알려 주는 나침반이었어요.

계단 함수에는 그 나침반이 없습니다. 0을 뺀 모든 자리에서 기울기가 정확히 0이고, 0에서는 기울기가 아예 없습니다(수직으로 튀어 오르니까요). 기울기가 0이면 "밀 필요 없다"는 뜻으로 읽히므로 가중치가 한 자리도 안 움직입니다.

말로만 하면 믿기 어려우니 실제로 재 봤습니다. 시그모이드의 기울기는 o × (1 − o)라는 아주 간단한 식으로 나옵니다. 출력값 o를 넣어 보면 이래요.

시그모이드의 기울기 o(1−o). 출력이 0이나 1에 붙을수록 기울기가 0에 가까워진다 — 너무 확신하는 노드는 잘 안 배운다는 뜻이기도 하다. 가장 잘 배우는 자리는 o = 0.5다.
출력 o0.0000.001 0.1000.5000.900 0.9991.000
기울기 o(1−o)0.0000000.000999 0.0900000.2500000.090000 0.0009990.000000

계단 함수의 출력은 0 아니면 1뿐입니다. 표의 양 끝 두 칸밖에 못 씁니다. 그리고 그 두 칸의 기울기가 0.000000이에요.

그래서 계단으로 1,000에폭을 돌려 봤습니다. 출력층 가중치가 어떻게 됐을까요?

# 계단 출력(0/1)으로 1000에폭 학습시킨 뒤 W2 : [-0.0091, -0.101] → [-0.0091, -0.101] # 소수 넷째 자리까지 한 자리도 안 움직였다

4,000번 고칠 기회가 있었는데 단 한 자리도 안 움직였습니다. 학습이 느린 것이 아니라 아예 일어나지 않은 것입니다. 이 두 줄은 뒤에서 여러분이 직접 돌려서 다시 볼 겁니다.

💡 한 문장으로

계단은 판정은 잘하지만 학습을 못한다. 매끄러운 곡선이라야 기울기가 나오고, 기울기가 나와야 "어느 쪽으로 얼마나"를 계산할 수 있다. 시그모이드는 정확도를 위해서가 아니라 학습을 위해서 쓰는 것이다.

ℹ️ 한 걸음 더 — 오늘날에는 시그모이드도 잘 안 쓴다

위 표를 다시 보세요. 시그모이드의 기울기는 아무리 커도 0.25입니다. 층을 하나 지날 때마다 기울기가 최대 0.25배로 줄어든다는 뜻이에요. 층이 10개면 0.25를 열 번 곱한 만큼 — 거의 0이 됩니다. 그래서 깊은 신경망에서는 입력 쪽 층이 거의 안 배워지는 문제가 생겼고, 이것을 기울기 소실(vanishing gradient)이라고 부릅니다. 오늘날 은닉층에는 ReLU처럼 양수 쪽 기울기가 1로 일정한 함수를 주로 씁니다. 이 이야기는 5절에서 다시 나옵니다.

4

역전파 — 오차를 뒤로 흘려 책임을 나눈다

이제 남은 물음 하나입니다. 은닉 노드에는 정답이 없습니다. 출력 노드는 "0.7을 냈는데 정답은 1이었다"고 말할 수 있지만, 은닉 노드 1이 낸 0.932는 맞은 것도 틀린 것도 아니에요. 정답이 없는데 어떻게 고칠까요?

답은 이렇습니다. 출력의 오차를 뒤로 흘려보내면서, 각자가 그 오차에 얼마나 기여했는지를 따져 나눠 준다. 이것이 역전파입니다. 새로운 개념은 딱 하나 — '오차를 뒤로 흘린다' 뿐이고, 나머지는 9차시에서 배운 경사하강법을 층마다 한 번씩 하는 것입니다.

입력 x 은닉 h 정답이 없다 출력 o 정답 t 가 있다 ① 순전파 — 값이 앞으로 흐른다 ② 역전파 — 오차의 책임이 뒤로 흐른다 은닉 노드의 책임 = 출력의 책임 × 자기 가중치 × 자기 기울기 ③ 각자 자기 책임만큼 자기 가중치를 고친다
한 점을 배우는 데 세 걸음이 든다. 값을 앞으로 흘리고(①), 오차의 책임을 뒤로 흘리고(②), 각자 자기 몫만큼 가중치를 고친다(③). 이 세 걸음을 네 점에 대해 한 번씩 하는 것이 1에폭이다.

식은 세 줄뿐이다

# ② 출력층의 책임 — '얼마나 틀렸나' 에 '시그모이드의 기울기' 를 곱한다 do = (o - t) * o * (1 - o) # ② 은닉층의 책임 — 출력층의 책임을 자기 가중치만큼 물려받고, 자기 기울기를 곱한다 dh[j] = do * W2[j] * h[j] * (1 - h[j]) # ③ 각자 자기 책임 × 자기에게 들어온 값 만큼 뺀다 (9차시 경사하강법 그대로) W2[j] -= lr * do * h[j] W1[j][k] -= lr * dh[j] * x[k] b1[j] -= lr * dh[j] b2 -= lr * do

두 번째 줄이 이 차시의 전부입니다. 천천히 읽어 보세요.

  • do — 출력 노드가 진 책임입니다. 얼마나 틀렸는지(o − t)에 그 자리의 기울기(o(1−o))를 곱했어요. 틀린 크기만큼, 그리고 움직일 여지가 있는 만큼입니다.
  • W2[j] — 은닉 노드 j가 출력에 얼마나 세게 이어져 있었나입니다. 세게 이어져 있었던 노드가 책임을 많이 집니다. 당연한 이야기예요. 연결이 약했던 노드는 오차에 기여한 몫도 작습니다.
  • h[j](1−h[j]) — 그 노드 자리의 기울기입니다. 자기가 움직일 수 있는 여지죠.

수학 시간에 배우는 이름으로는 연쇄 법칙(chain rule)입니다. "a가 b에 영향을 주고 b가 c에 영향을 준다면, a가 c에 준 영향은 두 영향을 곱한 것"이라는 규칙이에요. 은닉 노드는 출력에 직접 영향을 주지 않고 출력 노드를 거쳐서 줍니다. 그래서 거쳐 온 길만큼 곱해 주는 겁니다.

⚠️ 가장 흔한 실수 — 조용히 나빠지는 종류

은닉층의 책임을 쓸 때 W2[j]를 빼먹고 do * h[j] * (1 - h[j])라고 쓰는 실수가 가장 잦습니다. 이렇게 써도 오류 메시지는 하나도 안 납니다. 코드는 잘 돌아요. 그리고 여기가 고약한 자리인데, 씨앗 1로 돌리면 그대로 성공까지 합니다 — 네 점을 다 맞히고 손실도 0.000650까지 내려가요. 빠뜨린 W2[j]에는 부호가 들어 있습니다. 출력에 음수로 이어진 노드는 반대쪽으로 밀어야 하는데, 이 항이 없으면 모든 은닉 노드를 같은 쪽으로 밉니다. 더는 참기울기가 아닌 거예요. 네 점짜리 작은 문제라 그래도 자주 답에 닿을 뿐입니다.

그래서 실제로 재 봤습니다. 씨앗 30개를 돌리면 바른 식은 6개가 실패하는데(20%) 이 식은 13개가 실패합니다(43%). 성공한 판의 손실도 0.000636~0.001487로, 바른 식의 0.00035~0.00073보다 위에 있어요. 알아보는 자리는 딱 하나입니다 — 씨앗 1로 【1】을 돌렸을 때 마지막 손실이 0.000383이 아니라 0.000650이면 이 자리를 의심하세요. (손실이 0.13에서 멈추는 것만으로는 못 가립니다. 그건 5절의 웅덩이에서도 똑같이 나오거든요.)

9차시와 무엇이 같고 무엇이 다른가

🟰 같은 것 — 고리의 모양

예측 → 오차 → 기울기 → 갱신. 9차시에서 직선의 w와 b를 고칠 때 돌던 그 고리를 오늘도 그대로 돕니다.

손실을 재는 자도 같습니다 — 평균제곱오차예요. 네 점의 제곱오차를 더한 뒤 4로 나눕니다.

➗ 다른 것 — 함수는 새로 짠다

9차시의 mse·gradient를 가져다 쓰지 않습니다. 9차시는 직선 하나의 기울기를 직접 미분한 식이었고, 오늘은 층이 둘이라 식이 다릅니다.

13차시의 퍼셉트론 규칙(오차 × 입력)과도 다릅니다. 그쪽에는 기울기 o(1−o)가 아예 없었어요. 이어지는 것은 코드가 아니라 생각의 모양입니다.

💡 이름이 겹치는 함수 셋 — 헷갈리지 말 것

이 단원에는 predict라는 이름의 함수가 셋 있습니다. 9차시의 predict(xs, w, b)는 목록을 받아 목록을 돌려주고, 13차시의 predict(w1, w2, b, x1, x2)는 한 점을 받아 0 또는 1을 돌려주고, 오늘의 predict(net, x)는 그물과 한 점을 받아 0 또는 1을 돌려줍니다. 이름만 같고 서로 다른 함수예요. 차시마다 페이지가 다르니 부딪힐 일은 없지만, 세 코드를 나란히 놓고 볼 때는 기억해 두세요. train도 마찬가지입니다 — 9차시의 train은 경사하강, 오늘의 train은 역전파입니다.

5

늘 성공하지는 않는다 — 다섯에 하나는 실패한다

여기가 이 차시에서 가장 정직해야 하는 자리입니다. 교과서는 대개 잘된 결과만 보여 줍니다. 그런데 여러분이 실습에서 만날 화면은 다릅니다. 같은 코드, 같은 데이터인데 시작 가중치를 정하는 씨앗만 바꾸면 학습이 실패합니다. 얼마나 자주 실패할까요? 씨앗 0번부터 29번까지 서른 개를 전부 돌려 봤습니다.

# 은닉 2개 · lr 0.5 · 8000회 — 씨앗 30개 실패한 씨앗 : [3, 9, 11, 12, 23, 29] → 30개 중 6개 (20%) # 은닉을 3개로 늘리면 실패한 씨앗 : [] → 30개 중 0개

다섯에 하나꼴입니다. 학급이 스무 모둠이면 네 모둠쯤은 "선생님, 저희는 안 돼요" 하고 손을 듭니다. 그때 "씨앗을 바꿔 봐"라고 답하면 배울 것이 사라집니다. 실패한 화면이 오히려 가장 좋은 자료예요. 무슨 일이 일어난 것인지 뜯어봅시다.

실패한 씨앗 3에서 무슨 일이 났나

씨앗 3 · 은닉 2 · lr 0.5. 성공한 씨앗의 최종 손실은 0.00035~0.00073 사이인데, 실패한 씨앗은 0.1295다 — 350배 차이라 숫자만 봐도 갈린다.
에폭1100500 1,0002,0004,0008,000
손실0.2671870.261590 0.2586490.1760930.133722 0.1303750.129541

2,000회를 지나면 사실상 멈춥니다. 4,000회에서 8,000회로 두 배를 더 돌려도 0.130375에서 0.129541로, 0.0008밖에 안 줄어요. 더 돌리는 것이 답이 아니라는 신호입니다.

그때 네 점에 무엇을 냈는지 보면 원인이 보입니다.

씨앗 3의 학습 결과. 네 점 중 3개만 맞혔다.
입력정답출력은닉값 (h₁, h₂)판정
(0, 0)00.017(0.166, 0.725)맞음
(0, 1)10.979(0.706, 0.017)맞음
(1, 0)10.492(0.000, 0.000)틀림
(1, 1)00.493(0.001, 0.000)맞음

세 번째와 네 번째 줄의 은닉값을 보세요. 은닉 노드 둘이 모두 0.000으로 죽어 있습니다. x₁이 1인 두 입력에 대해 은닉층이 똑같이 아무것도 안 내는 거예요. 은닉 좌표에서 두 점이 완전히 겹쳐 버렸습니다. 겹친 두 점은 정답이 서로 다른데(1과 0) 출력 노드가 구별할 방법이 없습니다. 그래서 0.492와 0.493이라는 어정쩡한 값 — 동전 던지기를 낸 겁니다.

2절에서 성공한 경우에는 (0,0)과 (1,1)이 겹쳤습니다. 그건 정답이 같은 두 점이라 겹쳐도 좋았어요. 여기서는 정답이 다른 두 점이 겹쳤습니다. 같은 '겹침'인데 결과가 정반대입니다.

손실이 더 안 줄어드는 것도 설명됩니다. 내리막이 끝난 곳에 왔는데 그곳이 바닥이 아닙니다. 9차시에서 이름만 들었던 지역 최솟값(local minimum)이 이것입니다. 사방이 오르막이라 경사만 보고는 빠져나갈 수가 없어요.

그럼 어떻게 빠져나오나 — 두 가지가 듣고 하나는 안 듣는다

실패한 씨앗 3을 살려 보려고 한 시도들.
무엇을 바꿨나8,000회 손실결과
그대로 (은닉 2 · lr 0.5)0.129541실패
은닉 2 그대로, 24,000회로 세 배 더 돌리기 0.129151여전히 실패
은닉을 3개로 늘리기0.000412성공
은닉을 5개로 늘리기0.000316성공

세 배를 더 돌려도 손실이 0.0004 줄었을 뿐입니다. 더 오래 돌리는 것은 답이 아니에요. 은닉 노드를 하나 늘리면 바로 풀립니다. 길이 하나 더 생기는 셈이거든요.

★ 그런데 진짜 원인은 씨앗이 아니었다

여기서 한 걸음 더 갑니다. 씨앗 3을 그대로 두고 학습률만 바꿔 보면 이렇게 됩니다.

씨앗 3 · 은닉 2 · 8,000회 — 학습률만 바꿨다. 0.5에서만 실패한다.
학습률0.10.5 1.02.05.0
최종 손실0.022730.12954 0.000180.000080.00003
결과성공실패 성공성공성공

같은 시작점인데 걸음 크기만 바꾸면 빠져나옵니다. 그러니 "씨앗 3은 나쁜 씨앗"이라는 말은 틀렸습니다. 나쁜 것은 (씨앗 3, 학습률 0.5)라는 짝이에요.

🔑 다시 쓰는 문장

"어떤 시작점은 학습이 안 된다"가 아니라, "시작점과 걸음 크기가 맞물려 못 빠져나오는 웅덩이가 생긴다"가 맞다.

걸음이 작으면 웅덩이 안에서 얌전히 바닥으로 굴러가 갇힙니다. 걸음이 크면 웅덩이를 뛰어넘어 버리기도 해요. 학습률 1.0과 2.0이 그래서 성공한 겁니다. 다만 걸음이 너무 크면 이번엔 계속 튕겨 다니느라 아무 데도 못 앉습니다.

학습률을 바꾸면 — 빨라지는 문턱과 망가지는 문턱은 다르다

은닉 2 · 씨앗 1 · 8,000회. 마지막 줄(50.0)은 파이썬으로 돌린 결과다 — 이 학습률에서는 값이 워낙 크게 튀어 계산 환경에 따라 숫자가 달라져서 시뮬레이터의 선택지에는 넣지 않았다.
학습률손실 0.01 아래로 내려간 첫 에폭 8,000회 손실결과
0.05못 감0.250849실패 — 출력이 넷 다 0.5 언저리
0.1못 감0.014034성공 (겨우)
0.51,297회0.000383성공 — 이 차시의 정본
2.0301회0.000080성공
10.0322회0.000016성공
50.0못 감0.233526실패 — 출력 [0.0, 0.843, 0.843, 0.843]

0.5에서 2.0으로 올리면 1,297회가 301회로 네 배 이상 빨라집니다. 그런데 10.0까지 가도 아직 안 망가져요. 망가지는 것은 50.0에서입니다. 빨라지는 자리와 망가지는 자리 사이가 꽤 넓습니다. "학습률은 작을수록 안전하다"는 흔한 오해인데, 0.05를 보세요 — 너무 작아도 실패합니다.

★ 그리고 손실은 처음에 안 줄어든다

마지막으로 반드시 알고 시작해야 할 것이 있습니다. 성공하는 경우(씨앗 1)에도 처음 500회 동안은 아무 일도 안 일어난 것처럼 보입니다.

은닉 2 · lr 0.5 · 씨앗 1. 반복 수를 달리해 끝까지 돌려 본 결과.
반복최종 손실네 점의 출력네 점 다 맞혔나
200회0.26096[0.502, 0.51, 0.494, 0.5]아니오
500회0.25804[0.512, 0.526, 0.484, 0.489]아니오
1,000회0.03931[0.221, 0.833, 0.796, 0.186]예
2,000회0.00306[0.061, 0.948, 0.947, 0.054]예
4,000회0.00095[0.034, 0.971, 0.971, 0.03]예
8,000회0.00038[0.022, 0.981, 0.981, 0.019]예

500회까지 네 출력이 전부 0.5 근처에서 꼼짝하지 않습니다. 손실도 0.262에서 0.258로 거의 그대로예요. 그러다 1,000회 사이 어딘가에서 0.039로 뚝 떨어집니다. 한참 아무 일도 안 일어나다가 갑자기 풀립니다.

⚠️ 실습에서 이것을 모르면

시뮬레이터에서 반복을 500회로 줄여 놓고 "역시 안 되네"라며 포기하기 쉽습니다. 이 차시에서 "손실이 꾸준히 줄어든다"는 말은 사실이 아닙니다. 평평하게 가다가 계단을 하나 내려가듯 떨어져요. 시뮬레이터의 손실 곡선을 끝까지 보고 판단하세요.

6

1980년대의 방법이 왜 2010년대에야 세상을 바꿨나

오늘 배운 역전파는 새 발명이 아닙니다. 1980년대 중반에 이미 널리 알려졌어요. 우리가 방금 쓴 식 세 줄이 그때 정리된 것 그대로입니다. 그런데 인공지능이 뉴스에 오르내리기 시작한 것은 2010년대예요. 30년의 틈이 있습니다.

왜 그랬을까요? 방법을 알아도 돌릴 수가 없었기 때문입니다. 세 가지가 함께 갖춰져야 했고, 셋 중 하나만 없어도 안 됐습니다.

📚

① 데이터

층이 깊어지면 배우는 수가 수백만 개가 됩니다. 그만큼의 예를 보여 줘야 배웁니다. 오늘 우리 신경망이 배운 수는 9개였고 예는 네 점이었어요. 인터넷과 대규모 이미지 데이터 모음이 생기고 나서야 규모가 맞기 시작했습니다.

⚡

② 계산

역전파는 곱셈과 덧셈을 엄청나게 많이 반복합니다. 그런데 그 곱셈들은 서로 순서를 안 따져도 되는 것이 대부분이라 동시에 할 수 있어요. 그림을 그리려고 만든 GPU가 바로 그런 계산을 잘합니다.

🔧

③ 알고리즘

3절에서 본 기울기 소실 같은 문제들이 남아 있었습니다. ReLU 같은 새 함수, 학습 중 일부 노드를 일부러 쉬게 하는 방법 등 깊게 쌓아도 학습이 되게 하는 잔기술이 2000년대 후반에 하나씩 나왔습니다.

그래픽카드 실물 — 검은 덮개에 냉각팬 두 개가 달렸고, 팬 사이로 금속 방열판이, 아래쪽에 금색 단자가 보인다
그래픽카드(GPU). 원래는 게임 화면을 그리려고 만든 부품인데, 같은 계산을 수천 개 동시에 하는 구조라 역전파에 그대로 맞아떨어졌다. 인공지능을 위해 만든 물건이 아닌데 인공지능을 가능하게 했다. 출처: Chi Ho Chan (Hong Kong), Wikimedia Commons (CC BY 2.0)
서버실 — 파란 조명이 켜진 컴퓨터 본체 수십 대가 번호표 붙은 금속 선반에 층층이 놓여 벽처럼 늘어서 있다
데이터센터. 오늘 여러분의 신경망은 브라우저에서 몇 초면 학습이 끝나지만, 요즘의 큰 언어 모델은 이런 방을 가득 채운 계산 장치로 학습시킨다. 계산 자원의 크기가 곧 할 수 있는 일의 크기가 됐다. 출처: BalticServers.com, Wikimedia Commons (CC BY-SA 3.0)

그러니 "딥러닝이 발명되어 세상이 바뀌었다"는 말은 절반만 맞습니다. 방법은 30년 전에 있었고, 그것을 돌릴 조건이 뒤늦게 갖춰진 것입니다. 이런 일은 기술의 역사에서 자주 일어납니다.

⚠️ 오늘 만든 것의 크기를 정직하게 말하면

오늘 여러분이 만든 것은 은닉 노드 두 개, 배우는 수 아홉 개짜리 신경망입니다. 입력은 네 점이고 학습은 몇 초면 끝나요. 이것을 두고 "이제 딥러닝을 만들 줄 안다"고 말하면 지나칩니다.

맞는 말은 이겁니다 — 원리는 같고 규모가 다르다. 오늘 쓴 순전파·역전파·경사하강의 세 걸음은 규모가 몇 억 배가 되어도 그대로입니다. 달라지는 것은 층의 수, 노드의 수, 데이터의 양, 그리고 그 규모에서만 필요해지는 잔기술들이에요. 다음 차시에 이 train() 함수를 한 글자도 안 고치고 진짜 데이터에 붙여 볼 텐데, 그때 이 말의 뜻이 더 분명해질 겁니다.

인공신경망 도해 — 왼쪽에 작은 입력 점 셋, 가운데에 은닉 노드 셋, 오른쪽에 출력 노드 둘이 있고 각 층의 노드가 다음 층의 모든 노드와 화살표로 이어져 있다
흔히 보는 신경망 도해다. 왼쪽 점 셋이 입력, 가운데 원 셋이 은닉층, 오른쪽 원 둘이 출력. 오늘 만든 것(입력 2 · 은닉 2 · 출력 1)과 모양의 종류가 같고 크기만 다르다. 은닉층이 여기서는 한 겹인데, 이것을 여러 겹으로 쌓은 것을 '깊다(deep)'고 하고 거기서 딥러닝이라는 이름이 나왔다. 출처: Offnfopt, Wikimedia Commons (CC BY-SA 3.0)
💻

손으로 ① — 2층 신경망을 직접 학습시킨다

아래 시뮬레이터는 지금까지 읽은 것을 그 자리에서 계산합니다. 은닉 노드 수, 학습률, 반복 수, 씨앗을 고르고 ▶ 학습을 누르면 손실 곡선이 실시간으로 그려지고 네 점의 판정 색이 바뀝니다. 왼쪽 배경에 칠해지는 것은 지금 이 신경망이 평면 전체를 어떻게 판정하는가예요 — 13차시에서는 직선이었던 그 경계가 오늘은 휘어집니다.

💡 이 시뮬레이터는 파이썬과 같은 값을 낸다

브라우저가 쓰는 난수도 파이썬의 random.seed()를 그대로 옮겨 심었습니다. 그래서 같은 씨앗·같은 설정이면 아래 파이썬 실행기와 소수 여섯째 자리까지 같은 손실이 나옵니다. (은닉 1~5 × 씨앗 0~7 × 학습률 여섯 가지, 240판을 두 곳에서 돌려 전부 같은 것을 확인했습니다.) 시뮬레이터에서 본 숫자를 파이썬으로 검산해 보세요. 그것이 이 책의 방식입니다.

🧠 2층 신경망 학습기 — XOR INTERACTIVE

왼쪽은 입력 평면이다. 배경색이 이 신경망의 판정이고, 동그라미 넷이 XOR의 네 점이다(테두리 = 정답, 속 = 지금 낸 답). 오른쪽은 은닉 좌표다 — 은닉 노드가 2개일 때는 네 점을 (h₁, h₂) 평면에 찍고 출력 노드가 그은 초록 선을 함께 그린다. 은닉 노드가 2개가 아니면 은닉값을 막대로 보여 준다. 아래 그림은 손실 곡선이고 세로축은 로그 눈금이다.

에폭0
손실 (MSE)—
맞힌 점0 / 4
배우는 수9
0.01 아래로—
판정대기
2
아직 학습하지 않았습니다. 지금 배경은 학습 전의 판정이에요 — 무작위로 정해진 가중치가 그린 것입니다. ▶ 학습을 눌러 보세요.
[안내] 은닉 2개 · 학습률 0.5 · 8,000회 · 씨앗 1 로 시작합니다.

※ 반복 수에 상한이 있어 브라우저가 멈추는 일은 없습니다. 8,000회를 다 도는 데 걸리는 계산 시간은 1초가 안 되고(가장 긴 24,000회도 마찬가지입니다), 화면은 과정을 보여 주려고 일부러 천천히 그립니다. 급하면 ⏭ 끝까지를 누르세요.

과제 ① 표를 채운다 — 씨앗 여섯 개를 돌린다

은닉 2개 · 학습률 0.5 · 8,000회로 고정하고 씨앗만 바꿔 여섯 번 돌립니다. 매번 씨앗을 바꾸면 자동으로 초기화되니 ▶ 학습만 누르면 됩니다. 최종 손실은 소수 여섯째 자리까지 적으세요.

씨앗최종 손실맞힌 점 (n/4)성공 / 실패
0
1
2
3
4
9

다 채웠으면 손실 칸만 세로로 훑어보세요. 값이 두 무리로 갈립니다. 어디가 경계인가요? 그 경계가 곧 성공과 실패의 경계입니다. 숫자 하나만 보고도 성공했는지 알 수 있다는 뜻이에요.

과제 ② 반례를 만든다 — 은닉 1개로 성공시킬 수 있는가

1️⃣ 은닉 1개로 버튼을 누르면 은닉 노드가 하나로 줄고 반복이 4,000회가 됩니다. 이 상태에서 씨앗을 0, 1, 2, 3, 4, 5로 바꿔 가며 여섯 번 돌려 보세요. 네 점을 다 맞히는 씨앗을 하나라도 찾으면 오늘 수업의 결론이 뒤집힙니다. 찾아보세요.

씨앗012345
최종 손실
맞힌 점

여섯 개의 손실이 모두 어느 좁은 구간 안에 몰려 있을 겁니다. 그 구간을 적어 두세요. 2절의 성공한 손실(0.0004 언저리)과 비교하면 자릿수가 다릅니다. 그리고 오른쪽 막대 그림을 보세요 — 은닉 노드가 하나뿐이면 네 점을 한 줄 위에만 놓을 수 있습니다. 한 줄 위에 놓인 네 점을 점 하나로 나누는 것이 은닉 1개가 할 수 있는 전부예요. 그것은 결국 13차시의 퍼셉트론 하나와 같습니다.

과제 ③ 문턱을 찾는다 — 실패한 씨앗을 살려라

😵 씨앗 3 — 실패 사례 버튼을 누르면 은닉 2개 · 학습률 0.5 · 씨앗 3으로 맞춰집니다. 학습시켜 실패를 직접 확인한 뒤, 딱 한 가지만 바꿔서 성공시켜 보세요. 바꿀 수 있는 것은 셋입니다 — 은닉 노드 수, 학습률, 반복 수. 반복 칸에는 24,000회까지 있으니 5절의 표에 적힌 그 값을 직접 재 볼 수 있습니다.

바꾼 것바꾼 값최종 손실성공했나
아무것도 안 바꿈은닉 2 · lr 0.5 · 8,000회
반복만 늘림8,000 → ?
은닉만 늘림2 → ?
학습률만 바꿈0.5 → ?

셋 중 둘은 듣고 하나는 안 듣습니다. 안 듣는 것이 무엇인지 확인했나요? 그리고 학습률 칸에서 성공한 값이 여러 개일 겁니다. 0.5보다 작은 쪽에서도, 큰 쪽에서도 성공합니다. 0.5 하나만 콕 집어 실패한다는 사실이 왜 중요한지 5절을 다시 읽어 보세요.

💡 더 해 볼 것
  • 학습이 끝난 뒤 은닉 좌표(오른쪽 그림)의 네 점 자리를 공책에 옮겨 그리세요. 씨앗 1과 씨앗 2가 서로 다른 모양을 만듭니다. 둘 다 정답을 맞히는데 그림이 다릅니다.
  • 왼쪽 배경의 경계가 어느 에폭쯤에 휘기 시작하는지 보세요. 200회에서 멈춰 보고, 1,000회에서 멈춰 보고, 8,000회를 끝까지 돌려 비교하면 좋습니다.
  • 학습률 0.05로 8,000회를 돌려 보세요. 실패하는데 실패하는 모양이 씨앗 3과 다릅니다. 어떻게 다른가요?
💻

손으로 ② — 역전파를 직접 짜서 XOR을 넘는다

이제 시뮬레이터가 안에서 하고 있던 일을 여러분 손으로 짭니다. 아래 코드에는 빈칸 다섯 자리가 있어요. 4절의 식 세 줄이 그대로 답입니다. 채우지 않고 실행하면 SyntaxError가 납니다 — 정상이에요.

빈칸 다섯 자리와 힌트. ③은 코드에 두 군데 나옵니다(마지막 【8】에도 있어요).
빈칸무엇을 쓰나어디를 보면 되나
①시그모이드의 식3절 첫 코드 상자
②한 점의 제곱오차9차시에서 쓰던 그 자
③출력층의 책임4절 식 첫 줄
④은닉층의 책임4절 식 둘째 줄 — W2[j]를 빼먹지 마세요
⑤갱신 네 줄4절 식 셋째 묶음
⚠️ 채점은 '성공/실패'가 아니라 0.000383으로 한다

이 코드의 씨앗은 seed=1로 못박혀 있습니다. 빈칸을 바르게 채우면 【1】은 반드시 성공하고, 마지막 손실이 정확히 0.000383입니다. 그러니 '성공'이라는 글자만 보고 넘어가지 마세요.

  • 성공했는데 손실이 0.000650이면 — 빈칸 ④에서 W2[j]를 빼먹은 것입니다(4절 경고 상자). 화면은 멀쩡히 성공으로 나옵니다.
  • 【1】이 아예 실패하면 — 빈칸 ③이나 ⑤(갱신 네 줄)를 다시 보세요. 바른 코드라면 씨앗 1에서 실패할 수가 없습니다.
  • 손실이 0.13 언저리에서 멈췄다면 — 그것만으로는 못 가립니다. 그 값은 식이 틀렸을 때도, 씨앗이 나빴을 때도 나옵니다(5절). 씨앗이 1로 못박힌 이 코드에서 그 숫자가 나왔다면 식이 틀린 쪽입니다.
  • 【3】은 코드가 맞으면 여섯 씨앗 다 실패하고 손실이 0.1717~0.1758 사이에 들어옵니다. 이 범위를 벗어나면 뼈대(sig·forward)부터 확인하세요.

돌려 보고 확인할 것 셋

  1. 【1】의 마지막 네 줄 — 출력이 0.022 / 0.981 / 0.981 / 0.019인가? 13차시에서 50%에 갇혀 있던 그 네 점입니다. 은닉 두 개를 끼운 것만으로 넘었습니다.
  2. 【2】의 은닉 좌표 — 네 쌍을 공책의 모눈종이에 옮겨 찍고 h₂ = −0.993·h₁ + 0.492 선을 그어 보세요. 정말 직선 하나로 나뉘는지, 그리고 어느 두 점이 겹쳤는지 확인하세요.
  3. 【8】의 마지막 줄 — 계단으로 1,000에폭을 돌린 뒤 W2가 한 자리도 안 움직인 것을 눈으로 보세요. 3절에서 말로 읽었던 것을 여기서 확인합니다.
💡 코드를 고쳐 볼 것
  • epochs=8000을 500으로 바꿔 보세요. 실패합니다. 1000으로 바꾸면 성공합니다. 그 사이 어디에서 풀리는지 찾아보세요.
  • 【1】의 seed=1을 seed=3으로 바꿔 보세요. 손실이 0.129541에서 멈추고 은닉값에 0.000이 나타납니다. 그다음 hidden=2를 hidden=3으로 바꾸면 살아납니다.
  • lr=0.5를 lr=0.05로 바꿔 보세요. 8,000회를 다 돌아도 네 출력이 0.5 근처를 못 벗어납니다. 이것은 코드가 틀린 것이 아니라 걸음이 너무 작은 것입니다.
ℹ️ 이 코드는 다음 차시가 그대로 가져간다

코드 위쪽 sig부터 predict까지의 블록에 "여기까지 그대로"라는 표시가 붙어 있습니다. 15차시는 이 다섯 함수를 글자 하나 안 바꾸고 다시 싣고, train()에 넣는 데이터만 XOR 네 점에서 급식 잔반 240일치로 바꿉니다. 코드는 그대로인데 문제가 달라지는 것 — 그것이 다음 시간의 이야기예요. 그러니 이 블록은 함부로 고치지 말고, 고치고 싶으면 아래쪽 실험 부분만 만지세요.

📖

정리

🧱 층을 하나 더 쌓으면

입력과 출력 사이에 은닉층이 들어가면 배우는 수가 3개에서 9개로 늘고, 할 수 있는 일이 달라진다.

은닉층이 하는 일은 입력 공간을 다시 그리는 것이다. XOR 네 점이 은닉 좌표에서는 세 무리로 접히고, 그러면 직선 하나로 나뉜다.

📈 계단이 아니라 시그모이드

계단은 어디서나 기울기가 0이라 "어느 쪽으로 얼마나"를 계산할 수 없다. 실제로 1,000에폭을 돌려도 가중치가 한 자리도 안 움직였다.

시그모이드의 기울기는 o(1−o)이고 가장 클 때가 0.25다. 그래서 층이 깊어지면 기울기가 사라지는 문제가 생긴다.

↩️ 역전파

은닉 노드에는 정답이 없다. 그래서 출력의 오차를 뒤로 흘려 각자가 진 책임을 나눠 준다.

은닉 노드의 책임 = 출력의 책임 × 자기 가중치 × 자기 기울기. 9차시의 경사하강법을 층마다 한 번씩 하는 것이고, 새 개념은 '뒤로 흘린다' 하나다.

😵 그리고 실패한다

씨앗 30개 중 6개(20%)가 실패한다. 은닉을 3개로 늘리면 0개가 된다.

실패의 원인은 '나쁜 씨앗'이 아니라 시작점과 걸음 크기의 짝이다. 씨앗 3은 학습률 0.5에서만 실패하고 0.1·1.0·2.0·5.0에서는 성공한다.

오늘 나온 숫자 한눈에 — 전부 실제로 돌려서 나온 값이다.
무엇값
XOR 학습 성공 (은닉 2 · lr 0.5 · 씨앗 1 · 8,000회) 손실 0.262336 → 0.000383
그때 네 점의 출력0.022 / 0.981 / 0.981 / 0.019
은닉 좌표 네 쌍 (0.035, 0.041) · (0.932, 0.000) · (0.000, 0.924) · (0.031, 0.034)
은닉 좌표에서 출력 노드가 그은 선h₂ = −0.993·h₁ + 0.492
은닉 1개 · 씨앗 여섯 개 · 4,000회성공 0개 · 손실 0.1717~0.1758
은닉 2개 · 씨앗 서른 개실패 6개 (20%) — 씨앗 3·9·11·12·23·29
은닉 3개 · 씨앗 서른 개실패 0개
실패한 씨앗 3의 최종 손실0.129541 (성공은 0.00035~0.00073 — 350배 차이)
손실이 0.01 아래로 내려간 첫 에폭 (lr 0.5 / 2.0)1,297회 / 301회
계단 함수로 1,000에폭 뒤 W2[−0.0091, −0.101] → [−0.0091, −0.101]
📖 세 차시가 하나로 이어진다

9차시에서 우리는 기울기를 보고 내려가는 법을 배웠습니다. 13차시에서 그 방법으로 직선 하나를 배우게 했고, XOR 앞에서 막혔지요. 오늘 층을 하나 끼우고 오차를 뒤로 흘려 그 벽을 넘었습니다. 셋을 이어 주는 것은 코드가 아니라 '예측 → 오차 → 기울기 → 갱신'이라는 고리의 모양입니다. 세 차시의 코드는 서로 다릅니다. 같은 것은 생각의 모양이에요.

✅

확인 문제

✍️ 문제마다 답을 쓰고 제출하기를 누르세요. 제출하면 모범 답안이 열리고, 제출한 답은 선생님께 전달됩니다.

1. 은닉층이 하는 일을 '입력 공간'이라는 말을 써서 두 문장으로 설명하시오. 그리고 은닉 노드에 정답을 알려 주지 않는데도 학습이 되는 까닭을 한 문장 덧붙이시오.
📖 모범 답안

은닉층은 입력 공간의 네 점을 다른 좌표로 옮겨 놓는다. 그 새 좌표에서는 정답이 같은 점끼리 가까워지고 다른 점끼리 멀어져서, 출력 노드가 직선 하나로 나눌 수 있게 된다. 즉 은닉층은 "나누기 좋은 좌표계를 스스로 만드는" 일을 한다.

정답이 없는데도 배워지는 까닭은 출력의 오차를 뒤로 흘려 책임을 나누기 때문이다. 은닉 노드는 "네가 맞았다/틀렸다"는 말을 듣는 것이 아니라 "출력이 이만큼 틀렸는데 네가 출력에 이만큼 세게 이어져 있었으니 이만큼이 네 몫"이라는 말을 듣는다. 그 몫이 곧 은닉 노드에게는 정답을 대신하는 신호다.

덧붙임 — '입력 공간을 다시 그린다'는 표현은 은유가 아니라 좌표를 실제로 계산해 확인할 수 있는 사실이다. 2절과 문제 2번이 그 확인이다.

2. 오늘 직접 돌린 결과로 답하시오. 은닉 2개 · 학습률 0.5 · 씨앗 1로 8,000회 학습한 뒤, (가) 네 입력의 은닉 좌표 (h₁, h₂)를 소수 셋째 자리까지 적고, (나) 그 네 점을 모눈종이에 찍어 직선 하나로 나뉘는 것을 보이고, (다) 어느 두 점이 거의 겹쳤는지와 그렇게 겹쳐도 괜찮은 까닭을 쓰시오.
📖 모범 답안

(가) (0,0) → (0.035, 0.041) · (0,1) → (0.932, 0.000) · (1,0) → (0.000, 0.924) · (1,1) → (0.031, 0.034). 소수 셋째 자리까지 적어야 한다 — 둘째 자리로 줄이면 (0,0)과 (1,1)이 (0.03, 0.04)와 (0.03, 0.03)이 되어 무슨 일이 일어났는지 흐려진다.

(나) 네 점을 찍으면 원점 근처에 두 점, 오른쪽 아래에 (0,1), 왼쪽 위에 (1,0)이 놓인다. h₂ = −0.993·h₁ + 0.492 선을 그으면 원점 쪽 두 점은 선 아래, 나머지 둘은 선 위로 갈린다. 출력층 가중합도 −3.813 / +3.969 / +3.962 / −3.928로 부호가 정확히 그렇게 나뉜다.

(다) (0,0)과 (1,1)이 겹쳤다. 이 둘은 정답이 둘 다 0이므로 겹쳐도 상관없다 — 출력 노드가 둘을 구별할 필요가 없기 때문이다. 오히려 겹쳐 준 덕분에 문제가 쉬워졌다. 입력 평면에서 대각선으로 마주 보던 두 점이 한자리에 모였으니 나머지 둘만 반대편에 두면 되고, 그건 직선 하나로 되는 일이다. (반대로 정답이 다른 두 점이 겹치면 큰일이다 — 문제 5번에서 그 경우를 본다.)

3. 13차시에서 쓰던 계단 함수 대신 시그모이드를 쓰는 까닭을 '기울기'라는 말을 써서 설명하시오. 설명할 때 3절의 기울기 표에서 구체적인 값 두 개를 근거로 들고, 계단으로 1,000에폭을 돌렸을 때 실제로 무슨 일이 일어났는지도 함께 쓰시오.
📖 모범 답안

학습은 기울기를 보고 어느 쪽으로 얼마나 밀지 정하는 일이다(9차시 경사하강법). 그런데 계단 함수는 z = 0 한 자리를 빼면 어디서나 평평해서 기울기가 0이고, 그 한 자리에서는 수직으로 튀어 오르므로 기울기가 아예 정의되지 않는다. 기울기가 0이면 "밀 필요 없다"로 읽히므로 가중치가 움직이지 않는다.

근거 값 두 개 — 시그모이드의 기울기 o(1−o)는 o = 0.5일 때 0.250000으로 가장 크고, o = 0.000이나 o = 1.000일 때 0.000000이다. 계단 함수의 출력은 0 아니면 1뿐이므로 언제나 기울기 0인 자리에만 있다.

실제로 재 본 결과 — 계단 출력으로 1,000에폭(= 가중치를 고칠 기회 4,000번)을 돌린 뒤 W2가 [−0.0091, −0.101]에서 [−0.0091, −0.101]로, 소수 넷째 자리까지 한 자리도 안 움직였다. 학습이 느린 것이 아니라 아예 일어나지 않았다.

덧붙임 — 시그모이드의 기울기가 아무리 커도 0.25라는 점은 다른 문제를 낳는다. 층을 지날 때마다 기울기가 0.25배 이하로 줄어드니 층이 깊어지면 입력 쪽이 거의 안 배워진다(기울기 소실). 그래서 오늘날 은닉층에는 ReLU 같은 함수를 주로 쓴다.

4. 어떤 학생이 은닉층의 책임을 dh[j] = do * h[j] * (1 - h[j])라고 썼다. (가) 무엇을 빠뜨렸는지 쓰고, (나) 그 항이 어떤 뜻을 담고 있는지 설명하고, (다) 이 실수가 왜 찾기 어려운지, 그리고 어떤 숫자를 보면 알아챌 수 있는지 쓰시오.
📖 모범 답안

(가) W2[j]를 빠뜨렸다. 바른 식은 dh[j] = do * W2[j] * h[j] * (1 - h[j])다.

(나) W2[j]는 은닉 노드 j가 출력 노드에 얼마나 세게, 그리고 어느 쪽으로 이어져 있었나를 나타낸다. 세게 이어져 있던 노드는 출력의 오차에 많이 기여했으니 책임도 많이 져야 하고, 약하게 이어져 있던 노드는 책임도 적다. 더 중요한 것은 부호다 — 출력에 음수로 이어진 노드는 값을 반대쪽으로 밀어야 오차가 준다. 이 항이 없으면 모든 은닉 노드를 같은 쪽으로 밀게 되어, 더는 손실을 가장 빨리 낮추는 방향(참기울기)이 아니게 된다.

(다) 찾기 어려운 까닭은 오류 메시지가 하나도 안 나기 때문이다. 문법도 맞고 계산도 되고 프로그램은 끝까지 잘 돈다. 게다가 씨앗 1에서는 네 점을 다 맞히기까지 한다 — 화면만 보면 성공이다. 그래서 "돌아가니까 맞겠지"로 넘어가기가 쉽다.

알아채는 자리는 손실의 소수 여섯째 자리다. 바른 식으로 씨앗 1을 8,000회 돌리면 0.000383인데, 이 실수를 하면 같은 조건에서 0.000650이 된다. 화면이 '성공'이라도 이 숫자가 다르면 식을 다시 보라. 씨앗을 여럿 돌려 보면 더 분명해진다 — 실패하는 씨앗이 30개 중 6개에서 13개로 늘어난다.

반대로 "손실이 0.13에서 멈춘다"만으로는 못 가린다. 그 값은 씨앗을 잘못 만나 웅덩이에 갇혔을 때도 똑같이 나오기 때문이다(문제 5번). 그리고 "식이 틀렸으면 어느 씨앗에서도 성공하지 못하겠지"라고 생각하기 쉬운데, 그것도 틀렸다 — 실제로 재 보면 서른 개 중 열일곱 개가 성공한다. 틀린 식은 안 되게 만드는 것이 아니라 나빠지게 만든다.

5. 오늘 시뮬레이터로 채운 표를 보고 답하시오. (가) 은닉 노드를 1개로 줄이면 왜 반드시 실패하는가? 여러분이 적은 여섯 씨앗의 손실이 어느 구간에 몰려 있었는지 함께 쓰시오. (나) 씨앗 3은 학습이 실패한다. "반복을 더 늘리면 된다"는 주장이 왜 틀렸는지 숫자를 들어 반박하고, 실제로 통하는 방법 두 가지를 쓰시오.
📖 모범 답안

(가) 은닉 노드가 하나면 은닉 좌표가 1차원, 곧 수직선 하나다. 네 점이 전부 한 줄 위에 놓이고, 출력 노드가 할 수 있는 일은 그 줄을 점 하나로 자르는 것뿐이다. 그러면 왼쪽 무리와 오른쪽 무리 두 조각밖에 못 만드는데, XOR은 가운데 있는 것과 양 끝에 있는 것을 갈라야 하는 문제라 두 조각으로는 안 된다. 결국 은닉 1개짜리 신경망은 13차시의 퍼셉트론 하나와 같은 힘밖에 없다.

씨앗 여섯 개(0~5)의 최종 손실은 전부 0.1717 ~ 0.1758 사이에 몰린다. 성공한 경우의 0.0004와 견주면 자릿수가 다르다. 여섯 개 다 실패한다.

(나) 씨앗 3을 8,000회에서 24,000회로 세 배 늘려 봐도 손실은 0.129541 → 0.129151, 겨우 0.0004 줄어들 뿐 여전히 실패한다. 더 돌려도 안 되는 까닭은 내리막이 이미 끝났기 때문이다 — 사방이 오르막인 웅덩이(지역 최솟값)에 앉아 있어서 경사를 보고는 나갈 수가 없다. 실제로 은닉값을 보면 (1,0)과 (1,1)에서 은닉 두 개가 모두 0.000으로 죽어 있고, 그 바람에 정답이 다른 두 점이 은닉 좌표에서 겹쳐 출력이 0.492와 0.493이 된다.

통하는 방법 둘 — ① 은닉 노드를 늘린다(3개 → 0.000412 성공, 5개 → 0.000316 성공). ② 학습률을 바꾼다(0.1 → 0.02273 성공, 1.0 → 0.00018 성공, 2.0 → 0.00008 성공). 특히 ②가 중요하다. 같은 씨앗인데 걸음 크기만 바꾸면 빠져나온다는 것은 "씨앗 3이 나쁜 씨앗"이 아니라 "(씨앗 3, 학습률 0.5)라는 짝이 나쁘다"는 뜻이기 때문이다.

6. 역전파는 1980년대에 이미 알려져 있었는데 인공신경망이 널리 쓰이기 시작한 것은 2010년대다. 그 사이를 메운 조건 세 가지를 쓰고, 각각이 없으면 왜 안 되는지 한 줄씩 설명하시오. 그리고 "오늘 나는 딥러닝을 만들었다"고 말해도 되는지 판단하고 근거를 쓰시오.
📖 모범 답안

① 데이터 — 층이 깊어지면 배우는 수가 수백만 개가 된다. 그만큼의 예가 없으면 배울 것이 없고, 있는 것을 외워 버린다(11차시의 과적합). 인터넷과 대규모 데이터 모음이 생기고 나서야 규모가 맞았다.

② 계산 — 역전파는 곱셈과 덧셈을 엄청나게 반복한다. 다행히 그 곱셈들은 대부분 서로 순서를 안 따져도 되어 동시에 할 수 있고, 그림을 그리려고 만든 GPU가 그런 계산을 잘한다. 계산 장치가 없으면 방법을 알아도 끝날 때까지 기다릴 수가 없다.

③ 알고리즘 — 시그모이드의 기울기가 최대 0.25라 층이 깊어지면 입력 쪽 층이 거의 안 배워진다(기울기 소실). ReLU 같은 새 함수와 학습 중 일부 노드를 쉬게 하는 방법 등 깊게 쌓아도 학습이 되게 하는 잔기술이 필요했다.

판단 — "딥러닝을 만들었다"고 말하면 지나치다. 오늘 만든 것은 은닉층 한 겹, 노드 두 개, 배우는 수 아홉 개짜리다. '깊다(deep)'는 말은 은닉층을 여러 겹 쌓았다는 뜻인데 우리는 한 겹만 썼다. 정확한 말은 "딥러닝의 원리를 그대로 썼고 규모가 다르다"이다. 순전파·역전파·경사하강의 세 걸음은 규모가 몇 억 배가 되어도 오늘 쓴 것과 같다.

🔁 되돌아보기

오늘 13차시에서 막혔던 XOR 네 점을 은닉층 하나로 넘었고, 은닉 좌표를 직접 찍어 공간이 다시 그려졌다는 것을 눈으로 확인했으며, 같은 코드가 씨앗에 따라 다섯에 하나꼴로 실패하는 것도 직접 만들어 보았습니다. 공책에 한 줄만 적어 두세요 — 오늘 가장 안 풀린 것이 무엇이었는지. 다음 시간에는 오늘 짠 train()을 한 글자도 고치지 않고 급식 잔반 240일치 데이터에 붙입니다. 코드는 그대로인데 문제가 달라집니다.

🔎

더 알아보기

오늘의 역전파는 어디서 왔고, 층이 깊어지면 무엇에 부딪히며, 한 겹으로는 어디까지 되는가

왕립 스웨덴 과학원 표지가 붙은 나무 연단 뒤에서 강연하는 흰머리의 제프리 힌턴
역사

1986년의 논문 한 편 — '모르던 방법'이 널리 알려지다

여는 장면의 1969년 책은 민스키(Marvin Minsky)와 페퍼트(Seymour Papert)가 쓴 『퍼셉트론』입니다. 층을 쌓으면 된다는 것은 알았지만 여러 층을 학습시키는 방법이 없었지요. 오차를 거꾸로 흘려 기울기를 구하는 계산은 1970년대에 이미 몇몇 연구자가 따로 적어 두었지만(폴 워보스의 1974년 박사 논문이 자주 꼽힙니다), 신경망 연구자들 사이에 널리 퍼진 것은 1986년 럼멜하트·힌턴·윌리엄스가 과학 학술지 『네이처』에 실은 논문 뒤였습니다.

그 논문의 제목은 '오차를 역전파해 표현을 학습한다'는 뜻입니다. 논문이 보여 준 것은 은닉 노드가 사람이 가르쳐 주지 않은 쓸모 있는 특징을 스스로 만들어 낸다는 점이었어요. 오늘 2절에서 씨앗 1의 두 은닉 노드가 'x₂만 1일 때'와 'x₁만 1일 때'로 일을 나눠 가진 것이 바로 그 현상입니다.

사진은 2024년 스톡홀름에서 노벨 강연을 하는 제프리 힌턴입니다. 그는 그 뒤로도 신경망을 붙들었고, 2012년 그의 제자 크리제브스키·수츠케버와 함께 만든 AlexNet이 GPU 두 장으로 학습한 깊은 신경망으로 이미지 인식 대회 ImageNet에서 2위와 큰 차이로 우승했습니다. 6절의 데이터·계산·알고리즘이 한꺼번에 맞아떨어진 순간으로 꼽혀요. 힌턴은 2018년 튜링상(벤지오·르쿤과 함께), 2024년 노벨 물리학상(홉필드와 함께)을 받았습니다.

사진: 2024년 노벨 강연(스톡홀름 대학교)의 제프리 힌턴 · 출처: Jay Dixit, Wikimedia Commons (CC BY-SA 4.0)

층을 지난 뒤 남는 기울기의 최대 배율 ReLU (양수 쪽 ×1) 시그모이드 (최대 ×0.25) 1층 1 0.25 2층 1 0.0625 3층 1 0.0156 5층 1 0.00098 10층 1 약 0.000001 시그모이드 기울기만 곱해도 10층이면 100만분의 1
원리 더 깊이

기울기 소실 — 층을 지날 때마다 0.25배씩

3절에서 시그모이드의 기울기 o(1−o)는 가장 커도 0.25라고 했습니다. 그리고 4절 둘째 줄에서 은닉 노드의 책임은 뒤 층의 책임 × 가중치 × 자기 기울기였지요. 층이 하나 늘 때마다 이 곱셈이 한 번 더 붙습니다. 가중치는 빼고 시그모이드 기울기만 보면 한 층을 지날 때 많아야 0.25배, 10층이면 0.25를 열 번 곱한 약 0.00000095 — 100만분의 1쯤으로 줄어듭니다.

그러면 출력에 가까운 층은 배우는데 입력 쪽 층은 거의 제자리인 일이 생깁니다. 이것이 기울기 소실이고, 깊은 신경망이 오랫동안 잘 학습되지 않던 큰 까닭 가운데 하나입니다. (가중치가 크면 곱이 도리어 커질 수도 있는데, 그러면 이번엔 값이 걷잡을 수 없이 커지는 기울기 폭발이 생깁니다.)

가장 단순한 해결책이 ReLU입니다. 식은 max(0, z) — 음수는 0으로, 양수는 그대로 내보냅니다. 양수 쪽 기울기가 늘 1이라 활성화 함수 때문에 기울기가 줄지는 않고, 지수 계산이 없어 빠르기도 해요. 앞 카드의 AlexNet도 ReLU를 썼습니다.

공짜는 아닙니다. 음수 쪽 기울기는 0이라, 어떤 노드가 모든 입력에 음수만 받게 되면 그 노드는 더 배우지 못합니다('죽은 ReLU'). 5절 씨앗 3에서 은닉 노드 둘이 0.000에 붙어 버린 것과 닮았어요 — 기울기가 0에 가까운 자리에 갇힌 노드는 스스로 빠져나오기 어렵습니다.

계단 둘을 빼면 봉우리, 봉우리를 모으면 곡선 − = 은닉 노드 A 은닉 노드 B 봉우리 하나 점선: 목표 곡선 · 보라: 봉우리 6개(은닉 노드 12개)의 합
오해 바로잡기

은닉층 한 겹이면 무엇이든 된다? — 보편 근사 정리가 말하지 않는 것

오늘 은닉 노드 두 개로 XOR을 넘었습니다. 노드를 더 늘리면 어디까지 될까요? 1989년 조지 시벤코(George Cybenko)는 시그모이드 은닉층 한 겹이라도 노드만 충분히 많으면 정해진 범위 안의 어떤 연속함수든 원하는 만큼 가깝게 흉내 낼 수 있음을 증명했습니다. 이것을 보편 근사 정리라고 부릅니다.

그림이 그 까닭을 보여 줍니다. 시그모이드는 가중치를 키우면 계단에 가까워지고, 편향을 바꾸면 계단의 자리가 옮겨집니다. 자리가 다른 계단 둘을 빼면 봉우리 하나가 되고, 높이가 다른 봉우리를 여러 개 이어 붙이면 어떤 곡선이든 따라 그릴 수 있어요. 봉우리 하나에 은닉 노드가 둘씩 듭니다.

그런데 이 정리를 "은닉층 하나면 다 된다"로 읽으면 틀립니다. 정리는 그런 가중치가 있다고만 말할 뿐, 역전파가 그것을 찾아낸다고는 말하지 않습니다 — 씨앗 3은 풀 수 있는 구조(은닉 2개)였는데도 웅덩이에 갇혔지요. 노드가 몇 개 필요한지도 말하지 않는데, 복잡한 함수를 한 겹으로 흉내 내려면 노드 수가 엄청나게 불어날 수 있습니다. 층을 깊게 쌓으면 같은 일을 훨씬 적은 노드로 해내는 경우가 많고, 그것이 '깊이'를 쓰는 까닭입니다.