퍼셉트론을 사용한 and, or, xor 데이터 분류

딥러닝 역사에서 빼놓을 수 없는 첫 번째 겨울을 보내게 만든 XOR 문제.
지금 보면 어이없을 정도로 간단한 문제로 인해 10년 이상의 겨울을 보내야 했다.

아래 코드는 신경세포 하나를 의미하는 퍼셉트론(perceptron)을 사용해서
and, or, xor 문제를 해결하고 있다.
weights와 bias에 따른 결과를 보여주는 것은 너무 당연한데
놀랍게도 함수를 사용할 때 더 좋은 결과가 나올 수 있다는 사실에 놀랐다.
함수를 전달한다는 생각은 전혀 하지 못했다.

*퍼셉트론
n개의 이진수(binary)가 하나의 뉴런을 통과해서
가중합이 0보다 크면 활성화되는 가장 단순한 형태의 신경망 구조.


이번 내용은 "밑바닥부터 시작하는 데이터 과학"에 나오는 18장의 신경망을 참고했다.
사실 참고했다기 보다는 코드를 조금 내맘대로 수정했을 뿐이다.

밑바닥부터 시작하는 데이터 과학
국내도서
저자 : 조엘 그루스 / 하성주,박은정,김한결역
출판 : 인사이트 2016.06.03
상세보기


import matplotlib.pyplot as plt

def step_function(x):
''' 입력값이 양수와 0인 경우에 1, 음수라면 0 반환 '''
return 1 if x >= 0 else 0

def perceptron_output(weights, bias, x):
''' weights와 x는 요소 2개를 갖고 있는 리스트.
단순히 wx+b를 step_function에 전달한 결과 반환.
단순 곱셈과 덧셈이기 때문에 weights와 bias에 따라 결과가 달라진다는 것을 쉽게 알 수 있다. '''
return step_function(weights[0]*x[0] + weights[1]*x[1] + bias)

def logit_perceptron(weights, bias):
''' 데이터가 달라지면 결과도 달라진다는 것을 보여준다.
미리 정의된 4가지 데이터에 대해 검증. 활성화되었다면 동그라미, 비활성이라면 x 출력. '''
for x in ([0, 0], [0, 1], [1, 0], [1, 1]):
logit = 'ro' if perceptron_output(weights, bias, x) else 'rx'
plt.plot(x[0], x[1], logit, markersize=10)

# 위와 같은 코드.
# for x0 in [0, 1]:
# for x1 in [0, 1]:
# logit = 'ro' if perceptron_output(weights, bias, [x0, x1]) else 'rx'
# plt.plot(x0, x1, logit, markersize=10)

def logit_perceptron_by_func(func):
''' 전달된 코드(함수)에 따라 결과가 달라질 수 있다는 것을 보여준다.
함수 버전에서는 weights와 bias를 사용하지 않는다. '''
for x in ([0, 0], [0, 1], [1, 0], [1, 1]):
logit = 'ro' if func(x) else 'rx'
plt.plot(x[0], x[1], logit, markersize=10)

def set_common(title, plot_index):
plt.subplot(23*10 + plot_index) # 5 --> 235
plt.title(title)
plt.xlim(-0.5, 1.5) # 범위 설정이 없으면, 출력이 경계에 달라 붙는다.
plt.ylim(-0.5, 1.5)


# and, or은 가능. xor은 불가능.
set_common('and : data', 1)
logit_perceptron([2, 2], -3)
set_common('or : data', 2)
logit_perceptron([2, 2], -1)

# and, or, xor 모두 가능.
set_common('and : func', 4)
logit_perceptron_by_func(max)
set_common('or : func', 5)
logit_perceptron_by_func(min)
set_common('xor : func', 6)
logit_perceptron_by_func(lambda x: 0 if x[0] == x[1] else 1)

plt.show()