처음부터 만드는 퍼셉트론: 뉴런은 무엇을 계산하는가
순수 Python으로 퍼셉트론을 만들고 XOR 실패를 보며, 수렴 정리가 성공은 약속해도 기다릴 시간은 약속하지 않는 이유를 봅니다.
이 페이지에서
공장에 컨베이어 벨트가 하나 있습니다. 부품들이 그 위를 지나가고, 누군가는 어떤 부품을 출하하고 어떤 부품을 돌려보낼지 결정해야 합니다. 모든 부품에 대해 두 숫자가 측정됩니다. 밀리미터 단위의 너비와 그램 단위의 무게입니다. 가진 정보는 이것이 전부입니다.
이를 자동화하는 가장 뻔한 방법은 규칙을 적는 것입니다. 너비가 22밀리미터보다 작으면 합격. 공급업체가 합금을 바꾸고 무게가 달라지기 전까지는 잘 작동합니다. 그래서 조건을 하나 더 붙입니다. 그러다 허용 오차가 다시 조정되고 또 하나를 붙입니다. 6개월 뒤 그 함수는 40줄이 되어 있고, 아무도 19번째 줄이 왜 있는지 기억하지 못하며, 그 코드를 쓴 사람은 이미 회사를 떠났습니다.
다른 방법이 이 과정의 주제입니다. 규칙을 직접 쓰지 않습니다. 규칙의 형태를 씁니다. 빈칸이 있는 템플릿을 만들고, 예시가 그 빈칸에 무엇이 들어갈지 정하게 합니다. 이 뒤집기가 machine learning의 전부이며, 이 장에서 그 템플릿은 템플릿이 될 수 있는 가장 작은 형태입니다. 숫자 두 개와 임계값 하나입니다.
끝까지 읽으면 약 20줄의 Python으로 퍼셉트론을 작성하고, 그것이 성공하는 모습과 실패하는 모습을 모두 보며, 둘 다 이해하게 됩니다. 여기서 작성하는 파일은 다음 장에서 버릴 장난감이 아닙니다. 지금부터 스물아홉 장 뒤, tool loop와 permission model을 갖춘 agent로 끝나는 저장소의 첫 commit입니다.
모델: 가중합과 직선
섹션 링크: 모델: 가중합과 직선퍼셉트론은 측정값을 받아, 각 값에 자신이 제어하는 숫자를 곱하고, 모두 더한 뒤, 숫자 하나를 더 더하고, 그 부호를 봅니다.
한 부품의 측정값을 vector — 너비와 무게 — 로 씁시다. 퍼셉트론은 weight vector 와 bias 를 가집니다. 점수는
이고, 답은 그 점수의 부호입니다. 이면 합격, 아니면 불합격입니다.
이것이 모델의 전부입니다. 퍼셉트론이 이 공장에 대해 알게 될 모든 것은 세 숫자 안에 들어 있습니다.
기하학적으로 잠시 멈춰볼 가치가 있습니다. 이 그림은 식이 더 이상 한 줄에 들어가지 않게 되는 다음 스물아홉 장에서도 계속 작동하기 때문입니다. 인 점들의 집합, 즉 퍼셉트론이 정확히 판단을 보류하는 점들의 집합은 평면 위의 직선입니다. 한쪽에서는 점수가 양수이고 모든 것이 합격됩니다. 다른 쪽에서는 점수가 음수이고 모든 것이 불합격됩니다. 퍼셉트론에게 학습이란 그 직선을 움직이는 것입니다.
그 직선에 대한 두 사실은 대수에서 바로 따라 나오며, 둘 다 나중에 중요해집니다.
- 는 그 직선에 수직입니다. weight vector는 경계선을 따라 놓이지 않습니다. 그것은 경계를 가로질러, 합격되는 쪽을 향해 가리킵니다.
- 는 직선을 회전시키지 않고 밀어냅니다. bias가 없다면 직선은 반드시 원점을 지나야 합니다. 밀리미터와 그램을 측정하는 공장에서 이는 터무니없는 제약입니다. 너비도 무게도 0인 부품이 정확히 경계 위에 있다는 뜻이니까요.
학습 규칙, 그리고 왜 미적분이 필요 없는가
섹션 링크: 학습 규칙, 그리고 왜 미적분이 필요 없는가퍼셉트론은 아무것도 모르는 상태에서 시작합니다. 그리고 . 모든 점수가 0이므로 모든 것을 합격시킵니다.
이제 예시를 하나씩 보여줍니다. 합격 부품에는 , 불합격 부품에는 라는 label을 붙입니다. 각 예시에 대해 질문은 하나뿐입니다. 부호가 맞게 나왔는가? 이 질문을 간결하게 쓰는 방법은 가 양수인지 확인하는 것입니다. label과 점수의 부호가 일치하면 곱은 양수이고, 일치하지 않으면 음수입니다.
답이 예라면 아무것도 바꾸지 않습니다. 답이 아니라면 살짝 밀어줍니다.
이것이 알고리즘 전체입니다. 외우기보다 왜 이것이 올바른 밀어주기인지 이해할 가치가 있습니다. 어떤 부품이 합격이어야 했는데(), 점수가 음수로 나왔다고 해봅시다. 에 를 더하면, 그 같은 부품에 대한 점수 변화는
이며, 이는 양수입니다. 방금 틀린 부품의 점수가 올라갑니다. 필요한 방향이 바로 그것이었습니다. 이 규칙은 누군가 찍어낸 heuristic이 아닙니다. 눈앞의 사례를 확실히 개선하는 가장 작은 변화입니다. 물론 다른 사례를 망칠 수도 있습니다. 그래서 다시 한 바퀴 도는 것입니다.
없는 것에 주목하세요. 어디에도 derivative가 없습니다. 이는 실수가 아니며, 이 과정에서 처음으로 진짜 중요한 아이디어입니다.
여러분이 미분하고 싶어 할 대상은 error, 즉 잘못 분류된 부품의 개수입니다. 하지만 그 개수는 계단입니다. 직선을 조금 움직이는 동안 4에 평평하게 머물다가, 직선이 어떤 점을 가로지르는 순간 3으로 떨어집니다. derivative는 거의 모든 곳에서 0이고, 계단에서는 정의되지 않습니다. 미적분은 붙잡을 것이 없습니다. 퍼셉트론 규칙은 slope를 전혀 묻지 않음으로써 그 문제를 우회합니다. 오직 “맞았나 틀렸나?”만 묻고, 기하학적으로 정당화할 수 있는 방향으로 움직입니다.
이는 진짜 해결책이지만, 동시에 막다른 길입니다. 2장에서는 그냥 고른 것이 아니라 어딘가에서 나오는 loss가 필요하고, 4장에서는 자신이 얼마나 확신하는지 보고하는 모델이 필요하며, 5장에서는 layer가 하나보다 많은 무언가가 필요합니다. 그리고 “틀림”만 아는 규칙으로는 어느 것도 도달할 수 없습니다. 쓸 수 있는 slope를 되찾는 일이 다음 두 장을 강제합니다. 하지만 퍼셉트론은 후계자 중 누구도 할 수 없는 일을 할 수 있습니다. 미적분 없이 학습하는 것입니다.
작성하기
섹션 링크: 작성하기순수 Python, NumPy 없음. list와 loop만 씁니다. NumPy는 다음 장에서 등장합니다. 읽고 싶은 loop 안에 더 이상 산술이 들어맞지 않을 때입니다. 지금 도입하면, 산술을 바로 보고 싶은 정확히 그 순간에 library 뒤로 숨겨버리게 됩니다.
def score(w, b, x):
return w[0] * x[0] + w[1] * x[1] + b
def predict(w, b, x):
return 1 if score(w, b, x) >= 0 else -1
def train(data, epochs=200):
"""Returns (w, b, epoch_it_converged) — or None for the epoch if it never did."""
w, b = [0.0, 0.0], 0.0
for epoch in range(epochs):
mistakes = 0
for x, y in data:
if y * score(w, b, x) <= 0:
w[0] += y * x[0]
w[1] += y * x[1]
b += y
mistakes += 1
if mistakes == 0:
return w, b, epoch + 1
return w, b, None강조된 네 줄이 알고리즘입니다. 나머지는 모두 bookkeeping입니다.
그리고 벨트에서 측정한 여덟 개의 부품입니다. 네 개는 출하되었고, 네 개는 돌아왔습니다.
BELT = [
((18.0, 47.0), +1), ((19.5, 52.0), +1), ((20.2, 49.0), +1), ((21.0, 55.0), +1),
((24.0, 61.0), -1), ((25.5, 66.0), -1), ((23.0, 70.0), -1), ((26.0, 58.0), -1),
]
w, b, epoch = train(BELT, epochs=200)
print(epoch, w, b)이 여덟 부품은 직선 하나로 분리할 수 있습니다. 합격한 모든 부품은 22 mm보다 작고, 불합격한 모든 부품은 23 mm 이상입니다. 22밀리미터에 세운 수직 울타리가 일을 해냅니다. 따라서 퍼셉트론도 그것을 찾아야 합니다.
실행해봅시다.
None [-142.1, -13.0] 54.0200 epoch, 454번의 correction, 그런데도 수렴하지 않았습니다. weight는 크고 부호도 틀렸습니다. 뭔가 잘못됐습니다 — 사실 아무것도 잘못되지 않았다는 점만 빼면요. 그리고 그 이유가 이 장에서 가장 유용한 내용입니다.
수렴 정리, 그리고 그것이 실제로 주는 숫자
섹션 링크: 수렴 정리, 그리고 그것이 실제로 주는 숫자퍼셉트론에는 보장이 있습니다. 1962년 Novikoff가 증명했습니다.1 데이터가 어떤 직선으로든 분리될 수 있다면, 알고리즘은 멈추기 전까지 많아야
번 correction을 수행합니다. 여기서 는 데이터의 radius, 즉 가장 긴 example vector의 길이이고, 는 margin입니다. 이는 분리 hyperplane에서 가장 가까운 점까지의 거리인데, bias가 세 번째 좌표인 augmented space에서 측정한 거리입니다. 그래서 밀리미터 단위의 거리는 변하지 않아도 데이터를 centering하면 이 값이 바뀝니다.
이 보장은 무조건적이며 epoch, learning rate, 운을 언급하지 않습니다. 또한 시간도 언급하지 않습니다. 바로 그 생략이 핵심입니다.
우리 숫자를 넣어봅시다. 여덟 부품에서 직접 측정하고, bias를 상수 feature로 접어 넣으면 다음과 같습니다.
| radius | margin | bound | 실제 correction 횟수 | |
|---|---|---|---|---|
| 원래의 밀리미터와 그램 | 73.69 | 0.045 | 2,633,550 | 29,870 |
| 평균을 뺀 뒤 | 12.82 | 0.989 | 168 | 1 |
정리는 한 번도 위반되지 않았습니다. 원래 버전을 충분히 오래 실행하면 실제로 수렴합니다. 29,870번 correction을 거친 뒤 epoch 11,976에서 수렴합니다. bound인 2,633,550 안에 넉넉히 들어가며, 그 차이 자체가 요점입니다. 정리는 전형적 경우가 아니라 최악의 경우를 제한합니다. 단지 누구도 앉아서 기다리지 않을 만큼, 60배 더 많은 epoch가 필요했을 뿐입니다.
두 번째 행은 같은 여덟 부품, 같은 20줄의 코드에, 모든 측정값에서 평균 너비와 평균 무게를 빼는 세 줄을 더한 것입니다. 그게 전부입니다. 전체 변화는 그것뿐입니다. 점들의 구름을 (22, 57) 근처에 떠 있게 두는 대신 원점을 가로지르도록 옮깁니다. bound에 미치는 효과는 1만 5천 배입니다. 두 항이 동시에 좋아지기 때문입니다. 점들이 더 이상 멀리 떨어진 원점에서 측정되지 않으므로 는 74에서 13으로 떨어지고, 데이터에 닿기 위해 weight vector가 거대한 bias를 떠안지 않아도 되므로 는 0.045에서 0.989로 올라갑니다.
mean_w = sum(x[0] for x, _ in BELT) / len(BELT) # 22.15
mean_g = sum(x[1] for x, _ in BELT) / len(BELT) # 57.25
CENTRED = [(((x[0] - mean_w), (x[1] - mean_g)), y) for x, y in BELT]
w, b, epoch = train(CENTRED, epochs=200)
print(epoch, w, b)2 [-4.15, -10.25] 1.0두 epoch 만에 수렴했고, 정확히 한 번만 스스로를 correction했습니다.
여기에는 진짜 교훈이 있습니다. “입력을 normalize하는 것을 기억하라”가 아닙니다. 물론 그래야 하지만요. 핵심은 알고리즘이 끝나는지에 대한 보장은, 그것이 끝날 때 여러분이 그 자리에 있을지에 대해서는 아무것도 말해주지 않는다는 점입니다. 그리고 그 둘 사이의 간격은 대개 기하학입니다. 이는 6장의 initialisation, 10장의 learning-rate schedule, 13장의 quantisation에서 다시 만날 패턴의 첫 등장입니다. 수학은 그것이 가능하다고 말하고, engineering은 그것이 실용적인지 결정합니다. 정리만 가르치는 과정은 사흘 동안 훈련되는 모델을 여러분에게 건네고는 여러분을 탓합니다.
네 점, 하나의 직선, 해 없음
섹션 링크: 네 점, 하나의 직선, 해 없음이제 neural network의 첫 번째 시대를 끝낸 실패입니다. 그리고 그것은 네 행 안에 들어갑니다.
공장은 잊으세요. 각각 0 또는 1인 두 input을 가지고, 정확히 하나만 1일 때 답이 이 되기를 요구합시다.
| 0 | 0 | |
| 0 | 1 | |
| 1 | 0 | |
| 1 | 1 |
이것이 XOR, 즉 exclusive or입니다. 계속 읽기 전에 종이에 네 점을 그려보세요. 단위 정사각형의 네 꼭짓점입니다. 대각선에 놓인 두 점 과 은 합격으로 표시하고, 과 은 불합격으로 표시하세요. 이제 합격 두 점을 한쪽에, 불합격 두 점을 다른 쪽에 두는 직선 하나를 그려보세요.
그릴 수 없습니다. 어렵다거나 더 영리한 알고리즘이 필요하다는 뜻이 아닙니다. 그런 직선이 존재하지 않습니다. 세 줄의 대수가 그 이유를 보여줍니다. 어떤 퍼셉트론이 네 경우를 모두 맞힌다면, 네 행을 순서대로 읽어 다음을 얻습니다.
가운데 두 부등식을 더하면 이므로 입니다. 마지막 부등식은 라고 말합니다. 둘을 합치면 이고, 이는 를 요구하며, 다시 를 요구합니다. 그런데 첫 번째 부등식은 라고 말합니다. 그런 는 없습니다. 따라서 그런 weight도 없습니다. 어떤 숫자를 넣더라도, 퍼셉트론은 XOR을 분류할 수 없습니다.
그래도 실행해봅시다. 알고리즘이 실패하는 모습을 직접 보는 것은, 실패한다고 듣는 것보다 훨씬 가치가 있습니다.
100 epochs -> converged=None w=[0.0, 0.0] b=0.0 correct=2/4
1,000 epochs -> converged=None w=[0.0, 0.0] b=0.0 correct=2/4
100,000 epochs -> converged=None w=[0.0, 0.0] b=0.0 correct=2/4발산하지도 않고, 그럴듯한 답 근처에서 요동치지도 않습니다. 그것은 cycle합니다. weight space 안에서 짧은 loop를 걷고, 정확히 출발점으로 돌아오기를 영원히 반복합니다. 네 개 중 두 개를 맞히는데, 이는 찍어서 얻는 것과 같습니다. 10만 epoch와 100 epoch는 구분되지 않습니다. 더 오래 실행하면 끝낼 수 있는 진전이 일어나고 있지 않기 때문입니다. 이것을 벨트 예시와 비교해보세요. 벨트는 200 epoch에서 멈춘 것처럼 보였지만, 사실은 실제 답을 향해 갈리고 있었습니다. 바깥에서 보면 처음 몇 초 동안 둘은 비슷해 보입니다. 정리 없이 둘을 구별하는 것은 불가능합니다. 이는 정리를 알아야 하는 또 하나의 이유입니다.
Minsky와 Papert가 실제로 말한 것
섹션 링크: Minsky와 Papert가 실제로 말한 것1969년 Marvin Minsky와 Seymour Papert는 Perceptrons를 출간했습니다. 이 모델이 정확히 무엇을 표현할 수 있고 무엇을 표현할 수 없는지에 대한 책 한 권 분량의 수학적 연구였습니다.2 XOR은 그중 가장 많이 인용되는 결과이고, 그 인용은 보통 비난으로 쓰입니다. 그 책이 경쟁심이나 악의 때문에 15년 동안 neural network 연구를 죽였다는 식입니다.
책의 수학은 옳고, XOR 예시보다 더 흥미롭습니다. Minsky와 Papert의 주된 관심은 단일 퍼셉트론이 XOR을 할 수 있는지가 아니었습니다. 그들은 퍼셉트론에 제한된 receptive field가 주어질 때, 즉 각 unit이 input의 일부만 볼 때 무슨 일이 벌어지는지에 관심이 있었습니다. 그리고 어떤 그림이 연결되어 있는지 같은 이미지의 특정 전역적 속성은, unit을 얼마나 많이 쓰든 그런 방식으로는 계산할 수 없다는 것을 증명했습니다. 이는 locality에 대한 진짜로 깊은 결과이며, 대중적인 이야기와는 아무 관련이 없습니다.
대중적인 이야기는 역사적으로도 틀렸습니다. Minsky와 Papert는 multi-layer perceptron을 명시적으로 논의했고, 그 능력에 대한 문제는 열려 있다고 말했습니다. 그들은 이론을 확장하는 일이 “sterile”할 것이라고 의심했는데, 이는 증명이 아니라 예측이었고, 틀렸습니다. 1969년에 없었던 것은 layer를 쌓는 아이디어가 아니었습니다. 쌓아 올린 것을 train하는 방법이었습니다. 퍼셉트론 규칙으로는 할 수 없습니다. 각 unit이 얼마나 틀렸는지 알아야 하는데, 가운데 묻힌 unit에는 비교할 label이 없습니다. 그 간극은 1986년에 backpropagation이 대중화될 때까지 열려 있었고,3 그것을 닫는 일이 5장에서 할 일입니다.
그러므로 정직한 요약은 이렇습니다. 그 책은 실제 모델의 실제 한계를 증명했습니다. 1970년대 이 분야의 funding collapse에는 여러 원인이 있었고, 그중 하나는 1960년대 초 퍼셉트론에 대해 했던 약속들이 과장되어 있었다는 점입니다. 그리고 기술적 장애물은 풀 수 있었지만, 아직 아무도 그 도구를 갖고 있지 않았습니다.
살아남은 것
섹션 링크: 살아남은 것퍼셉트론은 68년이나 되었고, 여러분은 방금 하나를 작성했습니다. 이 과정의 끝에서 완성하게 될 기계 안에 그것의 어느 부분이 아직 남아 있는지 정확히 말할 가치가 있습니다. 답은 이렇습니다. 생각보다 많습니다.
여전히 남아 있음. 형태 — weight를 곱하고, 더하고, bias를 더하고, 결과에 nonlinear function을 적용하는 것 — 는 이 과정의 모든 neural network에서 unit 하나의 형태와 정확히 같습니다. 9장의 transformer block 안에 있는 것들도 포함됩니다. mistake가 있을 때 update하는 규칙은 변장한 stochastic gradient descent입니다. 3장의 방법을 특정 loss function에 적용하면 정확히 얻는 것이 그것입니다. 전체 dataset을 한 번에 쓰는 대신 몇 개의 예시씩 점진적으로 train하는 방식은 오늘날 모든 규모에서 모델을 train하는 방식으로 남아 있습니다. 3장은 그 trade-off가 실제로 어디에 놓이는지 측정합니다.
사라짐. threshold 자체입니다. 4장에서는 verdict 대신 probability를 출력하는 function으로 대체됩니다. “불합격”과 “불합격, 하지만 아슬아슬했음”은 서로 다른 정보이고, 부호는 그 차이를 버리기 때문입니다. single layer는 5장에서 대체됩니다. 그리고 손으로 고른 feature도 사라집니다. 누군가 이 벨트를 위해 너비와 무게를 골랐고, 그 선택이 알고리즘보다 더 많은 일을 했습니다. 8장은 모델이 스스로 feature를 고르기 시작하는 곳입니다.
다음으로 이어지는 곳
섹션 링크: 다음으로 이어지는 곳퍼셉트론은 두 가지에 동시에 막혔고, 그 둘은 결국 같은 것임이 드러납니다.
XOR을 표현할 수 없습니다. 직선 하나로는 충분하지 않기 때문입니다. 이를 고치려면 layer를 쌓아야 합니다. 첫 번째 layer가 공간을 휘게 만들고, 두 번째 layer가 휜 공간에 직선을 긋습니다. 그것이 5장입니다.
하지만 퍼셉트론 규칙으로는 쌓아 올린 것을 train할 수 없습니다. 그 규칙은 “틀림”만 알기 때문입니다. network 가운데 있는 unit에는 자신만의 label이 없어 무엇에 대해 틀렸는지 알 수 없습니다. 쌓아 올린 것을 train하려면 각 weight에 대해 얼마나 틀렸는지, 그리고 어느 방향인지 알아야 합니다. slope가 필요합니다. 그런데 퍼셉트론의 error function, 즉 계단에는 slope가 없습니다.
따라서 stack 전에 쓸 수 있는 derivative를 가진 loss function이 있어야 합니다. 단지 미분하기 편해서 고른 것이어서도 안 됩니다. 어딘가에서 나오고, 데이터에 대해 참인 무언가를 말하며, 그 gradient가 깔끔해 보이도록 역설계된 것이 아니라 그 의미에서 자연스럽게 나오는 것이어야 합니다.
그것이 2장이고, 퍼셉트론은 한 번도 답할 필요가 없었던 질문에서 시작합니다. “이 부품은 좋은가?”가 아니라, “이것이 진실이라면, 이 측정값들은 얼마나 그럴듯한가?”입니다.
출처와 방법
섹션 링크: 출처와 방법이 장과 함께 읽을 만한 자료도 있습니다. Rosenblatt의 원 논문 The Perceptron: A Probabilistic Model for Information Storage and Organization in the Brain (Psychological Review 65(6), 1958)은 평판보다 훨씬 읽기 쉽습니다. McCulloch와 Pitts의 A Logical Calculus of the Ideas Immanent in Nervous Activity (Bulletin of Mathematical Biophysics 5, 1943)는 뉴런을 가중합 위의 threshold로 처음 모델링한 논문입니다. Hal Daumé III의 A Course in Machine Learning 중 퍼셉트론 절은 같은 update를 다른 강조점으로 유도합니다. 그리고 위 박스가 준 것보다 더 많은 선형대수를 원한다면 Deisenroth, Faisal, Ong의 Mathematics for Machine Learning 2장과 3장을 보면 됩니다.
-
Novikoff, A. B. J. On convergence proofs for perceptrons. Proceedings of the Symposium on the Mathematical Theory of Automata, vol. 12, pp. 615–622 (Polytechnic Institute of Brooklyn, 1962). 위에서 사용한 mistake bound의 원래 진술과 증명입니다. ↩
-
Minsky, M. and Papert, S. Perceptrons: An Introduction to Computational Geometry (MIT Press, 1969; expanded edition 1988). XOR 결과는 기본적인 내용이며, 실질적인 결과는 order-limited predicate와 connectedness에 관한 것입니다. ↩
-
Rumelhart, D. E., Hinton, G. E. and Williams, R. J. Learning representations by back-propagating errors. Nature 323, pp. 533–536 (1986). ↩