Study/class note

머신러닝 / 퍼셉트론 R과 파이썬으로 구현하기

chanzae 2022. 2. 17. 16:58

ㅇ퍼셉트론(perceptron) --> "뇌세포 하나를 수학적으로 재현함"

     ㄴ 지각하다, 인지하다

기계를 학습시키려면 공부할 데이터(문제집과 답)를 줘야함.

AND 게이트 OR 게이트 Nand 게이트 Xor 게이트
(eXclusive or 게이트)
x1 x2 y x1 x2 y x1 x2 y x1 x2 y
F(0) F(0) 0 F(0) F(0) 0 F(0) F(0) 1 F(0) F(0) 0
F(0) T(1) 0 F(0) T(1) 1 F(0) T(1) 1 F(0) T(1) 1
T(1) F(0) 0 T(1) F(0) 1 T(1) F(0) 1 T(1) F(0) 1
T(1) T(1) 1 T(1) T(1) 1 T(1) T(1) 0 T(1) T(1) 0

 

 

 

 

ㅇand게이트 퍼셉트론 R로 구현하기

예제1. 아래의 행렬을 만들고 inputs라는 변수에 넣으시오.

# R
inputs <- matrix(c(0,0,1,0,0,1,1,1), nrow = 4, ncol = 2, byrow = T)
inputs

예제2. 아래의 행렬을 만들고 targets라는 변수에 넣으시오.

targets <- matrix(c(0,0,0,1), nrow = 4, ncol = 1, byrow = T)
targets

예제3. 아래의 가중치 행렬을 w라는 이름으로 생성하시오.

w <- matrix(c(0.3, 0.4, 0.1), nrow = 3)
w

예제4. 아래의 행렬을 만들고 x0이라는 변수에 담으시오.

x0 <- matrix(c(-1,-1,-1,-1), nrow = 4)
x0

예제5. inputs행렬과 x0행렬을 cbind를 이용해 서로 붙여서 new_inputs 변수에 담으시오.

new_inputs <- cbind(x0,inputs)
new_inputs

예제6. new_inputs와 w행렬과의 곱을 구하시오.

k <- new_inputs %*% w
k

예제7. 위에서 작성한 inputs, targets, x0, new_inputs코드를 가지고 아래의 and_pcn함수를 생성하시오.

inputs <- matrix(c(0,0,1,0,0,1,1,1), nrow = 4, ncol = 2, byrow = T)
targets <- matrix(c(0,0,0,1), nrow = 4, ncol = 1, byrow = T)
x0 <- matrix(c(-1,-1,-1,-1), nrow = 4)
new_inputs <- cbind(x0,inputs)

and_pcn <- function(ni){
  w <- matrix(c(0.3, 0.4, 0.1), nrow = 3)
  for (i in (1:nrow(ni))){
    k <- ni[i, ] %*% w
    print(k)
  }
}
and_pcn(new_inputs)

예제8. 위에서 출력되고 있는 k값이 0보다 크면 1, 0보다 작거나 같으면 0이 출력되도록 코드를 수정하시오.

and_pcn <- function(ni){
  w <- matrix(c(0.3, 0.4, 0.1), nrow = 3)
  for (i in (1:nrow(ni))){
    k <- ni[i, ] %*% w
    k_prime <- ifelse(k>0, 1, 0)
    print(k_prime)
  }
}
and_pcn(new_inputs)

예제9.  위에서 출력되고 있는 k_prime(예측값)과 정답(targets)과의 차이인 오차가 출력되게끔 코드를 수정하시오.

and_pcn <- function(ni, t){
  w <- matrix(c(0.3, 0.4, 0.1), nrow = 3)
  for (i in (1:nrow(ni))){
    k <- ni[i, ] %*% w
    k_prime <- ifelse(k>0, 1, 0)
    cost <- t[i,] - k_prime
    
    print(cost)
  }
}
and_pcn(new_inputs, targets)

예제10. 비용(cost) 또는 오차가 0이 아니면 (즉, 오차가 생기면) 가중치 w0, w1, w2의 변화가 일어나게끔 코드를 구현하시오.

and_pcn <- function(ni, t){
  w <- matrix(c(0.3, 0.4, 0.1), nrow = 3)
  for (i in (1:nrow(ni))){
    k <- ni[i, ] %*% w
    k_prime <- ifelse(k>0, 1, 0)  # 활성화 함수(계단함수)
    cost <- t[i,] - k_prime  # 비용(오차)함수
    if(cost != 0){
      for (j in 1:nrow(w)){
        w[j] <- w[j]+0.05 * ni[i,j]*cost
      }
    }
  }
  print(w)
}

and_pcn(new_inputs, targets)

예제11. 가중치의 변화가 없을 때 위의 for루프문으로 반복하는 작업이 중단되면서 가중치가 출력되게 하시오.

아래의 전체 for문이 계속 반복되도록 하시오 = 무한루프

inputs <- matrix(c(0,0,1,0,0,1,1,1), nrow = 4, ncol = 2, byrow = T)
targets <- matrix(c(0,0,0,1), nrow = 4, ncol = 1, byrow = T)
x0 <- matrix(c(-1,-1,-1,-1), nrow = 4)
new_inputs <- cbind(x0,inputs)

and_pcn <- function(ni, t){
  w <- matrix(c(0.3, 0.4, 0.1), nrow = 3)
  for (i in (1:4)){  
    for (i in (1:nrow(ni))){
      k <- ni[i, ] %*% w
      k_prime <- ifelse(k>0, 1, 0)  # 활성화 함수(계단함수)
      cost <- t[i,] - k_prime  # 비용(오차)함수
      if(cost != 0){
        for (j in 1:nrow(w)){
          w[j] <- w[j]+0.05 * ni[i,j]*cost
        }
      }
    }
    print(w)
  }
}

and_pcn(new_inputs, targets)

 

 

ㅇ파이썬으로 and 퍼셉트론 구현하기

예제1. inputs 변수를 행렬로 만드시오.

#python
import numpy as np

inputs = np.array([0,0,1,0,0,1,1,1]).reshape(4,2)

예제2. targets 변수를 행렬로 만드시오.

targets = np.array([0,0,0,1]).reshape(4,1)

예제3. 가중치 행렬 w를 만드시오.

w = np.array([0.3, 0.4, 0.1]).reshape(3,1)

예제4. x0 행렬을 만드시오.

x0 = np.array([-1,-1,-1,-1]).reshape(4,1)

예제5. inputs와 x0 행렬을 서로 붙여서 new_inputs라는 변수에 담으시오.

new_inputs = np.hstack((x0,inputs))

# 또는

new_inputs = np.column_stack((x0, inputs))

예제6. new_inputs(입력값)과 w(가중치) 행렬과의 곱을 구하시오.

k = np.dot(new_inputs, w)

예제7. 위의 결과를 출력하는 함수를 and_pcn이라는 함수로 아래와 같이 실행되게 하시오.

def and_pcn(ni, w):
    return np.dot(ni, w)
    
and_pcn(new_inputs, w)

예제8. 위에서 출력된 값이 0보다 크거나 같으면 1, 0보다 작으면 0을 출력하게끔 코드를 수정하시오.

def step_function(x):  #계단함수
    y = x >= 0
    
    return y.astype(np.int)  # y가 true = 1, false = 0

def and_pcn(ni, w):
    k = np.dot(ni, w)
    k_prime = step_function(k)
    
    return k_prime
    
and_pcn(new_inputs, w)

예제9. 위에서 출력된 결과(예상값)와 실제 정답(targets)과의 차이인 오차가 출력되게 코드를 수정하시오.

def step_function(x):  #계단함수
    y = x >= 0
    
    return y.astype(np.int)  # y가 true = 1, false = 0

def and_pcn(ni, w):
    k = np.dot(ni, w)
    k_prime = step_function(k)
    cost = targets - k_prime
    
    return cost
    
and_pcn(new_inputs, w)

예제10. 비용(cost) 또는 오차가 0이 아니면 가중치 w0,w1,w2의 변화가 일어나게끔 코드를 작성하시오. 그리고 가중치 3개를 출력하시오.

import numpy as np

inputs = np.array([0,0,1,0,0,1,1,1]).reshape(4,2)
targets = np.array([0,0,0,1]).reshape(4,1)
w = np.array([0.3, 0.4, 0.1]).reshape(3,1)
x0 = np.array([-1,-1,-1,-1]).reshape(4,1)
new_inputs = np.hstack((x0,inputs))

def step_function(x):  #계단함수
    y = x >= 0
    
    return y.astype(np.int)  # y가 true = 1, false = 0

def and_pcn(ni, w):
    targets = np.array([0,0,0,1]).reshape(4,1)
    
    for i in range(len(ni)):
        k = np.dot(ni[i,:], w)
        k_prime = step_function(k)
        cost = targets[i,:] - k_prime
        if cost != 0:
            for j in range(len(w)):
                w[j] = w[j] + 0.05 * ni[i,j] * cost
    
    
    print(w)
    
and_pcn(new_inputs, w)

 

=> step_function 함수 수정

: 파이썬의 부동소수점 오류로 인해 k값이 0으로 출력되지 않고 0에 근사한 값으로 출력되고 있음. 겉으로 보기엔 0이지만 포맷팅으로 전체 확인을 해보면 0에 근사한 값이 나옴. 따라서 부동소수점은 0보다 큰 값이 되므로 1이 출력됨.

np.round(x,2)로 코드를 수정해서 0.00으로 만들어야함. 

def step_function(x):  #계단함수
    y = np.round(x,2) >= 0
    
    return y.astype(np.int)  # y가 true = 1, false = 0

이때 y = np.round(x,2) >= 0 일때는 가중치가 0.4, 0.3, 0.1이 나오고, y = np.round(x,2) > 0 일때는 가중치가 0.35, 0.35, 0.1이 출력됨.

 

 

+) 지금까지의 코드를 전체 정리

import numpy as np

inputs = np.array([0,0,1,0,0,1,1,1]).reshape(4,2)  #and gate
targets = np.array([0,0,0,1]).reshape(4,1)  #정답
w = np.array([0.3, 0.4, 0.1]).reshape(3,1)  #가중치
x0 = np.array([-1,-1,-1,-1]).reshape(4,1)  #절편
new_inputs = np.hstack((x0,inputs))

def step_function(x):  #계단함수
    y = np.round(x,2) >= 0
    
    return y.astype(np.int)  # y가 true = 1, false = 0


def and_pcn(ni, w):
    targets = np.array([0,0,0,1]).reshape(4,1)  # and gate 정답
    
    for i in range(4):
        for i in range(len(ni)):
            k = np.dot(ni[i,], w)
            k_prime = step_function(k)
            cost = targets[i,] - k_prime
            if cost != 0:
                for j in range(len(w)):
                    w[j] = w[j] + 0.05 * ni[i,j] * cost
                    
        print(w)

    
and_pcn(new_inputs, w)

 

 

ㅇ활성화 함수의 종류 p318

뉴런에 입력되는 신호를 다음 신로호 보낼지 말지를 결정하는 함수(like 역치, 임계치)

현상 ---> 인문학자 : 발견 ---> 수학자 : 수학적 풀이 ---> 컴퓨터 과학자 : 코드로 완성

1. 계단함수 : 입력신호의 총합이 임계치를 넘느냐 안넘느냐를 숫자1과 0으로 리턴하는 함수

   ex :  f(0.3) = 1, f(-0.2) = 0

2. 시그모이드 함수 : 계단함수는 무조건 0 아니면 1을 리턴하지만 시그모이드 함수는 0~1 사이의 연속적인 실수값을 리턴함. 

단층 신경망(계단함수) : 입력층 ---> 출력층

다층 신경망(시그모이드) : 입력층 ---> 은닉층 ---> 출력층

 

신경망을 단층이 아니라 다층 신경망을 사용하려면 활성화 함수를 sigmoid함수를 사용해야 함.

시그모이드 함수의 문제점? 기울기 소실 문제가 발생해서 신경망 학습이 제대로 안되는 문제가 생김.

> 가중치가 제대로 갱신이 안되어서 분류를 못함 > 시그모이드 함수의 단점을 개선하고자 렐루함수 생김.

3. 렐루함수(Rectified Linear unit) 함수 : 입력값이 0보다 크면 그 값을 그 값을 그대로 출력하고 0 보다 작거나 같으면 0으로 출력하는 함수

 

예제1. 활성화 함수인 계단함수를 R로 생성하고 계단함수 그래프를 그리시오(p.319)

#R
step <- function(x){ifelse(round(x,2)>=0, 1, 0)}
step(-0.1)
step(1.4)

x <- seq(-5,5, 0.01)  # -5 ~ 5까지 0.001 간격으로 출력
x

plot(x,step(x), col = 'blue',type = 'o', cex = 0.5)

문제328. 이번에는 파이썬으로 계단함수를 만들고 계단함수 그래프를 그리시오.

#python
import numpy as np
import matplotlib.pyplot as plt

def step_function(x):
    return np.array(x > 0, dtype = np.int)

step_function(-0.2)
step_function(0.3)

x = np.arange(-5.0, 5.0, 0.1) # -5 ~ 5까지 0.1 간격
y = step_function(x)

plt.plot(x,y)
plt.show()

 

문제329. R로 시그모이드 함수를 만드시오.

#R
sigmoid <- function(x){ 1/ (1+exp(-x)) }
sigmoid(3) 
sigmoid(2)

 

문제330. (오늘의 마지막 문제) or게이트 퍼셉트론 함수를 파이썬으로 생성하시오.

import numpy as np

inputs = np.array([0,0,1,0,0,1,1,1]).reshape(4,2)  #and gate
# targets = np.array([0,0,0,1]).reshape(4,1)  #정답
w = np.array([0.3, 0.4, 0.1]).reshape(3,1)  #가중치
x0 = np.array([-1,-1,-1,-1]).reshape(4,1)  #절편
new_inputs = np.hstack((x0,inputs))

def step_function(x):  #계단함수
    y = np.round(x,2) >= 0
    
    return y.astype(np.int)  # y가 true = 1, false = 0


def and_pcn(ni, w):
    targets = np.array([0,1,1,1]).reshape(4,1)  # or gate 정답
    
    for i in range(4):
        for i in range(len(ni)):
            k = np.dot(ni[i,], w)
            k_prime = step_function(k)
            cost = targets[i,] - k_prime
            if cost != 0:
                for j in range(len(w)):
                    w[j] = w[j] + 0.05 * ni[i,j] * cost
                    
        print(w)

    
and_pcn(new_inputs, w)
반응형