단원 홈
2단원 · 9차시

선을 긋는 법을 스스로
손실이 줄어드는 쪽으로

8차시에서는 이웃에게 물어보는 방식으로 품종을 맞혔습니다. 오늘은 답이 이름표가 아니라 숫자인 문제를 풉니다. 그리고 사람이 눈대중으로 선을 긋는 대신, 기계가 스스로 선을 고쳐 나가게 만듭니다.

성취기준 12인기02-03 성취기준 12인기02-04
회귀손실(MSE)기울기 경사하강법학습률발산
🎯 학습 목표
  • 회귀와 분류의 차이를 '답의 종류'로 설명하고, 직선 모델 y = wx + b에서 기계가 찾아야 할 것이 두 숫자뿐임을 말할 수 있다.
  • 평균제곱오차(MSE)를 손으로 계산하고, 오차를 제곱하는 까닭 두 가지를 댈 수 있다.
  • 경사하강법의 한 걸음을 코드로 짜서 손실이 5305.40 → 7.33으로 줄어드는 것을 직접 재고, 학습률을 올려 발산하는 문턱(0.074)을 찾을 수 있다.
🤔

여는 장면 — 스물네 개의 점 위에 자를 대다

어느 반에서 시험이 끝난 뒤 두 가지를 적었습니다. 일주일 동안 그 과목을 공부한 시간과 시험 점수입니다. 스물네 명의 기록을 좌표평면에 점으로 찍으면 이렇게 보입니다.

# 공부 시간(시간) → 시험 점수(점) · 24명 ( 1.0, 52.1) ( 1.2, 52.9) ( 1.4, 52.3) ( 1.6, 61.3) ( 1.8, 54.4) ( 2.0, 61.0) ( 2.2, 66.7) ( 2.4, 60.2) ( 2.6, 66.6) ( 2.8, 69.0) ( 3.0, 64.9) ( 3.2, 70.0) ( 3.4, 74.9) ( 3.6, 74.1) ( 3.8, 78.6) ( 4.0, 74.6) ( 4.2, 77.1) ( 4.4, 77.5) ( 4.6, 83.2) ( 4.8, 89.0) ( 5.0, 87.4) ( 5.2, 90.9) ( 5.4, 88.7) ( 5.6, 94.1)

점들은 오른쪽 위로 올라갑니다. 자를 대고 선 하나를 그으면 대충 맞을 것 같습니다. 그런데 옆자리 친구가 그은 선과 내가 그은 선이 조금 다릅니다. 둘 중 어느 선이 더 좋은 선일까요?

"내 것이 더 잘 맞아 보이는데" 로는 끝나지 않습니다. 눈은 사람마다 다르고, 무엇보다 기계에게는 눈이 없습니다. 기계에게 선을 그으라고 시키려면 '더 좋다'를 숫자 하나로 바꿔 줘야 합니다. 숫자가 되어야 비교할 수 있고, 비교할 수 있어야 고칠 수 있습니다.

🎯 오늘의 물음

점 스물네 개를 가장 잘 지나는 직선을, 눈대중이 아니라 기계가 스스로 찾게 하려면 무엇을 알려 줘야 할까요?

오늘 여러분은 세 조각을 만듭니다. 모델(어떤 모양의 선을 쓸 것인가), 손실(얼마나 틀렸는가를 재는 자), 경사하강법(어느 쪽으로 고칠 것인가). 이 세 조각은 오늘 배우는 직선 하나에만 쓰이는 것이 아닙니다. 13차시의 퍼셉트론도, 14차시의 신경망도 같은 세 조각으로 돌아갑니다.

1

답이 이름표가 아니라 수일 때 — 회귀

8차시에서 씨앗의 품종을 맞힐 때 답은 A 아니면 B였습니다. 답이 몇 개의 이름표 중 하나인 문제를 분류라고 불렀지요. 오늘 답은 다릅니다. 시험 점수는 A도 B도 아니고 73.4점입니다. 답이 이렇게 연속적인 수인 지도학습을 회귀(regression)라고 합니다.

 분류회귀
답의 종류몇 개의 이름표 중 하나연속적인 수
이 책의 예씨앗 품종 A·B (8차시)공부 시간 → 시험 점수 (오늘)
다른 예스팸이다 / 아니다내일 잔반이 몇 kg 남을까
'맞았다'의 뜻이름표가 같다 (맞음/틀림)가깝다 (얼마나 빗나갔는가)
잴 때 쓰는 자정확도 — 몇 개를 맞혔나손실 — 평균 몇 점씩 빗나갔나
분류에는 '반쯤 맞음'이 없지만, 회귀에는 있다. 73점을 74점이라 답한 것과 40점이라 답한 것은 둘 다 틀렸지만 같은 정도로 틀리지는 않았다.

여기서 중요한 차이가 하나 생깁니다. 분류에서는 맞혔는지 아닌지만 세면 됐습니다. 회귀에서는 '틀렸다'가 정도의 문제입니다. 그래서 얼마나 틀렸는지를 재는 자가 먼저 필요합니다. 오늘 수업의 절반이 이 자를 만드는 일입니다.

모델 — 찾아야 할 것은 단 두 숫자

점들을 지나는 선의 모양을 우리가 먼저 정합니다. 오늘은 직선으로 하겠습니다.

y = w · x + b x = 공부 시간(입력) y = 시험 점수(예측) w = 기울기 — 한 시간 더 공부하면 점수가 몇 점 오르는가 b = 절편 — 하나도 공부하지 않았을 때의 점수

이 식에서 x는 데이터가 주는 값이고 y는 우리가 내놓는 답입니다. 우리가 고를 수 있는 것은 w와 b 둘뿐입니다. 이 둘을 가중치와 편향이라고 부릅니다.

💡 '학습한다'는 말의 정체

사람이 w = 8.5, b = 44.0 이라고 적어 넣으면 그것은 프로그래밍입니다. 데이터를 보고 기계가 이 두 숫자를 스스로 고쳐 나가면 그것이 학습입니다. 오늘 만들 프로그램에서 w와 b는 0에서 출발합니다. 아무것도 모르는 상태에서 시작해 스물네 개의 점만 보고 걸어갑니다.

좌표평면에 파란 점 수십 개가 오른쪽 위로 흩어져 있고, 그 사이를 빨간 직선 하나가 비스듬히 지나는 선형회귀 그림
점들 사이를 지나는 직선 하나를 찾는 것 — 오늘 하는 일이 그림 한 장으로는 이것이다. 어려운 것은 '직선을 긋는 것'이 아니라 어느 직선이 더 좋은지를 숫자로 정하는 것이다. 출처: Sewaqu, Wikimedia Commons (Public domain)

직선이 아니라 곡선을 쓸 수도 있습니다. 그러면 찾을 숫자가 셋, 넷으로 늘어납니다. 14차시에서 만들 신경망은 층이 하나 더 생기면서 찾을 숫자가 아홉 개가 됩니다. 개수만 달라질 뿐, 하는 일은 오늘과 똑같습니다 — 숫자를 고쳐 나가는 것입니다.

2

좋은 선을 숫자 하나로 재기 — 손실

선 두 개를 놓고 어느 쪽이 나은지 정해 봅시다. 점을 세 개만 골라 손으로 계산해 보겠습니다. (1.0, 52.1) · (3.0, 64.9) · (5.0, 87.4) 세 명입니다.

점실제 점수 선 ㉮ y = 9x + 42 선 ㉯ y = 7x + 48
예측오차예측오차
x = 1.052.1 51.0−1.1 55.0+2.9
x = 3.064.9 69.0+4.1 69.0+4.1
x = 5.087.4 87.0−0.4 83.0−4.4
오차를 그냥 더하면— +2.6 +2.6
제곱해 평균내면(MSE)— 6.06 14.86
세 점만 놓고 손으로 계산한 값이다. 오차를 그냥 더하면 두 선이 똑같이 2.6이 나와 구별이 안 된다. 제곱해서 평균내면 6.06과 14.86 — 선 ㉮가 확실히 낫다.

이 표가 오늘 가장 중요한 장면입니다. 오차를 그냥 더하면 안 됩니다. 선 ㉮는 −1.1과 −0.4로 잘 맞히고 한 점만 +4.1 빗나갔는데, 선 ㉯는 +2.9, +4.1, −4.4로 세 점이 고르게 크게 빗나갔습니다. 그런데 합은 둘 다 +2.6입니다. 플러스 오차와 마이너스 오차가 서로 지워 버렸기 때문입니다.

제곱하는 까닭 둘

① 부호가 서로 지우지 못하게

제곱하면 모두 0 이상이 됩니다. −4.4도 19.36, +4.1도 16.81. 어느 쪽으로 빗나갔든 벌점이 쌓입니다. 절댓값을 써도 되지만, 절댓값은 0에서 꺾여서 뒤에 배울 기울기 계산이 어색해집니다.

② 크게 빗나간 점에 더 무겁게

1점 빗나가면 벌점 1, 10점 빗나가면 벌점 100입니다. 10배 빗나가면 100배 미움받습니다. 그래서 이 자는 "조금씩 두루 틀리는 선"보다 "크게 한 번 틀리는 선"을 더 싫어합니다.

이렇게 만든 자를 손실(loss)이라고 부릅니다. 오차를 제곱해 평균낸 방식은 특히 평균제곱오차(mean squared error, MSE)라는 이름이 붙어 있습니다.

손실 = ( (예측₁ − 정답₁)² + (예측₂ − 정답₂)² + ⋯ + (예측ₙ − 정답ₙ)² ) ÷ n # 파이썬으로는 한 줄이다 def mse(pred, real): n = len(real) return sum((pred[i] - real[i]) ** 2 for i in range(n)) / n
⚠️ '비용'이라 부르지 않는다

책에 따라 이 값을 '비용 함수'라고도 부릅니다. 이 책에서는 쓰지 않습니다. 1단원에서 '비용'은 탐색의 g, 즉 출발점부터 지금까지 실제로 든 값이라는 뜻으로 이미 썼기 때문입니다. 같은 책에서 같은 낱말이 두 뜻이면 헷갈립니다. 이 단원에서는 손실로만 부릅니다.

손실은 하나의 숫자여야 한다

스물네 명 전체로도 재 봅시다. 선 ㉮와 선 ㉯를 스물네 개의 점 모두에 대 보면 손실은 각각 7.3338과 14.8938이 나옵니다. 아직 시작도 안 한 w = 0, b = 0 짜리 선 — 그러니까 모든 사람에게 0점을 주는 선 — 의 손실은 5305.40입니다.

여기서 손실의 쓸모가 분명해집니다. 스물네 개의 점, 스물네 개의 오차가 숫자 하나로 눌러졌습니다. 5305.40과 14.8938과 7.3338을 나란히 놓으면 누가 봐도 순서를 정할 수 있습니다. 비교할 수 있으면 고칠 수 있습니다. 이제 남은 물음은 하나입니다 — 어느 쪽으로 고쳐야 손실이 줄어드는가?

3

어느 쪽으로 갈 것인가 — 기울기와 한 걸음

손실이라는 자가 생겼으니, 이제 w와 b를 조금씩 바꿔 보면서 손실이 작아지는 쪽을 찾으면 됩니다. 가장 단순한 방법은 다 해 보는 것입니다. w를 0부터 20까지 0.01씩, b를 0부터 60까지 0.01씩 — 1,200만 가지를 전부 계산해 가장 작은 것을 고르면 됩니다.

직선 하나라면 그것도 됩니다. 그런데 14차시에서 만들 신경망은 찾을 숫자가 아홉 개입니다. 숫자가 하나 늘 때마다 경우의 수가 곱하기로 늘어납니다. 숫자 하나에 2,000가지씩만 따져도 아홉 개면 2,0009, 약 5 × 1029가지입니다. 1초에 10억 가지를 계산해도 우주 나이의 천 배가 넘게 걸립니다. 그래서 다른 길을 씁니다 — 지금 서 있는 자리에서 내리막을 찾아 그쪽으로 한 걸음 가는 것입니다.

기울기 — 지금 자리에서 어느 쪽이 오르막인가

손실을 w에 대해, b에 대해 각각 미분하면 "이 숫자를 조금 키우면 손실이 얼마나 커지는가"가 나옵니다. 이것을 기울기(gradient)라고 합니다. 평균제곱오차를 미분하면 식이 아주 짧게 떨어집니다.

# 오차 = 예측 − 정답 (부호를 살려 둔다. 이 부호가 방향을 알려 준다) err[i] = (w·x[i] + b) − y[i] dw = 2 × ( err₁·x₁ + err₂·x₂ + ⋯ + errₙ·xₙ ) ÷ n ← w 쪽 기울기 db = 2 × ( err₁ + err₂ + ⋯ + errₙ ) ÷ n ← b 쪽 기울기

두 식의 생김새가 거의 같습니다. 다른 점은 x를 곱하느냐 하나뿐입니다. 왜 그럴까요? b는 모든 점에 똑같이 더해집니다. b를 1 올리면 스물네 개의 예측이 전부 1씩 올라갑니다. 하지만 w는 x에 곱해집니다. w를 1 올리면 x = 1.0인 사람의 예측은 1만 오르지만 x = 5.6인 사람은 5.6이 오릅니다. 멀리 있는 점일수록 w를 더 세게 끌어당깁니다. 그래서 x를 곱합니다.

ℹ️ 앞의 2는 어디서 왔나

제곱을 미분하면 (u²)′ = 2u·u′ 이므로 2가 따라 나옵니다. 그런데 이 2를 지워도 학습은 됩니다. 실제로 지우고 돌려 보면 2000회 뒤 w = 9.52271, b = 39.98764, 손실 8.08792가 나옵니다. 그리고 학습률을 두 배인 0.02로 올리면 원래 결과와 소수 다섯째 자리까지 같아집니다. 상수 2를 지우는 것은 학습률을 절반으로 줄이는 것과 완전히 같은 일입니다. 그래서 실제 라이브러리들은 이 2를 생략하기도 합니다.

한 걸음 — 오르막의 반대쪽으로

기울기는 오르막의 방향입니다. 우리는 내려가고 싶으니 반대쪽으로 갑니다. 얼마나 갈지는 lr이라는 숫자로 정합니다.

w ← w − lr × dw b ← b − lr × db # lr = 학습률(learning rate). 한 걸음의 크기. # 부호가 핵심이다. '+' 로 쓰면 오르막으로 올라가 버린다.

이 두 줄을 계속 반복하는 것이 경사하강법(gradient descent)입니다. 말로 하면 이렇습니다 — 지금 직선으로 예측한다 → 정답과 견줘 오차를 낸다 → 오차로 기울기를 구한다 → 기울기의 반대쪽으로 lr만큼 옮긴다 → 다시 예측한다. 네 칸짜리 고리입니다.

① 예측 w·x + b 를 계산 24개 모두 ② 오차·손실 예측 − 정답 제곱해 평균 = 손실 ③ 기울기 dw = 2·Σ(err·x)/n db = 2·Σ err /n ④ 갱신 w ← w − lr·dw b ← b − lr·db 이 고리를 2000번 돈다 학습이라는 이름의 고리 13차시의 퍼셉트론도, 14차시의 신경망도 이 네 칸을 돈다. 칸 안의 식만 달라진다.

고리의 모양은 이 단원 끝까지 바뀌지 않는다. 13차시에서는 ③이 '오차 × 입력'이라는 더 간단한 규칙으로, 14차시에서는 오차를 층 사이로 되돌려 보내는 계산으로 바뀔 뿐이다.

손으로 한 걸음 — 세 점으로 따라가 보기

아까의 세 점 (1.0, 52.1) · (3.0, 64.9) · (5.0, 87.4)과 선 ㉮ y = 9x + 42에서 한 걸음만 직접 걸어 봅시다. 오차는 이미 구했습니다: −1.1, +4.1, −0.4.

dw = 2 × ( (−1.1)×1.0 + (+4.1)×3.0 + (−0.4)×5.0 ) ÷ 3 = 2 × ( −1.1 + 12.3 − 2.0 ) ÷ 3 = 2 × 9.2 ÷ 3 = 6.1333 db = 2 × ( −1.1 + 4.1 − 0.4 ) ÷ 3 = 2 × 2.6 ÷ 3 = 1.7333 # lr = 0.01 로 한 걸음 w ← 9 − 0.01 × 6.1333 = 8.9387 b ← 42 − 0.01 × 1.7333 = 41.9827 # 손실 6.0600 → 5.7043 로 내려갔다

기울기가 둘 다 양수였습니다. "w를 키우면 손실이 커진다"는 뜻이므로 w를 줄였습니다. 그리고 손실이 실제로 6.06에서 5.70으로 내려왔습니다. 한 걸음이 하는 일은 이게 전부입니다.

스물네 점에서의 첫 세 걸음

이제 진짜 데이터로 갑니다. w = 0, b = 0에서 출발해 lr = 0.01로 세 걸음만 아주 느리게 들여다봅시다.

회차손실wb dwdb다음 걸음
0회5305.4000 −507.662−143.458 w +5.0766 · b +1.4346
1회2902.575.076621.43458 −368.164−107.083 w +3.6816 · b +1.0708
2회1633.218.758262.50542 −266.798−80.643 w +2.6680 · b +0.8064
3회962.37411.42623.31185 −193.139−61.421 w +1.9314 · b +0.6142
실제로 돌려서 나온 값이다. 처음에는 모두에게 0점을 주고 있었으니 오차가 −52점씩 났고, 기울기가 −507이나 되어 첫 걸음에 w가 단번에 5.08까지 뛴다. 세 걸음 만에 손실이 5305 → 962로 줄었다.

표에서 눈여겨볼 것이 둘 있습니다. 첫째, 기울기가 점점 작아집니다 (−507 → −368 → −267 → −193). 골짜기 바닥에 가까워질수록 경사가 완만해지니, 같은 학습률을 써도 걸음이 저절로 작아집니다. 멈추라고 시키지 않아도 스스로 조심스러워지는 셈입니다.

둘째, w가 b보다 훨씬 빨리 움직입니다 (첫 걸음에 w는 +5.08, b는 +1.43). dw에는 x가 곱해져 있고 이 데이터의 x는 평균 3.3이니, dw가 db보다 서너 배 큽니다. 이 불균형이 나중에 문제가 됩니다. 5차시에서 정규화를 배운 까닭이 여기 있습니다 — 특성마다 단위가 다르면 어떤 방향은 성큼성큼, 어떤 방향은 종종걸음이 됩니다.

4

걸음의 크기 — 학습률 하나로 모든 것이 갈린다

지금까지 lr = 0.01을 아무 설명 없이 썼습니다. 학습률은 데이터에서 배우는 값이 아니라 사람이 정해 줘야 하는 값입니다. 이런 값을 초매개변수라고 부릅니다. 그리고 이 값 하나가 학습의 성패를 가릅니다.

코드는 한 글자도 바꾸지 않고 lr이라는 숫자 하나만 바꿔서 2000회씩 돌려 보면 이렇습니다.

학습률2000회 뒤 손실wb무슨 일이 났나
0.0001194.468318.06376.8838 2000회를 다 돌고도 출발선 근처다
0.017.32758.969942.1093 바닥에 거의 닿았다
0.12.023 × 10¹²—— 18회 만에 폭발해 중단
같은 데이터, 같은 코드, 같은 회차. 바뀐 것은 lr 한 글자뿐이다.
학습률이 너무 작다 lr = 0.0001 · 2000회로도 못 내려온다 손실이 가장 작은 자리 아직 한참 남았다 알맞다 lr = 0.01 · 바닥까지 내려간다 여기서 멈춘다 너무 크다 lr = 0.1 · 걸음마다 3배씩 커진다 골짜기를 건너뛰어 더 높이 오른다

가로축은 w, 세로축은 손실이다(실제로는 w·b 두 방향이 있어 그릇 모양이지만, 한 방향만 잘라 보면 이런 골짜기가 된다). 걸음이 작으면 도착을 못 하고, 크면 골짜기 폭보다 멀리 뛰어 반대쪽 벽의 더 높은 곳에 떨어진다. 거기서는 경사가 더 가파르니 다음 걸음은 더 커진다 — 이것이 발산이다.

너무 크면 — 걸음마다 세 배씩

lr = 0.1로 놓고 상한 없이 밀어붙이면 이렇게 됩니다.

0회 손실 5305.4 w 0 b 0 1회 손실 15493.2 w 50.7662 b 14.3458 2회 손실 46123.9 w −37.965 b −7.68317 3회 손실 138170 w 115.113 b 33.2562 4회 손실 414721 w −150.913 b −35.0238 10회 손실 3.04797e+08 w −4553.75 b −1176.51 50회 손실 3.92275e+27 w −1.63948e+13 b −4.27137e+12 635회 손실이 inf(무한대)가 되었다 637회 OverflowError — 코드가 죽었다

세 가지를 보십시오. 첫째, 손실이 걸음마다 약 세 배씩 커집니다. 둘째, w의 부호가 매 걸음 뒤집힙니다 (+50.8 → −38.0 → +115.1 → −150.9…). 골짜기를 좌우로 건너뛰면서 점점 높이 튀어 오르는 것입니다. 셋째, 635회에서 손실이 inf(무한대)가 되고, 637회에서 OverflowError가 나며 프로그램이 죽습니다.

⚠️ 상한을 두는 까닭

파이썬은 덧셈이 넘칠 때는 조용히 inf로 만들지만, 제곱(** 2)이 넘칠 때는 OverflowError를 던집니다. 그래서 오늘 코드에는 CAP = 1e12라는 상한이 들어 있습니다. 손실이 1조를 넘으면 발산으로 보고 스스로 멈춥니다. 이 상한을 지우면 여러분이 lr을 크게 넣는 순간 브라우저 탭이 오류로 멈춥니다. 모든 반복문에 끝이 있어야 합니다. while True는 쓰지 않습니다.

발산의 문턱은 정확히 어디인가

0.01은 되고 0.1은 안 된다면, 그 사이 어디에 경계가 있을 것입니다. lr을 0.005씩 올려 가며 500회씩 돌려 보고, 다시 0.001 눈금으로 좁혀 보면 경계가 딱 떨어집니다.

학습률500회 뒤 손실결과
0.00558.7509수렴 (느리다)
0.0119.9377수렴
0.028.0789수렴
0.057.3248수렴 (가장 빠른 축)
0.077.3247수렴
0.07352.9773수렴 — 하지만 요동친다
0.074—발산 (427회에서 중단)
0.075—발산 (196회)
0.1—발산 (18회)
문턱은 lr = 0.074다. 0.073까지는 살아남고 0.074부터 폭발한다. 0.073은 살아남긴 하지만 100회째 손실이 1993.0411까지 튀었다가 겨우 돌아온다 — 벼랑 끝에서 비틀거리는 것이다.

이 문턱은 데이터가 정합니다. 알고리즘이나 컴퓨터가 정하는 것이 아닙니다. 같은 데이터에서 x를 시간이 아니라 분 단위로 바꾸면(1.0시간 → 60분) 문턱이 0.074에서 2 × 10⁻⁵ 근처까지 내려갑니다. 정확히 3600배, 그러니까 60의 제곱만큼 작아집니다. lr = 0.01은 물론이고 0.0001, 0.00003도 전부 발산합니다.

ℹ️ 5차시의 정규화가 여기서 갚아진다

5차시에서 걸음 수와 공부 시간처럼 단위가 다른 특성을 0~1로 옮겨 놓았습니다. 그때는 거리 계산이 이유였습니다. 오늘 이유가 하나 더 생겼습니다 — 특성의 크기가 학습률의 안전 범위를 정합니다. 단위를 바꿨을 뿐인데 쓸 수 있는 학습률이 3600배 달라진다면, 여러 특성을 함께 쓸 때는 특성마다 안전 범위가 달라 하나의 학습률로는 감당할 수 없습니다. 정규화는 그 범위를 서로 맞춰 주는 일입니다.

너무 작으면 — 느린 것이 아니라 '아직 출발선'

lr = 0.0001로 2000회를 돌리면 w = 18.0637, b = 6.8838, 손실 194.4683에 있습니다. 손실 194는 5305에서 꽤 내려온 것처럼 보입니다. 하지만 직선을 보면 완전히 틀렸습니다 — 기울기가 18이나 되고 절편은 거의 0입니다. w만 배우고 b는 아직 시작도 못 했습니다.

재미있는 것은 이 자리의 정체입니다. lr = 0.01로 20회 걸었을 때가 w = 18.1098, b = 6.8988입니다. 거의 같은 자리지요. 학습률을 100배 줄이면 같은 자리에 가는 데 100배의 회차가 듭니다. 실제로 lr = 0.0001로 200,000회를 돌리면 손실 7.3275, w 8.9702, b 42.1082 — 마침내 도착합니다. 길을 잘못 든 것이 아니라 같은 길을 100배 잘게 나눠 걷고 있었을 뿐입니다.

💡 0.01은 '알맞은' 값이 아니라 '안전한' 값이다

위 표를 보면 0.01보다 0.05가 훨씬 낫습니다. 손실이 10 아래로 처음 내려가는 회차가 lr = 0.01은 777회, lr = 0.05는 155회입니다. 다섯 배 빠릅니다. 그런데도 사람들이 0.01 같은 작은 값부터 시작하는 까닭은, 너무 작으면 오래 걸릴 뿐이지만 너무 크면 아예 망가지기 때문입니다. 느린 실패는 되돌릴 수 있고, 발산한 실패는 되돌릴 수 없습니다.

🧭

직선이 걸어가는 것을 눈으로 — 경사하강 재생기

지금까지 표로 본 숫자들을 움직이는 그림으로 확인합시다. 왼쪽에는 스물네 개의 점과 지금의 직선이, 오른쪽에는 손실 곡선이 함께 그려집니다. 직선이 움직일 때마다 오른쪽 곡선이 한 칸 내려가는 것을 보십시오. 초록 점선은 공식으로 구한 정답선입니다 — 목적지가 어디인지 미리 표시해 둔 것입니다.

🧭 경사하강 재생기 INTERACTIVE

학습률 슬라이더를 움직이면 곧바로 처음부터 다시 시작합니다. [한 걸음]으로 한 번씩, [재생]으로 2000회까지 이어서 봅니다. 빨간 실선은 각 점의 오차이고, 손실은 이 선들의 길이를 제곱해 평균낸 값입니다. 학습률을 0.074 이상으로 올리면 직선이 화면 밖으로 튀어 나가고 손실 곡선이 위로 치솟습니다.

회차0
손실5305.3988
w (기울기)0.0000
b (절편)0.0000
다음 dw-507.662
다음 db-143.458
정답선과의 차이8.9346
상태준비

정답선(최소제곱 해)은 w = 8.93457 · b = 42.24510 · 손실 7.32469 입니다. '정답선과의 차이'는 지금 w가 그 값에서 얼마나 떨어져 있는지입니다.

[안내] 학습률 0.010 · 출발점 w=0, b=0 · 손실 5305.3988
📝 과제 ① — 표를 채워라 (공책에 옮겨 적는다)

학습률을 아래 값으로 맞추고 [재생]을 눌러 끝까지 돌린 뒤, 기록 칸에 찍히는 200회·500회의 손실과 마지막 상태를 적으십시오. 그 회차에 닿기 전에 멈춰 버리면 손실 칸에는 —를 적고, 마지막 칸에 발산(몇 회에서 멈췄는지)을 적으십시오.

학습률200회 손실500회 손실수렴 / 발산
0.005
0.020
0.050
0.100

적고 나서 스스로 답해 보십시오 — 학습률을 두 배로 올리면 손실도 절반이 됩니까? 표의 숫자로 확인하십시오.

📝 과제 ② — 문턱을 찾아라

슬라이더를 0.070에 놓고 [재생]합니다. 수렴합니다. 이제 0.001씩 올려 가며 같은 일을 반복해, 상태 칸에 '발산'이 처음 뜨는 값을 찾으십시오. 찾았으면 그 바로 아래 값에서 손실 곡선이 어떤 모양인지도 함께 보십시오 — 내려가다가 한 번 크게 튀었다가 돌아옵니다.

그 다음, 출발점을 w = 100, b = −50으로 바꾸고 학습률을 다시 0.010으로 두어 재생해 보십시오. 2000회에서의 w를 출발점 (0, 0)일 때의 8.9699와 견주어 적으십시오. 아주 멀리서 출발했는데도 거의 같은 곳에 와 있습니까?

ℹ️ 시뮬레이터와 파이썬은 같은 계산을 한다

이 재생기가 쓰는 데이터·공식·계산 순서는 아래 파이썬 실습과 완전히 같습니다. 그래서 재생기에서 lr = 0.01로 2000회를 돌리면 손실이 7.3275, w가 8.9699로 찍히고, 파이썬을 돌려도 같은 값이 나옵니다. 둘을 나란히 놓고 대조해 보십시오. 다르면 둘 중 하나가 틀린 것입니다.

5

공식이 있는데 왜 굴러 내려가는가

사실을 하나 밝혀야 합니다. 직선 하나를 맞추는 문제에는 공식이 있습니다. 손실이 가장 작아지는 w와 b를 미분해서 0이 되는 자리를 풀면 한 번의 계산으로 답이 나옵니다. 최소제곱법(least squares)이라고 합니다.

w = ( n·Σxy − Σx·Σy ) ÷ ( n·Σx² − (Σx)² ) b = ( Σy − w·Σx ) ÷ n # 이 데이터에 넣으면 w = 8.93457 b = 42.24510 손실 = 7.32469

2000회를 걸어서 얻은 답은 w = 8.96994, b = 42.10931, 손실 7.32745였습니다. 공식 해와 거의 같지만 완전히 같지는 않습니다. 회차를 늘리면 어떻게 되는지 보십시오.

회차wb손실공식 해와의 차이(w)
100회16.2883914.01885126.646337.35 × 10⁰
500회11.3254733.0680619.937682.39 × 10⁰
2000회8.9699442.109317.327453.54 × 10⁻²
10000회8.9345742.245107.324696.18 × 10⁻¹²
40000회8.9345742.245107.324693.25 × 10⁻¹³
회차를 다섯 배로 늘릴 때마다 차이가 자릿수째로 줄어든다. 다만 정확히 0 이 되지는 않는다 — 경사하강법은 목표에 다가갈 뿐 도착을 선언하지 않는다.

그렇다면 공식이 있는데 왜 굴러 내려갈까요? 공식이 있는 모델이 드물기 때문입니다. 직선처럼 단순한 모양에는 공식이 있지만, 13차시의 퍼셉트론에도 14차시의 신경망에도 "이렇게 계산하면 답이 나온다"는 공식이 없습니다. 경사하강법은 공식이 없을 때도 쓸 수 있는 방법이고, 그것이 이 방법이 살아남은 이유입니다. 오늘 공식이 있는 문제로 연습하는 까닭도 여기 있습니다 — 정답을 알고 있어야 경사하강이 제대로 가고 있는지 확인할 수 있기 때문입니다.

⚠️ '경사하강이 정답을 찾는다'가 아니다

이 데이터를 만들 때 우리는 y = 8.5x + 44.0이라는 직선에 흔들림을 얹었습니다. 그런데 경사하강이 찾아낸 것은 8.93이지 8.50이 아닙니다. 공식으로 구해도 8.93입니다. 둘이 다른 것이 정상입니다. 표본 스물네 개에 얹힌 흔들림 때문에, 이 스물네 점에서 손실이 가장 작은 직선은 데이터를 만든 직선과 다릅니다. 경사하강법의 목표는 앞쪽이지 뒤쪽이 아닙니다. 기계는 세상의 진리를 찾는 것이 아니라 가진 데이터에 가장 잘 맞는 답을 찾습니다. 이 구별이 11차시의 과적합으로 이어집니다.

가로축 θ₀, 세로축 θ₁ 평면 위에 빨강·파랑 화살표가 줄지어 이어지며, 처음 몇 개는 길게 꺾여 내려오고 뒤로 갈수록 짧아져 (0, 1) 부근에 모이는 경사하강 경로 도해
숫자 두 개(θ₀, θ₁)를 고치는 경사하강이 실제로 지나간 길 — 화살표 하나가 한 걸음이다. 처음 몇 걸음은 길고 방향도 크게 꺾이지만, 그 뒤로는 한 줄로 늘어서며 점점 짧아져 (0, 1) 부근에 모인다. 바닥에 가까워질수록 경사가 완만해져 같은 학습률에서도 걸음이 저절로 작아지는 것 — 우리 실습에서 기울기가 −507에서 −193으로 줄어든 것과 같은 장면이다. (이 그림에는 등고선이 없다. 손실이 같은 자리를 이은 등고선 위에 오늘 데이터의 실제 경로를 그린 그림은 '더 알아보기'에 있다.) 출처: Eviatar Bach, Wikimedia Commons (CC0)
💻

손으로 — 스무 줄로 만드는 학습 기계

먼저 준비운동입니다. 아까 손으로 계산한 세 점을 코드로 확인해 봅시다. 여러분이 종이에 쓴 값과 같은지 보십시오.

손실 6.06과 14.86, 기울기 6.1333과 1.7333, 한 걸음 뒤 손실 5.7043. 표에 적힌 값과 같았습니까? 같았다면 여러분의 손계산과 컴퓨터의 계산이 같은 일을 한 것입니다.

본 실습 — 빈칸 여섯 곳을 채운다

이제 스물네 개의 점으로 갑니다. 아래 코드에는 ?????로 비워 둔 자리가 여섯 곳 있습니다. 그 여섯 자리가 오늘 배운 전부입니다. 나머지는 결과를 보여 주는 부분입니다.

빈칸어디무엇을 채우나
①mse()오차를 제곱해 더한다
②predict()직선의 식 — 이 한 줄이 '모델' 전부다
③dw오차에 그 점의 x를 곱해 평균낸다
④db오차만 평균낸다 (x를 곱하지 않는다)
⑤train()기울기의 반대쪽으로 한 걸음 (두 줄)
⑥w_ls최소제곱 공식
③이 이 차시에서 가장 조용한 함정이다. x를 빠뜨려도 오류가 나지 않는다. 다만 w와 b가 둘 다 16.68120에서 굳고 손실이 122.34458에서 더 안 내려간다. 더 무서운 것은 그 다음이다 — 학습률을 0.001에서 0.05까지 어떤 값으로 바꿔도 답이 똑같다. "학습률을 바꿔도 결과가 안 변한다"면 lr이 아니라 기울기 식을 의심하라.
💡 채우기 전에 실행하면

그대로 실행하면 SyntaxError가 납니다. ?????는 파이썬이 모르는 글자이기 때문입니다. 이것은 정상입니다. 오류 메시지에 몇 번째 줄인지 나오니, 그 줄부터 채우면 됩니다. 다 채웠는데도 이상하면 ↺ 처음 코드로를 눌러 되돌릴 수 있습니다.

도전 — 숫자 하나만 바꿔서 부숴 본다

빈칸을 다 채워 돌아가면, 이제 망가뜨릴 차례입니다. 성공한 코드만 보면 배우는 것이 없습니다. 아래 여섯 가지를 하나씩 해 보고 무엇이 어떻게 달라졌는지 공책에 적으십시오.

바꿀 것어떻게무엇을 볼 것인가
① 학습률을 크게lr = 0.1 몇 회에서 멈추는가? 그때 손실은?
② 학습률을 작게lr = 0.0001 2000회로 도착하는가? 그때 b는 얼마인가?
③ 부호를 뒤집기w -= 를 w += 로 ⚠️ lr = 0.01이면 40걸음에 발산한다. 그런데 lr = 0.0001로 하면 발산 판정에 안 걸리고 2000회를 다 돌면서 손실 2.808 × 10⁸, w −4367이 된다. 죽지도 않으면서 완전히 틀린 상태 — 상한만으로는 못 잡는다
④ 이상한 점 하나 추가X 뒤에 5.0, Y 뒤에 20 추가 w가 8.96994 → 6.73916으로 끌려간다. 7시간 예측도 104.9 → 94.1점. 한 사람이 스물네 명을 이긴다
⑤ 단위 바꾸기X 를 분 단위로 (x × 60) lr 0.01·0.0001·0.00003 전부 발산한다. 0.00002에서야 돈다 — 문턱이 3600배 작아졌다
⑥ 앞의 2를 지우기dw·db 의 2 × 를 삭제 2000회 뒤 w 9.52271, 손실 8.08792. 그 뒤 lr을 0.02로 올리면 원래와 소수 다섯째 자리까지 같아진다
전부 실제로 돌려서 나온 값이다. 여러분의 화면에도 같은 숫자가 나와야 한다. 다르면 어딘가를 잘못 고친 것이다.
6

배운 범위 밖 — 104.9점이라는 답

학습이 끝났으니 써 봅시다. 배운 직선은 y = 8.97x + 42.11입니다.

공부 시간예측 점수 
2.0시간60.0점배운 범위 안
4.0시간78.0점배운 범위 안
5.6시간92.3점배운 범위 안 (맨 끝)
7.0시간104.9점배운 범위 밖
10.0시간131.8점배운 범위 밖
100점 만점인 시험에서 104.9점과 131.8점이라고 답한다.

코드에 오류는 없습니다. 학습도 제대로 됐습니다. 그런데 답이 틀렸습니다. 왜일까요?

모델이 본 데이터는 1.0시간에서 5.6시간까지뿐입니다. 그 구간에서는 한 시간에 약 9점씩 오르는 것이 사실이었습니다. 모델은 그 사실을 끝없이 연장합니다. 20시간이면 221점, 100시간이면 939점이라고 답할 것입니다. 배운 구간 밖으로 선을 늘려 답하는 것을 외삽(extrapolation)이라고 합니다.

⚠️ 모델은 '모른다'고 말할 줄 모른다

사람이라면 "10시간 공부한 사람 데이터는 본 적이 없어서 모르겠는데" 라고 답합니다. 모델은 그러지 못합니다. w · x + b를 계산할 뿐이고, x가 10이든 1000이든 계산은 됩니다. 답이 나온다는 것과 그 답을 믿어도 된다는 것은 전혀 다른 말입니다. 인공지능이 자신 있게 틀린 답을 내놓는 장면을 뉴스에서 볼 때, 그 뿌리에 이 성질이 있습니다.

고칠 방법은 몇 가지가 있습니다. ① 예측 결과를 0~100으로 잘라 내기 — 손쉽지만 근본은 그대로입니다. ② 입력 범위를 벗어나면 "범위 밖"이라고 알리기 — 정직한 방법입니다. ③ 6시간 이상 공부한 학생의 데이터를 실제로 더 모으기 — 가장 옳지만 가장 오래 걸립니다. ④ 직선 대신 위로 갈수록 완만해지는 다른 모양을 쓰기.

회차를 줄인다고 해결되지도 않습니다. 7시간 예측값은 100회에 128.0점, 300회에 118.0점, 1000회에 106.6점, 2000회에 104.9점, 10000회에 104.8점입니다. 학습이 잘될수록 오히려 104.8점에 가까워집니다 — 문제는 학습이 덜 된 것이 아니라 직선이라는 모양을 우리가 골랐다는 것입니다.

📖

정리 — 오늘 만든 세 조각

조각하는 일오늘의 모습
모델입력을 받아 답을 내놓는 식 y = w·x + b (숫자 2개)
손실얼마나 틀렸는지를 수 하나로 MSE = Σ(예측−정답)² / n
경사하강어느 쪽으로 얼마나 고칠지 w ← w − lr · dw
이 세 조각과 그것을 잇는 네 칸짜리 고리(예측 → 오차 → 기울기 → 갱신)가 이 단원 나머지의 뼈대다.

오늘 손실을 5305.40에서 7.33까지, 724배 줄였습니다. 그런데 그 줄어듦의 96%가 처음 열 걸음에서 일어났습니다(5305 → 214). 나머지 1990걸음이 한 일은 4%입니다. 학습은 처음이 요란하고 뒤로 갈수록 조용해집니다. 그래서 손실 그래프는 로그 눈금으로 봐야 뒷부분이 보입니다.

⚠️ 다음 시간을 위해 정직하게 짚어 둘 것

13차시와 14차시도 오늘의 고리 모양을 그대로 씁니다 — 예측하고, 오차를 내고, 기울기를 구하고, 반대쪽으로 한 걸음. 그것은 사실입니다.

그러나 오늘 만든 mse()·gradient()를 다음 차시에 그대로 복사해 쓰지는 않습니다. 13차시의 퍼셉트론은 '오차 × 입력'이라는 더 단순한 규칙을 쓰고, 14차시의 신경망은 오차를 층 사이로 되돌려 보내는 계산을 씁니다. 고리 안의 식이 달라집니다. 이어지는 것은 코드가 아니라 '예측 → 오차 → 기울기 → 갱신'이라는 생각의 순서입니다. 그리고 오늘 배운 학습률의 성질 — 너무 크면 발산하고 너무 작으면 못 간다 — 은 14차시에서도 그대로 여러분을 괴롭힐 것입니다.

✅

확인 문제

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

1. 회귀와 분류의 차이를 '답의 종류'로 설명하고, 각각의 예를 이 책에서 하나씩 들어 보세요.
📖 모범 답안

분류는 답이 몇 개의 이름표 중 하나인 문제입니다. 8차시에서 씨앗의 품종을 A인지 B인지 맞힌 것이 분류입니다. 맞았거나 틀렸거나 둘 중 하나여서 '정확도'(몇 개를 맞혔나)로 잽니다.

회귀는 답이 연속적인 수인 문제입니다. 오늘 공부 시간으로 시험 점수를 맞힌 것이 회귀입니다. 73점을 74점이라 답한 것과 40점이라 답한 것은 둘 다 틀렸지만 정도가 다르므로, '얼마나 빗나갔는가'를 재는 손실로 잽니다.

같은 급식 잔반 문제도 '내일 몇 kg 남을까'를 물으면 회귀이고, '많이 남을까 아닐까'를 물으면 분류가 됩니다. 문제가 아니라 물음이 갈래를 정합니다.

2. 경사하강법의 한 걸음을 말로 풀어 설명하세요 — 무엇을 계산해서, 어느 쪽으로, 얼마나 움직입니까? 그리고 db를 구할 때는 왜 x를 곱하지 않습니까?
📖 모범 답안

한 걸음: ① 지금의 w·b로 24명의 점수를 예측한다. ② 예측에서 정답을 빼 오차를 구하고, 제곱해 평균내면 손실이다. ③ 오차로부터 dw·db를 계산한다 — 이것은 손실이 가장 가파르게 커지는 방향이다. ④ 그 반대쪽으로 lr배만큼 움직인다 (w ← w − lr·dw). 즉 오르막을 계산해서 내리막으로, 학습률만큼 갑니다.

x를 곱하지 않는 까닭: b는 모든 점의 예측에 똑같이 더해집니다. b를 1 올리면 24개 예측이 전부 1씩 올라갑니다. 그러니 어느 점이 b를 얼마나 끌어당기는지는 오차의 크기만으로 정해집니다. 반면 w는 x에 곱해지므로, w를 1 올렸을 때 x = 5.6인 사람의 예측은 5.6이 오르고 x = 1.0인 사람은 1만 오릅니다. 영향이 x에 비례하므로 x를 곱합니다.

3. [오늘 시뮬레이터로 한 것] 과제 ②에서 찾은 발산 문턱은 얼마였습니까? 그리고 그 바로 아래 값에서 손실 곡선은 어떤 모양이었고, 500회 손실은 얼마였습니까?
📖 모범 답안

문턱은 lr = 0.074입니다. 0.073까지는 살아남고 0.074부터 발산해 427회에서 중단됩니다(0.075는 196회, 0.1은 18회에 중단).

바로 아래 값 lr = 0.073은 수렴하기는 하지만 곡선이 한 번 크게 치솟습니다. 100회에 1993.0411까지 올라갔다가 200회에 779.6248, 500회에 52.9773으로 내려옵니다. 참고로 0.070은 500회에 7.3247로 곧장 바닥에 닿습니다.

까닭: 골짜기를 건너뛰기는 하는데 아직 반대쪽 벽의 더 낮은 자리에 떨어지기 때문입니다. 걸음이 조금만 더 커지면 더 높은 자리에 떨어지고, 그때부터는 걸음마다 커져 돌아올 수 없습니다. 문턱 근처는 '되기는 되는데 믿을 수 없는' 구간입니다.

4. [오늘 파이썬으로 한 것] 도전 ②에서 lr = 0.0001로 2000회를 돌렸을 때 w와 b는 얼마였습니까? 손실 194는 5305에서 많이 내려온 값인데, 그렇다면 '거의 다 왔다'고 말해도 됩니까?
📖 모범 답안

w = 18.0637, b = 6.8838, 손실 194.4683입니다.

'거의 다 왔다'가 아닙니다. 정답은 w 8.93, b 42.25인데 지금 w는 두 배가 넘고 b는 거의 0입니다. 직선으로 그리면 원점 근처에서 가파르게 솟는, 점들과 전혀 다른 선입니다. 손실이 작아 보이는 것과 답이 맞는 것은 다릅니다.

이 자리의 정체가 재미있습니다. lr = 0.01로 20회 걸었을 때가 w = 18.1098, b = 6.8988로 거의 같은 자리입니다. 학습률을 100배 줄였으니 같은 자리까지 100배의 회차가 든 것입니다. 실제로 lr = 0.0001로 200,000회를 돌리면 손실 7.3275에 도착합니다. 길을 잘못 든 것이 아니라 너무 잘게 걷고 있었을 뿐입니다.

5. 어떤 친구가 "손실이 더 안 줄어드니까 학습이 끝난 것"이라고 말합니다. 오늘 본 것 중에서 손실이 안 줄어드는데 학습이 끝난 것이 아닌 경우를 두 가지 이상 들고, 각각을 어떻게 구별할지 쓰세요.
📖 모범 답안

㉠ 학습률이 너무 작다. lr = 0.0001은 2000회에 손실 194에서 거의 안 움직이는 것처럼 보이지만, 실제로는 아주 천천히 내려가는 중입니다. 구별법: 회차를 10배로 늘려 본다. 계속 내려가면 느린 것이다.

㉡ 기울기 식이 틀렸다. 빈칸 ③에서 x를 빠뜨리면 w = b = 16.68120, 손실 122.34458에서 완전히 굳습니다. 오류도 안 납니다. 구별법: 학습률을 바꿔 본다. 0.001에서 0.05까지 어떤 값을 넣어도 답이 똑같다면 lr 문제가 아니라 식이 틀린 것입니다.

㉢ 사실은 발산했다. 부호를 +로 뒤집고 lr = 0.0001을 주면 발산 판정(1조 초과)에 걸리지 않은 채 2000회를 다 돌고 손실 2.808 × 10⁸, w −4367이 됩니다. 구별법: 손실이 처음 값(5305)보다 커졌는지 본다. 커졌으면 반대로 가고 있는 것입니다.

진짜로 끝난 경우는 손실이 바닥값(여기서는 7.3247) 가까이에 눌러앉고, 회차를 늘려도 소수 아래 자리만 바뀔 때입니다.

6. 학습된 모델이 7시간에 104.9점이라고 답했습니다. 이 답의 문제는 무엇이며 어떻게 고칠 수 있겠습니까? 그리고 오늘 만든 세 조각(모델·손실·경사하강)이 14차시의 신경망에서 각각 무엇이 될지 예상해 보세요.
📖 모범 답안

문제: 100점 만점 시험에서 나올 수 없는 점수입니다. 모델은 1.0~5.6시간만 보았는데 그 구간의 규칙(한 시간에 약 9점)을 밖으로 끝없이 연장했습니다(외삽). 모델에게는 '만점이 100'이라는 사실도, '본 적 없는 구간'이라는 감각도 없습니다. 학습을 더 시켜도 해결되지 않습니다 — 10000회를 돌리면 오히려 104.8점으로 굳습니다. 문제는 학습이 덜 된 것이 아니라 직선이라는 모양을 우리가 골랐다는 것입니다.

고치는 길: ① 결과를 0~100으로 잘라 낸다(급한 대로), ② 입력이 학습 범위 밖이면 값 대신 "범위 밖"이라고 알린다(가장 정직), ③ 6시간 이상 공부한 학생 데이터를 실제로 더 모은다(가장 옳음), ④ 위로 갈수록 완만해지는 곡선 모양으로 모델을 바꾼다.

세 조각의 앞날: 모델은 숫자 2개에서 아홉 개(14차시의 신경망)로 늘어나고 층이 생깁니다. 손실은 예측과 정답의 거리를 재는 자로 그대로 남습니다(분류에서는 다른 자를 쓰기도 합니다). 경사하강은 그대로 쓰되, 층이 여럿이라 기울기를 뒤에서 앞으로 되돌려 계산해야 합니다 — 그것이 14차시에서 배울 역전파입니다. 새로 배울 것은 '기울기를 어떻게 구하느냐' 하나뿐이고, 나머지 고리는 오늘 것 그대로입니다.

🔁 되돌아보기

오늘 '좋은 선'을 손실이라는 숫자 하나로 바꾸고, 그 숫자가 줄어드는 쪽으로 스물네 개의 점만 보며 2000걸음을 걸어 y = 8.97x + 42.11에 도착했습니다. 학습률을 0.074까지 올려 발산도 직접 겪었습니다. 다음 시간에는 이름표가 없는 데이터를 놓고 기계가 스스로 무리를 짓게 합니다 — 정답을 알려 주지 않아도 배울 수 있는지 보게 됩니다.

🔎

더 알아보기

오늘의 공식이 태어난 자리, 문턱 0.074의 정체, 그리고 그릇이 아닌 산맥

검은 우주를 배경으로 한 회색의 둥근 왜행성 세레스. 표면 곳곳에 크고 작은 구덩이가 보인다
역사

잃어버린 별을 되찾은 계산 — 최소제곱법의 출발

1801년 1월 1일, 이탈리아 팔레르모의 천문학자 주세페 피아치가 새 천체를 찾아냈습니다. 지금의 왜행성 세레스입니다. 그런데 몇 주 따라가다가 세레스가 태양 쪽으로 들어가 햇빛에 가려지는 바람에 놓쳐 버렸습니다. 남은 것은 짧은 기간에 잰 흔들림이 섞인 관측값 몇 개뿐이었지요.

스물네 살의 수학자 카를 프리드리히 가우스가 이 관측값들로 궤도를 계산했고, 그해 12월 말 천문학자들은 가우스가 짚은 자리 근처에서 세레스를 다시 찾아냈습니다. 가우스가 쓴 방법의 핵심이 오늘 5절의 생각입니다 — 모든 관측을 한꺼번에 가장 잘 설명하도록, 빗나간 정도의 제곱을 모두 더한 값이 가장 작아지는 답을 고르는 것.

이 방법을 책으로 먼저 펴낸 사람은 프랑스의 르장드르(1805년)이고, 가우스는 1809년 책에서 자신은 그보다 앞서 이 방법을 써 왔다고 밝혀 누가 먼저냐는 다툼이 생기기도 했습니다. 오늘 스물네 개의 점에 직선을 맞춘 일은 흔들리는 관측에서 궤도를 찾던 일과 같은 물음입니다. 사진은 2015년 탐사선 돈(Dawn)이 세레스에 다가가 찍은 모습입니다.

사진: 탐사선 돈이 찍은 세레스(2015) · 출처: NASA / JPL-Caltech / UCLA / MPS / DLR / IDA / Justin Cowart, Wikimedia Commons (Public domain)

출발 (0, 0) 20걸음 · w 18.1 2000걸음 · 바닥 근처 가로 w (−1 ~ 20) · 세로 b (−2 ~ 60) 보라 고리 = 손실이 같은 자리 (바닥 + 15·60·200·600) 분홍 선 = lr 0.01 로 실제로 걸은 길
원리 더 깊이

문턱 0.074는 어디서 오는가 — 골짜기의 모양

그림은 오늘 데이터의 손실을 등고선으로 그린 것입니다. 고리 하나가 손실이 같은 자리를 이은 선이고, 분홍 선은 lr = 0.01로 실제로 걸은 길입니다. 고리가 동그랗지 않고 좁고 긴 골짜기라는 점을 보세요. 가로(w) 쪽으로는 벽이 가파르고, 골짜기를 따라가는 쪽으로는 바닥이 아주 완만합니다. 그래서 처음 20걸음 만에 w가 18까지 달려가 골짜기 바닥에 닿고, 나머지 걸음은 골짜기를 따라 천천히 기어 올라가는 데 씁니다. 3절에서 본 'w는 성큼성큼, b는 종종걸음'이 바로 이 모양입니다.

휘어진 정도를 방향별로 재 보면 가장 가파른 방향이 가장 완만한 방향보다 약 97배 더 휘어 있습니다. 학습률의 한계는 가장 가파른 방향이 정합니다. 걸음이 그 방향 벽의 폭을 넘으면 반대쪽 벽의 더 높은 곳에 떨어지기 때문이지요. 이 데이터에서 그 한계를 계산하면 2 ÷ 27.33 ≈ 0.0732가 나옵니다(27.33은 가장 가파른 방향의 휨). 오늘 실험에서 0.073은 살아남고 0.074는 폭발한 까닭이 이 계산 하나로 설명됩니다.

그런데 학습률을 이 한계 아래로 묶어 두면 완만한 방향에서는 한 걸음이 너무 작아 도착이 늦습니다. 2000걸음을 걸어도 공식 해와 조금 어긋나 있던 까닭입니다. 공부 시간을 0~1로 정규화하면 두 방향의 휨 차이가 약 18배로 줄어 골짜기가 한결 동그래집니다. 5차시의 정규화가 학습 속도까지 바꾸는 이유가 이것입니다.

맑은 하늘 아래 구름이 걸린 산맥. 앞쪽에는 뾰족한 바위 봉우리와 깊은 골짜기가 여러 겹으로 이어진다
생각할 거리

그릇이 아니라 산맥이라면 — 신경망의 손실 지형

경사하강법은 흔히 짙은 안개 속에서 산을 내려오는 사람에 빗대어집니다. 멀리는 보이지 않고 발밑의 경사만 느껴지니, 가장 가파르게 내려가는 쪽으로 한 발씩 옮기는 것이지요. 오늘 직선 모델의 손실은 바닥이 하나뿐인 그릇이었습니다. 그래서 과제 ②에서 w = 100, b = −50처럼 멀리서 출발해도 거의 같은 자리에 도착했습니다.

신경망의 손실은 그렇게 단순하지 않습니다. 사진처럼 봉우리와 골짜기가 여러 겹 이어진 산맥에 가깝습니다. 어느 비탈에서 출발하느냐에 따라 다른 바닥에 닿을 수 있고, 평평한 고갯마루에서는 경사가 거의 0이라 한참을 머뭇거리기도 합니다. 그래서 신경망은 같은 데이터로 학습해도 처음 숫자를 무엇으로 두느냐에 따라 결과가 조금씩 달라집니다.

실제 인공지능은 데이터가 매우 많아 한 걸음마다 전부를 훑기도 어렵습니다. 그래서 데이터를 조금씩 떼어 일부만 보고 기울기를 어림해 걷는 방법(확률적 경사하강법)을 씁니다. 걸음이 조금 비틀거리지만 훨씬 자주 나아갈 수 있지요. 이렇게 어림한 걸음으로도 쓸 만한 바닥을 찾아낸다는 것이, 오늘의 네 칸짜리 고리가 지금의 인공지능을 받치는 까닭입니다.

사진: 구름이 걸린 산맥과 골짜기 · 출처: Liz Van, Wikimedia Commons (CC BY-SA 3.0)