기존 장에서 이미 학습된 것에서 정해를 찾는 과정이었다면 이번 장은 훈련 데이터로부터 가중치 매개변수의 최적값을 자동으로 획득하는 것을 학습할 예정이다.
E = 1/2 * Σ(t_i - y_i)^2
간단하게 위의 공식인데 정말 단순하게 t_i가 정답 레이블이고 y_i는 신경망 출력 레이블로 그냥 잘못나온 값에 제곱이고 1/2는 미분 편하게 하려고 하는거다. 마침 밑 목차가 수치미분이니깐 나누는걸로 보인다.
틈새 시장으로 원-핫 인코딩에 대해서 소개가 나오는데 정답 레이블에 하나의 원소만 1로 하고 그 외의 것들은 0으로 하는 것을 원-핫 인코딩이라고 한다.
E = -Σ(t_i * log(y_i))
이것도 공식은 간단하다. 이거는 다른것보다 구현하는 과정에서 조금 포인트가 있는데 로그 안에 0이 들어가면 음의 무한대를 향해서 발산하므로 아래와 같이 delta를 통해서 이것이 발생하는 상황을 방지해준다.
def CEE(y, t):
delta = 1e-7
return -np.sum(t*np.log(y+delta))
미분 관련 내용은 아직 따끈따끈해서 대강 넘어가겠다. 책에서도 미분 자체에 대한 설명보다는 파이썬에서 계산과정에서 나올 수 있는 문제들에 집중하여 수치미분을 구현하였다. 코드는 아래와 같다.
def numerical_diff(f, x):
h = 1e-4
return (f(x + h) - f(x - h)) / (2 * h)
앞서 수치 미분을 통해 미분을 구현해 보았다. 그런데 수치 미분은 하나의 차원에 대해서 국한되어 계산되므로 신경망에서 다차원으로 이루어진 가중치 매개변수에 대해서는 적용하기에 적합하지 않다.
기울기를 잘 활용하면 함수의 최소값을 찾을 수 있는데 이것이 경사 하강법이다. 최적의 매개변수 값을 찾아가는 문제에 경사 하강법을 많이 사용한다. 현재 위치에서 기울기가 낮은 방향으로 정해진 거리만 이동한다. 여기서 정해진 거리를 학습률(learning rate)이라고 한다.
2장에서 단순한 함수의 미분은 변수가 하나였지만, 신경망에서는 가중치가 수천 수만 개의 다차원을 이루고 있어 기울기를 계산하는 것이 부담된다. 아래는 기울기를 쉽게 구하는 방법 중 하나이다.
def gradient(f, x):
h = 1e-4
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
x[idx] = tmp_val + h
fxh1 = f(x)
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val
return grad
단순하게 보자면 모든 변수의 편미분을 벡터로 정리한 것이다. 이를 그대로 사용해 단순하게 경사하강법을 수행하는 것이 gradient descent이다.
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size):
# Weight랑 bias 초기화 해야함
def predict(self, x):
# forward 과정
def loss(self, x, t):
# 손실 함수 구하는거
def accuracy(self, x, t):
# 정확도 구하는거
def gradient(self, x, t):
# 가중치 매개변수 기울기
2층짜리 신경망을 하나의 클래스로 구현해보았다.
# 미니배치 학습
def train(network, x_train, t_train, epochs, batch_size, learning_rate):
train_size = x_train.shape[0]
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(epochs):
# 미니배치 획득
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 기울기 계산
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)
print(f"Epoch {i+1}, Loss: {loss}")
앞서 구현한 TwoLayerNet을 바탕으로 미니배치 학습을 구현했다.
# 시험 데이터로 평가
x_test, t_test = load_mnist(flatten=True, normalize=False)
test_acc = network.accuracy(x_test, t_test)
print(f"정확도 : {test_acc}")
학습한 모델이 실제로 얼마나 잘 작동하는지 시험 데이터로 정확도를 평가한다.
다음은 이렇게 만든 신경망을 더 깊게 쌓아보는 과정을 진행할 예정이다.