훈련 데이터로부터 가중치 매개변수의 최적값을 자동으로 획득하는 것을 의미한다.
신경망은 위 이미지처럼 있는 그대로 학습한다.
기계학습 문제는 데이터를 훈련 데이터(train_data)와 시험 데이터(test_data)로 나누는 것이 일반적이다.
신경망도 하나의 지표를 기준으로 최적의 매개변수 값을 탐색하는데 이때 손실 함수를 사용한다.
손실 함수는 신경망 성능의 '나쁨'을 나타내는 지표로 현재 신경망이 얼마나 잘 처리하지 못하느냐를 나타낸다.
가장 많이 사용하는 손실함수는 오차제곱합이다.
여기서 는 신경망의 출력(예상 값), 는 정답 레이블, 는 데이터의 차원 수를 의미힌다.
만약 이전의 MNIST를 예로 들면 와 는 다음과 같이 10개짜리 데이터가 된다.
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y는 softmax의 함수 출력을
t는 윈소의 위치를 말한다.
이제 오차제곱합을 구현했다.
import numpy as np
def sum_squared_error(y, t):
return 0.5 * np.sum((y - t) ** 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]
sum_squared_error(np.array(y), np.array(t)) # np.float64(0.09750000000000003)
여기서 정답이 2고 예측도 2라고 한다면 손실 함수 출력이 작다.
하지만 만약 정답과 예측이 다르면
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
sum_squared_error(np.array(y), np.array(t)) # np.float64(0.5975)
이렇게 손실 함수의 출력이 높은 것을 볼 수 있고, 이것을 보고 오차가 작으니 정답에 가깝운 것을 알 수있게 된다.
다른 자주 쓰는 손실 함수로는 교차 엔트로피 오차(cross entropy error)
수식과 그래프는 아래와 같다.
해당 식은 자연로그를 계산한다.
예를 들어 정답 레이블이 2고 신경망의 출력이 0.6이라면 교차 엔트로피의 오차는 가 된다.
또한 신경망의 출력이 0.1이면 이 된다.
즉 교차 엔트로피의 오차는 정답일 때의 출력이 전체 값을 정하게 된다.
x가 1일 때 y는 0이 되고, x가 0에 가까워질수록 y는 점점 작아진다.
정답이 아닌 경우는 0이 되어 결과에 영향을 주지 않는다.
이것을 코드로 구현해보자.
"""
y와 t는 넘파이 배열이다.
그리고 log를 계산하는데 delta를 더했다.
그 이유는 0이 입력되면 -inf가 되어 더이상 계산할 수 없기 때문이다.
"""
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
t = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0]) # 정답 2
y = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]) # 예측 2
cross_entropy_error(y, t) # np.float64(0.510825457099338)
y = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]) # 예측 7
cross_entropy_error(y, t) # np.float64(2.302584092994546)
정답이 똑같이 2인 경우에 하나는 예측이 2고 다른 하나는 예측이 7이다.
이때 오차는 각각 0.5, 2.3이 나왔다.
즉 오차 값이 작을수록 정답이라는 의미가 된다.
만약 훈련 데이터가 100개가 있으면 100개를 다 계산하고 손실 함수 값들의 합을 지표로 삼는다.
이렇게 평균을 통해 1000개든 10000개든 개수에 상관없이 평균 솔실 함수를 구할 수 있다.
하지만 그 데이터가 10만개, 100만개가 넘어간다면 일일이 손실함수를 계산하기가 힘들다.
그래서 일부러 근사치를 이용한다.
훈련 데이터로부터 일부만 골라 학습을 수행한다.
이것을 미니배치라고 한다.
MNIST를 이용하여 미니배치를 구현했다.
from dataset.mnist import load_mnist
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
print(x_train.shape) # (60000, 784)
print(t_train.shape) # (60000, 10)
train_size = x_train.shape[0]
batch_size = 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(train_size, batch_size) # 60000의 숫자 중에서 10개 랜덤으로 선택
# array([ 3890, 7615, 310, 55119, 44854, 15208, 41309, 35443, 10515, 4749])
# 데이터가 하나인 경우
def cross_entropy_error(y, t):
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
# 데이터가 배치로 묶인 경우
def cross_entropy_error(y, t):
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
원 핫 인코딩일 때 t가 0이면 교차 엔트로피도 0이므로 계산을 무시한다.