MLP: 다층 퍼셉트론으로 임의의 함수를 근사하다

다층 퍼셉트론(MLP)의 구조와 보편 근사 정리를 이해한다. 깊이와 너비의 트레이드오프, MNIST 분류기 완전 구현, 하이퍼파라미터 선택 가이드까지 실전 중심으로 MLP를 완전히 파악한다.

· 6 min read · PALDYN Team

지난 글에서 역전파가 연쇄 법칙을 통해 모든 층의 기울기를 계산한다는 것을 배웠다. 이 역전파로 학습할 수 있는 가장 기본적인 신경망 구조가 **다층 퍼셉트론(Multi-Layer Perceptron, MLP)**이다. MLP는 딥러닝의 출발점이자 가장 이해하기 쉬운 형태다. 이번 글에서는 MLP의 구조, 보편 근사 정리(Universal Approximation Theorem), 깊이와 너비의 트레이드오프, 그리고 MNIST 손글씨 분류기 완전 구현을 다룬다.

MLP란

MLP는 완전 연결 층(Fully Connected Layer)을 여러 개 쌓은 신경망이다. 단일 퍼셉트론과 달리 은닉층을 가지며, 비선형 활성화 함수를 통해 선형 분리 불가능한 문제도 해결할 수 있다.

  • 입력층: 원시 특성을 받음
  • 은닉층(≥1개): 특성을 변환하며 패턴을 학습
  • 출력층: 최종 예측을 생성

XOR 문제를 예로 들면, MLP는 다음과 같이 해결한다:

import torch
import torch.nn as nn

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

# 단층 퍼셉트론: XOR 해결 불가
# 2층 MLP: 해결 가능
model = nn.Sequential(
    nn.Linear(2, 4),   # 은닉층: 2차원을 4차원으로
    nn.ReLU(),
    nn.Linear(4, 1),   # 출력층
    nn.Sigmoid(),
)

optimizer = torch.optim.Adam(model.parameters(), lr=0.1)
criterion = nn.BCELoss()

for _ in range(1000):
    optimizer.zero_grad()
    loss = criterion(model(X), y)
    loss.backward()
    optimizer.step()

pred = (model(X) > 0.5).float()
print(pred.t())  # tensor([[0., 1., 1., 0.]]) — XOR 해결!

보편 근사 정리

보편 근사 정리(Universal Approximation Theorem, Hornik 1989):

충분히 많은 뉴런을 가진 1개의 은닉층 MLP는, 임의의 연속 함수를 임의의 정밀도로 근사할 수 있다.

이것이 MLP가 강력한 이유다. 이론적으로 어떤 함수든 근사할 수 있다. 단, 이 정리는 존재 증명이다. 파라미터 수가 충분하면 존재는 하지만, 역전파로 실제로 그 파라미터를 찾을 수 있는지는 별개의 문제다.

실용적 시사점:

  • 복잡한 문제일수록 더 큰 은닉층이 필요
  • 단, 너무 크면 과적합(Overfitting)이 발생
  • 깊은 네트워크가 같은 파라미터 수에서 더 효율적인 경우가 많음

MLP 구조와 보편 근사 정리

깊이(Depth) vs 너비(Width)

import torch.nn as nn

# 좁고 깊은 네트워크 (파라미터 약 5만)
deep_narrow = nn.Sequential(
    nn.Linear(784, 64), nn.ReLU(),
    nn.Linear(64, 64),  nn.ReLU(),
    nn.Linear(64, 64),  nn.ReLU(),
    nn.Linear(64, 64),  nn.ReLU(),
    nn.Linear(64, 10),
)

# 넓고 얕은 네트워크 (파라미터 약 20만)
wide_shallow = nn.Sequential(
    nn.Linear(784, 256), nn.ReLU(),
    nn.Linear(256, 10),
)

# 실무 결론:
# - 같은 파라미터 수면 깊은 네트워크가 유리 (계층적 특성 학습)
# - 너무 깊으면 기울기 소실/폭발 위험 (→ ResNet, BatchNorm 필요)
# - 일반적으로 깊이 3~7 + 드롭아웃이 좋은 시작점

실제 연구 결과에 따르면, 깊은 네트워크는 계층적(hierarchical) 특성을 학습한다. 첫 층은 단순한 패턴, 중간 층은 조합된 패턴, 마지막 층은 추상적 개념을 표현하는 경향이 있다.

MNIST 분류기 완전 구현

import torch
import torch.nn as nn
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# 데이터 준비
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])
train_data = datasets.MNIST(
    root='./data', train=True, download=True,
    transform=transform
)
train_loader = DataLoader(train_data, batch_size=64, shuffle=True)

# 모델 정의
class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Flatten(),
            nn.Linear(784, 512), nn.ReLU(),
            nn.Linear(512, 256), nn.ReLU(),
            nn.Linear(256, 10),
        )
    def forward(self, x):
        return self.net(x)

model = MLP()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()

# 학습
for epoch in range(5):
    model.train()
    total_loss, correct = 0, 0
    for X, y in train_loader:
        optimizer.zero_grad()
        out = model(X)
        loss = criterion(out, y)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
        correct += (out.argmax(1) == y).sum().item()
    print(f"Epoch {epoch+1} | Loss: {total_loss/len(train_loader):.3f}"
          f" | Acc: {correct/len(train_data):.3f}")

MLP MNIST 구현

하이퍼파라미터 선택 가이드

MLP 설계 시 결정해야 하는 주요 하이퍼파라미터:

하이퍼파라미터일반적 시작점조정 방법
은닉층 수2~4개과소적합 시 증가
은닉층 크기64~5122의 거듭제곱 권장
활성화 함수ReLUGELU도 좋음
학습률1e-3 (Adam)LR Scheduler 사용
배치 크기32~256GPU 메모리에 맞게
정규화Dropout(0.3~0.5)과적합 시 추가

MLP의 한계

MLP는 강력하지만 이미지, 시퀀스 데이터에는 비효율적이다. 28×28 이미지를 784차원 벡터로 펼치면 공간적 구조 정보를 잃는다. 인접한 픽셀이 관련 있다는 사실을 전혀 활용하지 못한다. 이것이 이미지에 CNN(Convolutional Neural Network), 시퀀스에 RNN이나 Transformer를 사용하는 이유다.

MLP는 여전히 분류 헤드(classifier head), 피드포워드 레이어(FFN), 임베딩 변환 등 다양한 곳에서 핵심 구성 요소로 사용된다.


지난 글: 순전파와 역전파: 신경망 학습의 핵심 원리

다음 글: 가중치 초기화: Xavier, He, 그리고 수렴의 비밀


읽어주셔서 감사합니다. 😊