수달이네 기술 블로그

5. ANN과 퍼셉트론 본문

AI공부/딥러닝

5. ANN과 퍼셉트론

슬픈 수달이 2026. 1. 31. 15:09

생물학적 뉴런

신경계를 구성하는 기본 단위, 정보를 수집, 처리 전달.

  • 수상돌기: 다른 뉴런, 외부 자극으로부터 신호 수신
  • 세포체: 신호를 처리하고 통합
  • 축삭: 다음 뉴런, 근육, 샘등 다른 조직에 전달
  • 시냅스: 축삭 끝에서 화학적 신호, 전기적 신호로 타 세포와 연결

인공신경망(ANN)

생물학적 신경망의 구조와 기능을 모방한 계산 모델, 여러 뉴런을 계층적으로 연결해 구성.

  • 입력층, 은닉층: 입력 데이터, 가중치, 활성화 함수등 연산으로 특징을 추출.
  • 출력층: 예측값, 결과 생성.
    • 각 층의 뉴런은 다음층의 뉴런과 연결되어 데이터를 전달, 처리.
    • 데이터에 기반한 학습으로 가중치를 조정하고 문제를 해결.
  • 이미지분류, 자연어처리, 음성인식등에 사용
  • ANN은 다층 구조와 비선형 활성화 함수로 복잡한 데이터 간의 관계를 학습할 수 있음.

인공신경망의 역사

1940~1980년대(ANN연구의 시작, 단층 퍼셉트론)

  • 1943년, 워런 맥컬록(Warren McCulloch), 월터 피츠(Walter Pitts)는 생물학적 뉴런을 수학적으로 모델링한 맥컬록-피츠 뉴런을 제안, ANN의 기초를 마련함
  • 1958년, 프랭크 로젠블랫(Frank Rosenblatt)은 단층 퍼셉트론(perceptron)을 개발, ANN이 학습, 분류문제를 해결함을 보여줌
  • 1969년, 마빈 민스키(Marvin Minsky), 시모어 페이퍼트(Seymour Papert)가 퍼셉트론의 한계를 지적, 비선형 문제가 해결 불가함을 제시해 ANN연구의 침체기가 됨.

1980~2000년대(역전파의 발견, 다층 퍼셉트론)

역전파 알고리즘(backpropagation)재발견되어 ANN이 다시 주목받기 시작.

  • 제프리 힌턴(Geoffrey Hinton)등 연구자들이 다층 퍼셉트론(Multi-Layer Perceptron, 딥러닝)으로 비선형 문제를 해결할 수 있음을 확인하여 ANN연구가 다시 활발해짐.
  • 1990년대, 합성곱 신경망(CNN)과 순환 신경망(RNN)등 특화된 구조가 개발되어 ANN이 더 복잡한 문제를 다룰 수 있게 했다.

퍼셉트론

1958년 프랭크 로젠블랫(Frank Rosenblatt)이 제안한 인공 뉴런 모델. 가장 간단한 형태

  • 입력값과 해당 가중치(weight)의 곱을 모두 더한 값에 편향(bias)를 더하고, 이를 활성화 함수로 변환하여 이진 출력을 생성함
  • 출력값이 다를경우 가중치를 조정하여 학습을 진행한다.
  • 단층 구조로써 선형적으로 분리 가능한 문제는 해결하나 XOR문제같은 비선형 문제는 해결하지 못한다.

  • AND문제와 OR문제는 선형으로 분리가 가능하나, XOR은 선형으로 분리 불가함을 나타냄.

AND연산 구현

# 논리 회귀(단층 퍼셉트론)로 AND 문제 풀기

import torch
import torch.nn as nn
import torch.optim as optim

X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [0], [0], [1]])

model = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

optimizer = optim.SGD(model.parameters(), lr=1)

epochs = 1000

for epoch in range(epochs + 1):
    y_pred = model(X)
    loss = nn.BCELoss()(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0:
        y_bool = (y_pred >= 0.5).float()
        accuracy = (y == y_bool).float().sum() / len(y) * 100
        print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')

# Epoch    0/1000 Loss: 0.882778 Accuracy: 50.00%
# Epoch  100/1000 Loss: 0.144232 Accuracy: 100.00%
# Epoch  200/1000 Loss: 0.081804 Accuracy: 100.00%
# Epoch  300/1000 Loss: 0.056598 Accuracy: 100.00%
# Epoch  400/1000 Loss: 0.043082 Accuracy: 100.00%
# Epoch  500/1000 Loss: 0.034699 Accuracy: 100.00%
# Epoch  600/1000 Loss: 0.029009 Accuracy: 100.00%
# Epoch  700/1000 Loss: 0.024902 Accuracy: 100.00%
# Epoch  800/1000 Loss: 0.021803 Accuracy: 100.00%
# Epoch  900/1000 Loss: 0.019382 Accuracy: 100.00%
# Epoch 1000/1000 Loss: 0.017440 Accuracy: 100.00%
  • 위 그림의 AND연산과 같은 그래프를 그려주었다. (분류문제)
    • 해결 가능함을 확인 가능하다.

OR연산 확인

# 논리 회귀(단층 퍼셉트론)로 OR 문제 풀기

X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [1], [1], [1]])

model = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

optimizer = optim.SGD(model.parameters(), lr=1)

epochs = 1000

for epoch in range(epochs + 1):
    y_pred = model(X)
    loss = nn.BCELoss()(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0:
        y_bool = (y_pred >= 0.5).float()
        accuracy = (y == y_bool).float().sum() / len(y) * 100
        print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')

# Epoch    0/1000 Loss: 0.497065 Accuracy: 75.00%
# Epoch  100/1000 Loss: 0.088124 Accuracy: 100.00%
# Epoch  200/1000 Loss: 0.046544 Accuracy: 100.00%
# Epoch  300/1000 Loss: 0.031271 Accuracy: 100.00%
# Epoch  400/1000 Loss: 0.023452 Accuracy: 100.00%
# Epoch  500/1000 Loss: 0.018727 Accuracy: 100.00%
# Epoch  600/1000 Loss: 0.015571 Accuracy: 100.00%
# Epoch  700/1000 Loss: 0.013318 Accuracy: 100.00%
# Epoch  800/1000 Loss: 0.011630 Accuracy: 100.00%
# Epoch  900/1000 Loss: 0.010319 Accuracy: 100.00%
# Epoch 1000/1000 Loss: 0.009272 Accuracy: 100.00%
  • OR연산 또한 Accuracy 100%로 해결 가능함을 확인할 수 있다.

XOR연산 확인

# 논리 회귀(단층 퍼셉트론)로 XOR 문제 풀기

X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [1], [1], [0]])

model = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

optimizer = optim.SGD(model.parameters(), lr=1)

epochs = 1000

for epoch in range(epochs + 1):
    y_pred = model(X)
    loss = nn.BCELoss()(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0:
        y_bool = (y_pred >= 0.5).float()
        accuracy = (y == y_bool).float().sum() / len(y) * 100
        print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')

# Epoch    0/1000 Loss: 0.713088 Accuracy: 50.00%
# Epoch  100/1000 Loss: 0.693148 Accuracy: 50.00%
# Epoch  200/1000 Loss: 0.693147 Accuracy: 75.00%
# Epoch  300/1000 Loss: 0.693147 Accuracy: 75.00%
# Epoch  400/1000 Loss: 0.693147 Accuracy: 50.00%
# Epoch  500/1000 Loss: 0.693147 Accuracy: 50.00%
# Epoch  600/1000 Loss: 0.693147 Accuracy: 50.00%
# Epoch  700/1000 Loss: 0.693147 Accuracy: 50.00%
# Epoch  800/1000 Loss: 0.693147 Accuracy: 50.00%
# Epoch  900/1000 Loss: 0.693147 Accuracy: 50.00%
# Epoch 1000/1000 Loss: 0.693147 Accuracy: 50.00%
  • 학습을 반복해도 50% (반반 확률 찍기)를 넘지 못함
    • 결과를 보아 XOR연산은 해결 불가능 함을 확인함.

위 코드에서

model = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

해당 부분, nn.Linear(2,1)이 부분이 퍼셉트론이라 한다.

  • 이게 여러층 쌓아, 그 중간을 비선형화 시키면 다층 퍼셉트론이 된다.
  • 해당 다층 퍼셉트론을 딥러닝이라 부르기 시작한다.
  • 지금까지 층이 하나만 있던 것들은 모두 머신러닝