[책 요약] 밑바닥부터 시작하는 딥러닝1-Chapter 4. 신경망 학습

데이터에서 학습한다!

  • 신경망의 특징은 데이터를 통해 가중치 매개변수의 값을 자동으로 결정한다는 점이다.
  • 데이터 주도 학습
    • 기계학습은 데이터가 생명이다. 데이터에서 답을 찾고 패턴을 찾는다.
    • 보통 어떤 문제를 해결하려 할 때 사람은 이런저런 규칙성을 생각하고 프로그램을 만들려고 한다. 기계학습에서는 모아진 데이터로부터 규칙을 찾아내는 역할을 기계가 담당한다.
    • 이미지에서 특징(Feature)을 추출하고 그 특징의 패턴을 기계학습 기술로 학습하는 방법이 있다. 여기서 말하는 특징은 입력 데이터(이미지)에서 본질적인 데이터(중요한 데이터)를 추출할 수 있도록 설계된 변환기를 가리킨다.
    • 이미지의 특징은 보통 벡터로 기술하고, 컴퓨터 비전 분야에서는 SIFT, SURF, HOG등의 특징을 많이 사용한다.
    • 이런 특징을 사용하여 이미지 데이터를 벡터로 변환하고 변환된 벡터를 가지고 지도 학습 방식의 대표 분류 기법인 SVM, KNN 등으로 학습할 수 있다.
  • 규칙을 사람이 만드는 방식에서 기계가 데이터로부터 배우는 방식으로의 패러다임 변환

  • 훈련 데이터와 시험 데이터
    • 기계학습 문제는 데이터를 훈련 데이터와 시험 데이터로 나눠서 수행한다.
    • 훈련 데이터를 활용하여 최적의 매개변수를 찾고 시험 데이터를 사용하여 앞서 훈련한 모델의 성능을 평가한다.
    • 우리가 원하는 것은 범용적으로 사용할 수 있는 모델이기 때문에 범용 능력을 평가하기 위해서는 훈련 데이터와 시험 데이터를 분리하는 것이 필요하다.
    • 범용 능력은 아직 보지 못한 데이터로도 문제를 올바르게 풀어내는 능력이다.

손실함수

  • 손실 함수(Loss Function)은 신경망 성능의 ‘나쁨’을 나타내는 지표로, 현재의 신경망이 훈련 데이터를 얼마나 잘 처리하지 못하느냐를 나타난다.
  • 평균 제곱 오차(Mean Squared Error)
    • 가장 많이 쓰이는 손실함수는 평균 제곱 오차이다.
      • n은 class 갯수, y_i는 신경망의 출력, t_i는 정답 레이블
      • 1/2를 곱해줄 수도 있음
    • 교차 엔트로피 오차(cross entropy error)
      • t_k는 정답에 해당하는 인덱스의 원소만 1이고 나머지는 0이다(one-hot encoding)
      • 따라서 실질적으로 정답일 때의 \(\log_e y_k\) 의 값을 자연로그를 계산하게 된다.
      • 앞에 마이너스가 붙은 이유는 log 함수가 마이너스 값이기 때문에..
        def cross_entropy_error(y, t):
            delta = 1e-7
            return -np.sum(t*np.log(y+delta))
         
        t = [0, 0, 1]
        y = [0.1, 0.5, 0.4]
        cross_entropy_error(np.array(y), np.array(t)) # 0.9162
         
    • 미니배치 학습
      • 총 합을 배치 N으로 나눠준다
      • 데이터가 너무 많은 경우, 일일이 손실함수를 구하는 것이 현실적이지 않을 수 있다.
      • 이런 경우 일부 데이터를 추려 전체의 ‘근사치’로 이용할 수 있다. 이 일부를 미니배치(mini-batch)라고 한다.
  • 왜 손실함수를 설정하는가?
    • 우리는 정확도를 올리는 것이 목적인데 왜 손실 함수의 값이라는 우회적인 방법을 채택한 것일까?
    • 신경망 학습에서는 최적의 매개변수를 탐색할 때 손실 함수의 값을 가능한 한 작게 하는 매개변수를 찾는다.
    • 이때 매개변수의 미분을 계산하고, 그 미분 값을 단서로 매개변수의 값을 서서히 갱신하는 과정을 반복한다.
    • 정확도를 지표로 하게 되면 대부분의 장소에서 0이 되기 때문에 미분이 불가능하다.
      • 내 생각에 정확도를 미분 가능한 함수로 정의하는게 어렵다는 걸로 설명하는게 더 좋을 것 같은..?
    • 따라서 미분이 가능한 손실 함수를 정의하고 미분을 통해 매개변수의 값을 조정한다.
    • 또한 활성화 함수를 계단 함수로 할 경우, 계단 함수의 미분은 대부분의 장소에서 0이다.
    • 정확도는 매개변수의 미소한 변화에는 거의 반응을 보이지 않고, 반응이 있더라도 그 값이 불연속적으로 갑자기 변화한다. 계단 함수를 활성화 함수로 사용하지 않는 이유

경사법(경사 하강법)

  • 신경망의 최적의 매개변수는 손실 함수가 최솟값이 될 때의 매개변수 값이다
  • 매개변수 공간이 광대하여 어디가 최솟값이 되는 지는 짐작할 수 없다.
  • 이런 상황에서 기울기를 잘 이용해 함수의 최솟값을 찾으려는 것이 경사법이다.
  • 주의할 점은 각 지점에서 함수의 값을 낮추는 방안을 제시하는 지표가 기울기이지만, 기울기가 가리키는 곳에 정말 함수의 최솟값이 있는지는 보장할 수 없다(안장점 또는 고원 등의 이유)
  • 경사법은 현 위치에서 기울어진 방향으로 일정 거리만큼 이동한다.
  • 그리고 그 위치에서 마찬가지로 기울기를 구하고 또 그 기울어진 방향으로 나아가기를 반복한다.
  • 경사법을 수식으로 나타내면,
    • \(\eta\)는 학습률(learning rate)로서, 한 번의 학습으로 얼마만큼 학습해야 할지, 즉 매개변수 값을 얼마나 갱신하느냐를 정하는 것이다.

학습 알고리즘 구현하기

  1. 미니배치: 훈련 데이터 중 일부를 무작위로 가져온다.
  2. 기울기 산출: 미니배치의 손실 함수 값을 줄이기 위해 각 가중치 매개변수의 기울기를 구한다. 기울기는 손실 함수의 값을 가장 작게 하는 방향을 제시한다.
  3. 매개변수 갱신: 가중치 매개변수를 기울기 방향으로 아주 조금 갱신한다
  4. 1~단계를 반복한다
  • 데이터를 미니배치로 무작위로 선정하기 때문에 확률적 경사하강법(stochastic gradient descent, SGD)라고 부른다.
# coding: utf-8
%cd /content/drive/MyDrive/deep-learning-from-scratch/ch04
import sys, os
sys.path.append('/content/drive/MyDrive/deep-learning-from-scratch/')  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
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()

정리

  • 기계학습에서 사용하는 데이터셋은 훈련 데이터와 시험 데이터로 나눠 사용한다.
  • 훈련 데이터로 학습한 모델의 범용 능력을 시험 데이터로 평가한다.
  • 신경만 학습은 손실 함수를 지표로, 손실 함수의 값이 작아지는 방향으로 가중치 매개변수를 갱신한다.
  • 가중치 매개변수를 갱신할 때는 가중치 매개변수의 기울기를 이용하고, 기울어진 방향으로 가중치의 값을 갱신하는 작업을 반복한다.
  • 아주 작은 값을 주었을 때의 차분으로 미분하는 것을 수치 미분이라고 한다.
  • 수치 미분을 이용해 가중치 매개변수의 기울기를 구할 수 있다.