Skip to main content

퍼셉트론과 MLP

학습 목표

  • 퍼셉트론(Perceptron)의 수학적 구조를 이해한다
  • 퍼셉트론의 한계(XOR 문제)와 다층 퍼셉트론(MLP)의 해결 방식을 설명할 수 있다
  • PyTorch로 MLP를 구현할 수 있다
  • 범용 근사 정리(Universal Approximation Theorem)의 의미를 이해한다

왜 중요한가

퍼셉트론은 모든 신경망의 기본 단위입니다. CNN의 합성곱 필터, RNN의 순환 유닛, Transformer의 Feed-Forward 레이어 모두 퍼셉트론의 확장입니다. 이 기본 구조를 이해하면 어떤 복잡한 아키텍처도 분해하여 이해할 수 있습니다.

퍼셉트론 (단일 뉴런)

퍼셉트론은 1958년 Frank Rosenblatt가 제안한 최초의 신경망 모델입니다. 입력값에 가중치(Weight)를 곱하고, 편향(Bias)을 더한 뒤, 활성화 함수(Activation Function)를 통과시켜 출력을 생성합니다.

수학적 표현

y=f(i=1nwixi+b)=f(wTx+b)y = f\left(\sum_{i=1}^{n} w_i x_i + b\right) = f(\mathbf{w}^T \mathbf{x} + b) 여기서:
  • x=[x1,x2,,xn]\mathbf{x} = [x_1, x_2, \ldots, x_n]: 입력 벡터
  • w=[w1,w2,,wn]\mathbf{w} = [w_1, w_2, \ldots, w_n]: 가중치 벡터
  • bb: 편향
  • ff: 활성화 함수
  • yy: 출력

PyTorch로 구현

import torch
import torch.nn as nn

# 단일 퍼셉트론: 3개 입력 → 1개 출력
perceptron = nn.Linear(in_features=3, out_features=1)

# 가중치와 편향 확인
print(f"가중치 (w): {perceptron.weight.data}")
print(f"편향 (b): {perceptron.bias.data}")

# 입력 데이터
x = torch.tensor([[1.0, 2.0, 3.0]])

# 순전파: y = wx + b (활성화 함수 없이)
output = perceptron(x)
print(f"출력: {output.data}")

퍼셉트론의 한계: XOR 문제

단일 퍼셉트론은 선형으로 분리 가능한(Linearly Separable) 문제만 풀 수 있습니다. AND, OR 게이트는 직선 하나로 분류할 수 있지만, XOR은 불가능합니다.
입력ANDORXOR
(0,0)000
(0,1)011
(1,0)011
(1,1)110
1969년 Minsky와 Papert는 이 한계를 수학적으로 증명했고, 이로 인해 첫 번째 “AI 겨울”이 시작되었습니다.
import torch
import torch.nn as nn

# XOR 데이터
X = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=torch.float32)
y = torch.tensor([[0], [1], [1], [0]], dtype=torch.float32)

# 단일 퍼셉트론으로는 XOR을 학습할 수 없음
single_layer = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

criterion = nn.BCELoss()
optimizer = torch.optim.SGD(single_layer.parameters(), lr=0.5)

# 학습 시도 (수렴하지 않음)
for epoch in range(1000):
    output = single_layer(X)
    loss = criterion(output, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

print(f"단일 퍼셉트론 예측: {single_layer(X).detach().round().flatten().tolist()}")
# 예상 출력: XOR 패턴을 정확히 학습하지 못함

다층 퍼셉트론 (MLP)

XOR 문제의 해결책은 **은닉층(Hidden Layer)**을 추가하는 것입니다. 다층 퍼셉트론(Multi-Layer Perceptron, MLP)은 입력층, 하나 이상의 은닉층, 출력층으로 구성됩니다.

MLP의 수학적 표현

2층 MLP (은닉층 1개)의 경우: h=f1(W1x+b1)\mathbf{h} = f_1(\mathbf{W}_1 \mathbf{x} + \mathbf{b}_1) y=f2(W2h+b2)\mathbf{y} = f_2(\mathbf{W}_2 \mathbf{h} + \mathbf{b}_2) 은닉층이 비선형 활성화 함수 f1f_1을 사용하기 때문에, MLP는 비선형 결정 경계를 학습할 수 있습니다.

PyTorch로 XOR 해결

import torch
import torch.nn as nn

# XOR 데이터
X = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=torch.float32)
y = torch.tensor([[0], [1], [1], [0]], dtype=torch.float32)

# 다층 퍼셉트론: 은닉층 추가
mlp = nn.Sequential(
    nn.Linear(2, 4),     # 입력 2 → 은닉 4
    nn.ReLU(),           # 비선형 활성화
    nn.Linear(4, 1),     # 은닉 4 → 출력 1
    nn.Sigmoid()         # 출력을 0~1로 변환
)

criterion = nn.BCELoss()
optimizer = torch.optim.Adam(mlp.parameters(), lr=0.01)

# 학습
for epoch in range(2000):
    output = mlp(X)
    loss = criterion(output, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

# 결과 확인
predictions = mlp(X).detach().round()
print(f"MLP 예측: {predictions.flatten().tolist()}")
# 출력: [0.0, 1.0, 1.0, 0.0] — XOR 학습 성공!

범용 근사 정리

**범용 근사 정리(Universal Approximation Theorem)**는 하나의 은닉층과 충분한 수의 뉴런을 가진 MLP가 임의의 연속 함수를 원하는 정밀도로 근사할 수 있음을 증명합니다. 단, 이 정리는 존재성만 보장합니다. 실제로 그러한 가중치를 찾을 수 있는지(학습 가능성)는 별개의 문제입니다. 실무에서는 넓고 얕은 네트워크보다 좁고 깊은 네트워크가 효율적으로 학습되는 경우가 많으며, 이것이 “딥(Deep)” 러닝이 각광받는 이유입니다.

완전 연결 계층 (Fully Connected Layer)

MLP의 각 층은 완전 연결(Fully Connected, FC) 또는 밀집(Dense) 계층이라고 부릅니다. 모든 입력 노드가 모든 출력 노드와 연결됩니다.
import torch.nn as nn

# 다양한 MLP 아키텍처
class SimpleClassifier(nn.Module):
    """3-class 분류를 위한 MLP"""
    def __init__(self, input_dim, hidden_dims, num_classes):
        super().__init__()
        layers = []
        prev_dim = input_dim
        for h_dim in hidden_dims:
            layers.append(nn.Linear(prev_dim, h_dim))
            layers.append(nn.ReLU())
            layers.append(nn.Dropout(0.2))  # 과적합 방지
            prev_dim = h_dim
        layers.append(nn.Linear(prev_dim, num_classes))
        self.network = nn.Sequential(*layers)

    def forward(self, x):
        return self.network(x)

# 사용 예시
model = SimpleClassifier(
    input_dim=784,         # 28×28 이미지를 펼친 입력
    hidden_dims=[256, 128, 64],
    num_classes=10         # MNIST 10개 클래스
)

# 파라미터 수 확인
total_params = sum(p.numel() for p in model.parameters())
print(f"전체 파라미터 수: {total_params:,}")
정해진 규칙은 없지만 일반적인 가이드라인이 있습니다. 은닉층의 뉴런 수는 보통 입력 차원과 출력 차원 사이의 값으로 설정하며, 층이 깊어질수록 점진적으로 줄이는 패턴(예: 256 → 128 → 64)을 자주 사용합니다. 실제로는 교차 검증(Cross-Validation)이나 하이퍼파라미터 탐색으로 최적의 구조를 찾습니다.
가능하지만 효율적이지 않습니다. 28x28 이미지를 784차원 벡터로 펼치면 공간 정보가 손실됩니다. MLP는 이미지의 지역적 패턴(에지, 코너)을 인식하는 구조가 없어서, CNN에 비해 훨씬 많은 파라미터와 데이터가 필요합니다.
깊은 네트워크는 더 복잡한 함수를 표현할 수 있지만, 기울기 소실(Gradient Vanishing) 문제와 과적합 위험이 있습니다. ResNet의 스킵 연결(Skip Connection), BatchNorm 등 다양한 기법이 이 문제를 해결합니다.

체크리스트

  • 퍼셉트론의 수학적 구조(y=f(wTx+b)y = f(\mathbf{w}^T\mathbf{x} + b))를 이해한다
  • XOR 문제가 왜 단일 퍼셉트론으로 풀 수 없는지 설명할 수 있다
  • MLP에서 비선형 활성화 함수의 역할을 설명할 수 있다
  • PyTorch의 nn.Linearnn.Sequential로 MLP를 구현할 수 있다

다음 문서