AI(ML & DL)

[딥러닝] 퍼셉트론(Perceptron)과 경사 하강법(Gradient Descent)

ch010104 2025. 9. 18. 20:28

1. 목표: 점들을 가르는 최적의 직선 찾기

  • 위와 같이 파란 점과 빨간 점, 두 그룹의 데이터가 주어졌다고 가정
  • 우리의 목표는 이 두 그룹을 가장 잘 나눌 수 있는 하나의 직선을 긋는 것
  • 이 직선을 기준으로 새로운 점이 나타났을 때, 그 점이 파란 그룹에 속할지, 빨간 그룹에 속할지 예측할 수 있음
  • 머신러닝에서는 이 직선을 결정 경계(Decision Boundary)라고 부름
  • 퍼셉트론 알고리즘은 바로 이 결정 경계를 찾아가는 과정임

2. 퍼셉트론 알고리즘의 원리

  • 퍼셉트론은 아주 간단하고 직관적인 방식으로 학습
  • 잘못 분류된 데이터를 발견하면, 결정 경계(직선)를 조금씩 움직여서 올바르게 분류될 때까지 이 과정을 반복

예측 공식

  • 어떤 점의 좌표 $(x_1, x_2)$가 주어졌을 때, 퍼셉트론은 다음 식으로 어느 그룹에 속하는지 판단
  • 파란 점은 양수(+1), 빨간 점은 음수(-1)로 분류
  • : 각 입력()에 대한 가중치(weight)
    - 이 가중치들이 직선의 기울기를 결정
  • : **편향(bias)**
    - 직선의 위치(y절편)를 조절
  • : 괄호 안의 계산 결과가 양수이면 +1, 음수이면 -1을 반환하는 함수

학습 규칙 (가중치 업데이트)

핵심은 '잘못 분류했을 때' 가중치()와 편향()을 어떻게 업데이트 하느냐에 있음

  1. 빨간 점(-1)을 파란 영역(+1)으로 잘못 예측한 경우
    • 직선을 빨간 점 쪽으로 더 가깝게 이동시켜야 함
    • 이를 위해 의 값을 더 작게 만들어야 함
    • 따라서, 가중치와 편향에서 일정 값을 빼줌
    • (p는 점의 좌표)
  2. 파란 점(+1)을 빨간 영역(-1)으로 잘못 예측한 경우
    • 직선을 파란 점 쪽으로 더 가깝게 이동시켜야 함
    • 의 값을 더 크게 만들어야 함
    • 따라서, 가중치와 편향에 일정 값을 더해줌
  • (알파)는 **학습률(learning rate)**이라고 하며, 직선을 한 번에 얼마나 많이 움직일지를 결정하는 값임
  • 학습률이 너무 크면 직선이 너무 많이 움직여 최적의 위치를 찾기 어렵고(변동성이 크다), 너무 작으면 학습 속도가 느려짐

Python 실습 코드: 퍼셉트론

import numpy as np
import matplotlib.pyplot as plt

# 데이터 준비 (4개 점, 두 개 클래스)
X = np.array([
    [2, 2],   # class 1
    [3, 1],   # class 1
    [-1, -1], # class -1
    [-2, -3]  # class -1
])
y = np.array([1,  1, -1, -1])  # 퍼셉트론은 보통 -1, +1 라벨 사용

# 초기 가중치/바이어스
w = np.array([-1.0, -1.5]) 
b = 0.0
eta = 0.1   # 학습률 (alpha)

# 분류 직선을 그리는 함수
def plot_decision_boundary(w, b, X, y, step):
    plt.clf()  # 이전 그림 지우기
    # 데이터 산점도
    for i in range(len(y)):
        if y[i] == 1:
            plt.scatter(X[i,0], X[i,1], c='blue', marker='o')
        else:
            plt.scatter(X[i,0], X[i,1], c='red', marker='x')

    # 결정경계: w1*x1 + w2*x2 + b = 0
    x1_vals = np.linspace(-4, 4, 100)
    if w[1] != 0:
        x2_vals = -(w[0]/w[1])*x1_vals - b/w[1]
        plt.plot(x1_vals, x2_vals, 'k-')

    plt.xlim(-4, 4)
    plt.ylim(-4, 4)
    plt.title(f"Perceptron Learning - Step {step}")
    plt.grid(True)
    plt.draw()
    plt.pause(0.01)

# 학습 루프
plt.ion()
step = 0
plot_decision_boundary(w, b, X, y, step)

for epoch in range(20):  # 최대 20번 반복
    error_found = False
    for i in range(len(X)):
        # 오분류된 경우
        if y[i] * (np.dot(w, X[i]) + b) <= 0:  
            # 가중치 업데이트
            w = w + eta * y[i] * X[i]
            b = b + eta * y[i]
            step += 1
            plot_decision_boundary(w, b, X, y, step)
            input("Enter 키를 누르면 다음 step으로 진행합니다...")
            error_found = True
    if not error_found:
        print("모든 점이 올바르게 분류되었습니다. 학습 종료!")
        break

plt.ioff()
plt.show()

3. 퍼셉트론의 한계와 경사 하강법

  • 퍼셉트론은 매우 직관적이지만 한계가 있음
  • 단순히 '잘못 분류했는가'에만 의존할 뿐, '얼마나 많이 잘못 분류했는가'의 정도는 고려하지 않는다는 점
  • 이 때문에 학습 과정이 비효율적일 수 있음
  • 이러한 한계를 극복하기 위해 등장한 개념이 바로 경사 하강법(Gradient Descent)

개념

  • 경사 하강법의 핵심 아이디어는 비용 함수(Cost Function)를 정의
  • 이 비용 함수의 값을 최소화하는 방향으로 가중치를 업데이트하는 것
  • 비용 함수는 모델이 얼마나 예측을 못하는지를 나타내는 '오차'의 크기
  • 마치 언덕(비용 함수 그래프)에서 가장 낮은 지점(비용 최소값)을 찾아 내려가는 것
  • 현재 위치에서 가장 가파른 경사(기울기, Gradient)를 따라 한 걸음씩 이동하는 방식
  • 비용 함수 (Cost Function): 예측값과 실제값의 차이를 기반으로 계산
  • 가중치 업데이트: 비용 함수를 가중치()로 미분하여 기울기를 구하고, 이 기울기의 반대 방향으로 학습률()만큼 가중치를 이동시김

 

Python 실습 코드: 경사 하강법을 이용한 로지스틱 회귀

  • 로지스틱 회귀(Logistic Regression)와 같은 다른 분류 모델에서 널리 사용
import numpy as np
import matplotlib.pyplot as plt

# 데이터 준비
X = np.array([
    [2, 2],   # class 1
    [3, 1],   # class 1
    [-1, -1], # class 0
    [-2, -3]  # class 0
])
y = np.array([1, 1, 0, 0])  # 로지스틱 회귀는 {0,1} 라벨 사용

# 파라미터 초기화
w = np.array([-1.0, -1.5])
b = 0.0
eta = 0.1  # 학습률

# 시그모이드 함수
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

# 결정경계 그리기 (위 퍼셉트론 코드와 유사)
def plot_decision_boundary(w, b, X, y, step):
    # ... (위 코드와 동일) ...
    plt.title(f"Logistic Regression (GD) - Step {step}")
    # ... (위 코드와 동일) ...
    
# 학습 루프
plt.ion()
step = 0
plot_decision_boundary(w, b, X, y, step)

for epoch in range(20):  # 최대 20 step
    # 예측 (시그모이드 함수 사용)
    z = np.dot(X, w) + b
    y_hat = sigmoid(z)

    # 손실함수 (cross entropy)
    loss = -np.mean(y*np.log(y_hat+1e-8) + (1-y)*np.log(1-y_hat+1e-8))

    # Gradient 계산
    dw = np.dot(X.T, (y_hat - y)) / len(y)
    db = np.mean(y_hat - y)

    # 업데이트
    w -= eta * dw
    b -= eta * db

    step += 1
    plot_decision_boundary(w, b, X, y, step)
    print(f"Step {step}, Loss = {loss:.4f}")
    input("Enter 키를 누르면 다음 step으로 진행합니다...")

plt.ioff()
plt.show()

 

  • 퍼셉트론과 달리, 모든 데이터의 오차를 종합하여 계산된 손실(Loss)을 최소화하는 방향으로 결정 경계를 이동

4. 정리

  • 퍼셉트론: 구현이 간단하고 직관적이지만, 오차의 정도를 반영하지 못하는 한계가 있습니다.
  • 경사 하강법: 비용 함수를 정의하고 기울기를 이용해 점진적으로 최적의 해를 찾아가는 강력한 방법으로, 로지스틱 회귀 등 다양한 머신러닝 모델의 핵심 학습 원리입니다.