콘텐츠로 이동

4차시: 퍼셉트론 - 뉴런을 흉내 낸 최초의 학습 기계

⏰ 80분 · 퍼셉트론 · 가중합 · 결정 경계 · XOR 문제 · 난이도 ●●●○○

학습목표: 퍼셉트론의 수학적 구조를 NumPy로 구현하고, AND·OR·XOR 문제로 선형 분리의 한계를 설명할 수 있다.

오늘의 질문: “뇌세포 하나를 코드로 흉내 낸다면, 그것은 무엇을 할 수 있고 무엇을 할 수 없을까요?”


가중합과 활성화 함수 두 줄로 뉴런을 표현합니다.

파이썬 코드 10줄로 AND·OR 게이트를 만듭니다.

가중치 슬라이더를 돌리며 직선이 회전하는 것을 관찰합니다.

한 개의 직선으로 풀 수 없는 문제가 있음을 직접 확인합니다.


생물학적 뉴런의 작동 원리를 관찰한 뒤, 입력·가중치·임계값이라는 세 가지 요소로 단순화합니다. 퍼셉트론 수식을 유도합니다.

구현: NumPy로 AND 게이트 만들기 (20분)

섹션 제목: “구현: NumPy로 AND 게이트 만들기 (20분)”

v1에서 v3까지 점진적으로 코드를 발전시키며 퍼셉트론을 구현합니다. OR 게이트도 가중치만 바꿔 완성합니다.

가중치 w1, w2, bias를 바꾸며 2D 평면 위의 결정 경계선이 어떻게 움직이는지 관찰합니다.

클라이맥스: XOR에 도전하고 실패하기 (20분)

섹션 제목: “클라이맥스: XOR에 도전하고 실패하기 (20분)”

XOR 게이트를 만드는 퍼셉트론을 찾으려 시도하고, 어떤 가중치로도 풀 수 없음을 확인합니다.

형성 평가와 성찰을 통해 ‘다층’의 필요성을 정리합니다.


개념 1. 뉴런을 수식으로 옮기기

섹션 제목: “개념 1. 뉴런을 수식으로 옮기기”

커피숍 갈지 말지 결정하는 상황을 떠올려봅니다. 판단에는 여러 입력이 들어옵니다. 친구가 가자고 하는지($x_1$), 과제가 끝났는지($x_2$), 지갑 사정은 괜찮은지($x_3$). 각 요소의 중요도(가중치) 는 사람마다 다릅니다. 친구가 중요하면 $w_1$이 크고, 돈이 중요하면 $w_3$가 큽니다. 모든 요소의 중요도 가중 합계가 내 결심의 문턱을 넘으면 “간다”, 못 넘으면 “안 간다”로 결정됩니다.

생물학적 뉴런도 동일한 구조로 동작합니다. 수상돌기로 여러 신호가 들어오고, 세포체에서 합산되어, 임계값을 넘으면 축삭을 따라 발화합니다. 1958년 로젠블랫(Rosenblatt)은 이 구조를 수식 두 줄로 정리했습니다. 이것이 퍼셉트론(Perceptron) 입니다.

퍼셉트론의 수학적 정의

$$ z = w_1 x_1 + w_2 x_2 + b $$

$$ y = \begin{cases} 1 & \text{if } z \geq 0 \ 0 & \text{if } z < 0 \end{cases} $$

기호의 의미는 다음과 같습니다.

기호의미역할
$x_1, x_2$입력값판단 재료 (예: 센서 값, 픽셀 밝기)
$w_1, w_2$가중치(weight)각 입력을 얼마나 중요하게 볼지
$b$편향(bias)결정의 문턱을 조절
$z$가중합입력과 가중치의 선형 결합
$y$출력0 또는 1 (발화 여부)

$z \geq 0$이면 1, 아니면 0을 내는 함수를 계단 함수(step function) 라고 부릅니다. 가중합 위에 덮인 이 함수가 활성화 함수(activation function) 입니다.

flowchart LR
  X1[입력 x1] -->|가중치 w1| SUM[가중합<br/>z = w1·x1 + w2·x2 + b]
  X2[입력 x2] -->|가중치 w2| SUM
  B[편향 b] --> SUM
  SUM --> ACT[계단 함수]
  ACT --> Y[출력 y<br/>0 또는 1]

여러분이 매일 쓰는 스마트폰의 얼굴 잠금 해제 첫 단계, 이메일 스팸 필터 초기 버전이 모두 이 구조에서 출발했습니다.


개념 2. NumPy로 퍼셉트론 구현하기

섹션 제목: “개념 2. NumPy로 퍼셉트론 구현하기”

개념을 코드로 옮기겠습니다. 목표는 AND 게이트입니다. 두 입력이 모두 1일 때만 1을 출력하는 논리 연산입니다.

$x_1$$x_2$AND 결과
000
010
100
111

v1: 가중합만 계산하기 (가장 단순한 버전)

섹션 제목: “v1: 가중합만 계산하기 (가장 단순한 버전)”
# 실행 환경: Python 3.10+, numpy 필요
import numpy as np
x = np.array([1, 1]) # 입력: x1=1, x2=1
w = np.array([0.5, 0.5]) # 가중치: 일단 같은 값
b = -0.7 # 편향: 임계값 역할
z = np.dot(x, w) + b # 가중합
print(z)
0.3

np.dot(x, w)는 $w_1 x_1 + w_2 x_2$를 한 줄로 계산합니다. 두 배열의 내적입니다.

v1은 숫자만 뱉습니다. 0 또는 1로 바꾸려면 계단 함수가 필요합니다.

import numpy as np
def step(z):
# z가 0 이상이면 1, 아니면 0 <- 여기가 활성화 함수
return 1 if z >= 0 else 0
def perceptron(x, w, b):
z = np.dot(x, w) + b # <- 여기가 가중합
return step(z) # <- 여기가 활성화
x = np.array([1, 1])
w = np.array([0.5, 0.5])
b = -0.7
print(perceptron(x, w, b))
1

위 코드의 9번째 줄 z = np.dot(x, w) + b가 바로 가중합 수식 $z = w_1 x_1 + w_2 x_2 + b$입니다. 10번째 줄 step(z)활성화 함수입니다.

v3: AND 게이트 완성 - 모든 입력 조합 테스트

섹션 제목: “v3: AND 게이트 완성 - 모든 입력 조합 테스트”

함수가 네 가지 입력 모두에서 올바르게 동작하는지 확인합니다.

import numpy as np
def step(z):
return 1 if z >= 0 else 0
def perceptron(x, w, b):
z = np.dot(x, w) + b
return step(z)
# AND 게이트용 가중치와 편향
w_and = np.array([0.5, 0.5])
b_and = -0.7
# 네 가지 입력 조합을 모두 테스트
inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
print("AND 게이트 진리표")
print("x1 x2 | 출력")
print("-" * 18)
for x1, x2 in inputs:
x = np.array([x1, x2])
y = perceptron(x, w_and, b_and)
print(f" {x1} {x2} | {y}")
AND 게이트 진리표
x1 x2 | 출력
------------------
0 0 | 0
0 1 | 0
1 0 | 0
1 1 | 1

AND가 동작합니다. 가중치 두 개와 편향 한 개만으로 논리 게이트를 학습시킨 것입니다.

OR 게이트 - 편향만 바꾸면 됩니다

섹션 제목: “OR 게이트 - 편향만 바꾸면 됩니다”

OR은 “둘 중 하나라도 1이면 1”입니다. AND보다 문턱이 낮아야 합니다.

import numpy as np
def step(z):
return 1 if z >= 0 else 0
def perceptron(x, w, b):
return step(np.dot(x, w) + b)
# OR 게이트: 가중치는 같고, 편향만 올림 (문턱을 낮춤)
w_or = np.array([0.5, 0.5])
b_or = -0.2 # <- AND는 -0.7, OR은 -0.2
for x1, x2 in [(0, 0), (0, 1), (1, 0), (1, 1)]:
x = np.array([x1, x2])
print(f"OR({x1},{x2}) = {perceptron(x, w_or, b_or)}")
OR(0,0) = 0
OR(0,1) = 1
OR(1,0) = 1
OR(1,1) = 1

편향 $b$만 $-0.7$에서 $-0.2$로 바꿨더니 AND가 OR로 바뀌었습니다. 편향은 결정의 문턱 높이입니다.


🚨 에러 경험: 가중치를 잘못 주면?

섹션 제목: “🚨 에러 경험: 가중치를 잘못 주면?”

아래 코드를 실행하면 어떤 결과가 나올지 예측해봅니다.

import numpy as np
def step(z):
return 1 if z >= 0 else 0
def perceptron(x, w, b):
return step(np.dot(x, w) + b)
# "AND 게이트를 만들겠다"며 모두 양수로 설정
w = np.array([0.5, 0.5])
b = 0.1 # 편향을 양수로!
for x1, x2 in [(0, 0), (0, 1), (1, 0), (1, 1)]:
x = np.array([x1, x2])
print(f"({x1},{x2}) -> {perceptron(x, w, b)}")
(0,0) -> 1
(0,1) -> 1
(1,0) -> 1
(1,1) -> 1

에러 메시지는 없지만 결과가 전부 1입니다. 원인: 편향이 양수이면 입력이 모두 0일 때도 $z = 0 + 0 + 0.1 = 0.1 \geq 0$이라 1을 출력합니다. 결정의 문턱이 너무 낮아진 것입니다. 논리 에러는 파이썬이 잡아주지 않습니다. 직접 진리표와 대조해야 발견됩니다.


개념 3. 결정 경계 — 직선이 두 영역을 가른다

섹션 제목: “개념 3. 결정 경계 — 직선이 두 영역을 가른다”

퍼셉트론이 0과 1을 바꾸는 경계는 $z = 0$인 지점입니다.

$$ w_1 x_1 + w_2 x_2 + b = 0 $$

이 식을 $x_2$에 대해 풀면 $x_2 = -\dfrac{w_1}{w_2} x_1 - \dfrac{b}{w_2}$입니다. 직선의 방정식입니다. 즉 퍼셉트론은 2D 평면을 하나의 직선으로 두 영역 으로 나누는 장치입니다. 직선의 한쪽은 “1”, 반대쪽은 “0”입니다.

AND의 경우 $w_1 = w_2 = 0.5$, $b = -0.7$이므로 경계선은 $0.5 x_1 + 0.5 x_2 - 0.7 = 0$, 즉 $x_1 + x_2 = 1.4$가 됩니다. 점 $(1,1)$만 직선 위쪽에 있고 나머지 세 점은 아래쪽에 있습니다. 그래서 $(1,1)$만 1을 출력합니다.

결정 경계 시각화 실습

import numpy as np
import matplotlib.pyplot as plt
def plot_decision_boundary(w1, w2, b, title):
# 네 가지 입력 점
points = [(0,0), (0,1), (1,0), (1,1)]
labels_and = [0, 0, 0, 1] # AND의 정답
fig, ax = plt.subplots(figsize=(5, 5))
for (x1, x2), y in zip(points, labels_and):
color = 'red' if y == 1 else 'blue'
ax.scatter(x1, x2, c=color, s=200, edgecolor='black', zorder=3)
# 결정 경계: w1*x1 + w2*x2 + b = 0 -> x2 = -(w1*x1 + b)/w2
x_line = np.linspace(-0.5, 1.5, 100)
if w2 != 0:
y_line = -(w1 * x_line + b) / w2
ax.plot(x_line, y_line, 'g--', linewidth=2, label='결정 경계')
ax.set_xlim(-0.5, 1.5)
ax.set_ylim(-0.5, 1.5)
ax.axhline(0, color='gray', lw=0.5)
ax.axvline(0, color='gray', lw=0.5)
ax.set_xlabel('x1'); ax.set_ylabel('x2')
ax.set_title(title)
ax.grid(True, alpha=0.3)
ax.legend()
plt.show()
# AND 게이트의 결정 경계
plot_decision_boundary(0.5, 0.5, -0.7, "AND 게이트")

실행하면 파란 점 3개(0 클래스)와 빨간 점 1개(1 클래스)를 초록 점선이 깔끔하게 가릅니다.

슬라이더처럼 값을 바꿔가며 관찰하기

# 편향만 바꿔가며 직선이 어떻게 이동하는지 확인
for b in [-1.2, -0.7, -0.2, 0.3]:
plot_decision_boundary(0.5, 0.5, b, f"b = {b}")

$b$가 작아지면 직선이 오른쪽 위로, 커지면 왼쪽 아래로 평행 이동합니다. $w_1$과 $w_2$의 비율을 바꾸면 직선이 회전합니다.

파라미터기하학적 효과
$b$ (편향)직선의 평행 이동
$w_1 : w_2$ 비율직선의 기울기(회전)
$w_1, w_2$ 부호 반전”1” 영역과 “0” 영역이 뒤집힘

개념 4. XOR의 벽 — 직선 하나로는 풀 수 없다

섹션 제목: “개념 4. XOR의 벽 — 직선 하나로는 풀 수 없다”

XOR(배타적 논리합)은 “둘이 다를 때만 1”입니다.

$x_1$$x_2$XOR
000
011
101
110

2D 평면에 점을 찍어봅니다. $(0,0)$과 $(1,1)$은 “0 클래스”(파란색), $(0,1)$과 $(1,0)$은 “1 클래스”(빨간색)입니다. 두 클래스는 대각선 방향으로 교차 배치됩니다.

flowchart LR
  A["(0,0) → 0<br/>파랑"] 
  B["(0,1) → 1<br/>빨강"]
  C["(1,0) → 1<br/>빨강"]
  D["(1,1) → 0<br/>파랑"]

직접 실패해보기: XOR을 만들 수 있는 $w_1, w_2, b$를 찾아봅니다.

import numpy as np
def step(z):
return 1 if z >= 0 else 0
def perceptron(x, w, b):
return step(np.dot(x, w) + b)
# XOR 정답
xor_truth = {(0,0): 0, (0,1): 1, (1,0): 1, (1,1): 0}
# 아무 가중치나 시도해봅니다
candidates = [
(np.array([0.5, 0.5]), -0.2), # OR과 유사
(np.array([1.0, -1.0]), 0.0), # 대각선 시도
(np.array([-0.5, 0.5]), 0.1),
(np.array([0.7, 0.3]), -0.5),
]
for w, b in candidates:
correct = 0
for (x1, x2), truth in xor_truth.items():
pred = perceptron(np.array([x1, x2]), w, b)
if pred == truth:
correct += 1
print(f"w={w}, b={b}: {correct}/4 정답")
w=[0.5 0.5], b=-0.2: 2/4 정답
w=[ 1. -1.], b=0.0: 3/4 정답
w=[-0.5 0.5], b=0.1: 2/4 정답
w=[0.7 0.3], b=-0.5: 2/4 정답

4/4이 나오는 조합이 하나도 없습니다. 어떤 가중치를 넣어도 최대 3개까지만 맞습니다.

왜일까요? 빨간 점 두 개 $(0,1), (1,0)$은 대각선 양 끝에 있고, 파란 점 두 개 $(0,0), (1,1)$은 반대 대각선 양 끝에 있습니다. 하나의 직선으로는 이 네 점을 색깔별로 분리할 수 없습니다. 기하학적 사실입니다.이 한계를 선형 분리 가능성(linear separability) 의 한계라고 부릅니다. 1969년 민스키와 페퍼트가 저서 『퍼셉트론』에서 수학적으로 증명한 사실입니다. 이 발표 이후 신경망 연구는 약 15년간 겨울을 맞았습니다.

문제선형 분리 가능?단층 퍼셉트론
AND✅ 가능풀림
OR✅ 가능풀림
NAND✅ 가능풀림
XOR불가능못 풂

해결책은 의외로 단순합니다. 직선을 두 개 이상 쓰면 됩니다. 퍼셉트론을 여러 층으로 쌓으면 첫 번째 층이 중간 특징(예: “OR이지만 AND는 아님”)을 만들고, 두 번째 층이 그 특징들을 다시 조합합니다. 이것이 다층 퍼셉트론(MLP) 이고, 현대 딥러닝의 출발점입니다.

flowchart LR
  X1[x1] --> H1[은닉 뉴런1<br/>OR 역할]
  X2[x2] --> H1
  X1 --> H2[은닉 뉴런2<br/>NAND 역할]
  X2 --> H2
  H1 --> OUT[출력 뉴런<br/>AND 역할]
  H2 --> OUT
  OUT --> Y[XOR 결과]

여러분이 사용하는 얼굴 인식, 음성 비서, 번역기는 모두 이 ‘쌓기’ 덕분에 가능합니다. 오늘 배운 퍼셉트론 하나가 벽돌 한 장이고, 다음 차시부터 이 벽돌을 어떻게 쌓을지 배웁니다.


활동 유형: 짝 활동 (2인)

활동 지시문

  1. 짝과 함께 아래 코드를 실행합니다. w1, w2, b 값을 자유롭게 바꿔가며 NAND 게이트(AND의 반대: 둘 다 1일 때만 0)를 만들어 봅니다.
  2. 성공한 가중치 조합을 아래 표에 기록합니다.
  3. 그다음 같은 방식으로 XOR을 만들어 봅니다. 10분간 시도하고, 안 되면 “왜 안 되는가”를 짝에게 설명합니다.
import numpy as np
def perceptron(x1, x2, w1, w2, b):
z = w1*x1 + w2*x2 + b
return 1 if z >= 0 else 0
# 여기 값을 바꿔가며 시도합니다
w1, w2, b = ?, ?, ?
for x1, x2 in [(0,0),(0,1),(1,0),(1,1)]:
print(f"({x1},{x2}) -> {perceptron(x1, x2, w1, w2, b)}")

기록표

게이트w1w2b성공 여부
NAND
XOR

토론 질문

  1. AND를 만들던 가중치에서 어떤 부호를 바꾸면 NAND가 될까요?
  2. XOR을 만드는 데 실패했다면, 그 실패는 여러분의 탓입니까 아니면 퍼셉트론 자체의 한계입니까? 종이에 네 점을 찍고 직선을 그어보며 설명합니다.
  3. 만약 직선이 아니라 곡선 하나를 그릴 수 있다면 XOR을 풀 수 있을까요? 어떤 모양이어야 할까요?

🔧 실습 활동: 결정 경계 슬라이더

섹션 제목: “🔧 실습 활동: 결정 경계 슬라이더”

ipywidgets를 사용하면 주피터 노트북에서 슬라이더로 가중치를 실시간 조작할 수 있습니다. 구글 코랩(Colab)에서 바로 실행됩니다.

1단계: 코랩 접속 및 코드 붙여넣기 (3분)

섹션 제목: “1단계: 코랩 접속 및 코드 붙여넣기 (3분)”

colab.research.google.com 에서 새 노트북을 만들고 아래 코드를 붙여넣습니다.

셀을 실행하면 슬라이더 세 개가 나타납니다. w1, w2, b를 움직이며 직선이 어떻게 변하는지 관찰합니다.

토글 버튼으로 목표 게이트를 바꾸며, 네 점을 모두 올바르게 분류하는 조합을 찾아봅니다. XOR에서는 끝내 실패합니다.

# 실행 환경: Google Colab 또는 Jupyter Notebook
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider, Dropdown
# 세 가지 논리 게이트의 정답
truth_tables = {
'AND': {(0,0):0, (0,1):0, (1,0):0, (1,1):1},
'OR': {(0,0):0, (0,1):1, (1,0):1, (1,1):1},
'XOR': {(0,0):0, (0,1):1, (1,0):1, (1,1):0},
}
def simulate(w1, w2, b, gate):
truth = truth_tables[gate]
fig, ax = plt.subplots(figsize=(6, 6))
correct = 0
for (x1, x2), y in truth.items():
# 퍼셉트론 예측
pred = 1 if (w1*x1 + w2*x2 + b) >= 0 else 0
ok = (pred == y)
if ok: correct += 1
# 정답 색상 (빨강=1, 파랑=0) + 예측 맞으면 테두리 초록, 틀리면 빨강
color = 'red' if y == 1 else 'blue'
edge = 'lime' if ok else 'black'
ax.scatter(x1, x2, c=color, s=400, edgecolor=edge, linewidth=3, zorder=3)
# 결정 경계 그리기
x_line = np.linspace(-0.5, 1.5, 100)
if w2 != 0:
y_line = -(w1 * x_line + b) / w2
ax.plot(x_line, y_line, 'g--', linewidth=2)
# 1영역 음영 처리
xx, yy = np.meshgrid(np.linspace(-0.5, 1.5, 200), np.linspace(-0.5, 1.5, 200))
zz = w1*xx + w2*yy + b
ax.contourf(xx, yy, zz, levels=[0, 1e9], colors=['#ffcccc'], alpha=0.3)
ax.set_xlim(-0.5, 1.5); ax.set_ylim(-0.5, 1.5)
ax.set_xlabel('x1'); ax.set_ylabel('x2')
ax.set_title(f"{gate} | 정답 {correct}/4 | w1={w1:.2f}, w2={w2:.2f}, b={b:.2f}")
ax.grid(True, alpha=0.3)
plt.show()
interact(simulate,
w1=FloatSlider(min=-2, max=2, step=0.1, value=0.5),
w2=FloatSlider(min=-2, max=2, step=0.1, value=0.5),
b =FloatSlider(min=-2, max=2, step=0.1, value=-0.7),
gate=Dropdown(options=['AND','OR','XOR'], value='AND'));

관찰 포인트

  • AND 모드에서 $b$를 $-0.7$ 근처로 두면 “4/4 정답”이 뜹니다
  • OR 모드에서 $b$를 $-0.2$ 근처로 조절하면 역시 “4/4 정답”이 됩니다
  • XOR 모드에서 슬라이더를 어떻게 움직여도 “4/4 정답”은 나타나지 않습니다

AND의 결과를 뒤집은 것이 NAND입니다. 퍼셉트론 가중치 w_nand와 편향 b_nand를 설정하여 NAND 진리표를 만들어 봅니다.

힌트

AND는 $w=[0.5, 0.5], b=-0.7$이었습니다. “뒤집는다”는 것은 가중합의 부호를 반대로 만드는 것입니다. 모든 부호를 반대로 해봅니다.

정답 코드
import numpy as np
def step(z):
return 1 if z >= 0 else 0
def perceptron(x, w, b):
return step(np.dot(x, w) + b)
w_nand = np.array([-0.5, -0.5]) # AND 가중치의 부호 반대
b_nand = 0.7 # AND 편향의 부호 반대
for x1, x2 in [(0,0),(0,1),(1,0),(1,1)]:
print(f"NAND({x1},{x2}) = {perceptron(np.array([x1,x2]), w_nand, b_nand)}")
NAND(0,0) = 1
NAND(0,1) = 1
NAND(1,0) = 1
NAND(1,1) = 0

입력이 세 개인 AND는 “셋 다 1일 때만 1”입니다. $x_1, x_2, x_3$를 받는 퍼셉트론을 구현합니다.

힌트

가중치 배열 길이를 3으로 늘리고, 편향은 “셋 다 1일 때만 문턱을 넘도록” 설정합니다. 가중치 합이 문턱보다 조금 크도록.

정답 코드
import numpy as np
def perceptron(x, w, b):
return 1 if np.dot(x, w) + b >= 0 else 0
w = np.array([0.5, 0.5, 0.5])
b = -1.2 # 세 입력이 모두 1일 때 합 1.5, -1.2 더하면 0.3 >= 0
for x1 in [0,1]:
for x2 in [0,1]:
for x3 in [0,1]:
x = np.array([x1,x2,x3])
print(f"({x1},{x2},{x3}) -> {perceptron(x, w, b)}")
(0,0,0) -> 0
(0,0,1) -> 0
(0,1,0) -> 0
(0,1,1) -> 0
(1,0,0) -> 0
(1,0,1) -> 0
(1,1,0) -> 0
(1,1,1) -> 1

도전: 두 퍼셉트론을 조합하여 XOR 만들기

섹션 제목: “도전: 두 퍼셉트론을 조합하여 XOR 만들기”

XOR은 한 개의 퍼셉트론으로는 불가능하지만, NAND와 OR의 결과를 다시 AND로 묶으면 만들 수 있습니다. 즉 퍼셉트론을 두 층으로 쌓습니다.

힌트

XOR(x1, x2) = AND( OR(x1, x2), NAND(x1, x2) )

첫 번째 층에서 OR과 NAND를 각각 계산하고, 그 두 결과를 두 번째 층 AND의 입력으로 넣습니다.

정답 코드
import numpy as np
def perceptron(x, w, b):
return 1 if np.dot(x, w) + b >= 0 else 0
def AND(x1, x2):
return perceptron(np.array([x1,x2]), np.array([0.5, 0.5]), -0.7)
def OR(x1, x2):
return perceptron(np.array([x1,x2]), np.array([0.5, 0.5]), -0.2)
def NAND(x1, x2):
return perceptron(np.array([x1,x2]), np.array([-0.5,-0.5]), 0.7)
def XOR(x1, x2):
s1 = OR(x1, x2) # 첫째 층 출력 1
s2 = NAND(x1, x2) # 첫째 층 출력 2
return AND(s1, s2) # 둘째 층
for x1, x2 in [(0,0),(0,1),(1,0),(1,1)]:
print(f"XOR({x1},{x2}) = {XOR(x1,x2)}")
XOR(0,0) = 0
XOR(0,1) = 1
XOR(1,0) = 1
XOR(1,1) = 0

두 층을 쌓자 직선 하나로 풀 수 없던 문제가 풀립니다. 이것이 다층 퍼셉트론의 힘입니다.


오늘 직접 만든 퍼셉트론은 현대 딥러닝 코드 안에 그대로 살아 있습니다.

  • PyTorch의 nn.Linear: $z = Wx + b$를 계산합니다. 퍼셉트론의 가중합과 동일합니다. 가중치 행렬이 다차원으로 커졌을 뿐입니다.
  • 활성화 함수: 오늘 쓴 계단 함수 대신 실무에서는 ReLU($\max(0, z)$)나 시그모이드를 씁니다. 이유는 다음 차시에서 다룹니다(학습을 위해 미분 가능해야 함).
  • 이진 분류 모델의 마지막 층: 스팸/정상, 양성/악성 같은 이진 판정은 본질적으로 “가중합이 문턱을 넘는가”입니다. 구조가 그대로입니다.
  • 선형 SVM: 퍼셉트론의 직계 후손입니다. 결정 경계를 “마진이 최대가 되는 직선”으로 잡는다는 점만 다릅니다.

Keras로 쓰면 오늘 만든 퍼셉트론이 이렇게 한 줄이 됩니다.

# 실행 환경: Python 3.10+, tensorflow 2.x
from tensorflow.keras import layers, models
model = models.Sequential([
layers.Dense(1, activation='sigmoid', input_shape=(2,)) # <- 퍼셉트론 한 개
])
model.compile(optimizer='sgd', loss='binary_crossentropy')

Dense(1)이 바로 오늘 우리가 손으로 만든 퍼셉트론 하나입니다.



객관식 1. 퍼셉트론의 수식 $y = \text{step}(w_1 x_1 + w_2 x_2 + b)$에서 편향 $b$의 역할은 무엇입니까?

① 입력의 크기를 조절한다 ② 결정의 문턱(임계값)을 조절한다 ③ 출력을 0과 1 사이로 정규화한다 ④ 입력이 음수일 때만 동작한다

정답 확인

정답: ② 편향 $b$는 가중합에 더해져서 계단 함수의 문턱을 실질적으로 이동시킵니다. $b$가 작을수록 문턱이 높아져 출력이 1이 되기 어렵고, $b$가 클수록 쉬워집니다. 2D 평면에서는 결정 경계 직선의 평행 이동으로 나타납니다.

객관식 2. 다음 중 단층 퍼셉트론으로 풀 수 없는 문제는?

① AND ② OR ③ NAND ④ XOR

정답 확인

정답: ④ XOR의 1-클래스 점 $(0,1), (1,0)$과 0-클래스 점 $(0,0), (1,1)$은 대각선 방향으로 교차 배치되어 있어 하나의 직선으로 분리할 수 없습니다. 이것을 선형 분리 불가능(not linearly separable)이라 하며, 다층 퍼셉트론이 필요한 이유입니다.

객관식 3. 2차원 입력 퍼셉트론의 결정 경계 방정식 $w_1 x_1 + w_2 x_2 + b = 0$에서, $w_1 : w_2$ 비율을 바꾸면 기하학적으로 어떤 변화가 일어납니까?

① 직선의 평행 이동 ② 직선의 회전(기울기 변화) ③ 직선이 곡선이 됨 ④ 아무 변화 없음

정답 확인

정답: ② $x_2 = -(w_1/w_2) x_1 - b/w_2$ 형태로 정리하면 기울기가 $-w_1/w_2$입니다. 이 비율이 바뀌면 직선이 회전합니다. 평행 이동은 $b$의 역할입니다.

서술형 1. XOR 게이트를 단층 퍼셉트론으로 구현할 수 없는 이유를 (1) 기하학적 관점과 (2) 해결 방향 두 가지로 설명하시오.

예시 답안

(1) 기하학적 관점: XOR의 1-클래스 점 $(0,1), (1,0)$과 0-클래스 점 $(0,0), (1,1)$은 단위 정사각형의 대각선 양 끝에 교차 배치되어 있습니다. 단층 퍼셉트론의 결정 경계는 직선 하나뿐이므로, 어떤 직선을 그어도 두 클래스를 완벽히 분리할 수 없습니다. 이를 선형 분리 불가능 문제라고 합니다.(2) 해결 방향: 퍼셉트론을 두 층 이상으로 쌓으면 됩니다. 첫 번째 층에서 OR과 NAND 같은 중간 특징을 각각 계산하고, 두 번째 층에서 그 두 출력을 AND로 묶으면 XOR을 만들 수 있습니다. 즉 직선 두 개를 조합하여 비선형 결정 경계를 만드는 것입니다. 이 구조가 다층 퍼셉트론(MLP) 이며, 현대 딥러닝의 기본 틀입니다.

자기점검 체크리스트

  • 퍼셉트론의 수식 $z = w_1 x_1 + w_2 x_2 + b$와 계단 함수의 역할을 설명할 수 있다
  • NumPy로 AND, OR, NAND 게이트를 구현할 수 있다
  • 가중치와 편향을 바꿨을 때 결정 경계 직선이 어떻게 움직이는지 설명할 수 있다
  • XOR이 단층 퍼셉트론으로 풀리지 않는 이유를 기하학적으로 말할 수 있다
  • “뉴런을 코드로 흉내 내면 무엇을 할 수 있고 없는가”에 자기 말로 답할 수 있다

퍼셉트론에서 활성화 함수(계단 함수)가 하는 일은 무엇입니까?

AND 게이트에서 가중치는 그대로 두고 편향 b만 -0.7에서 -0.2로 바꾸면 어떤 게이트가 됩니까?

2D 평면에서 퍼셉트론의 결정 경계는 어떤 형태입니까?

XOR 문제를 해결하려면 어떻게 해야 합니까?


아래 질문에 한두 문장씩 답을 적어봅니다.

  • 오늘 배운 개념 중에서 가장 인상 깊었던 것은 무엇이며, 그 이유는 무엇입니까?
  • 단층 퍼셉트론이 XOR에서 실패하는 장면을 직접 겪은 후, “인공지능의 한계”에 대한 내 생각이 어떻게 바뀌었습니까?
  • 아직 완전히 이해되지 않은 부분이 있다면 어디이며, 무엇을 더 알아보고 싶습니까?
  • 오늘 만든 퍼셉트론 코드는 단 10줄 남짓입니다. 이렇게 단순한 장치가 현대 AI의 뿌리라는 사실에서 어떤 인사이트를 얻었습니까?

5차시에서는 오늘 만난 XOR의 벽을 직접 무너뜨립니다. 퍼셉트론 여러 개를 층층이 쌓은 다층 퍼셉트론(MLP) 을 구현하고, 계단 함수 대신 시그모이드·ReLU를 쓰는 이유를 다룹니다. 그리고 가장 중요한 질문 하나를 던집니다.

“가중치를 일일이 손으로 설정했는데, 컴퓨터가 스스로 올바른 가중치를 찾게 하려면 어떻게 해야 할까요?”

이 질문의 답이 바로 ‘학습’입니다.