🚀 What I Studied/AI

[AI] Perceptron

박낑깡이 2022. 10. 28. 17:17

🎯 퍼셉트론 학습 알고리즘

 

 

 

Python으로 퍼셉트론 구현하기

import numpy as np
def step_func(t):   # 퍼셉트론의 활성화 함수
    if t > 0.: return 1 
    else: return 0
    
X = np.array([ # 훈련 데이터 세트
    [0, 0, 1], # 맨 끝의 1은 바이어스를 위한 입력 신호 1이다. 
    [0, 1, 1], 
    [1, 0, 1],
    [1, 1, 1]
])
y = np.array([0, 0, 0, 1]) # 정답을 저장하는 넘파이 행렬 
W = np.zeros(len(X[0])) # 가중치를 저장하는 넘파이 행렬
def perceptron_fit(X, Y, epochs=10): # 퍼셉트론 학습 알고리즘 구현 
    global W
    eta = 0.2 # 학습률
    
    for t in range(epochs):
        print("epoch=", t, "======================") 
        for i in range(len(X)):
            predict = step_func(np.dot(X[i], W))
            error = Y[i] - predict # 오차 계산
            W += eta * error * X[i] # 가중치 업데이트 
            print("현재 처리 입력=", X[i], "정답=", Y[i], "출력=", predict, "변경된 가중치=", W) 
    print("================================")
def perceptron_predict(X, Y): # 예측 
    global W
    for x in X:
        print(x[0], x[1], "->", step_func(np.dot(x, W)))
        
perceptron_fit(X, y, 6)
perceptron_predict(X, y)

결과

 

 

sklearn으로 퍼셉트론 구현

from sklearn.linear_model import Perceptron

# 샘플과 레이블.
X = [[0,0],[0,1],[1,0],[1,1]] 
y = [0, 0, 0, 1]

# 퍼셉트론 생성. tol는 종료 조건.
# random_state는 난수의 seed.
clf = Perceptron(tol=1e-3, random_state=0)

# 학습. 
clf.fit(X, y)

# 테스트. 
print(clf.predict(X))

 

 

🎯 다중 퍼셉트론 (MLP : Multilayer Perceptron)

: 입력층과 출력층 사이에 은닉층(hidden layer)을 가지고 있는 퍼셉트론

 

활성화 함수

: 입력 신호의 총합을 출력 신호로 변환하는 함수

- 신경망의 활성화 함수는 비선형이어야 한다.

(선형 함수일 경우 아무리 층이 많아져도 하나의 함수로 대치될 수도 있기 때문에 여러 층을 쌓는 효과를 볼 수 없다.)

 

 

🎯활성화 함수 종류

1. 시그모이드(sigmoid) 함수

  • 기울기 소멸 문제 (Vanishing Gradient Problem)

: 시그모이드(sigmoid)함수에서는 x의 절댓값이 클수록 기울기는 0에 수렴하게 된다. 이는 역전파 중에 이전의 기울기와 현재 기울기를 곱하면서 점점 기울기가 사라지게 된다. -> 신경망의 학습 능력이 제한되는 포화(saturation)가 발생

 

 

<Python Code>

import numpy as np
import matplotlib.pylab as plt

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

#그래프 그러보기
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.show()

 

 

2. ReLU (Rectified Linear Unit) 함수 

<Python Code>

def relu(x):
    return np.maximum(0,x)

#그래프 그러보기
x = np.arange(-10, 10)
y = relu(x)
plt.plot(x, y)
plt.ylim(-1, 10.1)
plt.show()

 

 

3. tanh 함수

<Python Code>

def tanh(x):
    return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))

#그래프 그러보기
x = np.arange(-10.0, 10.0, 0.1)
y = tanh(x)
plt.plot(x, y)
plt.ylim(-1.1, 1.1)
plt.show()

 

 

 

Python으로 MLP 순방향 패스 구현하기

import numpy as np

# sigmoid 함수 
def actf(x):
    return 1/(1+np.exp(-x))

# sigmoid 함수의 미분치 
def actf_deriv(x):
    return x*(1-x)

# 입력유닛의 개수, 은닉유닛의 개수, 출력유닛의 개수 
inputs, hiddens, outputs = 2, 2, 1
learning_rate=0.2

# 훈련 샘플과 정답
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) 
T = np.array([[0], [1], [1], [0]])
W1 = np.array([[0.10, 0.20], [0.30, 0.40]])
W2 = np.array([[0.50], [0.60]]) 
B1 = np.array([0.1, 0.2])
B2 = np.array([0.3])

# 순방향 전파 계산 
def predict(x):
    layer0 = x                     # 입력을 layer0에 대입
    Z1 = np.dot(layer0, W1)+B1     # 행렬의 곱을 계산
    layer1 = actf(Z1)              # 활성화 함수를 적용한다.
    Z2 = np.dot(layer1, W2)+B2     # 행렬의 곱을 계산한다. 
    layer2 = actf(Z2) # 활성화 함수를 적용한다. 
    return layer0, layer1, layer2
def test():
    for x, y in zip(X, T):
        layer0, layer1, layer2 = predict(x) 
        print(x, y, layer2)
test()

# 학습이 없으므로 난수만 출력

 

 

 

🎯 손실 함수 (Loss function)

지도학습 시 알고리즘이 예측한 값과 실제 정답의 차이를 비교하기 위한 함수

'학습 중에 알고리즘이 얼마나 잘못 예측하는 정도'를 확인하기 위한 함수로써 최적화(Optimization)를 위해 최소화하는 것이 목적인 함수

- L : 손실 함수

- arg min : arguments of minimum을 축약한 수학적 표현으로, 목적 함수를 최소화하는 입력값을 찾는 역할 (목적함수 = L)

- x : 학습 데이터의 입력값

- y : 학습 데이터의 정답

- Θ : 알고리즘 학습 시 사용되는 모든 파라미터의 벡터

- ~Θ : 추정된 최적의 파라미터

 

 

🎯 평균 제곱 오차 (MSE)

- 예측값과 정답 간의 평균 제곱 오차

 

 

🎯경사하강법

- 목표 : 손실함수 값을 최소로 하는 가중치를 찾는 것

- 신경망 학습 문제 -> 최적화 문제(optimization)

  • 손실함수를 가중치로 미분한 값이 양수 -> 가중치를 감소
  • 손실함수를 가중치로 미분한 값이 음수 -> 가중치를 증가 

 

<Python Code>

 

손실함수 : y = (x-3)^2 +10

gradient : y' = 2x - 6

x = 10
learning_rate = 0.2 
precision = 0.00001 
max_iterations = 100

# 손실함수를 람다식으로 정의한다. 
loss_func = lambda x: (x-3)**2 + 10

# gradient를 람다식으로 정의한다. 손실함수의 1차 미분값이다. 
gradient = lambda x: 2*x-6

# gradient 강하법
for i in range(max_iterations):
    x = x - learning_rate * gradient(x) 
    print("손실함수값(", x, ")=", loss_func(x))
print("최소값 = ", x)

 

 

2차원 gradient 시각화 Python Code

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-5, 5, 0.5)
y = np.arange(-5, 5, 0.5)
X, Y = np.meshgrid(x,y)  # 참고박스
U = -2*X          # gradient의 음수
V = -2*Y

plt.figure()
Q = plt.quiver(X, Y, U, V, units='width')
plt.show()

 

 

 

🎯 역전파 학습 알고리즘 (Back Propagation)

: input과 output을 알고 있는 상태(supervised learning)에서 신경망을 학습시키는 방법

 

과정

1. 입력이 주어지면 순방향으로 계산하여 출력을 계산

2. 실제 출력과 우리가 원하는 출력 간의 오차를 계산

3. 이 오차를 역방향으로 전파하면서 오차를 줄이는 방향으로 가중치를 변경

 

3-1. 가중치와 바이어스를 0부터 1 사이의 난수로 초기화

3-2. 수렴할 때까지 모든 가중치에 대해 다음을 반복

  • 손실함수 E의 gradient 를 계산

- 역전파 알고리즘의 유도 : 미분의 chain rule 이용

 

 

Dynamic Programming (동적 계획법)

: 하나의 큰 문제를 여러 개의 작은 문제로 나누어서 그 결과를 저장해 다시 큰 문제를 해결할 때 사용하는 것 (문제해결 패러다임)

 

 

numpy를 이용한 MLP 구현

import numpy as np

# sigmoid 함수 
def actf(x):
    return 1/(1+np.exp(-x))

# sigmoid 함수의 미분치 
def actf_deriv(x):
    return x*(1-x)

# 입력유닛의 개수, 은닉유닛의 개수, 출력유닛의 개수 
inputs, hiddens, outputs = 2, 2, 1
learning_rate=0.2

# 훈련 샘플과 정답
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) 
T = np.array([[1], [0], [0], [1]])

순방향 전파 구현

W1 = np.array([[0.10,0.20], [0.30,0.40]]) 
W2 = np.array([[0.50],[0.60]])
B1 = np.array([0.1, 0.2])
B2 = np.array([0.3])

# 순방향 전파 계산 
def predict(x):
    layer0 = x                    # 입력을 layer0에 대입한다.
    Z1 = np.dot(layer0, W1)+B1    # 행렬의 곱을 계산
    layer1 = actf(Z1)             # 활성화 함수를 적용한다.
    Z2 = np.dot(layer1, W2)+B2    # 행렬의 곱을 계산한다. 
    layer2 = actf(Z2)             # 활성화 함수를 적용한다. 
    return layer0, layer1, layer2

오차 역전파 구현

# 역방향 전파 계산 
def fit():
    global W1, W2, B1, B2                 # 외부에 정의된 변수를 변경해야 한다.
    for i in range(90000):                # 9만번 반복한다.
        for x, y in zip(X, T):            # 학습 샘플을 하나씩 꺼낸다.
            x = np.reshape(x, (1, -1))    # 2차원 행렬로 만든다. 1
            y = np.reshape(y, (1, -1))    # 2차원 행렬로 만든다.
            
            layer0, layer1, layer2 = predict(x)              # 순방향 계산
            layer2_error = layer2-y                          # 오차 계산
            layer2_delta = layer2_error*actf_deriv(layer2)   # 출력층의 델타 계산
            layer1_error = np.dot(layer2_delta, W2.T)        # 은닉층의 오차 계산 2 
            layer1_delta = layer1_error*actf_deriv(layer1)   # 은닉층의 델타 3
            
            W2 += -learning_rate*np.dot(layer1.T, layer2_delta) # 4 
            W1 += -learning_rate*np.dot(layer0.T, layer1_delta) 
            B2 += -learning_rate*np.sum(layer2_delta, axis=0) # 5 
            B1 += -learning_rate*np.sum(layer1_delta, axis=0)

 

def test():
    for x, y in zip(X, T):
        x = np.reshape(x, (1, -1))            # 하나의 샘플을 꺼내서 2차원 행렬로 만든다. 
        layer0, layer1, layer2 = predict(x)
        print(x, y, layer2)                   # 출력층의 값을 출력해본다.
fit() 
test()