728x90
반응형

오버피팅

  • 기계학습에서는 오버피팅 문제가 많다.
  • 오버피팅은 신경망이 훈련 데이터에만 지나치게 적응되어 그 외의 데이터에는 제대로 대응하지 못하는 상태를 말한다.

 

오버피팅 일어나는 경우들

  • 매개변수가 많고 표현력이 높은 모델
  • 훈련 데이터가 적은 경우

오버피팅 강제로 일으켜 확인해보기

  • 60,000개 MNIST 데잍중 300개 사용, 7층 네트워크 사용해 복잡성 높이기, 뉴런 100개, 활성화 함수는 ReLU사용

 

# 4_1 오버피팅 

import os
import sys

sys.path.append(os.pardir)  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
import matplotlib.pyplot as plt
from mnist import load_mnist
from multi_layer_net import MultiLayerNet
from optimizer import SGD

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
# 오버피팅 재현하기 위해 학습 데이터 수 줄이기
x_train = x_train[:300]
t_train = t_train[:300]

# 훈련 수행 코드
network = MultiLayerNet(input_size = 784, hidden_size_list=[100,100,100,100,100,100], output_size=10)
optimizer = SGD(lr = 0.01) # 학습률이 0.01인 SGD로 매개변수 갱신

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)
        
        epoch_cnt += 1
        if epoch_cnt >= max_epochs:
            break
            
            
# 그래프
markers = {'train': 'o', 'test': 's'}
x = np.arange(max_epochs)
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()

 

[그림1] 훈련 데이터(train)와 시험 데이터(test)의 에폭별 정확도 추이

  • 100에폭을 지나는 무렵부터 훈련 데이터의 정확도는 거의 100%이다. 그러나 시험 데이터는 큰 차이를 보이는데, 이유는 훈련 데이터에만 적응(fitting)해버린 결과다.

가중치 감소

  • 오버피팅 억제용으로 많이 이용해온 방법
  • 학습 과정에서 큰 가중치에 대해서는 그에 상응하는 큰 페널티를 부과해 오버피팅을 억제하는 방법
  • 원래 오버피팅은 가중치 매개변수의 값이 커서 발생하는 경우가 많기 때문이다.
# weight decay(가중치 감쇠) 설정 =======================
#weight_decay_lambda = 0 # weight decay를 사용하지 않을 경우
weight_decay_lambda = 0.1
# ====================================================

network = MultiLayerNet(input_size = 784, hidden_size_list=[100,100,100,100,100,100], output_size=10,  weight_decay_lambda=weight_decay_lambda)

 

[그림2] 가중치 감소 적용시 훈련 데이터와 시험 데이터에 대한 정확도 추이

 

  • 가중치 감소 적용시 여전히 차이가 있지만, 가중치 감소를 이용하지 않은 경우와 비교하면 확연히 그 차이가 줄어들었다.
  • 그리고 훈련 데이터에 대한 정확도도 100%(1.0)에 도달하지 못한 점도 있다.

 

드롭아웃(DropOut)

  • 신경망 모델이 복잡해지면 가중치 감소만으로 대응하기 어려워진다. 이럴때 드롭아웃(DropOut)기법을 이용한다.
  • 뉴런을 임의로 삭제하면서 학습하는 방법이다.
    • 훈련 때 은닉층의 뉴런을 무작위로 골라 삭제한다.
    • 삭제한 뉴런은 신호를 전달하지 않게 된다
  • 훈련때는 데이터를 흘릴 때마다 삭제할 뉴런을 무작위로 선택하고, 시험 때는 모든 뉴런에 신호를 전달한다. 
  • 시험 때는 각 뉴런의 출력에 훈련 때 삭제 안 한 비율을 곱해 출력한다.

일반 신경망과 드롭아웃 적용한 신경망

[그림3] 일반 신경망과 드롭아웃 적용한 신경망

class Drouput:
    def __init__(self, dropout_ratio=0.5):
        self.dropout_ratio = dropout_ratio
        self.mask = None
        
    def forward(self, x , train_flg = True):
        if train_flg:
            self.mask = np.random.rand(*x.shape) > self.dropout_ratio
            return x * self.mask
        else:
            return x * (1.0 - self.dropout_ratio)
        
    def backward(self, dout):
        return dout * self.mask
  • 순전파 때마다 self.mask에 삭제할 뉴런 False표시
  • self.mask는 x와 형상이 같은 배열 무작위 생성, 그 값이 dropout_ratio보다 큰 원소만 True로 설정한다.
  • 역전파 때의 동작도 ReLU와 같다. 순전파 때 신호를 통과시키는 뉴런은 똑같이 통과시키고 순전파 때 통과시키지 않은 뉴런은 역전파 때도 신호를 차단한다.

 

드롭아웃 사용시와 사용하지 않을 시의 비교

import os
import sys
sys.path.append(os.pardir)  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
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 = False  # 드롭아웃을 쓰지 않을 때는 False
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()

 

 

[그림4] 왼쪽 드롭아웃 미사용, 오른쪽 드롭아웃 사용

 

앙상블 학습(ensemble learning)

  • 기계학습에서 애용
  • 개별적으로 학습시킨 여러 모델의 출력을 평균 내어 추론하는 방식
  • 같은, 비슷한 구조의 네트워크를 5개 준비해 따로 학습시키고, 시험 때는 그 5개의 출력을 평균 내어 답하는 구조
  • 앙상블 학습시 신경망의 정확도가 몇% 개선된다는 것이 실험적으로 알려져 있다.
  • 드롭아웃은 앙상블 학습과 같은 효과(대략) 하나의 네트워크로 구현했다고 생각할 수 있다.

 

출처 : 밑바닥부터 시작하는 딥러닝

https://www.hanbit.co.kr/store/books/look.php?p_code=B8475831198

 

밑바닥부터 시작하는 딥러닝

직접 구현하고 움직여보며 익히는 가장 쉬운 딥러닝 입문서

www.hanbit.co.kr

 

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기