명제란?
(1) 명제 : 그 내용이 참인지 거짓인지를 명확하게 판별할 수 있는 문장이나 식
① 참인 명제 : 내용이 항상 옳은 명제
② 거짓인 명제 : 내용에 대하여 한 가지라도 옳지 않은 경우가 있는 명제
출처:네이버 지식백과 '명제
'5는 3보다 크다.' 와 '5는 3보다 작다.'라는 문장은 둘 다 명제지만,
전자는 참인 명제, 후자는 거짓인 명제이다.
하지만 '나는 파이썬보다는 똑똑하다.'같은 주관적인(?) 문장은 명제가 될 수 없다.
고등학생 때는 p 가 '총'을 쏴서 q가 '피'를 흘린다고 외웠지만
우리는 ..얼은이니까..!
똑같이 외워주고 이와 더불어서
p 집합이 q 집합의 부분집합임을 잘 알아두도록 하자.
| p | q | p->q |
|---|---|---|
| T | T | T |
| F | T | T |
| F | F | T |
| T | F | F |
굵은 글씨 부분이 많이들 헷갈리는 부분인 것 같은데,
이건 특정 명제를 가져와서 부정을 해보기보다는 집합의 개념으로 명제를 이해하는게 깔끔할 것 같다.
p가 거짓이라면 ~p의 집합 내에는 원소가 아무것도 없는 공집합일 것이고,
공집합은 모든 집합의 부분집합이므로 모든 q에 대해 부분집합,
즉 모든 q에 대한 충분조건이 될 수 있는 것이다.
집합과 명제, 논리는 철학책 좀 보거나 어릴때 '논리야, 놀자!'책을 한번이라도 봤다면
개념 이해가 엄청나게 어렵진 않을 것이다.
하지만.. 왜 코드로 구현하려니 머리가 터질 것 같은지..?
집합 {0, 1}과 NOT, AND, OR연산으로 구성되는 식과 그에 대한 연산 0 = True 1 = False
| 논리 | 논리식 | 논리회로 |
|---|---|---|
| NOT | \bar{A} | ![]() |
| OR | A + B | ![]() |
| AND | A\cdot B | ![]() |
| XOR | A \oplus B | ![]() |
| NOR | \bar{A + B} | ![]() |
| NAND | \bar{A \cdot B} | ![]() |
이제 코드를 확인해보자 ..!
아래 코드에서는 numpy를 import한 뒤에
인공신경망의 마지막 layer에서 처리해주는 연산인 시그모이드 함수를 정의해준다.
import numpy as np
def activation(z):
return 1 / (1+np.exp(-z))
AND 연산은 x, y 모두 True 여야 True 값을 결과로 얻을 수 있는 연산이고,
표로 시각화하면 다음과 같다.
| x | y | result |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
이 때 wx, wy, bias 에 넣어준 값은 weight value,
즉 각 레이어에서 입력된 변수에 곱해주는 가중치로 임의의 값인데,
위 표와 같이 result 값을 얻을 수 있다면 어떤 상수가 들어가든 상관 없다
def AND(x,y):
wx = 50
wy = 50
bias = -60
if activation((wx*x + wy*y + bias)) < 0.5:
return 0
else:
return 1
print(f"x=0, y=0: {AND(0,0)}")
print(f"x=0, y=1: {AND(0,1)}")
print(f"x=1, y=0: {AND(1,0)}")
print(f"x=1, y=1: {AND(1,1)}")
x=0, y=0: 0 x=0, y=1: 0 x=1, y=0: 0 x=1, y=1: 1
OR 연산은 아래 표와 같이 x, y 둘 중 하나라도 True 라면 결과값이 True인 "합집합"과 비슷한 개념으로 이해하면 된다.
| x | y | result |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
이 연산도 동일하게 가중치를 랜덤으로 돌려보았다
def OR(x,y):
wx = 100
wy = 100
bias = -50
if activation((wx*x + wy*y + bias)) < 0.5:
return 0
else:
return 1
print(f"x=0, y=0: {OR(0,0)}")
print(f"x=0, y=1: {OR(0,1)}")
print(f"x=1, y=0: {OR(1,0)}")
print(f"x=1, y=1: {OR(1,1)}")
x=0, y=0: 0 x=0, y=1: 1 x=1, y=0: 1 x=1, y=1: 1
not AND 연산이니까 AND연산의 결과에서 not만 붙여주면 아래와 같은 표를 얻을 수 있다
| x | y | result |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
코드에서도 간단하게,
AND 연산과 같은 절댓값을 가지지만 부호만 다른 가중치를 넣어주면 된다
def NAND(x,y):
wx = -50
wy = -50
bias = 60
if activation((wx*x + wy*y + bias)) < 0.5:
return 0
else:
return 1
print(f"x=0, y=0: {NAND(0,0)}")
print(f"x=0, y=1: {NAND(0,1)}")
print(f"x=1, y=0: {NAND(1,0)}")
print(f"x=1, y=1: {NAND(1,1)}")
x=0, y=0: 1 x=0, y=1: 1 x=1, y=0: 1 x=1, y=1: 0
not OR 연산 == OR연산의 결과에서 not 붙여주기!
| x | y | result |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 0 |
이 코드도 OR 연산에서 부호만 바꿔주었다.
이상 구현해봤던 AND, OR, NAND, NOR 연산은 선형분리가 가능하다는 점을 기억하자.
def NOR(x,y):
wx = -100
wy = -100
bias = 50
if activation((wx*x + wy*y + bias)) < 0.5:
return 0
else:
return 1
선형 분리가 불가능한
입력값 두 개가 같으면 False, 다르면 True를 반환하는데
사람한테 설명하면 쉽지만 이걸 컴퓨터한테 알려주기가 쉽지만은 않다.
| x | y | result |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
XOR 연산을 구현하는 방법은
1)NOR 연산 활용
2)NAND, OR, AND 연산 활용
두 가지를 배웠다.
def XOR1(x, y):
a = NOR(x,x)
b = NOR(y,y)
c = NOR(a,b)
d = NOR(x,y)
e = NOR(c,d)
return e
결국 우리가 원하는 건 c,d 값이 같으면 0, 다르면 1이 출력되는 것이다.
| c | d | result |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
우리는 아래 두 가지로 분류해서 c,d의 값을 살펴볼 수 있다.
1) (x,y)=(0,0) or (1,1) 일 때
| (x,y) | a | b | c | d |
|---|---|---|---|---|
| (0,0) | 0 | 0 | 0 | 0 |
| (1,1) | 0 | 0 | 0 | 0 |
(0파티..!)
2) (x,y)= (1,0) or (0,1) 일 때
| (x,y) | a | b | c | d |
|---|---|---|---|---|
| (1,0) | 0 | 0 | 0 | 1 |
| (0,1) | 0 | 0 | 0 | 1 |
이렇게 c,d를 정의해줌으로써 XOR를 구현할 수 있다.
print(f"x=0, y=0: {XOR1(0,0)}")
print(f"x=0, y=1: {XOR1(0,1)}")
print(f"x=1, y=0: {XOR1(1,0)}")
print(f"x=1, y=1: {XOR1(1,1)}")
x=0, y=0: 0 x=0, y=1: 1 x=1, y=0: 1 x=1, y=1: 0
이보다 더 간단하게 XOR을 구현하는 방법도 있다.
def XOR(x, y):
a=NAND(x,y)
b=OR(x,y)
c=AND(a,b)
return c
코드는 NOR 다섯개를 가지고 오는 것보다 훨씬 간단하다!
얘도 하나하나 따져보면 머리가 훨씬 덜 아픈 느낌이다.
| (x,y) | a | b |
|---|---|---|
| (0,0) | 1 | 0 |
| (1,0) | 1 | 1 |
| (1,0) | 1 | 1 |
| (1,1) | 0 | 1 |
| a | b | c |
|---|---|---|
| 1 | 0 | 0 |
| 1 | 1 | 1 |
| 1 | 1 | 1 |
| 0 | 1 | 0 |
print(f"x=0, y=0: {XOR(0,0)}")
print(f"x=0, y=1: {XOR(0,1)}")
print(f"x=1, y=0: {XOR(1,0)}")
print(f"x=1, y=1: {XOR(1,1)}")
x=0, y=0: 0 x=0, y=1: 1 x=1, y=0: 1 x=1, y=1: 0
이렇게 논리 게이트 구현 완료!