본문 바로가기

복습용 기술공부

230313 멀티 레이어 퍼셉트론 연습

@ 멀티 레이어 퍼셉트론 이해하기위해 정리하는 글

 

※ 파이썬에서는 10e-50보다 작은 수를 0으로 처리함

-> 부동소수점 오차 방지를 위해 10e-5 소수점으로 작업

▼ 부동소수점 : 가수부와 지수부로 나누어서 저장, 2^n이 아니면 약간의 오차 발생,

javascript의 Bigint에서 오차가 발생하는 원인 상기하기

 

퍼셉트론 함수 만들기 1

단일 퍼셉트론 동작

epsilon = 0.000001 # 부동소수점 오차 방지
def perceptron(x1, x2):
    w1, w2, b = 1.0, 1.0, -1.5
    sum = x1*w1 + x2*x2 + b
    if sum > epsilon :
         return 1
    else :
        return 0
# 출력, AND 최적화
print(perceptron(0,0))
print(perceptron(0,1))
print(perceptron(1,0))
print(perceptron(1,1))

>>

0
0
0
1

멀티 레이어 퍼셉트론 동작 원리

import numpy as np
def perceptron(X1, X2):
    X = np.array([X1,X2])
    W = np.array
    b = -1.5
    sum = np.dot(W,X) + b
    if sum > epsilon:
        return 1
    else :
        return -0

# step_func 함수, <- 안에 내적으로 계산해서 넣

def step_func(t):
    if t > epsilon :
        return 1
    else : 
        return 0

step1 ) 임의의 학습 시킬 데이터 지정

# 학습을 시킬려면 학습 데이터 필요
X = np.array([[0,0,1], # 맨 끝의 1은 바이어스를 위한 갓,
               [0,1,1],
               [1,0,1],
               [1,1,1]])
X.shape, len(X[0])

>>

((4, 3), 3)

step 2) 임의의 종속변수 행렬 지정, 구할 가중치 초기화(저장할 행렬 생성)

y = np.array([0, 0, 0, 1]) # 종속변수 행렬
W = np.zeros(len(X[0])) # 가중치를 저장하는 행렬

step 3) 퍼셉트론 학습 알고리즘 

 

원래는 객체지향 코딩을 해야하지만 쉽게 이해하기 위해서 함수로 사용

global로 전역변수 가져오기

 

# 퍼셉트론 학습 알고리즘
def perceptron_fit(X, y , epochs=10):
    global W
    eta = 0.2 # 학습률
    # 오차 계산 => 학습로직
    # 학습 횟수 만큼 반복
    for t in range(epochs):
        print('epoch = ', t, '='*10)
        # 데이타 만큼 반복
        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=', W)
        print('='*20)

실행

print(perceptron_fit(X, y, 10))

>>

epoch =  0 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [0. 0. 0.]
현재 입력= [0 1 1] 정답= 0 예측= 0 변경된 W= [0. 0. 0.]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [0. 0. 0.]
현재 입력= [1 1 1] 정답= 1 예측= 0 변경된 W= [0.2 0.2 0.2]
====================
epoch =  1 ==========
현재 입력= [0 0 1] 정답= 0 예측= 1 변경된 W= [0.2 0.2 0. ]
현재 입력= [0 1 1] 정답= 0 예측= 1 변경된 W= [ 0.2  0.  -0.2]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [ 0.2  0.  -0.2]
현재 입력= [1 1 1] 정답= 1 예측= 0 변경된 W= [0.4 0.2 0. ]
====================
epoch =  2 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [0.4 0.2 0. ]
현재 입력= [0 1 1] 정답= 0 예측= 1 변경된 W= [ 0.4  0.  -0.2]
현재 입력= [1 0 1] 정답= 0 예측= 1 변경된 W= [ 0.2  0.  -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 0 변경된 W= [ 0.4  0.2 -0.2]
====================
epoch =  3 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.2]
현재 입력= [0 1 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.2]
현재 입력= [1 0 1] 정답= 0 예측= 1 변경된 W= [ 0.2  0.2 -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 0 변경된 W= [ 0.4  0.4 -0.2]
====================
epoch =  4 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.4 -0.2]
현재 입력= [0 1 1] 정답= 0 예측= 1 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 1 변경된 W= [ 0.4  0.2 -0.4]
====================
epoch =  5 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [0 1 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 1 변경된 W= [ 0.4  0.2 -0.4]
====================
epoch =  6 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [0 1 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 1 변경된 W= [ 0.4  0.2 -0.4]
====================
epoch =  7 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [0 1 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 1 변경된 W= [ 0.4  0.2 -0.4]
====================
epoch =  8 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [0 1 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 1 변경된 W= [ 0.4  0.2 -0.4]
====================
epoch =  9 ==========
현재 입력= [0 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [0 1 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 0 1] 정답= 0 예측= 0 변경된 W= [ 0.4  0.2 -0.4]
현재 입력= [1 1 1] 정답= 1 예측= 1 변경된 W= [ 0.4  0.2 -0.4]
====================

이때의 W 

array([ 0.4,  0.2, -0.4])

 

 

※ bool 함수를 int 타입으로 변경 후 return 하면 0, 1로 받을 수 있음 // 아이디어로 사용하기

 

활성함수(Activation Function) 종류

계단함수 _ 단일 퍼셉트론에서 사용

sigmoid 함수

Hyperbolic Tangent 보다 곡선이 더 급함, 오차 폭이 큼 -> 이상치에 더 영향을 받음

 

Hyperbolic Tangent 함수 (tanh)

Relu 함수

- rgb 등에서 사용, 0보다 낮게 가는 leaky Relu도 있음

 

순방향 MLP

미분을 통해서 극값에 이를 때 까지 탐색하게 됨

 

ex) sigmoid를 이용해 구해보기

 

step 1) 함수 정의

# 활성화 함수 (시그모이드)
def actf(x):
    return 1.0 / (1.0 + np.exp(-x))
# 시그모이드 함수의 미분치
# d/dx(sigmoid(x)) = sigmoid(x)(1-sigmoid(x))
def actf_deriv(x):
    return x * (1-x)

step 2) 입력값 주기

# 입력 유닛수, 은닉 유닛수, 출력 유닛수
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],[0],[0],[1]])
# 가중치, 바이어스
W1 = np.array([[0.10, 0.20],[0.30, 0.60]])
W2 = np.array([[0.50],[0.60]])
B1 = np.array([0.1,0.2])
B2 = np.array([0.3])

step 3) 순방향 전파 계산 함수

# 순방향 전파 계산
def predict(x):
    layer0 = x #입력 레이어
    Z1 = np.dot(layer0, W1) + B1 # 가중치 행렬곱 계산
    layer1 = actf(Z1) # 활성화 함수 적용
    Z2 = np.dot(layer1, W2) + B2 # 가중치 행렬곱 계산
    layer2 = actf(Z2) # 활성화 함수 적용
    return layer0, layer1, layer2

step 4) test 함수 만들기

def test():
    # print(predict(X))
    for x, y in zip(X,T):
        # print(x,y)
        x = np.reshape(x, (1,-1)) # -1은 알아서 찾아주게끔
        layer0, layer1, layer2 = predict(x)
        print(x,y,layer2)

실행 결과

test()
>>
[[0 0]] [0] [[0.70938314]]
[[0 1]] [0] [[0.73367104]]
[[1 0]] [0] [[0.71791234]]
[[1 1]] [1] [[0.74074894]]

+ 추가 오차함수 (MSE, RMSE)로 구해보기

# 오차 함수
def MSE(target, y):
    return (0.5 *   #데이터 사이즈만큼 바뀜 (n개)
            np.sum((y-target)**2))
            
print(MSE(target, y)) # MSE
print(np.sqrt(MSE(target,y))) #RMSE 확인

순간변화율(gradient)

step 1) 임의의 손실함수를 정의

# 그래디언트 
x = 10
learning_rate = 0.2 # 학습을 어느정도로 시킬지, 학습 스텝, 경사 비율
# 너무 크면, 점짐적 하강하지 못하고 발산, 너무 작으면 아주 오랜 시간 걸림
predision = 0.00001 # 최소 크기
max_iterations = 100 # 반복 횟수
# 손실함수를 람다식으로 정의
loss_func = lambda x: (x-3)**2 + 10 #예시

step 2) step 1의 gradient 정의

# 그래디언트를 람다식으로 정의,
# 손실함수의 1차 미분값
gradient = lambda x: 2*x - 6

위의 과정을 이용해 GD(경사하강법) 을 구해보기

# 그래디언트 강하법
for i in range(max_iterations):
    x = x - learning_rate * gradient(x)
    print('손실함수 =(',x,')',loss_func(x))

list에 담아서 그래프로 표현

list1 = []
list2 = []
for i in range(max_iterations):
    x = x - learning_rate * gradient(x)
    list1.append(x)
    list2.append(loss_func(x))
    print('손실함수 : (', list1[i], ')', list2[i])

역방향(역전파, Backpropagation)

predict(x)를 순방향 전파 함수로 정의 (위 쪽에 작성)

max_iterations, learning_rate는 직접 찾아가면서 해야함(뭐가 알맞는지 잘 알 수 없음, 직접 하면서 찾기)

# 역방향 전파 계산
max_iterations = 90000 #임의로 주는 횟수
def fit():
    global W1, W2, B1, B2
    for i in range(max_iterations): # 학습 횟수 만큼 반복
        for x, y in zip(X,T) : # 학습 샘플을 하나씩
            x = np.reshape(x, (1, -1)) # 2차원 행렬로 변환
            y = np.reshape(y, (1, -1)) # 2차원 행렬로 변환
            layer0, layer1, layer2 = predict(x) # 순방형 계산
            layer2_error = layer2 - y # 오차 계산 , y는 여기서는 임의로 오차를 적어줌
            layer2_delta = layer2_error * actf_deriv(layer2) # 출력층 델타
            layer1_error = np.dot(layer2_delta, W2.T) # 은닉층 오차 계산, .T는 뒤집음
            layer1_delta = layer1_error * actf_deriv(layer1) # 은닉층 델타
            
            W2 += -learning_rate * np.dot(layer1.T, layer2_delta)
            W1 += -learning_rate * np.dot(layer0.T, layer1_delta)
            B2 += -learning_rate * np.sum(layer2_delta, axis = 0)
            B1 += -learning_rate * np.sum(layer1_delta, axis = 0)

학습 최적화 - 1. 미니 배치 경사 하강법

풀 배치 경사 하강법 시 전체를 보고 작업하기에 비효율 적임, 이를 해결하기 위해 나눠서 사용

※ SGD(확률적 경사 하강법) <- 복잡한 데이터 3차원 굴곡 상황에서 최적화 안되는 문제 해결하기 위해서 사용 (GD 업그레이드 버전)

 

step 1 ) 데이터 학습데이터와 테스트 데이터 나누기

# 미니배치
import tensorflow as tf
import numpy as np

# 데이터를 학습 데이터와 테스트 데이터 나누기
(x_train, y_train), (x_test, y_test) = \
    tf.keras.datasets.mnist.load_data()

step 2) batch_size 지정

batch_size = 12 # 배치 크기

step 3) 학습

selected = np.random.choice(data_size, batch_size)

x_batch = x_train[selected]
y_batch = y_train[selected]

optimizer 종류

학습률 : 너무 크면 발산, 너무 적으면 너무 느리게 작동 ~> 얼마나 적게 계산해서 백미분 시키냐 정함

 

모멘텀 : 가속도 개념, 어느 정도 가중치를 줘서 다시 언덕을 올라가서 떨어지게끔?
adagrad : 학습을 하면서 점점 학습률이 줄어들게 해주는 것
RMSprop : adagrad 수정판, 요즘 간간히 사용, 가중을 하는데 이동 평균을 구해서 가중 (평균치를 이용한 가중치)
Adam : 요즘 많이 사용, RMSprop + 모멘텀, 좋은 것만 뽑아서 사용, 연산이 많음

 


tenserflow 설치 방법

-by window

tenserflow 설치
1. 새 가상환경 만들기
conda create -n tf29py38 python=3.8

2. 가상환경 실행
tf29py38
tensorflow 2.9가 python 3.8에서 제일 안정적임

3. tensorflow numpy pandas jupyter notebook lab seaborn matplotlib tqdm 설치
conda install 설치할 것들


4. 주피터 노트북 내에 가상환경이 인식이 안 될 경우
conda install ipykernel
python -m ipykernel install --user --name tf29py38 --display-name tf20py38

5. 커널 선택

 

※ gpu 사용하려면 좋은 컴퓨터 쓰던가, 없으면 colab 이용하기 _