본문 바로가기

[Pytorch] Overfitting(과적합) 방지하는 방법

Derrick 발행일 : 2022-05-15
728x90
반응형

 

1. Feature 줄이기 (모델의 복잡도 줄이기)

- Overfitting을 방지하기 위한 첫번째 방법은 모델의 "Feature를 줄이는 방법"이다.
 보통 Neural Network의 복잡도는 hidden layer(은닉층)의 수, parameter의 수로 결정되는데, 모델의 복잡도가 수준 이상으로 높아도 Overfitting(과적합)이 일어날 수 있다.
 ex) 3개 층의 hidden layer를 2개로 줄이는 등

 

2. Data Augmentation (데이터 증식)

 적은 양의 Training data로 학습시킨 모델의 경우, 해당 데이터만의 패턴을 모두 학습하여 Overfitting이 발생할 확률이 높다. 이를 방지하기 위해 의도적으로 기존의 데이터를 조금씩 변형하여 데이터의 총량을 늘리는 데, 이 기법을 "Data Augmentation"이라고 한다.
 → 이미지의 경우, 자주 사용되며 이미지를 Rotation, Crop, Flip 등을 통해 데이터를 증식시킨다.

 

# 이미지 전처리(증식) & 정규화 Example

train_transforms = transforms.Compose(
    [transforms.RandomRotation(50),       # 랜덤 각도로 회전
     transforms.RandomResizedCrop(32),    # 이미지 Resize (32x32)
     transforms.RandomHorizontalFlip(),   # 랜덤으로 수평 뒤집기 (좌우반전)
     transforms.ToTensor(),               # 이미지를 Tensor로 변환
     # RGB의 모든 픽셀을 정규화
     transforms.Normalize(mean=[0.4914, 0.4822, 0.4465], std=[0.2471, 0.2435, 0.2616])]    
)
test_transforms = transforms.Compose(
    [transforms.Resize([32,32]),          # 이미지 Resize
     transforms.ToTensor(),               # 이미지를 Tensor로 변환
     transforms.Normalize(mean=[0.4914, 0.4822, 0.4465], std=[0.2471, 0.2435, 0.2616])]
)

 

[ 출처 : https://buffml.com/image-data-augmentation/ , 강아지]

 

3. Regularization - Weight Decay (가중치 감소)

Weight Decay대표적인 Regularization 기법으로, Training 과정에서 큰 Weight(가중치)에 대해서 이에 상응하는 큰 패널티를 적용해서 Overfitting을 줄이는 방법이다.
복잡한 모델의 경우, 학습이 진행되면서 처음엔 작은 값이었던 weight의 값들이 점차 증가되고 이에 따라 Training data에 영향을 많아 받음으로써 Overfitting이 발생하는 경우가 많다.
→ 이 경우 "weight들의 값이 증가하는 것을 제한함"으로써, 모델의 복잡도를 감소/제한시키고 결과적으로 Overfitting을 방지하는 기법이다.

 

# optimizer 선언할 때, weight decay를 설정할 수 있다.
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=0.1)

 

Weight decay값을 크게 할수록 가중치(W)값은 작아지므로 Overfitting을 완화할 수 있지만, 너무 크게 설정하면 Underfitting 현상이 발생할 수 있으므로, 적당한 값으로 설정하는 것이 좋다.

 

4. Dropout (드랍아웃)

학습을 진행하면서 각 Layer에 존재하는 Node들을 무작위로 turn on/off 시키는 것을 "Dropout"이라고 한다. 이를 통해 특정 조합에 너무 의존적으로 학습하는 것을 방지하고, 매번 서로 다른 신경망을 ensemble하는 효과를 내기 때문에 Overfitting을 방지할 수 있다.

 

[ Dropout ]

 

Dropout를 할 때 주의할 점은, training mode와 evaluation mode를 구분해서 사용해야 한다는 것이다. ( = model.train( ), model.eval( ) )
→ 학습할 때는 node를 무작위로 선택하지만, Test set에서는 모든 node를 사용해서 학습!
→ 만약 dropout 비율을 0.5로 한다면, training할 때마다 절반의 뉴런(node)만 사용한다는 의미!

 

# Dropout이 사용되는 예

layer1 = nn.Sequential(
    nn.Conv2d(3,32,3, padding=1),
    nn.ReLU(),
    nn.Dropout(0.5),                        # Dropout 적용
    nn.Conv2d(32,64,3),
    nn.ReLU(),
    nn.Dropout(0.5),                        # Dropout 적용
    nn.MaxPool2d()
)

 

5. Early Stop (조기 종료)

학습하는 횟수(epoch)이 증가할수록 Train loss는 작아지지만, 도중에 Overfitting이 발생하게 되면 오히려 모델의 성능이 떨어질 수 있다. 이러한 문제를 방지하기 위해 이전 epoch과 비교하여 Loss가 증가했다면, 학습을 중단하는 기법을 "Early stoppping"이라고 한다.


 

[ Early Stop, from Bjarten Github ]

 

# Early Stopping - Import code

import EarlyStopping
from pytorchtools import EarlyStopping

 

# Early Stopping class 선언

class EarlyStopping:
    """설정한 patience 이후로 validation loss가 감소되지 않으면 학습 Early Stop"""
    def __init__(self, patience=7, verbose=False, delta=0, path='checkpoint.pt'):
        """
        Args(인자):
            patience (int): validation loss가 개선된 후 기다리는 기간 (default = 7)
            verbose (bool): True일 경우 각 validation loss의 개선 사항 메세지 출력 (default = False)
            delta (float): 개선되었다고 인정되는 monitered quantity의 최소 변화 (default = 0)
            path (str): checkpoint 저장 경로
        """
        self.patience = patience
        self.verbose = verbose
        self.counter = 0
        self.best_score = None
        self.early_stop = False
        self.val_loss_min = np.Inf
        self.delta = delta
        self.path = path

    def __call__(self, val_loss, model):

        score = -val_loss

        if self.best_score is None:
            self.best_score = score
            self.save_checkpoint(val_loss, model)
        elif score < self.best_score + self.delta:
            self.counter += 1
            print(f'EarlyStopping counter: {self.counter} out of {self.patience}')
            if self.counter >= self.patience:
                self.early_stop = True
        else:
            self.best_score = score
            self.save_checkpoint(val_loss, model)
            self.counter = 0

    def save_checkpoint(self, val_loss, model):
        '''validation loss가 감소하면 모델을 저장'''
        if self.verbose:
            print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}).  Saving model ...')
        torch.save(model.state_dict(), self.path)
        self.val_loss_min = val_loss


# Training model part  - - -
... '''model 코드 생략'''

# early stop 초기화 (실행 전)
early_stopping = EarlyStopping(patience = patience, verbose = True)

...

# validation loss가 감소했을 경우 현재 모델을 checkpoint로 설정
early_stopping(valid_loss, model)        ''' Test loss의 경우 test set으로 변경하면 된다 '''

 

 

 
[ 참고 : early-stopping-pytorch by Bjarten ]

 

 

 

댓글