[밑바닥딥러닝] 14. 과대적합(Overfitting) 대응 - 규제, 드롭아웃

2021. 10. 16. 21:20Deep Learning

본 게시글은 한빛미디어 『밑바닥부터 시작하는 딥러닝, 사이토 고키, 2020』의 내용을 참조하였음을 밝힙니다.

 

 

과대적합(Overfitting)은 모델의 표현력이 복잡해지거나, 훈련 데이터 수가 적을 때 주로 발생한다. 

 

모델이 과대적합되면 훈련 데이터에 대해서만 정확해지기 때문에 범용적인 모델을 만들 수 없어진다. 

 

이번 장에서는 과대적합을 막기 위한 L1, L2 규제와 드롭아웃(dropout)이라는 방법에 대해서 알아보도록 하자.

 

 

 

l1, l2 규제


l1, l2 규제

출처 : https://medium.com/analytics-vidhya/l1-vs-l2-regularization-which-is-better-d01068e6658c

 

L1 규제는 기존 손실값에 (람다(λ)값이 곱해진) 가중치의 절대값을 더한다. 

 

가중치 중에 큰 값은 큰 손실을 지니기 때문에 가중치 갱신 때 크게 변하도록 한다. 

 

다시 말해 (기존 방식에 비해 더 큰) 가중치 감소가 이루어진다. 

 

L2 규제 역시 기존 손실값에 가중치의 제곱값을 더해준다. 

 

L2 규제를 구현해보자. 

class TwoLayerNet:
	.
	.
	def loss(self, x, t):
        y = self.predict(x)

        if self.l2:
            weight_decay = 0
            for idx in range(1, 3):
                W = self.params['W' + str(idx)]
                weight_decay += 0.5 * weight_decay_lambda * np.sum(W ** 2)
            return self.lastlayer.forward(y, t) + weight_decay

        y = self.predict(x)
        return self.lastlayer.forward(y, t)

l2 규제에서는 최종 층에서 계산한 손실값에 l2 규제값을 더해준다. 

 

L2 규제값은 각 가중치(W)를 제곱한 것의 총합(np.sum)을 2로 나눠준 값이다.

 

기존(규제없음) vs L2규제

손실 값은 크지만 정확도 측면에서 L2 규제를 적용한 쪽이 더 나은 성능을 보이고 있다. 

 

규제에 관한 자세한 설명은 본 블로그에서 찾을 수 있으니 참조 바란다.

 

https://humankind.tistory.com/7?category=943344 

 

3-1. 규제 - 릿지 회귀(Ridge Regression)

이전 장에서 살펴봤듯이, 예측 모델이 훈련세트에만 정확하게 예측하도록 훈련되어 검증 세트에서의 효과가 떨어지는 것을 과대 적합이라고 한다. 이러한 과대 적합 문제를 해결하는 방법 중

humankind.tistory.com

 

 

 

 

드롭아웃(Dropout)


드롭아웃(Dropout)

출처 : https://kh-kim.github.io/nlp_with_deep_learning_blog/docs/1-14-regularizations/04-dropout/

 

드롭아웃(Dropout)일정 비율대로 의도적으로 각 층의 노드들을 죽이는(Drop) 기법이다. 

 

드롭아웃은 일정 비율(30%, 50%, 70% 등)로 각 층의 노드들을 드롭시킴으로써 모델이 특정 노드에만 

 

의존하지 않도록 한다. 옆에 노드가 없더라도 옆의 노드들이 여러가지 표현력을 골고루 익힐 수 있도록 하는 효과이다.

 

드롭아웃은 훈련 시에 적용하며, 테스트 시에는 모든 뉴런을 사용하지만 각 뉴런에 [1 - 드롭아웃 비율]을 곱한다.

 

import numpy as np

class Dropout:

    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

드롭아웃의 순전파(forward)는 위에 기술한 바와 같고, backward는 흘러온 역전파 값에 순전파 때 사용했던

 

드롭아웃 마스크(mask)를 적용하여 흘려보낸다.