Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬으로 배우는 단일 뉴런 신경망의 기본 원리

신경망(Neural Network)은 딥러닝의 가장 중요한 핵심 요소로, 다양한 분야에서 폭넓게 활용되고 있습니다. 오늘날 신경망은 이미지 분류, 음성 인식, 객체 탐지 등 수많은 실용적인 문제를 해결하는 데 사용되고 있습니다.


그렇다면 신경망은 정확히 무엇이고, 어떻게 작동할까요? 이번 글에서는 신경망의 기본 구조와 작동 원리를 살펴보고, 파이썬으로 간단한 단일 뉴런 신경망을 직접 구현해 보겠습니다.

신경망의 기본 구성 요소

신경망은 여러 구성 요소로 이루어져 있으며, 대표적인 요소는 다음과 같습니다.

  • 입력층(Input Layer), x
  • 임의의 개수를 가지는 은닉층(Hidden Layers)
  • 출력층(Output Layer), ŷ
  • 각 층 사이를 연결하는 가중치(W)와 편향(b)의 집합
  • 각 은닉층에 적용되는 활성화 함수(Activation Function), σ

아래 다이어그램은 2계층 신경망을 나타냅니다. 참고로 신경망의 계층 수를 셀 때는 일반적으로 입력층을 제외합니다.

파이썬으로 배우는 단일 뉴런 신경망의 기본 원리

다이어그램에서 원은 뉴런(neuron)을 의미하고, 선은 시냅스(synapse)를 나타냅니다. 시냅스는 입력값과 가중치를 곱하는 역할을 하며, 가중치는 뉴런 간 연결의 '강도'라고 생각할 수 있습니다. 결국 가중치가 신경망의 최종 출력을 결정짓는 핵심 요소입니다.

순전파(Feed Forward) 신경망의 작동 방식

간단한 피드포워드(feed forward) 신경망이 작동하는 과정을 단계별로 정리하면 다음과 같습니다.

  1. 입력을 행렬(2차원 숫자 배열) 형태로 받습니다.
  2. 입력값에 가중치 집합을 곱합니다.
  3. 활성화 함수를 적용합니다.
  4. 출력값을 반환합니다.
  5. 데이터가 담고 있는 목표 출력값과 예측 출력값 사이의 차이인 오차(error)를 계산합니다.
  6. 오차에 따라 가중치를 약간씩 조정합니다.

학습을 위해서는 이 과정을 1,000회 이상 반복하며, 더 많은 데이터로 학습할수록 출력 결과의 정확도가 높아집니다.

예제 데이터

예를 들어 '공부한 시간'과 '수면 시간'을 입력으로, '시험 점수'를 출력으로 삼는 모델을 생각해 볼 수 있습니다.

공부 시간, 수면 시간 (입력) / 시험 점수 (출력)
2, 9 → 92
1, 5 → 86
3, 6 → 89
4, 8 → ?

모델은 앞의 세 데이터를 학습하여 네 번째 경우의 시험 점수를 예측하게 됩니다.

파이썬 예제 코드

이제 NumPy만을 사용해 단일 뉴런 신경망을 구현한 예제 코드를 살펴보겠습니다.

from numpy import exp, array, random, dot, tanh

class my_network():
    def __init__(self):
        random.seed(1)
        # 3x1 가중치 행렬
        self.weight_matrix = 2 * random.random((3, 1)) - 1

    def my_tanh(self, x):
        return tanh(x)

    def my_tanh_derivative(self, x):
        return 1.0 - tanh(x) ** 2

    # 순전파(forward propagation)
    def my_forward_propagation(self, inputs):
        return self.my_tanh(dot(inputs, self.weight_matrix))

    # 신경망 학습
    def train(self, train_inputs, train_outputs, num_train_iterations):
        for iteration in range(num_train_iterations):
            output = self.my_forward_propagation(train_inputs)
            # 출력 오차 계산
            error = train_outputs - output
            adjustment = dot(train_inputs.T, error * self.my_tanh_derivative(output))
            # 가중치 행렬 조정
            self.weight_matrix += adjustment

# 드라이버 코드
if __name__ == "__main__":
    my_neural = my_network()
    print('학습 시작 시 무작위 가중치')
    print(my_neural.weight_matrix)

    train_inputs = array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
    train_outputs = array([[0, 1, 1, 0]]).T

    my_neural.train(train_inputs, train_outputs, 10000)
    print('학습 후 새로운 가중치')
    print(my_neural.weight_matrix)

    # 새로운 상황으로 신경망 테스트
    print("새로운 예제로 네트워크 테스트 ->")
    print(my_neural.my_forward_propagation(array([1, 0, 0])))

실행 결과

Random weights when training has started
[[-0.16595599]
[ 0.44064899]
[-0.99977125]]
Displaying new weights after training
[[5.39428067]
[0.19482422]
[0.34317086]]
Testing network on new examples ->
[0.99995873]

결과 해석

실행 결과를 보면, 학습이 시작될 때는 -1과 1 사이의 무작위 값으로 초기화된 가중치가 사용됩니다. 10,000번의 반복 학습을 거친 후에는 가중치가 [[5.39428067], [0.19482422], [0.34317086]]로 조정된 것을 확인할 수 있습니다.

마지막으로 새로운 입력 [1, 0, 0]을 넣어 테스트한 결과 약 0.99995의 출력이 반환되었습니다. 이는 학습 데이터의 패턴을 신경망이 잘 학습했음을 의미하며, tanh 활성화 함수의 특성상 출력값이 1에 가까울수록 해당 클래스에 속할 가능성이 높다고 해석할 수 있습니다.

이처럼 단 하나의 뉴런만으로도 간단한 패턴 학습이 가능합니다. 이 기본 개념을 바탕으로 은닉층을 추가하고 뉴런 수를 늘려가면, 이미지 인식이나 자연어 처리 같은 복잡한 딥러닝 모델로 발전시킬 수 있습니다.