Ch3 신경망

Study/밑바닥부터 시작하는 딥러닝 2021. 1. 6. 15:51

 

 

 

 

 
  • 퍼셉트론은 가중치를 사람이 수동으로 조정해야 함.
  • 신경망은 가중치 매개변수의 적절한 값을 데이터로부터 자동으로 학습하는 능력을 가짐
 

3.1 신경망

3.1.1 신경망의 예

  • 구조 : 입력층, 은닉층 (사람 눈에 보이지 않음), 출력층
 

3.1.2 퍼셉트론 복습

  • y = (0 (b+w1x1+w2x2<=0)
  • y = (1 (b+w1x1+w2xw>0)
  • b는 편향을 나타내는 매개변수, 뉴런이 얼마ㅏ 쉽게 활성화되느냐를 제어
  • w1, w2 는 신호의 가중치를 나타내는 매개변수, 각 신호의 영향력을 제어
 
  • 위 식을 y=h(b+w1x1+w2x2)
  • h(x)=0 (x<=0)
  • h(x)=1 (x>0) 으로 나타낼 수 있음
  • 입력 신호의 총 합이 h(x) 함수를 거쳐 반환되며, 그 변환된 값이 y의 출력이 됨
 

3.1.3 활성화 함수의 등장

  • 활성화 함수 : 입력 신호의 총합을 출력 신호로 변환화는 함수
  • a=b+w1x1+w2x2 = y=h(a) -> h : 활성화함수
 

3.2 활성화 함수

  • 계단 함수 : 임계값을 경계로 출력이 바뀜, 퍼셉트론에서는 활성화 함수로 계단 함수를 이용함
  • 활성화 함수를 계단 함수에서 다른 함수로 변경하는 것이 신경망의 첫 단계
 

3.2.1 시그모이드 함수

  • h(x) = 1/(1+exp(-x))
  • 신경망에서는 활성화 함수로 시그모이드 함수를 이용하여 신호를 변환하고, 그 변환된 신호를 다음 뉴런에 전달
 

3.2.2 계단 함수 구현하기

In [1]:
import numpy as np
import matplotlib.pyplot as plt

def step_function(x):
    if x>0:
        return 1
    else:
        return 0
 

3.2.2 계단 함수의 그래프

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

x=np.arange(-5.0, 5.0, 0.1)
y=step_function(x)
plt.plot(x,y)
plt.ylim(-0.1, 1.1)
plt.show()
 
 

3.2.4 시그모이드 함수 구현하기

In [3]:
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()
 
 

3.2.5 시그모이드 함수와 계단 함수 비교

  • 계단 함수는 0과 1 하나의 값을 돌려주는 반면, 시그모이드는 연속적인 값으로 돌려줌
  • 입력 값이 커지면 1에 같거나 가까워지고, 입력 값이 작으면 0이거나 0에 가까워짐
 

3.2.6 비선형 함수

  • 선형 함수를 이용하면 신경망의 층을 깊게 하는 의미가 없어짐
  • 신경망 모형을 사용할 때는 활성화 함수로 반드시 비선형 함수를 사용해야 함
 

3.2.7 ReLU 함수

  • 입력이 0을 넘으면 그 입력을 그대로 출력하고, 0 이하이면 0을 출력하는 함수
In [4]:
def relu(x):
    return np.maximum(0, x)
 

3.3 다차원 배열의 계산

 

3.3.1 다차원 배열

In [5]:
A=np.array([1,2,3,4]) #1차원 배열
B=np.array([[1,2],[3,4],[5,6]])
 

3.3.2 행렬의 곱

  • 대응하는 차원의 원소 수가 일치해야 함
In [6]:
A=np.array([[1,2],[3,4]])
B=np.array([[5,6],[7,8]])
np.dot(A,B)
Out[6]:
array([[19, 22],
       [43, 50]])
 

3.3.3 신경망에서의 행렬 곱

In [7]:
X=np.array([1,2])
W=np.array([[1,3,5],[2,4,6]])
Y=np.dot(X,W)
print(Y) #행렬의 곱으로 신경망의 계산 수행
 
[ 5 11 17]
 

3.4 3층 신경망 구현하기

 

3.4.1 표기법 설명

  • w(a) _ 12 : a 층의 가중치, 앞층 2번뉴런에서 다음층의 1번 뉴런으로 (책 참고)
 

3.4.2 각 층의 신호전달 구현하기 - 책 참고

In [8]:
# 입력층에서 1층으로의 신호 전달
X=np.array([1.0, 0.5])
W1=np.array([[0.1, 0.3, 0.5],[0.2, 0.4, 0.6]])
B1=np.array([0.1, 0.2, 0.3])

A1 = np.dot(X, W1) + B1
Z1 = sigmoid(A1)

print(A1)
print(Z1)
 
[0.3 0.7 1.1]
[0.57444252 0.66818777 0.75026011]
In [9]:
# 1층에서 2층으로의 신호 전달
W2=np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
B2=np.array([0.1,0.2])

A2 = np.dot(Z1,W2) + B2
Z2 = sigmoid(A2)
In [10]:
# 2층에서 출력층으로의 신호 전달
def identity_function(x):
    return(x)

W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
B3 = np.array([0.1, 0.2])

A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3)

Y
Out[10]:
array([0.31682708, 0.69627909])
 
  • 출력층의 활성화 함수는 풀고자 하는 문제의 성질에 맞게 정함
  • 회귀에서는 항등 함수를, 이진 분류에서는 시그모이드 함수를, 다중 클래스 분류에서는 소프트맥스 함수를 사용하는 것이 일반적
 

3.5 출력층 설계하기

  • 신경망은 분류와 회귀 모두에 이용할 수 있음
  • 분류 : 데이터가 어느 클래스에 속하는지를 예측하는 문제 -> 소프트맥스 함수
  • 회귀 : 입력 데이터에서 연속적인 수치를 예측하는 문제 -> 항등함수
 

3.5.1 항등 함수와 소프트맥스 함수 구현하기

  • 항등 함수 : 입력을 그대로 출력
  • 소프트맥스 함수 : y_k = exp(a_k) / summation(exp(a_i))
In [11]:
a=np.array([0.3, 2.9, 4.0])

def softmax(a):
    exp_a=np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y= exp_a/sum_exp_a
    return y

softmax(a)
Out[11]:
array([0.01821127, 0.24519181, 0.73659691])
 

3.5.2 소프트맥스 함수 구현 시 주의점

  • 소프트맥스 함수는 지수 함수를 사용하는데, 지수 함수는 범위가 너무 커지면 오버플로 문제가 발생함
  • 입력 신호 중 최댓값을 빼주면 올바르게 계산 가능
In [12]:
import warnings
warnings.filterwarnings(action='ignore')

a=np.array([1010,1000,990])
np.exp(a)/np.sum(np.exp(a))
Out[12]:
array([nan, nan, nan])
In [13]:
c=np.max(a)

np.exp(a-c) / np.sum(np.exp(a-c))
Out[13]:
array([9.99954600e-01, 4.53978686e-05, 2.06106005e-09])
In [14]:
def sofmax(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
 

3.5.3 소프트맥스 함수의 특징

In [15]:
a=np.array([0.3, 2.9, 4.0])
y=softmax(a)
print(y)
np.sum(y)
 
[0.01821127 0.24519181 0.73659691]
Out[15]:
1.0
 
  • 소프트맥스 함수 출력의 총합은 1
  • 이 성질 덕분에 소프트맥스 함수의 출력을 확률로 해석할 수 있음
  • 문제를 확률적, 통계적으로 대응할 수 있게 되는 것
  • 소프트맥스 함수를 적용해도 각 원소의 대소 관계는 변하지 않음
 

3.5.4 출력층의 뉴런 수 정하기

  • 분류에서는 분류하고 싶은 클래스 수로 설정하는 것이 일반적
 

3.6 손글씨 숫자 인식

  • 순전파 (forward propagation) : 입력층에서 출력층으로
 

3.6.1 MNIST dataset

In [16]:
!pip install Pillow
 
Requirement already satisfied: Pillow in c:\programdata\anaconda3\envs\tf_gpu\lib\site-packages (8.0.1)
In [17]:
import sys, os
sys.path.append(os.pardir)
from dataset.mnist import load_mnist

from PIL import ImageTk, Image
In [18]:
(x_train, t_train), (x_test, t_test) = \
    load_mnist(flatten=True, normalize=False)
 
  • normalize : 입력 이미지의 픽셀 값을 정규화 하는지
  • flatten : 입력 이미지를 1차원 배열로 만들지
  • one_hot_label : 레이블을 원핫인코딩 형태로 만들지
In [19]:
print(x_train.shape)
print(t_train.shape)
print(x_test.shape)
print(t_test.shape)
 
(60000, 784)
(60000,)
(10000, 784)
(10000,)
In [20]:
def img_show(img):
    pil_img=Image.fromarray(np.uint8(img))
    pil_img.show()

img=x_train[0]
label=t_train[0]
print(label)
 
5
In [21]:
print(img.shape)
img=img.reshape(28,28)
print(img.shape)
 
(784,)
(28, 28)
In [22]:
img_show(img)
 

3.6.2 신경망의 추론 처리

In [23]:
import pickle
In [24]:
def get_data():
    (x_train, t_train), (x_test, t_test) = \
    load_mnist(flatten=True, normalize=False, one_hot_label=False)
    return x_test, t_test

def init_network():
    with open('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
In [25]:
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.9207
 
  • 정규화 : 데이터를 특정 범위로 변환하는 처리
  • 전처리 : 신경망의 입력 데이터에 특정 변환을 가하는 것
  • 백색화 : 전체 데이터를 균일하게 분포시킴
 

3.6.3 배치 처리

  • 배치 : 하나로 묶은 입력 데이터
In [26]:
x,_ = get_data()
network=init_network()
W1,W2,W3 = network['W1'], network['W2'], network['W3']

print(x.shape)
print(x[0].shape)
print(W1.shape)
print(W2.shape)
print(W3.shape) # 다차원 배열의 대응하는 차원의 원소 수가 일치함
 
(10000, 784)
(784,)
(784, 50)
(50, 100)
(100, 10)
In [27]:
x,_ = get_data()
network=init_network()

batch_size=100
accuracy_cnt=0

for i in range(0,len(x),batch_size):
    x_batch=x[i:i+batch_size]
    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.9207
 
  • 데이터를 배치로 처리함으로써 효율적이고 빠르게 처리할 수 있음
 

3.7 정리

  • 신경망에서는 활성화 함수로 시그모이드 함수나 ReLU 함수 같은 매끄럽게 변화하는 함수를 이용
  • 넘파이의 다차원 배열을 잘 사용하면 신경망을 효율적으로 구현할 수 있음
  • 기계학습 문제는 크게 회귀와 분류로 나눌 수 있음
  • 출력층의 활성화 함수로는 회귀에서는 주로 항등 함수를, 분류에서는 주로 소프트맥스 함수를 이용
  • 분류에서는 출력층의 뉴런 수를 분류하려는 클래스 수와 같에 설정
  • 입력 데이터를 묶은 것을 배치라 하며, 추론 처리를 이 배치 단위로 진행하면 결과를 훨씬 빠르게 얻을 수 있음

'Study > 밑바닥부터 시작하는 딥러닝' 카테고리의 다른 글

Ch6 학습 관련 기술들  (0) 2021.01.25
Ch5 오차역전파법  (0) 2021.01.25
Ch4 신경망 학습  (0) 2021.01.19
Ch2 퍼셉트론  (0) 2021.01.06
TOP