그 동안 일이 있어서... 진짜 오랫만에 새로운 글을 쓰게 되었습니다. 어느정도 상황이 정리되어서 마음을 다잡고 또 글을 작성해 보겠습니다. 이번에는 주제를 인공신경망(artificial neural network, ANN)에 대해서 다루어 보겠습니다. 어마어마하게 방대하고 어려운 부분이라고 생각이 됩니다. 왜냐하면 이게바로 Deep Learning에 대한 시작이고, 기계학습이라고 불리우는 Machine Learning에서 벗어나는 첫단추이기 때문입니다.
얼마나 많은 횟수로 글이 작성될지 모르겠지만, 주저리주저리 글로 혹은 실제 Python 코드로 그것도 아니면 그림으로 열심히 풀어보겠습니다. 그렇다면 첫 단추로 인간의 뉴런(Neuron)과 그 형상을 빌려와 구현된 최초 알고리즘인 퍼셉트론(Perception)에 대해서 알아보겠습니다. 퍼셉트론 부분은 아래의 2단계로 구성됩니다.
- 뉴런과 비교 및 SLP(Single Layer Perceptron) 구현
- MLP(Multi Layer Perceptron)의 등장배경 및 구현
1. Perceptron 이란?
우선 퍼셉트론(Perception)이 뭔지 알아보겠습니다. 이를 위해서는 인간의 뉴런(Neuron)부터 알아봐야 하는데... 인간의 뇌에는 전기적인 방법으로 신호를 전달하는 신경계를 구성하는 세포가 있는데 이것이 뉴런입니다. 뉴런은 상호간에 시냅스라는 구조로 신호를 주고받으면서 정보를 전달합니다. 이런 뉴런은 인간의 뇌에 엄청나게 많이 구성되어 있습니다.
퍼셉트론은 뉴런의 형상을 빌려와 구현된 최초 알고리즘으로 Input과 Output의 구조로 설명이 가능합니다. 구조적으로 여러개의 Input이 가능하고, 1개의 Output이 존재합니다. 또한, 이 output은 다른 퍼셉트론의 input이 될 수 있습니다. 참으로 간단하지 않나요??
퍼셉트론의 개념을 그림으로 표현하면 위의 그림과 같습니다. Node라고 정의한 동그란 모형은 인간의 뉴런이라고 생각하면 됩니다. 외부의 자극 즉 input이 들어오면 Node에서는 각 input에 대해서 가중치를 적용하여 연산하고, 특정 조건에 따라서 Y에 적절한 답을 전달하게 됩니다. Y의 경우 임계치에 따라서 0, 1에 대한 전기적인 output을 발생시킵니다.
이를 수학적으로 정리하면, Y = X1*W1 + X2*W2 (단, Y>임계치 이면 1 / Y<=임계치 이면 0) 입니다. 이 수학적인 개념까지 적용해서 도식화를 해보겠습니다. 그렇게되면 앞으로 우리가 다룰 퍼셉트론의 모형은 아래와 같습니다.
Node는 SUM과 AF(Activation Function)으로 구성되며, 이는 수학식에서 합과 임계치로 판단되는 활성화함수를 단순히 그림으로 표현한 것입니다.
이게 퍼셉트론에 대한 간단한 개념 정리입니다. 이를 통해서 추후에는 ANN(인공신경망)까지 발전하게 되는 것 입니다. 최초에는 이 퍼셉트론을 2개 계층으로 쌓아서 구성하면, 그 어떠한 것도 구현하여 답을 구할 수 있다고 했습니다. 뭐 따지고 보면 이론적으로는 컴퓨터도 만들수가 있겠네요. 이것이 왜 가능한지 아래에서 살펴보겠습니다.
2. SLP 구현
위에서 알아본 퍼셉트론을 1개 사용해서 무언가는 구현하는 것을 Single Layer Perceptron(단층 퍼셉트론 : SLP)라고 합니다. 이것을 가지고 한번 Computer의 기초를 만들어 볼 수 있습니다. 컴퓨터구조론에는 논리게이트(Logic gate)라는 것이 존재합니다. 논리게이트에는 우리에게 익숙한 and gate, or gate, nand gate, xor gate같은 것들이 있습니다. 결국 이런 것들을 조합해서 중앙처리장치도 만들고 결국 컴퓨터도 만들게 되는 것입니다.
어라 그런데 갑자기 퍼셉트론 이야기하다가 왜 논리게이트를 이야기하는지 궁금하시죠?? 바로 이런 논리게이트를 퍼셉트론으로 구현이 가능하기 때문입니다. 결국 위에서 말한 퍼셉트로으로 컴퓨터를 만드는게 역설적으로 가능하게 되는 것 입니다.
그럼 한번 SLP구조를 가지고 논리게이트를 만들어 볼까요??
[AND Gate]
and 는 아래와 같이 동작합니다. 입력되는 2개의 값이 모두 1일때만 결과가 1이 나오고, 입력값 중 1개 이상이 0일 경우에는 그 결과는 0이 됩니다. 이 gate의 표현되는 모양과 진리표는 아래와 같습니다.
X1, X2, Y는 주어졌기 때문에, 위의 퍼셉트론에서 남은 인자 W1, W2에 대해서 정해지면 완성이 되게 됩니다. 아참 임계치도 정해야 겠네요~!! 실제로 Python으로 구현하려고 하기 때문에, 논리적으로 만들어 보겠습니다. AND Gate의 W1, W2와 임계치의 관계를 아래와 같이 정리가 가능합니다.
- W1 == W2 이면, W1 < 임계치 < W1+W2 사이의 값
- W1 != W2 이면, max(W1, W2) < 임계치 < W1+W2 사이의 값
여기서 W1과 W2는 각 input에 대한 퍼셉트론의 가중치(weight)이며, 임계치는 결과에 대한 판단을 위한 임계치(bias)가 됩니다. 위에서의 임계치와 output의 관계를 정의해보면...
- y = 0 if, 퍼셉트론의 sum 결과가 임계치보다 작거나 같으면
- y = 1 if, 퍼셉트론의 sum 결과가 임계치보다 크면
그렇다면, 코드로 확인해 보겠습니다.
import numpy as np
class LogicGate:
def __init__(self, w1, w2, b):
self.w1 = w1
self.w2 = w2
self.b = b
def andgate(self, x1, x2):
x = np.array([x1, x2])
w = np.array([self.w1, self.w2])
y = np.dot(x, w.T) - self.b
if y > 0 :
return 1
else:
return 0
클래스를 하나 생성하고, 이때 생성자로 인자를 weight와 bias를 받습니다. 이는 각 각 가중치와 임계치의 역할을 하게 됩니다. 그리고, andgate를 위한 함수를 하나 생성합니다. 향후 신경망에서 사용되는 기본적은 연산은 matrix에 대한 연산이 되기 때문에 강제로 matrix로 바꾸어 줍니다.
입력하는 x에 대한 집합, w에 대한 집합은 모두 np.array를 통해서 1x2 배열로 만들어 주고, np.dot을 통해서 행렬곱을 수행합니다. 주의할 점은 제작시 x와 w의 행렬 모양이 1x2로 동일하기 때문에 w를 Transform을 통해서 2x1로 만들어 줍니다.
추가적으로 bias에 대해서도 판단시 output이 임계치가 아닌 0을 기준으로 판단하게 하기 위해서 sum쪽으로 옮겨 줍니다. 결국 y의 판단자는 x * w - b가 0과 어떤 관계인지를 판단하는 코드가 되겠습니다. 그럼 결과를 확인해 보면....
logic = LogicGate(1, 1, 1.7)
print(logic.andgate(0,0))
print(logic.andgate(0,1))
print(logic.andgate(1,0))
print(logic.andgate(1,1))
=============================
0
0
0
1
임계치도 위의 조건에 맞게 설정하여 생성자에 넣어주고, andgate에 input을 설정하여 출력해주면... AND gate진리표와 동일한 결과가 나오게 됩니다.
[OR Gate]
and 는 아래와 같이 동작합니다. 입력되는 2개의 값이 모두 0일때만 결과가 0이 나오고, 입력값 중 1개 이상이 1일 경우에는 그 결과는 1이 됩니다. 이 gate의 표현되는 모양과 진리표는 아래와 같습니다.
OR Gate의 W1, W2와 임계치의 관계를 아래와 같이 정리가 가능합니다.
- W1 == W2 이면, 0 < 임계치 < W1 사이의 값
- W1 != W2 이면, 0 < 임계치 < min(W1, W2) 사이의 값
여기서 W1과 W2는 각 input에 대한 퍼셉트론의 가중치(weight)이며, 임계치는 결과에 대한 판단을 위한 임계치(bias)가 됩니다. 위에서의 임계치와 output의 관계를 정의해보면...
- y = 0 if, 퍼셉트론의 sum 결과가 임계치보다 작거나 같으면
- y = 1 if, 퍼셉트론의 sum 결과가 임계치보다 크면
그렇다면, 코드로 확인해 보겠습니다.
import numpy as np
class LogicGate:
def __init__(self, w1, w2, b):
self.w1 = w1
self.w2 = w2
self.b = b
def andgate(self, x1, x2):
x = np.array([x1, x2])
w = np.array([self.w1, self.w2])
y = np.dot(x, w.T) - self.b
if y > 0 :
return 1
else:
return 0
어차피 각 gate의 코드는 동일합니다. 로직상 달라지는 부분은 input에 대한 가중치와 정해진 가중치에 대해서 임계치로 설정한 값에 gate가 동작하기 때문입니다.
logic = LogicGate(1, 1, 0.3)
print(logic.orgate(0,0))
print(logic.orgate(0,1))
print(logic.orgate(1,0))
print(logic.orgate(1,1))
==============================
0
1
1
1
임계치도 위의 조건에 맞게 설정하여 생성자에 넣어주고, orgate에 input을 설정하여 출력해주면... OR gate진리표와 동일한 결과가 나오게 됩니다.
[NAND Gate]
nand 는 아래와 같이 동작합니다. 입력되는 2개의 값이 모두 1일때만 결과가 0이 나오고, 입력값 중 1개 이상이 0일 경우에는 그 결과는 1이 됩니다. 이 gate의 표현되는 모양과 진리표는 아래와 같습니다.
NAND Gate의 W1, W2와 임계치의 관계를 아래와 같이 정리가 가능합니다. (AND Gate와 동일하죠...)
- W1 == W2 이면, W1 < 임계치 < W1+W2 사이의 값
- W1 != W2 이면, max(W1, W2) < 임계치 < W1+W2 사이의 값
여기서 W1과 W2는 각 input에 대한 퍼셉트론의 가중치(weight)이며, 임계치는 결과에 대한 판단을 위한 임계치(bias)가 됩니다. 위에서의 임계치와 output의 관계를 정의해보면... AND Gate와 결과를 1 -> 0, 0 -> 1로 바꿔줍니다.
- y = 1 if, 퍼셉트론의 sum 결과가 임계치보다 작거나 같으면
- y = 0 if, 퍼셉트론의 sum 결과가 임계치보다 크면
그렇다면, 코드로 확인해 보겠습니다.
import numpy as np
class LogicGate:
def __init__(self, w1, w2, b):
self.w1 = w1
self.w2 = w2
self.b = b
def nandgate(self, x1, x2):
x = np.array([x1, x2])
w = np.array([self.w1, self.w2])
y = np.dot(x, w.T) - self.b
if y > 0 :
return 0
else:
return 1
logic = LogicGate(1, 1, 1.7)
print(logic.nandgate(0,0))
print(logic.nandgate(0,1))
print(logic.nandgate(1,0))
print(logic.nandgate(1,1))
=============================
1
1
1
0
임계치도 위의 조건에 맞게 설정하여 생성자에 넣어주고, orgate에 input을 설정하여 출력해주면... NAND gate진리표와 동일한 결과가 나오게 됩니다.
문제점....
이렇게 퍼셉트론에 대해서 And, Or, Nand gate에 대해서 코드로 구현을 해보았습니다. 컴퓨터도 이런 논리회로를 통해서 만들어졌기 때문에, 우리도 컴퓨터를 만들수가 있겠죠?? 하지만 여기서 퍼셉트론의... 정확히 말하자만 Single Layer Perceptron의 치명적인 문제가 나오게 됩니다.
이 문제때문에 수년간 ANN의 발전이 지연됬다고 해도 과언이 아닙니다. 바로 XOR gate를 구현하는 문제입니다. 이는 다음에 알아보겠습니다.
-Ayotera Lab-
댓글