본문 바로가기

Study/AI

[모두의 딥러닝](Pytorch) #4. XOR 문제에서 발견한 퍼셉트론의 한계 + 다층 퍼셉트론(신경망)을 통한 해결

반응형

'모두의 딥러닝' 개정 2판 + 세종대학교 최유경 교수님의 인공지능(2021)으로 공부한 글입니다.

 

# 신경망의 이해

# 6장: 퍼셉트론(perceptron)

입력 값이 일정한 수준을 넘으면 참을, 그렇지 않으면 거짓을 내보내는 회로는 뇌의 뉴런과 비슷한 매커니즘을 갖고 있습니다. 뉴런 또한 신경 말단에서 자극을 받아 생기는 전위가 임계 값을 넘으면 다음 뉴런으로 신호를 전달하고, 그렇지 않으면 아무것도 하지 않기 때문입니다. 뉴런은 서로 긴밀히 연결되어서 인간이 '생각'할 수 있게 합니다. 그렇다면 컴퓨터에도 뉴런과 비슷한 매커니즘을 도입하면 인공적으로 '생각'하게 만들 수도 있을 것 같습니다.

이런 아이디어를 바탕으로 출발한 연구가 바로 인공 신경망(Artificial Neural Network, 신경망) 연구입니다. 뉴런-뉴런 연결을 여러 층의 퍼셉트론-퍼셉트론 연결로 치환해봅시다. 퍼셉트론(perceptron)은 신경망을 이루는 가장 기본 단위로, 입력 값과 활성화 함수를 사용해서 출력 값을 다음 단계로 넘기는 역할을 합니다. 선형분류기, Feedforward network, Forward Propagation이라고도 합니다. 신경망의 기본 구조는 여러 층의 퍼셉트론을 서로 연결시키고 복잡하게 조합해서 주어진 입력 값에 대한 판단을 하도록 하는 것입니다.

뉴런 vs. 퍼셉트론 (출처: 모두의 딥러닝)
f라는 활성화함수를 거쳐서 0또는 1로 출력된다.

# 6.1 가중치, 가중합, 바이어스, 활성화 함수

앞서서 선형 회귀와 로지스틱 회귀를 해보면서 사용했던 기울기 a와 y 절편 b 변수를 기억하실 겁니다. 이제 이 변수들의 이름을 좀 더 딥러닝 영역에서 정의해봅시다. 

퍼셉트론에서는 이제부터 a는 w라는 가중치(weight)로, b는 바이어스(bias, 편향)로 불리게 될 것입니다. 

그리고 입력 값(x)과 가중치(w)의 곱을 모두 더하고 거기에 바이어스(b)를 더한 값을 가중합(weighted sum)이라고 부릅니다. 이 가중합의 결과를 활성화 함수(activation function)가 판단해서 0이나 1을 출력합니다. 이 활성화 함수의 예로는 로지스틱 회귀에서 다뤘던 시그모이드 함수가 있습니다.

 

# 6.2 퍼셉트론의 과제

앞서 다룬 선형 회귀와 로지스틱 회귀를 통해서 머신러닝이 결국 선 또는 2차원 평면을 그리는 작업이라는 것을 배웠고, 비슷한 개념인 퍼셉트론 역시 선을 긋는 작업이라고 할 수 있습니다. 그러나 실제로는 선을 긋는 것으로는 해결할 수 없는 상황이 있습니다.

 

# 6.3 XOR 문제

컴퓨터에게 주어지는 데이터는 binary data입니다. 그리고 컴퓨터는 로직의 집합체이기 때문에 이 데이터를 컴퓨터가 처리하는 가장 기본적인 방식은 논리연산입니다. 따라서 인공지능을 구현하기 위해서는 컴퓨터에서 논리연산을 계산할 수 있어야 하는 것입니다. 때문에 과학자들은 기존에 갖고 있던 선형모델로 AND/OR/XOR 같은 논리연산을 처리하는 방법을 연구했습니다.

이때 XOR(exclusive OR) 문제를 통해서 퍼셉트론의 한계를 알 수 있습니다.

여기서 잠깐! 이산수학에서 배운 개념을 되짚고 넘어가볼까요?

 

⬛ 논리 회로(logit circuit)

논리 연산을 통해 전기 장치를 제어하는 통로로, 컴퓨터 같은 전기 장치를 작동하게 만드는 기초 부품입니다. 게이트(gate)는 논리 회로의 기초 구성 요소입니다. 0 또는 1이라는 두 가지의 디지털 값 입력이 들어가면, 불(bool) 연산을 통해 하나의 값을 출력해냅니다. 이런 게이트가 모여 논리 회로가 구성됩니다.

 

기본 게이트의 종류는 4가지가 있습니다. 곧, 논리연산자의 종류죠. AND, OR, NOT, XOR 게이트가 있고 NOT 게이트를 제외하고 2개의 값을 입력으로 받습니다. 나머지 연산들은 보기만 해도 감이 올텐데, XOR 게이트는 좀 생소합니다. XOR 연산자는 배타적 논리합이라고도 불립니다. 입력 값이 같지 않을 때에 1을 출력합니다. 그러니까 입력 값들이 서로 배타적일 경우에만 1을 출력하는 것입니다.

출처: 포프 소프트웨어 수학

그 외에 NAND, NOR, XNOR 게이트 등이 있습니다. NAND과 NOR 게이트만 있으면 다른 모든 게이트를 구현할 수 있기 때문에 많이 사용되고, 이 둘을 따로 범용 게이트(universal gate)라고 부릅니다.

NAND 게이트는 AND 게이트와 NOT 게이트가 결합된 게이트로, 두 입력값을 (불)곱한 결과의 보수를 결괏값으로 출력합니다. 간단하게는 AND 게이트의 반대되는 값(Negative And)을 출력한다고도 설명할 수 있습니다. NOR 게이트는 OR 게이트와 NOT 게이트가 결합된 게이트로, 두 입력값을 (불)합한 결과의 보수를 결괏값으로 출력합니다. 

출처: 포프 소프트웨어 수학

 

XOR 문제는 이렇게 논리 회로에 등장하는 개념입니다. AND 게이트는 입력값이 둘 다 1일 때 결괏값이 1로 출력됩니다. OR 게이트는 입력값 중 하나라도 1이면 결괏값이 1로 출력됩니다. XOR 게이트는 두 입력값이 다를 때, 즉 둘 중 하나만 1일 때 결괏값으로 1이 출력됩니다. XOR 게이트는 NAND 게이트, OR 게이트, AND 게이트를 결합하여 나타낼 수 있습니다. 입력값의 NAND 게이트 결과와 OR 게이트 결과에 AND을 취하면 바로 XOR 연산의 결과와 같아집니다.

 

그럼 위의 진리표를 그래프로 좌표 평면에 나타내 볼까요? 결괏값이 0이면 흰 점, 1이면 검은 점으로 나타내보겠습니다. 

출처: 모두의 딥러닝

그럼 위와 같은 그래프가 그려집니다. 임의의 직선을 그었을 때, AND와 OR 게이트는 검은 점과 흰 점을 구분할 수 있습니다. 즉, 선형으로 구분 가능하여 linearly separable합니다. 그러나 XOR 게이트의 경우, 어떤 선을 긋더라도 구분할 수 없는 문제가 발생합니다.

 

이 문제는 MIT 마빈 민스키(Marvin Minsky) 교수가 1969년도 발표한 퍼셉트론즈(Perceptrons)라는 논문에서 소개되었습니다. 인공지능이 이런 간단한 XOR 문제조차 해결하지 못 한다는 점에서 인공지능 연구는 긴 침체기를 겪게 됩니다.

 

그러던 중 이 문제를 해결한 돌파구가 바로 다층 퍼셉트론(multilayer perceptron) 개념입니다.

 

# 7장: 다층 퍼셉트론(multilayer perceptron)

이 XOR 문제의 한계를 극복하는 방법은 바로 좌표 평면 자체에 변화를 주는 것입니다. 

출처: 모두의 딥러닝

그러기 위해서는 두 개의 퍼셉트론을 한 번에 계산할 수 있어야 합니다. 그리고 숨어있는 층인 은닉층(hidden layer)을 만들어서 이를 가능하게 할 수 있습니다.

출처: 모두의 딥러닝

입력층과 은닉층의 그래프를 집어넣어 보면 그림과 같이 좌표 평면이 왜곡됩니다.

출처: 모두의 딥러닝

그림의 왼쪽 그림에서는 어떤 직선도 파란색 영역과 빨간색 영역을 구분할 수 없지만 오른쪽 직선에서는 직선으로 영역을 구분할 수 있게 됩니다.

 

# 7.1 다층 퍼셉트론의 설계

출처: 모두의 딥러닝

위 그림은 다층 퍼셉트론이 입력층과 출력층 사이에 숨어있는 은닉층을 만드는 것을 도식화한 것입니다. 

(다시 한 번 퍼셉트론이란? 퍼셉트론은 신경망을 이루는 가장 기본 단위로, 입력 값과 활성화 함수를 사용해서 출력 값을 다음 단계로 넘겨주는 역할)

가운데 점선으로 둘러싸인 부분이 은닉층입니다. 가운데 숨어있는 은닉층으로 퍼셉트론이 각각 자신의 가중치인 w와 바이어스인 b 값을 보내고, 이 은닉층에서 모인 값이 한 번 더 시그모이드 함수(σ)를 이용해 최종 값으로 결과를 보냅니다. 은닉층에 모이는 중간 정거장을 노드(node)라고 하고 기호로는 n으로 표시합니다. 각 노드의 값은 각각 단일 퍼셉트론의 값과 같습니다.

위 두 식의 결괏값이 출력층으로 보내지고, 출력층에서도 역시 시그모이드 함수를 통해 y 값이 정해집니다.

위의 식을 통해 출력값 y가 계산됩니다.

 

각각의 가중치(w)와 바이어스(b)의 값을 정해주어야 합니다. 2차원 배열로 표시하고, 은닉층을 포함해 총 가중치 6개와 바이어스 3개를 정해줘야 합니다.

 

# 7.2 XOR 문제의 해결

XOR 게이트를 구현하려면, 앞서 설명했던 것과 같이 NAND 게이트와 OR 게이트를 구현한 후에 두 결과에 AND를 취하면 됩니다.

NAND 게이트와 OR 게이트, AND 게이트를 구현하기 위해서는 적절하게 가중치를 설정해주어야 합니다. 나중에는 가중치와 편향을 설정하는 과정을 자동화할 수 있으나, 우선은 널리 알려진 조합으로 가중치와 바이어스 값을 설정하고 실험해보겠습니다.

다음과 같이 가중치 w와 바이어스 b 값을 정하고 이를 이용하여 XOR 문제를 해결해봅시다. 

출처: 모두의 딥러닝
출처: 모두의 딥러닝

계산을 해보면 우리가 원하는 값과 비슷한 값이 나오게 됩니다. 이렇게 다층 퍼셉트론을 사용하면 XOR 문제를 해결할 수 있습니다.

다만 유의해야 할 점이 있습니다. 이번에는 변수를 자동으로 최적화하지 않고 이미 알고 있던 값을 사용했다는 점입니다. 이렇게 인위적으로 파라미터 값을 설정하여 (순전파)Forward Propagation을 하면 XOR 로직을 구현할 수 있지만 실제로 자동화하기 위해서, 즉 머신러닝을 돌리기 위해서는 새로운 최적화 알고리즘이 필요합니다. 바로 오차 역전파입니다. 앞서 배운 경사하강법과 대응되는 MLP에서의 최적화 알고리즘이죠. 다음 포스트에서는 이 오차 역전파에 대해 다루겠습니다.

 

# 7.3 코딩으로 구현하기: MLP를 통한 XOR 문제 해결

그럼 위의 XOR 게이트를 함수로 구현하여, 함수에 정해둔 가중치와 편향을 넣어 계산해봅시다.

 

import numpy as np

w11 = np.array([-2,-2])
w12 = np.array([2,2])
w2 = np.array([1,1])
b1 = 3
b2 = -1
b3 = -1

numpy 모듈을 import 하고 정해둔 가중치와 편향을 변수에 대입합니다.

 

def MLP(x,w,b):
  y = np.sum(w*x)+b
  if y<=0: # y 값이 0 이하면 return 0
    return 0
  else:	# y 값이 0 넘으면 return 1
    return 1

그리고 MLP(Multilayer Perceptron)라는 다층 퍼셉트론 함수를 정의하고 계산 결과에 따라 0 또는 1을 return하게 합니다. (기준치는 왜 0일까요?)

 

# NAND 게이트
def NAND(x1,x2):
  return MLP(np.array([x1,x2]),w11,b1)

# OR 게이트
def OR(x1,x2):
  return MLP(np.array([x1,x2]),w12,b2)

# AND 게이트
def AND(x1,x2):
  return MLP(np.array([x1,x2]),w2,b3)

# XOR 게이트
def XOR(x1,x2):
  return AND(NAND(x1,x2),OR(x1,x2))

그리고 각 게이트의 정의에 따라서 적절한 가중치와 편향 인자를 MLP 함수에 집어넣는 함수를 만듭니다.

 

if __name__=='__main__':
  for x in [(0,0),(1,0),(0,1),(1,1)]:
    y = XOR(x[0],x[1])
    print("입력 값: "+ str(x)+ " 출력 값: "+str(y))

반복문으로 입력값을 넣어 최종 값을 출력합니다. 그러면 아래와 같은 값이 출력됩니다.

이렇게 은닉층을 여러 개 쌓아올려 XOR과 같은 문제를 해결하는 과정이 사람의 신경망을 닮았다고 해서 이런 방법을 '인공 신경망'이라고 부르고, 간단히 신경망이라고 부릅니다.

 

# (Pytorch) 7.4.1 코딩으로 구현하기: 단일 퍼셉트론

작성한 코드는 최유경 교수님의 인공지능 강의 코드의 사본입니다.

 

https://colab.research.google.com/drive/1rcDiVsaqIv6Sgl-lSOGE5Z_j6cihCd6I#scrollTo=BuHSQSrbhkpN

 

Google Colaboratory Notebook

Run, share, and edit Python notebooks

colab.research.google.com

단일 퍼셉트론이기 때문에 아무리 파라미터를 변경해도 Accuracy가 0.5인 것을 볼 수 있습니다.

 

# (Pytorch) 7.4.2 코딩으로 구현하기: 다층 퍼셉트론(MLP)

작성한 코드는 최유경 교수님의 인공지능 강의 코드의 사본입니다.

 

https://colab.research.google.com/drive/1di82aH5y6MAE7SYlNqaPYg6KUpLhM98y#scrollTo=Ap0SGc0bl0WS

 

Google Colaboratory Notebook

Run, share, and edit Python notebooks

colab.research.google.com

Accuracy가 1로 나온 것을 보아 성공적으로 학습되었음을 알 수 있습니다.

# (Pytorch) 7.4.3 코딩으로 구현하기: 더 깊고 넓은 다층 퍼셉트론(MLP)

작성한 코드는 최유경 교수님의 인공지능 강의 코드의 사본입니다.

 

https://colab.research.google.com/drive/1Vo6vmfj8nR-wvD7UsQuxd_lVP_h8OEZa#scrollTo=Px1iYcB9lq-I

 

Google Colaboratory Notebook

Run, share, and edit Python notebooks

colab.research.google.com

 

깊이는 은닉층(hidden layer)의 수를 의미합니다. 은닉층이 많을수록 깊다고 합니다.

넓이는 feature의 수를 의미합니다. feature가 많을수록 넓다고 합니다.

위의 단순한 MLP 모델보다 최종 loss도 적고 평가한 Hypothesis의 error도 적은 것을 알 수 있습니다.

반응형