본문 바로가기

Python/DeepLearning

신경망 학습의 핵심 개념 - 오버피팅

 오버피팅이란 신경망이 훈련 데이터에만 지나치게 적응되어 그 외의 데이터에는 제대로 대응하지 못하는 상태를 말한다. 신경망은 주어지지 않은(훈련하지 않은) 데이터가 주어져도 바르게 식별해낼 수 있어야 한다. 오버피팅은 다음 두 경우에 일어난다.

- 매개변수가 많고 표현력이 높은 모델

- 훈련 데이터가 적은 모델

 구글 번역을 생각해보자. 완벽한 것 같지만 가끔 이런 문제가 일어난다.

핫도그 세계주세요.

 일부러 판단하기 어렵게 7층 네트워크를 가지고 있으며 훈련 데이터는 300개밖에 주어지지 않은 척박한 신경망을 만들어본다. 활성화 함수는 RelU이다.


(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

x_train = x_train[:300]
t_train = t_train[:300]

학습 데이터는 300개로 제한한다.

network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10,
                        weight_decay_lambda=weight_decay_lambda)
optimizer = SGD(lr=0.01)

6개의 hidden layer를 가지고 있으며 각 레이어는 100개의 노드를 가지고 있다. SGD를 사용하여 0.01씩 조정하여주자.

max_epochs = 201
train_size = x_train.shape[0]
batch_size = 100

train_loss_list = []
train_acc_list = []
test_acc_list = []

iter_per_epoch = max(train_size / batch_size, 1)
epoch_cnt = 0

for i in range(1000000000):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    grads = network.gradient(x_batch, t_batch)
    optimizer.update(network.params, grads)

    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("epoch:" + str(epoch_cnt) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc))

        epoch_cnt += 1
        if epoch_cnt >= max_epochs:
            break

 201세대를 돌며 세대마다 정확도를 저장하여 분석해보자.

일정 세대를 넘어가니 학습 데이터와 테스트 데이터와의 간극이 생겼다. 내가 알고 있는건 누구보다도 잘 말하지만 모르는 데이터에 대해선 우물쭈물하게 되는 것이다. 그래도 300개의 데이터를 가지고 60% 이상의 정확도를 갖는건 대단하다. 무작위로 뽑아서 대답하면 10%니까.

 오버피팅을 억제하기 위한 방법 중 한 가지는 가중치 감소이다. 임의로 가중치를 커지지 않게 해서 훈련 데이터에 관한 적합도를 떨어뜨리는 것이다.

훈련 데이터와 테스트 데이터간은 차이가 줄었지만 테스트 데이터의 정확도는 떨어진 것을 확인할 수 있다. 


 두번쨰 방법으로 드롭아웃이라는 기법이 있다. 훈련 때에는 뉴런을 임의로 삭제하면서 학습을 서로 달리하게 하고 테스트 때에는 모든 뉴런을 사용하여 판단하게 하는 것이다. 이런 생각은 누가 어떻게 하는지 모르겠지만 앙상블과 깊은 관련이 있다. 앙상블이란 네트워크를 여러개 만들어 각각 따로 실험하고, 이 결과를 합쳐 결론을 내는 것을 말한다. 

# coding: utf-8
import os
import sys
import numpy as np
import matplotlib.pyplot as plt
from mnist import load_mnist
from multi_layer_net_extend import MultiLayerNetExtend
from trainer import Trainer

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

x_train = x_train[:300]
t_train = t_train[:300]

use_dropout = True
dropout_ratio = 0.2

network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100],
                              output_size=10, use_dropout=use_dropout, dropout_ration=dropout_ratio)
trainer = Trainer(network, x_train, t_train, x_test, t_test,
                  epochs=301, mini_batch_size=100,
                  optimizer='sgd', optimizer_param={'lr': 0.01}, verbose=True)
trainer.train()

train_acc_list, test_acc_list = trainer.train_acc_list, trainer.test_acc_list

markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, marker='o', label='train', markevery=10)
plt.plot(x, test_acc_list, marker='s', label='test', markevery=10)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()