import numpy as np
# MSE 함수 구현defmean_squared_error(y, t):
return0.5 * np.sum((y-t)**2)
# 정답이 2일때
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# 예 1 : 2일 확률이 가장 높다고 했을 때
y = [0.1,0.2,0.6,0.0,0.05,0.02,0.0,0.0,0.0,0.03]
sum_squares_error(np.array(y), np.array(t))
>>> 0.10690000000000004
------------------------------------------------------
# 예 2 : 5일 확률이 가장 높다고 했을 때
y = [0.1,0.2,0.05,0.0,0.5,0.1,0.05,0.0,0.0,0.0]
sum_squares_error(np.array(y), np.array(t))
>>> 0.6075
손실 함수의 출력이 작을수록 정답에 가까울 것으로 판단할 수 있음
4.2.2 교차 엔트로피 오차 (cross entropy error)
: 밑이 e인 자연로그(loge)
: 신경망 모델의 출력
: 정답 레이블
실질적으로 정답일 때의 추정의 자연로그 계산 (정답이 아닌 것은 tk가 0 이므로 결과영향X)
교차 엔트로피 오차는 정답일 때의 출력이 전체 값을 정하게 됨
자연로그 y=logx의 그래프 : 정답출력이 커질수록 0에 다가가다가, 그 출력이 1일 때 0이 됨
Cross entropy 구현
defcross_entropy_error(y, t):
delta = 1e-7# log함수에 0을 입력하면 -inf 출력되므로 이를 막기위해 아주 작은 값 더해줌return -np.sum(t * np.log(y + delta))
수식 : 마지막에 N(데이터의 갯수)으로 나누어 '평균 손실 함수' 구함 --> 훈련 데이터 개수와 관계없이 언제든 통일된 지표 얻을 수 있음
미니 배치 : 데이터 일부를 추려 전체의 '근사치'로 이용하는 것
빅데이터를 대상으로 일일이 손실함수 계산하는 것은 현실적이지 않음
예) 60000장 중 100장 랜덤으로 뽑아 학습
import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정import numpy as np
from dataset.mnist import load_mnist
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True,
one_hot_label=True)
# 무작위로 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() --> 지정한 범위의 수 중에서 무작위로 원하는 개수만 꺼낼 수 있음
무작위로 선택한 인덱스를 사용 / 손실함수도 미니배치로 계산
4.2.4 (배치용) 교차 엔트로피 오차 구현하기
# 데이터가 하나인 경우와 데이터가 배치로 묶여 입력될 경우 모두 처리가능하게 구현defcross_entropy_error(y, t) :
if y.ndim == 1: #y가 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
# 정답레이블이 원-핫 인코딩이 아닌 경우 (숫자 레이블로 주어진 경우)defcross_entropy_error(y, t) :
if y.ndim == 1: #y가 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[np.arange(batch_size), t] + 1e-7)) / batch_size
원-핫 인코딩일 때 t가 0인 원소는 교차 엔트로피 오차도 0이므로, 그 계산은 무시해도 좋다는 것이 핵심
정답에 해당하는 신경망의 출력만으로 교차 엔트로피 오차 계산가능
t * np.log(y) 부분을 np.log(y[np.arange(batch_size), t])로 구현
np.arange(batch_size)는 0부터 batch_size -1까지 배열 생성
각 데이터의 정답레이블에 해당하는 신경망의 출력 추출
예) t = [2,7,0,9,4] 일 때, [y[0,2], y[1,7], y[2,0], y[3,9], y[4,4]]인 넘파이 배열 생성
4.2.5 왜 손실함수를 설정하는가?
'미분'의 역할에 주목하면 정확도 대신 손실함수 쓰는 이유 파악가능
신경망 학습에서는 최적의 매개변수 탐색 시 손실 함수 값 최소화하는 매개변수 값 찾음
이때 매개변수의 미분(기울기)을 계산하고, 그 값을 단서로 매개변수의 값을 서서히 갱신하는 과정 반복
미분 값의 양,음에 따라 반대방향으로 매개변수 변화시켜 손실함수 값 줄일 수 있음
미분 값이 0이 되면 가중치 매개변수의 갱신이 멈춤
정확도를 지표로 삼으면 매개변수의 미분이 대부분의 장소에서 0이 됨
정확도는 매개변수의 미소한 변화에는 거의 반응을 보이지 않고, 반응이 있더라도 그 값이 불연속적으로 갑자기 변화함
계단함수를 활성화함수로 사용하지 않는 것과 같은 이유
매개변수의 작은 변화가 주는 파장을 계단 함수가 말살하여 손실함수의 값에는 아무런 변화가 나타나지 않기 때문
# 미분 구현 (식을 곧이 곧대로 구현할 때)# 미분 구현의 나쁜 예defnumerical_diff(f, x):
h = 10e-50
retrun (f(x+h) - f(x)) / h
함수 f와 함수 f에 넘길 인수 x - 두 인수를 받음, 그러나 개선해야 할 점 있음
h에는 가급적 작은 값 대입하고 싶어 (0에 가까이 하고싶어) 너무 작은값 사용 : 반올림 오차문제(작은값 생략) --> 10e-4사용
f의 차분(임의 두 점에서의 함수 값들의 차이) 문제
x + h와 x 사이의 함수 f의 차분을 계산하지만, 이 계산에는 애당초 오차가 있음
'진정한 미분'은 x위치의 함수의 기울기(=접선)에 해당
그러나 구현에서는 (x+h)와 x사이의 기울기이므로 엄밀히 일치하지는 않음
h를 무한히 0으로 좁히는게 불가능하여 생기는 한계
수치 미분에는 오차가 포함됨
이 오차를 줄이기 위해 (x+h)와 (x-h)일 때의 함수f의 차분을 계산하는 방법을 쓰기도 함 = 중심차분 or 중앙차분
# 두 개선점 적용해 수치미분 다시 구현defnumerical_diff(f,x):
h = 1e-4return (f(x+h) - f(x-h)) / (2*h)
4.3.2 수치 미분의 예
2차함수 미분해보기 --> y = 0.01x^2 + 0.1x
# 2차 함수 구현하기deffunction_1(x):
return0.01*x**2 + 0.1*x
# 함수 그려보기import matplotlib.pyplot as plt
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()
복잡한 함수는 평평한 곳으로 파고들면서 '고원'상태 (학습이 진행되지 않는상태)가 될 수 있음
경사법 : 현 위치에서 기울어진 방향으로 일정 거리만큼 이동하여 함수의 값을 점차 줄이는 방법
이동한 곳에서 기울기 구한 다음 기울어진 방향으로 이동 반복
[경사법 수식] n기호(에타)는 갱신하는 양 (학습률) : 한번의 학습으로 얼마나 갱신할지
학습률과 같은 매개변수를 하이퍼파라미터라고 함 (사람이 직접 설정해야 하는 매개변수)
# 경사법 구현# f는 구현함수 / init_x는 초깃값 / lr은 학습률 / step_num은 반복 횟수defgradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
for i inrange(step_num):
grad = numerical_gradient(f, x)
x -= lr * grad
return x