티스토리 뷰
공부 : 밑바닥부터 시작하는 딥러닝 1 chapter 4.5~4.6
1. 2층 신경망 클래스 구현 (필요한 내용 주석으로)
import sys, os
sys.path.append(os.pardir)
from common.functions import *
from common.gradient import numerical_gradient
class TwoLayerNet: # 2층 신경망, input_size = 입력층 노드 수, hidden_size = 은닉층 노드 수, output_size = 출력층 노드 수
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size) # 1층의 가중치
self.params['b1'] = np.zeros(hidden_size) #1층의 편향
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size) # 2층의 가중치
self.params['b2'] = np.zeros(output_size) # 2층의 편향
def predict(self, x): # x : MNIST 이미지 데이터, predict = 2층 신경망 추론 결과 도출
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1 # 데이터와 가중치, 편향 연산 (1층)
z1 = sigmoid(a1) # 활성화 함수 : 시그모이드
a2 = np.dot(z1, W2) + b2 # 데이터와 가중치, 편향 연산 (2층)
y = softmax(a2) # 출력함수 : 소프트맥스
return y
def loss(self, x, t): # x : 이미지데이터, t : 정답 레이블, loss : 손실함수 계산
y = self.predict(x)
return cross_entropy_error(y, t)
def accuracy(self, x, t): # accuracy : 정확도 계산
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y==t) / float(x.shape[0])
return accuracy
def numerical_gradient(self, x, t): # 가중치, 편향의 기울기 계산
loss_W = lambda W: self.loss(x,t)
grads = {} # 기울기 값 저장
grads['W1'] = numerical_gradient(loss_W, self.params['W1']) # 1층의 가중치의 기울기
grads['b1'] = numerical_gradient(loss_W, self.params['b1']) # 1층의 편향의 기울기
grads['W2'] = numerical_gradient(loss_W, self.params['W2']) # 2층의 가중치의 기울기
grads['b2'] = numerical_gradient(loss_W, self.params['b2']) # 2층의 편향의 기울기
return grads
def gradient(self, x, t): # 기울기 계산 성능 개선
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
grads = {}
batch_num = x.shape[0]
# 앞에서부터
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
# 뒤에서부터
dy = (y - t) / batch_num
grads['W2'] = np.dot(z1.T, dy)
grads['b2'] = np.sum(dy, axis=0)
da1 = np.dot(dy, W2.T)
dz1 = sigmoid_grad(a1) * da1
grads['W1'] = np.dot(x.T, dz1)
grads['b1'] = np.sum(dz1, axis=0)
return grads
2. 미니배치 학습 구현
미니배치의 크기를 100으로 하여 mnist의 60,000개의 훈련 데이터 중 100개를 임의로 선택하여 매개변수 값을 갱신
=> 손실함수 값 최소화하도록 매개변수 값 갱신
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
train_loss_list = []
for i in range(iters_num):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# grad = network.numerical_gradient(x_batch, t_batch) # 기존 기울기 계산
grad = network.gradient(x_batch, t_batch) # 성능 개선 (속도 증가)
for key in ('W1', 'W2', 'b1', 'b2'):
network.params[key] -= learning_rate * grad[key]
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
그래프는 train_loss_list의 결과이다. train_loss_list는 미니배치 학습 과정에서의 손실함수 값이고, 해당 결과가 0에 가까워서 최소화를 함을 알 수 있다.
3. 시험 데이터로 평가하기
훈련데이터는 60,000개 중 100개를 임의로 뽑아 10,000번 반복하여 손실함수 값을 최소로 만들었다. 하지만 이것만 가지고는 모든 데이터에 대해 적용했다고 할 수는 없다.
epoch (에폭)을 이용해 시험 데이터(테스트 데이터)에 대한 정확도를 구해보자. (훈련 데이터와 다른 데이터)
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
train_loss_list = []
train_acc_list =[]
test_acc_list =[]
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(iters_num):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# grad = network.numerical_gradient(x_batch, t_batch) # 기존 기울기 계산
grad = network.gradient(x_batch, t_batch) # 성능 개선 (속도 증가)
for key in ('W1', 'W2', 'b1', 'b2'):
network.params[key] -= learning_rate * grad[key]
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
if i%iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
print("train_acc, test_acc : " + str(train_acc)+','+str(test_acc))
주황색 : test_acc, 파란색 : train_acc
에폭 : 60,000개의 데이터를 100개씩 배치해 실행하므로 600회 반복이 1epoch이다. 정확도의 일치여부를 판단하는 것이므로 시험 데이터를 600회 반복할 때마다 train_acc, test_acc 에 정확도 (accuracy)를 추가한다.
이를 통해 600회 반복마다의 훈련데이터와 시험데이터에 대한 정확도가 얼마나 일치하는 지 알 수 있다.
=> 두 그래프가 거의 일치하므로 손실함수를 최소화하는 과정이 잘 이루어졌다.
4. 4장 내용 정리
- 기계학습에서 사용하는 데이터셋은 훈련 데이터와 시험 데이터로 나눠 사용한다.
- 훈련 데이터로 학습한 모델의 범용 능력을 시험 데이터로 평가한다. (매개변수 갱신이 잘 되었는지)
- 신경망 학습은 손실 함수를 지표로, 손실 함수의 값이 작아지는 방향으로 가중치 매개변수를 갱신한다.
- 가중치 매개변수를 갱신할 때는 가중치 매개변수의 기울기를 이용하고, 기울어진 방향으로 가중치의 값을 갱신하는 작업을 반복한다.
- 아주 작은 값이 주어졌을 때 차분으로 미분하는 것 : 수치 미분
- 수치 미분을 이용해 가중치 매개변수의 기울기 (gradient)를 구한다.
- 수치 미분을 이용하여 매개변수의 기울기를 계산하면 시간이 걸린다. (구현 짧음) 오차역전파법은 기울기를 빠르게 구할 수 있다.
'딥러닝' 카테고리의 다른 글
오차역전파법 구현 (0) | 2021.01.14 |
---|---|
오차역전파법 - Affine, Softmax 구현 (0) | 2021.01.14 |
오차역전파법 - 활성화 함수 계층 구현하기 (0) | 2021.01.14 |
오차역전파법 - 계산 그래프 (0) | 2021.01.13 |
신경망 학습 절차 (0) | 2021.01.11 |