머신러닝/딥러닝 공부
분류 (7) - MNIST 숫자 손글씨 분류 모델 (다층 퍼셉트론) 본문
필요한 모듈을 import해준 뒤에 이전 포스팅에서 구현했던 다층 퍼셉트론 모델을 가져오겠습니다.
https://yhyun225.tistory.com/23
- import
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import keras
import math
from sklearn.utils import shuffle
- 다층 퍼셉트론 코드
class MultiLayer:
def __init__(self,learning_rate=0.01,batch_size=32,hidden_node=10):
self.w1=None #은닉층 가중치 행렬
self.b1=None #은닉층 바이어스 배열
self.w2=None #출력층 가중치 행렬
self.b2=None #출력층 바이어스 배열
self.lr=learning_rate #학습률
self.batch_size=batch_size
self.node=hidden_node #은닉층 노드 개수
self.losses=[] # 손실(훈련세트)
self.val_losses=[] # 손실(검증세트)
self.accuracy=[] # 정확도(훈련세트)
self.val_accuracy=[] # 정확도(검증세트)
def init_weights(self,m,n): # 가중치 초기화 함수
k=self.node
self.w1=np.random.normal(0,1,(m,k)) # 가우시안 분포로 초기화 (m x k) 행렬
self.b1=np.zeros(k) # 0으로 초기화
self.w2=np.random.normal(0,1,(k,n)) # 가우시안 분포로 초기화 (k x n) 행렬
self.b2=np.zeros(n) #0으로 초기화
def sigmoid(self,z1): #sigmoid 함수
z1=np.clip(z1,-100,None)
a1=1/(1+np.exp(-z1))
return a1
def softmax(self,z2): #softmax 함수
z2=np.clip(z2,-100,None)
exp_z2=np.exp(z2)
a2=exp_z2/np.sum(exp_z2,axis=1).reshape(-1,1)
return a2
def forward1(self,x): # 입력층 -> 은닉층 순전파
z1=np.dot(x,self.w1)+self.b1
return z1
def forward2(self,a1): # 은닉층 -> 출력층 순전파
z2=np.dot(a1,self.w2)+self.b2
return z2
def loss(self,x,y): # 손실 계산
z1=self.forward1(x)
a1=self.sigmoid(z1)
z2=self.forward2(a1)
a2=self.softmax(z2)
a2=np.clip(a2,1e-10,1-1e-10)
return -np.sum(y*np.log(a2)) #크로스 엔트로피
def backpropagation(self,x,y): # 역전파 알고리즘
z1=self.forward1(x)
a1=self.sigmoid(z1)
z2=self.forward2(a1)
a2=self.softmax(z2)
w2_grad=np.dot(a1.T,-(y-a2)) # 은닉층 가중치의 기울기 계산
b2_grad=np.sum(-(y-a2)) # 은닉층 바이어스의 기울기 계산
#은닉층으로 전파된 오차 계산
hidden_err=np.dot(-(y-a2),self.w2.T)*a1*(1-a1)
w1_grad=np.dot(x.T,hidden_err) # 입력층 가중치의 기울기 계산
b1_grad=np.sum(hidden_err,axis=0) #입력층 바이어스의 기울기 계산
return w1_grad,b1_grad,w2_grad,b2_grad
def minibatch(self,x,y):
iter=math.ceil(len(x)/self.batch_size)
x,y=shuffle(x,y)
for i in range(iter):
start=self.batch_size*i
end=self.batch_size*(i+1)
yield x[start:end],y[start:end]
def fit(self,x_data,y_data,epochs=40,x_val=None,y_val=None):
self.init_weights(x_data.shape[1],y_data.shape[1]) # 가중치 초기화
for epoch in range(epochs):
l=0 # 손실 누적할 변수
#가중치 누적할 변수들 초기화
for x,y in self.minibatch(x_data,y_data):
l+=self.loss(x,y) # 손실 누적
# 역전파 알고리즘을 이용하여 각 층의 가중치와 바이어스 기울기 계산
w1_grad,b1_grad,w2_grad,b2_grad=self.backpropagation(x,y)
# 은닉층 가중치와 바이어스 업데이트
self.w2-=self.lr*(w2_grad)/len(x)
self.b2-=self.lr*(b2_grad)/len(x)
# 입력층 가중치와 바이어스 업데이트
self.w1-=self.lr*(w1_grad)/len(x)
self.b1-=self.lr*(b1_grad)/len(x)
#검증 손실 계산
val_loss=self.val_loss(x_val,y_val)
self.losses.append(l/len(y_data))
self.val_losses.append(val_loss)
self.accuracy.append(self.score(x_data,y_data))
self.val_accuracy.append(self.score(x_val,y_val))
print(f'epoch({epoch+1}) ===> loss : {l/len(y_data):.5f} | val_loss : {val_loss:.5f}',\
f' | accuracy : {self.score(x_data,y_data):.5f} | val_accuracy : {self.score(x_val,y_val):.5f}')
def predict(self,x_data):
z1=self.forward1(x_data)
a1=self.sigmoid(z1)
z2=self.forward2(a1)
return np.argmax(z2,axis=1) #가장 큰 인덱스 반환
def score(self,x_data,y_data):
return np.mean(self.predict(x_data)==np.argmax(y_data,axis=1))
def val_loss(self,x_val,y_val): # 검증 손실 계산
val_loss=self.loss(x_val,y_val)
return val_loss/len(y_val)
모델을 학습시킬 mnist 숫자 손글씨 데이터 세트를 받아오겠습니다. mnist 숫자 손글씨 세트에 대한 설명은 밑의 포스팅에서 확인할 수 있습니다.
https://yhyun225.tistory.com/19
받아온 데이터 세트의 전처리를 해주겠습니다.
# mnist 데이터를 받아옴
(x_train,y_train),(x_test,y_test)=keras.datasets.mnist.load_data()
# 검증 세트 생성
x_train,x_val,y_train,y_val=train_test_split(x_train,y_train,stratify=y_train,test_size=0.2)
# 28 x 28 배열을 1 x 784 배열로 바꿈
x_train = x_train.reshape(x_train.shape[0],28*28)
x_val=x_val.reshape(x_val.shape[0],28*28)
x_test = x_test.reshape(x_test.shape[0],28*28)
# 0~255 값 분포를 0~1 사이에 분포하도록 바꿈
x_train = x_train.astype('float32') / 255.
x_val=x_val.astype('float32')/255.
x_test = x_test.astype('float32') / 255.
# one-hot encoding
y_train = keras.utils.to_categorical(y_train)
y_val=keras.utils.to_categorical(y_val)
y_test = keras.utils.to_categorical(y_test)
print(math.ceil(len(x_train)/256))
이제 모델을 생성한 뒤 학습을 시켜보겠습니다. 학습률은 0.1, 배치의 크기는 256, 은닉층은 100개의 노드를 갖도록 설정하고 40 에포크 동안 학습을 시켰습니다. 결과는 아래와 같습니다.
model=MultiLayer(learning_rate=0.1,batch_size=256,hidden_node=100)
model.fit(x_train,y_train,epochs=40,x_val=x_val,y_val=y_val)
훈련 세트에 대한 정확도는 약 91%, 검증 세트에 대한 정확도는 약 90%가 나오는 것을 확인할 수 있습니다.
이제 이 모델의 성능을 테스트해보겠습니다.
model.score(x_test,y_test)
테스트 세트에 대한 정확도는 90% 정도로, 이전에 구현했던 단층 퍼셉트론에 비해 높은 정확도를 보여줍니다.
다층 퍼셉트론은 기존의 모델들로는 학습이 힘들거나 불가능했던 비선형 데이터들을 분류할 수 있는 기회를 마련하여 좀 더 높은 정확도를 보였습니다. 하지만 다층 퍼셉트론은 이미지 데이터를 분류할 때 각 픽셀의 값을 일렬로 나열하여 입력값으로 사용하기 때문에 이미지에서 정보가 누실되는 단점이 있습니다.
다음 포스팅에서는 이미지 데이터에서 높은 효과를 보이는 합성곱 신경망(Convolutional Neural Network, CNN)에 대해 정리해보겠습니다.
'AI 공부 > Machine Learning' 카테고리의 다른 글
분류 (6) - 다층 퍼셉트론 코드 (파이썬 구현) (0) | 2021.12.02 |
---|---|
신경망 (3) - 역전파 알고리즘(BackPropagation algorithm) (1) | 2021.11.25 |
신경망 (2) - 다층 퍼셉트론(Multi Layer Perceptron)과 활성화 함수(Activation function) (0) | 2021.11.22 |
신경망 (1) - 단층 퍼셉트론 (Single Layer Perceptron) (0) | 2021.11.21 |
분류(5) - MNIST 숫자 손글씨 분류 모델( 다중 선형 분류 ) (0) | 2021.11.18 |