반응형
저번 시간에 딥러닝 구현에 대한 디테일을 살펴보았다.
이번에는 코드로 구현해보자.
#붓꽃 품종 분류 문제(전체 코드))
#은닉층 활성화 함수: ReLU
#출력층 활성화 함수: 소프트맥스 함수
#손실 함수: 교차 엔트로피 오차
#최적화 알고리즘: 확률적 경사 하강법
#배치 사이즈: 8
#은닉층의 뉴런 수: 25
#코드 흐름
#1. 데이터 입력과 전처리
#2. 각 층 구현
#3. 신경망 구축
#4. 미니 배치법으로 학습
#5. 정답률 측정
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
iris_data = datasets.load_iris()
input_data = iris_data.data
correct = iris_data.target
n_data = len(correct) #샘플 수
#standalization
ave_input = np.average(input_data, axis = 0)
std_input = np.std(input_data, axis = 0)
input_data = (input_data - ave_input) / std_input
#원핫 인코딩 변환
correct_data = np.zeros((n_data, 3))
for i in range(n_data):
correct_data[i, correct[i]] = 1.0
#훈련 데이터 테스트 데이터 분할
index = np.arange(n_data)
index_train = index[index % 2 == 0]
index_test = index[index % 2 != 0]
input_train = input_data[index_train, :] #훈련 데이터 입력
correct_train = correct_data[index_train, :] #훈련 데이터 정답
input_test = input_data[index_test, :] #테스트 데이터 입력
correct_test = correct_data[index_train, :] #테스트 데이터 정답
n_train = input_train.shape[0] #훈련 데이터 샘플 수
n_test = input_test.shape[0] #테스트 데이터 샘플 수
#입력 은닉 출력층 뉴런 개수
n_in = 4
n_mid = 25
n_out = 3
wb_width = 0.1
eta = 0.01
epoch = 1600
batch_size = 8
interval = 100
#확률적 경사 하강법
# class BaseLayer:
# def __init__(self, n_upper, n):
# #가중치와 편향(행렬과 벡터)
# self.w = wb_width * np.random.randn(n_upper, n)
# self.b = wb_width * np.random.randn(n)
# def update(self, eta):
# self.w -= eta * self.grad_w
# self.b -= eta * self.grad_b
#아다그라드 구현
class BaseLayer:
def __init__(self, n_upper, n):
self.w = wb_width * np.random.randn(n_upper, n) #가중치(행렬)
self.b = wb_width * np.random.randn(n) #편향(벡터)
self.h_w = np.zeros((n_upper, n)) + 1e-8
self.h_b = np.zeros(n) + 1e-8
def update(self, eta):
self.h_w += self.grad_w * self.grad_w
self.w -= eta / np.sqrt(self.h_w) * self.grad_w
self.h_b += self.grad_b * self.grad_b
self.b -= eta / np.sqrt(self.h_b) * self.grad_b
class MiddleLayer(BaseLayer):
def forward(self, x):
self.x = x
self.u = np.dot(x, self.w) + self.b
self.y = np.where(self.u <= 0, 0, self.u) #ReLU
def backward(self, grad_y):
delta = grad_y * np.where(self.u <= 0, 0, 1) #ReLU 미분
self.grad_w = np.dot(self.x.T, delta)
self.grad_b = np.sum(delta, axis = 0)
self.grad_x = np.dot(delta, self.w.T)
class OutputLayer(BaseLayer):
def forward(self, x):
self.x = x
u = np.dot(x, self.w) + self.b
#softmax function
self.y = np.exp(u) / np.sum(np.exp(u), axis = 1, keepdims=True)
def backward(self, t):
delta = self.y - t
self.grad_w = np.dot(self.x.T, delta)
self.grad_b = np.sum(delta, axis = 0)
self.grad_x = np.dot(delta, self.w.T)
#드롭아웃 구현
class Dropout:
def __init__(self, dropout_ratio) -> None:
self.dropout_ratio = dropout_ratio
def forward(self, x, is_train):
if is_train:
rand = np.random.rand(*x.shape) #난수 행렬
self.dropout = np.where(rand > self.dropout_ratio, 1, 0)
self.y = x * self.dropout
else:
self.y = (1 - self.dropout_ratio) * x
def backward(self, grad_y):
self.grad_x = grad_y * self.dropout
#각층 초기화 2
middle_layer_1 = MiddleLayer(n_in, n_mid)
dropout_1 = Dropout(0.5)
middle_layer_2 = MiddleLayer(n_mid, n_mid)
dropout_2 = Dropout(0.5)
output_layer = OutputLayer(n_mid, n_out)
#순전파
def forward_propagation(x, is_train):
middle_layer_1.forward(x)
dropout_1.forward(middle_layer_1.y, is_train)
middle_layer_2.forward(dropout_1.y)
dropout_2.forward(middle_layer_2.y, is_train)
output_layer.forward(dropout_2.y)
#역전파
def backpropagation(t):
output_layer.backward(t)
dropout_2.backward(output_layer.grad_x)
middle_layer_2.backward(dropout_2.grad_x)
dropout_1.backward(middle_layer_2.grad_x)
middle_layer_1.backward(dropout_1.grad_x)
#가중치, 편향 수정
def uppdate_wb():
middle_layer_1.update(eta)
middle_layer_2.update(eta)
output_layer.update(eta)
#교차 엔트로피 오차 계산
def get_error(t, batch_size):
return -np.sum(t * np.log(output_layer.y + 1e-7)) / batch_size
#오차 기록용 코드
train_error_x = []
train_error_y = []
test_error_x = []
test_error_y = []
#미니 배치법 구현
n_batch = n_train // batch_size #1에포크당 배치수
for i in range(epoch):
#오차 계측
forward_propagation(input_train, is_train=False)
error_train = get_error(correct_train, n_train)
forward_propagation(input_test, is_train=False)
error_test = get_error(correct_test, n_test)
#오차 기록
test_error_x.append(i)
test_error_y.append(error_test)
train_error_x.append(i)
train_error_y.append(error_train)
#경과 표시
if i % interval == 0:
print("Epoch: " + str(i) + "/" + str(epoch),
"Error_train: " + str(error_train),
"Error_test " + str(error_test))
#학습
index_random = np.arange(n_train)
np.random.shuffle(index_random) #인덱스 랜덤 섞기
for j in range(n_batch):
#미니배치 샘플 추출
mb_index = index_random[j * batch_size : (j + 1) * batch_size]
x = input_train[mb_index, :]
t = correct_train[mb_index, :]
#순전파 역전파
forward_propagation(x, is_train=True)
backpropagation(t)
#가중치, 편향 수정
uppdate_wb()
#기록된 오차를 그래프로 표시
plt.plot(train_error_x, train_error_y, label = "Train")
plt.plot(test_error_x, test_error_y, label = "Test")
plt.legend()
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()
#정답률 측정
forward_propagation(input_train, is_train=True)
count_train = np.sum(np.argmax(output_layer.y,
axis = 1) == np.argmax(correct_train, axis = 1))
forward_propagation(input_test, is_train=False)
count_test = np.sum(np.argmax(output_layer.y,
axis = 1) == np.argmax(correct_test, axis = 1))
print("Accuracy Train: ", str(count_train / n_train * 100) + "%",
"Accuracy Test: ", str(count_test / n_test * 100) + "%")
np.argmax(output_layer.y, axis = 1)
np.argmax(correct_train, axis = 1)
구현환경 - VS code(anaconda)
출력:
아다그라드 구현
#아다그라드 구현
class BaseLayer:
def __init__(self, n_upper, n):
self.w = wb_width * np.random.randn(n_upper, n) #가중치(행렬)
self.b = wb_width * np.random.randn(n) #편향(벡터)
self.h_w = np.zeros((n_upper, n)) + 1e-8
self.h_b = np.zeros(n) + 1e-8
def update(self, eta):
self.h_w += self.grad_w * self.grad_w
self.w -= eta / np.sqrt(self.h_w) * self.grad_w
self.h_b += self.grad_b * self.grad_b
self.b -= eta / np.sqrt(self.h_b) * self.grad_b
드롭아웃 구현
#드롭아웃 구현
class Dropout:
def __init__(self, dropout_ratio) -> None:
self.dropout_ratio = dropout_ratio
def forward(self, x, is_train):
if is_train:
rand = np.random.rand(*x.shape) #난수 행렬
self.dropout = np.where(rand > self.dropout_ratio, 1, 0)
self.y = x * self.dropout
else:
self.y = (1 - self.dropout_ratio) * x
def backward(self, grad_y):
self.grad_x = grad_y * self.dropout
samples = np.array([[5.0, 3.5, 1.0, 0.5], #iris1
[5.5, 2.5, 4.0, 1.0], #iris2
[7.0, 3.0, 6.0, 2.0], #iris3
[6.6, 2.5, 1.5, 0.2] #iris4
])
#표준화
ave_input = np.average(samples, axis = 0)
std_input = np.std(samples, axis = 0)
samples = (samples - ave_input) / std_input
#판정(False는 훈련데이터가 아니다)
forward_propagation(samples, False)
print(output_layer.y)
출력:
반응형
'Machine Learning' 카테고리의 다른 글
컨볼루션 신경망(CNN)(2) (0) | 2024.02.23 |
---|---|
컨볼루션 신경망(CNN)(1) (0) | 2024.02.14 |
딥러닝 다층화에 의한 문제점 및 구현에 필요한 과정 (1) | 2024.02.11 |
역전파 구현 및 시각화 해보기 (1) | 2024.02.11 |
역전파(2) (1) | 2024.01.05 |