AI 및 자동화

[DL] 신경망

lgvv 2024. 4. 17. 01:20

신경망

 

퍼셉트론의 경우 가중치 값을 우리가 적절히 정해줌.

그러나 신경망은 가중치 매개변수에 대한 적절한 값을 데이터로부터 자동으로 학습.

 

신경망

입력층: 가장 왼쪽 우리가 값을 넣어주는 부분

은닉층: 입력층과  출력층 사이 (사람 눈에 보이지 않아서 은닉층)

출력층: 가장 오른쪽 결과값

 

 

신경망

 

 

활성화 함수란?

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

 

y = h(b+ x1*w2 + x2*w2)
a = b+ x1*w2 + x2*w2 일때,
y = h(a)

 

활성화함수를 포함한 개념 전개

 

활성화 함수는 임계값을 경계로 출력이 바뀜

이런 함수를 계단 함수라고 함. 

 

시그모이드 함수

 

시그모이드 함수 정의

 

여기서 exp(-x)란 e의 -x제곱을 의미

 

계단함수 구현

# 계단함수 구현하기
def step_fucntion(x):
    y = x > 0 # 배열을 받기 위해서
    return y.astype(np.int) # 배열로 받아서 해당 타입은 int로 변환해서 반환
    
해당 함수의 경우 y는 조건에 따라 True 혹은 False를 가짐
이걸 int로 변환하면 False는 0 True는 1로 반환

 

 

시그모이드 함수 구현

# 시그모이드 함수 구현
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

x = np.array([-1.0, 1.0, 0.1])
y = sigmoid(x)

 

시그모이드 함수는 계단함수와 달리 매끄럽다.

즉, 계단함수는 0 또는 1만 뱉어낸다면 시그모이드 함수는 0.880, 0.233 등의 값을 뱉어낸다.

 

둘다 입력이 작으면 0에 가깝고 입력이 크면 1에 가깝다.

하지만 시그모이드 함수는 입력이 중요하면 큰 값을 출력하고 입력이 중요하지 않으면 작은 값을 출력한다.

 

비선형 함수

계단 함수와 시그모이드 함수 둘 다 비선형 함수에 속함.

 

신경망에서는 활성화 함수로 반드시 비선형 함수를 사용해야함.

왜냐하면 선형함수를 사용할 시, 층을 깊게하는 의미가 사라짐.

 

가령, 선형 함수의 경우

y = cx
h(x) = y

3층 신경망 함수
y(x) = h(h(h(x)))
y = c * c * c * x
즉 a = c^3과 동일

 

ReLU 함수 (Recified Linear Unit)

예전에는 시그모이드 함수 주로 사용했으나 요즘은 ReLU 주로 사용함.

ReLU는 입력이 0이 넘으면 그 입력을 그대로 출력하고 0 이하이면 0을 출력하는 함수.

 

# RELU 함수
def relu(x):
    return np.maximum(0, x)
    
두 값중 큰 값을 반환

 

 

3층 신경망 구현하기

입력층(0층) 2개, 첫 번째 은닉층(1층) 3개, 두 번째 은닉층(2층) 2개, 출력층(3층) 2개의 뉴런으로 구성.
1, 2층의 활성화 함수 : 시그모이드
3층의 활성화 함수 : 항등함수

출력층의 활성화 함수는 풀고자 하는 문제의 성질에 맞게 정한다.
예를 들어 회귀에는 항등함수2클래스 분류에는 시그모이드 함수,
다중 클래스 분류에는 소프트맥스 함수를 사용하는 것이 일반적

import numpy as np

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

# 항등함수
def identity_function(x):
    return x

# 3.4.3 구현 정리
def init_network():
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])

    return network


def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)

    return y


network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)  # [ 0.31682708  0.69627909]

print(y)

 

순전파: 입력층에서 출력층으로.

 

출력층 설계하기

신경망은 분류와 회귀 모두에 이용분류는 사진 속 인물의 성별을 분류회귀는 입력 데이터에서 (연속적인) 수치를 예측사진 속 인물의 몸무게를 예측하는 문제가 회귀

 

회귀 -> 항등분류 -> 소프트맥스

 

항등함수의 표현

 

시그마로 표현

 

소프트맥스 함수

소프트맥스 함수 수식

 

컴퓨터의 오버플로 문제로 해당 부분처럼 변형하여 구현

해당 수식에 대한 증명은 별도로 포스팅 할 예정.

 

수식이 의미하는 바는

지수 함수를 계산할 때 어던 정수를 더하거나 빼도 결과는 바뀌지 않음.

C'에는 오버플로를 막을 목적으로 사용하므로 입력 신호 중 최댓값을 이용하는게 일반적임.

 

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)  # 오버플로 대책
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a

    return y

 

소프트맥스 함수는 0과 1사이의 실수

 

따라서 소프트맥스 합수의 총합은 1이며 출력 총합이 1이 된다는 점은 소프트 맥스 함수의 중요한 성질 => 확률로 변환할 수 있음.

 

소프트맥스 함수의 특성항 각 원소의 대소 관계는 변하지 않음. 왜냐하면 exp(x)가 단조 증가이기 때문

입력부 사이의 대소관계가 결과값 사이의 대소관계로 그대로 이어짐.

 

신경망을 이용한 분류에서는 일반적으로 가장 큰 출력을 내는 뉴런에 해당하는 클래스로만 인식

또한 소프트맥스 함수를 적용해도 가장 큰 출력의 위치는 달라지지 않음.

즉, 출력부에 소프트맥스 함수를 생략해도 된다. 이로 인하여 지수함수 계산에 드는 자원 낭비를 줄일 수 있음.

 

기계학습의 문제 풀이는 학습추론의 두 단계를 거쳐 이루어짐.

 

손글씨 숫자 인식

import sys
import os
import pickle
import numpy as np
sys.path.append(os.pardir)  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
from mnist import load_mnist
from common.functions import sigmoid, softmax


# 3.6.1 MNIST 데이터셋
'''
0~9 숫자 이미지로 구성.
훈련 이미지 60000장, 시험 이미지 10000장
28*28 크기의 회색조 이미지이며 각 픽셀은 0~255의 값을 가짐
레이블은 정답에 해당하는 숫자
'''아하 
# 처음 한 번은 몇 분 정도 걸림
# 이미지를 numpy 배열로 저장
# flatten : 입력 이미지를 평탄화(1차원 배열로)
# normalize : 입력 이미지를 정규화(0.0~1.0 사이의 값으로)
# one_hot_label : 레이블을 원-핫 인코딩 형태로 저장
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True,
                                                  normalize=False)

# 각 데이터의 형상 출력
print(x_train.shape)  # (60000, 784)
print(t_train.shape)  # (60000,)
print(x_test.shape)  # (10000, 784)
print(t_test.shape)  # (10000,)


# 3.6.2 신경망의 추론 처리
'''
입력층 784개, 출력층 10개,
은닉층 50개, 100개로 구성(임의)
'''


def get_data():
    (x_train, t_train), (x_test, t_test) = \
        load_mnist(flatten=True, normalize=True, one_hot_label=False)
    return x_test, t_test


def init_network():
    with open("python/ch3.신경망/sample_weight.pkl", 'rb') as f:
        # 학습된 가중치 매개변수가 담긴 파일
        # 학습 없이 바로 추론을 수행
        network = pickle.load(f)

    return network


def predict(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = softmax(a3)

    return y


x, t = get_data()
network = init_network()
accuracy_cnt = 0

'''
for i in range(len(x)):
    y = predict(network, x[i])
    p = np.argmax(y)  # 확률이 가장 높은 원소의 인덱스를 얻는다.
    if p == t[i]:
        accuracy_cnt += 1

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))  # Accuracy:0.9352
'''

# 3.6.3 배치 처리
batch_size = 100

for i in range(0, len(x), batch_size):
    x_batch = x[i:i+batch_size] # 0~99, 100~=199 이렇게 묶어서 처리함.
    y_batch = predict(network, x_batch) 
    p = np.argmax(y_batch, axis=1)
    accuracy_cnt += np.sum(p == t[i:i+batch_size])

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))  # Accuracy:0.9352

 

와 코드 진짜 어렵다 .. 

 

딥러닝에 전처리 활발히 사용.

앞의 예에서는 각 픽셀을 255로 나누는 단순 정규화 수행하였으나, 현업에서는 데이터 전체의 분포를 고려해 전처리 수행

전체 평균과 표준 편차를 이용해, 데이터들이 0을 중심으로 분포하도록 이동하거나 데이터의 범위를 제한하는 정규화 수행. 전체 데이터를 균일하게 분포시키는 데이터 백색화 기법도 있음.

 

위에꺼 분석하려면 형상을 파악해야 함.

 

 

배치란?
컴퓨터로 계산할 때 큰 이점을 줌. 이미지 1장당 처리 시간을 대폭 줄여주는 것.

수치 계산 라이브러리 대부분이 큰 배열 효율적으로 처리하도록 고도화되어 있음.

커다란 신경망에서는 데이터 전송이 병목으로 작용하는 경우가 자주 있어서 배치 처리를 통해 버스에 주는 부하를 줄임.

 

정확히는 느린 I/O를 통해 데이터를 읽는 횟수가 줄어 빠른 CPU나 GPU로 순수 계산을 수행하는 비율이 높아짐.

컴퓨터에서는 작은 배열을 여러 번 계산하는 것보다 큰 배열을 한꺼번에 계산하는게 더 빠름.

 

정리

 - 신경망에서는 활성화 함수로 시그모이드 함수와 ReLU 함수 같은 매끄럽게 변화하는 함수 이용

 - 넘파이의 다차원 배열을 잘 사용하면 신경망을 효율적으로 구현

 - 기계학습 문제는 회귀와 분류로 나눌 수 있음

 - 출력층의 활성화 함수로는 회귀에서는 주로 항등 함수, 분류에서는 주로 소프트맥스 함수 이용

 - 분류에서는 출력층의 누런 수를 분류하려는 클래스 수와 같게 설정

 - 입력 데이터를 묶는 것을 배치라 함. 배치 단위 수행시 더 빨ㄹ ㅣ수행 가능

 

 

 

 

'AI 및 자동화' 카테고리의 다른 글

티스토리 크롤링 포스팅 제목과 링크 추출 자동화 (Python)  (10) 2024.10.01
[DL] 신경망 학습  (0) 2024.04.23
[DL] 퍼셉트론  (0) 2024.04.17