학습이란 훈련 데이터로부터 가중치 매개변수의 최적값을 자동으로 획득하는 것을 뜻한다.
신경망의 특징은 데이터를 보고 학습 할 수 있다는 점이다.
자동으로 결정한다는 뜻기계학습은 데이터가 생명이다. 데이터에서 답을 찾고 데이터에서 패턴을 발견하고 데이터로 이야기를 만드는 것이 기계학습.

위 이미지에서 5를 인식하고 싶다면 이미지에서 특징을 추출하고 그 특징의 패턴을 기계학습 기술로 학습하는 방법이 있다.
여기서의 특징이란, 입력 데이터에서 본질적인 데이터를 정확하게 추출할 수 있도록 설계된 변환기를 가리킨다.
이미지의 특징은 보통 벡터로 기술한다.
컴퓨터 비전 분야에서는 SIFT, SURF, HOG 등의 특징을 사용하고, 이들의 특징을 사용하여 이미지 데이터를 벡터로 변환하고, 변환된 벡터를 가지고 지도 학습 방식의 대표 분류 기법인 SVM, KNN으로 학습 가능하다.

규칙을 '사람'이 만드는 방식에서 '기계'가 데이터로부터 배우는 방식으로의 패러다임 전환.
💡
딥러닝을 종단간 기계학습이라고도 함.
- 여기서 종단간은 '처음부터 끝까지'라는 의미
- 데이터(입력)에서 목표한 결과(출력)를 사람의 개입 없이 얻는다는 뜻을 답고 있음.
신경망은 주어진 데이터를 온전히 학습하고, 주어진 문제의 패턴을 발견하려고 시도한다.
end-to-end로 학습할 수 있다.기계학습 문제는 데이터를 훈련 데이터와 시험 데이터로 나눠 학습과 실험을 수행하는 것이 일반적임.
왜 나눌까??
범용 능력은 아직 보지 못한 데이터(훈련 데이터에 포함되지 않는 데이터)로도 문제를 올바르게 풀어내는 능력
그래서 데이터셋 하나로만 매개변수의 학습과 평가를 수행하면 올바른 평가가 될 수 없음
신경망 학습에서는 현재의 상태를 하나의 지표로 표현한다.
신경망 학습에서 사용하는 지표는 손실 함수이라고 한다.
나쁨을 나타내는 지표로, 현재의 신경망이 훈련 데이터를 얼마나 잘 처리하지 못하느냐를 나타냄.가장 많이 쓰이는 손실 함수는 오차제곱합이다.

오차제곱합은 각 원소의 출력(추정 값)과 정답 레이블(참 값)의 차()를 제곱한 후, 그 총합을 구한다.
## MNIST 손글씨 SSE 예제
# y_k
# 첫 번째 인덱스부터 순서대로 숫자 '0','1',..일 때의 값
# Softmax 함수 출력값. (확률로 해석 가능)
# 이미지가 '0'일 확률은 0.1로 해석
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
# t_k
# 정답을 가리키는 원소는 1 (숫자 2가 정답)
# 원-핫 인코딩 : 한 원소뫈 1로 하고 그 외는 0으로 표기
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# SSE
def sum_squares_error(y: np.array, t: np.array):
return 0.5 ** np.sum((y-t)**2)
# 정답은 '2'
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# ex1: '2'일 확률이 가장 높다고 추정함 (0.6)
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
sum_squares_error(np.array(y), np.array(t)")
>>> 0.09750000....
# ex2: '7'일 확률이 가장 높다고 추정함 (0.6)
y = [0.1, 0.05, 0.0, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
sum_squares_error(np.array(y), np.array(t)")
>>> 0.5975000....
ex1)가 오차가 더 작으니 정답에 더 가까울 것으로 판단할 수 있음또 다른 손실 함수로서 교차 엔트로피 오차도 자주 이용한다.

신경망 출력이 0.6이라면 교차 엔트로피 오차는 -log0.6으로 결과는 0.51이 된다.
신경망 출력이 0.1이라면 -log0.1으로 출력은 2.30이 된다.
즉, 교차 엔트로피 오차는 정답일 때의 출력이 전체 값을 정하게 된다.
자연로그 = 의 그래프이다.
1일 때, 는 0이 되고, 가 0에 가까워질수록 의 값은 점점 작아진다.마찬가지로, 정답에 해당하는 출력이 커질수록 0에 다가가다가, 그 출력이 1일 때 0이 된다.
def cross_entory_error(y: np.array, t: np.array):
delta = 1e-7
return -np.sum(t*np.log(y + delta))
np.log를 계산할 때 delta를 더했는데 이것은 np.log() 함수에 0을 입력하면 -inf가 되어서 계산을 진행할 수 없게 되기 때문이다.
0이 되지 않도록 하기 위해서 delta를 더해주는 것이다.# CEE 계산 (정답 2)
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
cross_entropy_error(np.array(y), np.array(t))
>>> 0.510825...
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
cross_entropy_error(np.array(y), np.array(t))
>>> 2.3025840...
기계학습 문제는 훈련 데이터에 대한 손실 함수의 값을 구하고, 그 값을 최대한 줄여주는 매개변수를 찾아내는 것이다.
100개 있으면 그로부터 계산한 100개의 손실 함수 값들의 합을 지표로 삼는 것훈련 데이터 모두에 대한 손실 함수의 합을 구하는 방법을 생각해볼 때 교차 엔트로피의 오차는 다음과 같이 구해볼 수 있다.

데이터가 개라면
마지막에 으로 나누어 정규화한다.
평균 손실 함수를 구하는 것하지만 빅데이터 수준이 되면 N이 매우 거대한 값이 되므로 일일이 손실 함수를 계산하는 것은 비현실적이다.
이러한 일부를 미니배치 라고 한다.
import sys,os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist # MNIST 데이터 셋을 읽어오는 함수(훈련 데이터와 시험 데이터를 읽는다)
(x_train, t_train), (x_test, t_test) = \
load_mnist(normalize=True, one_hot_label=True) # one_hot_label = True 로 원-핫 인코딩을 한다. -> 정답위치만 1 나머지 0
print(x_train.shape) # (60000,784) # 28x28x1 픽셀을 flatten
print(t_train.shape) # (60000,10)
train_size = x_train.shape[0]
batch_size = 10
# 훈련 데이터 중 10개만 랜덤으로 추출하는 함수
# 이 함수가 출력한 배열을 미니배치로 뽑아낼 데이터의 인덱스로 사용
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
np.random.choice(60000,10)
>>> array([8013, 14666, 52210, 12420, 8107, 21411, 27210, 10153, 48920, 58223])
미니배치 같은 배치 데이터를 지원하는 교차 엔트로피 오차를 구현하기 위해서는 교차 엔트로피 오차(데이터를 하나씩 처리하는 구현)를 조금만 바꿔주면 된다.
def cross_entropy_error(y: np.array, t: np.array):
# 미니 배치 shape을 맞추기 위함
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
batch_size = y.shape[0]
return -np.sum(t * np.log(y + 1e-7)) / batch_size
y : 신경망의 출력t : 정답 레이블y가 1차원이라면, 즉 데이터 하나당 교차 엔트로피 오차를 구하는 경우는 reshape 함수로 데이터의 형상을 바꿔준다.
그리고 배치의 크기로 나눠 정규화하고 이미지 1장당 평균의 교차엔트로피 오차를 계산한다.
우리의 궁극적인 목적은 높은 정확도를 끌어내는 매개변수를 찾는 것이다. 그렇다면 정확도라는 지표를 놔두고 손실 함수의 값이라는 우회적인 방법을 택하는 이유는 대체 뭘까??
이 의문은 신경망 학습에서의 미분의 역할에 주목하면 해결된다.
미분(정확도는 기울기)을 계산하고, 그 미분 값을 단서로 매개변수의 값을 서서히 갱신하는 과정을 반복한다.가중치 매개변수의 손실 함수의 미분이란 가중치 매개변수의 값을 아주 조금 변화시켰을 때, 손실 함수가 어떻게 변하나라는 의미이다.
만약 이 미분 값이 음수면 그 가중치 매개변수를 양의 방향으로 변화시켜 손실 함수의 값을 줄일 수 있다.
반대로, 미분 값이 양수면 가중치 매개변수를 음의 방향으로 변화시켜 손실 함수의 값을 줄일 수 있다.
만약 미분 값이 0이면 어느 쪽으로 움직여도 손실 함수의 값이 줄어들지 않으므로 가중치 매개변수의 갱신이 멈추게 된다.
정확도를 지표로 삼아서는 안 되는 이유는 미분 값이 대부분의 장소에서 0이 되어 매개변수를 갱신할 수 없기 때문이다.

정확도는 매개변수의 미소한 변화에는 거의 반응을 보이지 않고, 반응이 있더라도 그 값이 불연속적으로 갑자기 변화한다.
이는 계단 함수를 활성화 함수로 사용하지 않는 이유와도 연결이 된다.
0 이외의 곳)에서 0이다.계단 함수는 한순간만 변화를 일으키지만, 시그모이드 함수의 미분은 그래프와 같이 출력 (세로축의 값)이 연속적으로 변하고 곡선의 기울기도 연속적으로 변한다.
0이 되지는 않는다.0이 되지 않는 덕분에 신경망이 올바르게 학습할 수 있는 것.미분은 특정 순간의 변화량을 뜻한다.

위 식은 함수의 미분을 나타낸 식이다.
작은 변화가 함수 를 얼마나 변화시키느냐를 의미0에 가깝게 한다는 의미다음은 함수를 미분하는 나쁜 구현의 예이다.
#나쁜 구현 예
# 함수의 이름은 수치 미분에서 따온 numerical_diff
def numerical_diff(f, x):
h = 1e-50
return (f(x + h) - f(x)) / h
하지만 위 미분 계산에는 오차가 있다.
이 오차를 개선한 그래프를 그려보면 다음과 같다.

진정한 미분 : 위치의 함수의 기울기(이를 접선이라 함)위 구현에서의 미분 : 와 사이의 기울기이 오차를 줄이기 위해 와일 떄의 함수 의 차분을 계산하는 방법을 쓰기도 한다.
이 차분은 를 중심으로 그 전후의 차분을 계산한다는 의미에서 중심 차분 혹은 중앙 차분이라 한다.
이를 활용하여 수치 미분을 다시 구현하면 다음과 같이 작성할 수 있다.
def numerical_diff(f, x):
h = 1e-4 # 0.0001
return (f(x+h) - f(x-h)) / (2*h)
간단한 이차함수를 미분해보면 코드는 다음과 같다.
import numpy as np
import matplotlib.pylab as plt
def numerical_diff(f, x):
h = 1e-4 # 0.0001
return (f(x+h) - f(x-h)) / (2*h)
def function_1(x):
return 0.01*x**2 + 0.1*x
x = np.arange(0.0,20.0,0.1)
y = function_1(x)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.plot(x,y)
plt.show()
위 코드는 를 나타낸 파이썬 코드이다.
그래프는 다음과 같다.

이렇게 계산된 미분 값은 에 대한 의 변화량, 즉 함수의 기울기에 해당한다.
가 5일때와 10일 때의 진정한 미분은 차례로 0.2와 0.3이다.
인수들의 제곱 합을 계산하는 식은 다음과 같다.
코드로 구현하면 다음과 같다.
# 넘파이의 배열의 각 원소를 제곱하고 그 합을 구하는 구현
def function_2(x: np.array):
return x[0]**2 + x[1]**2
# 또는 return np.sum(x**2)
2개라는 것이다.그래서 어느 변수에 대한 미분이냐, 즉 와 중 어느 변수에 대한 미분이냐를 구별해야 한다.
이렇게 변수가 여럿인 함수에 대한 미분을 편미분이라고 한다.
편미분은 변수가 하나인 미분과 마찬가지로 특정 장소의 기울기를 구한다.
모든 변수의 편미분을 벡터로 정리한 것을 기울기라고 한다.
기울기는 다음과 같이 구현할 수 있다.
def function_2(x):
return x[0]**2 + x[1]**2
def numerical_grdient(f: function, x: np.array):
h = 1e-4 # -.---1
grad = np.zeros_like(x) # x와 형상이 같은 배열 생성
# 넘파이 배열 x의 각 원소에 대해 수치 미분을 구함.
for idx in range(x.size):
tmp_val = x[idx]
# f(x+h) 계산
x[idx] = tmp_val + h
fxh1 = f(x)
# f(x-h) 계산
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 값 복원
return grad
'''세 점 (3,4), (0,2), (3,0) 에서의 기울기'''
numerical_gradient(function_2, np.array([3.0, 4.0]))
numerical_gradient(function_2, np.array([0.0, 2.0]))
numerical_gradient(function_2, np.array([3.0, 0.0]))
기울기 결과에 마이너스를 붙인 벡터를 그리면 다음과 같다.

기울기는 각 지점에서 낮아지는 방향을 가리킨다.
더 정확히 말하자면, 기울기가 가리키는 쪽은 각 장소에서 함수의 출력을 가장 크게 줄이는 방향이다.
기계학습 문제 대부분은 학습 단계에서 최적의 매개변수를 찾아낸다.
신경망 역시 최적의 매개변수(가중치와 편향)를 학습 시에 찾아야 한다.
최적이란 손실 함수가 최솟값이 될 때의 매개변수 값그러나, 일반적인 문제의 손실 함수는 매우 복잡하다.
이런 상황에서 기울기를 잘 이용해 함수의 최솟값(또는 가능한 한 작은 값)을 찾으려는 것이 경사법이다.
경사법은 현 위치에서 기울어진 방향으로 일정 거리만큼 이동한다.
그런 다음 이동한 곳에서도 마찬가지로 기울기를 구하고, 또 그 기울어진 방향으로 나아가기를 반복한다.
이렇게 해서 함수의 값을 점차 줄이는 것이 경사법이다.
경사법을 수식으로 나타내면 다음과 같다.

한번의 학습으로 얼마만큼 학습해야 할지, 즉 매개변수 값을 얼마나 갱신하는지를 정하는 것이 학습률이다.
변수의 수가 늘어도 같은 식(각 변수의 편미분 값)으로 갱신한다.
또한 학습률의 값은 미리 0.01, 0.001 등 특정 값으로 정해두어야 한다.
신경망 학습에서는 보통 이 학습률 값을 변경하면서 올바르게 학습하고 있는지를 확인하면서 진행한다.
경사하강법을 구현하면 다음과 같다.
def gradient_descent(f, init_x, lr=0.01, step_num=100):
'''
f: 최적화 하려는 함수
init_x : 초깃값
lr : learning rate
step_num : 경사법에 따른 반복 횟수
'''
x = init_x
# 함수의 기울기를 구하고, 그 기울기에 학습률을 곱한 값으로 갱신하는 처리를 step_num번 반복한다.
for i in range(step_num):
grad = numerical_gradient(f, x)
x -= lr * grad
return x
학습률이 너무 크면 큰 값으로 발산하고, 반대로 너무 작으면 거의 갱신되지 않은 채 끝나버린다.
💡
학습률 같은 매개변수를 하이퍼파라미터라고 한다.이는 가중치와 편향 같은 신경망의 매개변수와는 성질이 다른 매개변수이다.
신경망의 가중치 매개변수는 훈련 데이터와 학습 알고리즘에 의해 자동으로 획득되는 매개변수인 반면, 학습률 같은 하이퍼파라미터는 사람이 직접 설정해야 하는 매개변수인 것이다.
일반적으로 이 하이퍼파라미터들은 여러 후보 값 중에서 시험을 통해 가장 잘 학습하는 값을 찾는 과정을 거쳐야 한다.
신경망 학습에서도 기울기를 구해야 하는데, 여기서의 기울기란 가중치 매개변수에 대한 손실 함수의 기울기이다.
가중치가 , 손실 함수가 인 신경망 경우 편미분을 한다.
그리고 손실 함수 이 얼마나 변하는지에 대해서 알려주는 것이 이다.

import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
from common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient
class SimpleNet:
def __init__(self):
self.W = np.random.randn(2,3) # 정규분포로 초기화
def predict(self, x): # 예측을 수행하는 함수
return np.dot(x, self.W)
def loss(self, x, t): # 손실 함수의 값을 구하는 함수
'''
x: 입력 데이터
t: 정답 레이블
'''
z = self.predict(x)
y = softmax(z)
loss = cross_entropy_error(y, t)
return loss
# 기울기 구하기
x = np.array([0.6, 0.9])
t = np.array([0, 0, 1])
net = simpleNet()
f = lambda w: net.loss(x, t)
dW = numerical_gradient(f, net.W)
print(dW) # 기울기 출력
>>> [[ 0.21924763 0.14356247 -0.36281009]
[ 0.32887144 0.2153437 -0.54421514]]
예측을 수행하는 predict(x)와 손실 함수의 값을 구하는 loss(x,t)가 있다.
인수 x는 입력 데이터, t는 정답 레이블이다.
기울기는 numerical_gradient(f,x)를 통해 구할 수 있다.
f는 함수, x는 함수 f의 인수이다.
그래서 여기에서는 net.W를 인수로 받아 손실 함수를 계산하는 새로운 함수 f를 정의했다.
그리고 이 새롭게 정의한 함수를 numerical_gradient(f,x)에 넘긴다.
dW는 numerical_gradient(f,net.W)의 결과로, 그 형상은 2x3의 2차원 배열이다.
신경망의 기울기를 구한 다음에는 경사법에 따라 가중치 매개변수를 갱신하기만 하면 된다.
신경망 학습의 절차는 다음과 같다.
전제
1단계 - 미니배치
2단계 - 기울기 산출
3단계 - 매개변수 갱신
4단계 - 반복
이것이 신경망 학습이 이뤄지는 순서이며 경사 하강법으로 매개변수를 갱신하는 방법이다.
이때 데이터를 미니배치로 무작위로 선정하기 때문에 확률적 경사 하강법이라고 부른다.
대부분의 딥러닝 프레임워크는 확률적 경사 하강법의 영어 머리글자를 딴 SGD라는 함수로 이 기능을 구현하고 있다.
import sys, os
sys.path.append(os.pardir)
from common.functions import *
from common.gradient import numerical_gradient
class TwoLayerNet:
def __init__(self,
input_size,
hidden_size,
ouput_size,
weight_init_std=0.01):
# 가중치 초기화
self.params = {}
self.params['W1'] = weight_init_std * \
np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * \
np.random.randn(hidden_size, ouput_size)
self.params['b2'] = np.zeros(output_size)
def predict(self, x):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
return y
# x: 입력 데이터, t: 정답 레이블
def loss(self, x, t):
y = self.predict(x)
return cross_entropy_error(y, t)
def accuracy(self, x, t):
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
# x: 입력 데이터, t: 정답 레이블
def numerical_gradient(self, x, t):
loss_W = lambda W: self.loss(x, t)
grads = {}
grads['W1'] = numerical_gradient(loss_W, self.params['W1']) # (784, 100)
grads['b1'] = numerical_gradient(loss_W, self.params['b1']) # (100,)
grads['W2'] = numerical_gradient(loss_W, self.params['W2']) # (100, 10)
grads['b2'] = numerical_gradient(loss_W, self.params['b2']) # (10,)
return grads
중요 변수와 메서드를 정리한 표는 다음과 같다.


params 변수에는 이 신경망에 필요한 매개변수가 모두 저장되고, params 변수에 저장된 가중치 매개변수가 예측 처리(순방향 처리)에서 사용된다.
grads 변수에는 params 변수에 대응하는 각 매개변수의 기울기가 저장된다.
TwoLayerNet의 메서드들을 살펴보면 init을 통해 클래스를 초기화한다.
loss(self, x ,t)는 손실 함수의 값을 계산하는 메서드이다.
교차 엔트로피 오차를 구하도록 구현했다.numerical_gradient(self, x, t) 메서드는 각 매개변수의 기울기를 계산한다.
마지막 gradient(self,x,t)는 오차역전파법을 사용하여 기울기를 효율적이고 빠르게 계산한다.
미니배치 학습이란 훈련 데이터 중 일부를 무작위로 꺼내고(미니배치), 그 미니배치에 대하여 경사법으로 매개변수를 갱신합니다.
import numpy as np
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)
train_loss_list=[]
# 하이퍼파라미터
iters_num = 10000 # 반복 횟수
train_size = x_train.shape[0]
batch_size = 100 # 미니배치 크기
learning_rate = 0.1
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
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','b1','W2','b2'):
network.params[key] -= learning_rate * grad[key]
# 학습 경과 기록
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
이 코드에서는 미니배치 크기를 100으로 했다.
매번 60,000개의 훈련 데이터에서 임의로 100개의 데이터를 추려내고 그 미니배치를 대상으로 확률적 경사 하강법을 수행해 매개변수를 갱신한다.
경사법에 의한 갱신 횟수를 10,000번으로 설정하고, 갱신할 때마다 훈련 데이터에 대한 손실 함수를 계산하고, 그 값을 배열에 추가한다.
이 손실함수의 값이 변화하는 추이를 그래프로 나타내면 다음과 같다.

학습 횟수가 늘어가면서 손실 함수의 값이 줄어든다.
위 그래프를 통해 손실 함수의 값이 점점 내려가는 것을 확인했는데 이 손실 함수 값이란 훈련 데이터의 미니배치에 대한 손실 함수의 값이다.
다만 이 결과만으로는 다른 데이터셋에도 비슷한 학습효과를 발휘할 지는 확신할 수 없다.
그래서 신경망 학습에서는 훈련 데이터 외의 데이터를 올바르게 인식하는지를 확인해야 한다.
신경망 학습의 원래 목표는 범용적인 능력을 익히는 것이다.
이를 위해 다음 구현에서는 학습 도중 정기적으로 훈련 데이터와 시험 데이터를 대상으로 정확도를 기록한다.
💡
에폭은 하나의 단위이다.
- 1에폭은 학습에서 훈련 데이터를 모두 소진했을 때의 횟수에 해당한다.
- ex) 훈련 데이터 10,000개를 100개의 미니배치로 학습할 경우, 확률적 경사 하강법을 100회 반복하면 모든 훈련 데이터를 '소진'한 게 된다.
- 이 경우,
100회가1에폭이 된다.
import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
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 = []
# 1에폭당 반복 수
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', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
# 학습 경과 기록
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
# 1에폭당 정확도 계산
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))
# 그래프 그리기
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
이 코드를 실행시켜 얻은 그래프는 다음과 같다.

학습(에폭)이 진행될수록 훈련데이터와 시험 데이터를 사용하고 평가한 정확도가 모두 좋아지고 있다.
- 기계학습에서 사용하는 데이터셋은 훈련 데이터와 시험 데이터로 나눠 사용한다.
- 훈련 데이터로 학습한 모델의 범용 능력을 시험 데이터로 평가한다.
- 신경망 학습은 손실 함수를 지표로, 손실 함수의 값이 작아지는 방향으로 가중치 매개변수를 갱신한다.
- 가중치 매개변수를 갱신할 때는 가중치 매개변수의 기울기를 이용하고, 기울어진 방향으로 가중치의 값을 갱신하는 작업을 반복한다.
- 아주 작은 값을 주었을 때의 차분으로 미분하는 것을 수치미분이라고 한다.
- 수치 미분을 이용해 가중치 매개변수의 기울기를 구할 수 있다.
- 수치 미분을 이용한 계산에는 시간이 걸리지만, 그 구현은 간단하다. (오차역전파는 기울기를 고속으로 구할 수 있다.)