Machine learning & Deep learning

[Machine learning] Dropout 내가 궁금했던 모든 것 정리

ysk1m 2025. 2. 15. 14:26

머신러닝을 처음 공부할 때 dropout이라는 개념을 봤을 때, 중퇴?라는 뜻으로 외웠던 게 기억났고 그냥 도중 나가는 건가? 이렇게 생각했었습니다. 

 

그때만 해도 제가 공부하기에는 그냥 과적합을 방지하기 위해 몇 개의 node를 kill 하는 거는구나라고 생각했었습니다. 얼마나 얕게 공부했었는지...

 

Dropout에 대해 다시 자세히 공부하면서 가졌던 궁금증을 정리하고 기억하고자 포스팅을 하게 됐습니다. 

편히 읽어보시면서 놓친 개념이 없는지 확인해 보세요~~  

Dropout

Dropout Implementation


Dropout의 정확한 개념은 신경망에서 특정 비율만큼의 뉴런을 무작위로 비활성화하여 과적합을 방지하는 정규화 기법입니다.

def train_step(data, p):
    # p = dropout rate
    h1 = np.maximum(0, np.dot(w1, data) + b1)  
    u1 = (np.random.rand(*h1.shape) < p)  # Dropout mask 생성
    h1 *= u1  # 뉴런 중 일부를 무작위로 0으로 설정

    h2 = np.maximum(0, np.dot(w2, h1) + b2)
    u2 = (np.random.rand(*h2.shape) < p)  # Dropout mask 생성
    h2 *= u2  # 뉴런 중 일부를 0으로 설정

    return np.dot(w3, h2) + b3

 

Dropout을 구현하는 코드로 한줄한줄 자세하게 보겠습니다.

h1 = np.maximum(0, np.dot(w1, data) + b1)

 

첫 번째 hidden layer의 선형 변환을 수행한 후, ReLU 활성화 함수를 적용합니다. np.maximum()을 통해 0보다 작으면 0으로 0보다 크면 그대로 출력하여 ReLU 함수를 구현해 줍니다.

u1 = (np.random.rand(*h1.shape) < p)

 

먼저 *는 파이썬의 unpacking 연산자로 튜플형태인 h1.shape을 unpack 하여 전달합니다. 예를 들어 (5,10)으로 들어오면 5,10으로 전달됩니다.

 

h1.shape만큼 0~1 사이의 난수가 형성되고 그중 p보다 작으면 그대로 남기고 p보다 크면 0으로 만들어줍니다. 

 

0~1에서 10개를 생성할 때 p를 0.8로 설정해 놓으면 10개 중 8개가 true로 나오는 겁니다. 정확히 8개가 나오는 것은 아니지만 0과 1 사이에서 균일하게(randomly uniform) 10개의 실수를 생성하기 때문에 대략적으로 나온다고 이해하시면 될 것 같습니다. 

h1 *= u1

 

즉, 마스크 u1을 h1에 곱하여, dropout을 적용합니다. p 확률로 뉴런을 남기고 1-p확률로 뉴런을 제거하는 것으로 이해하시면 됩니다.

 

이 부분이 전 처음 알았던 내용이어서 집중해서 보시면 좋을 것 같습니다!!

def test_step(data):
    h1 = np.maximum(0, np.dot(w1, data) + b1) / p
    h2 = np.maximum(0, np.dot(w2, h1) + b2) / p
    return np.dot(w3, h2) + b3

 

테스트를 할 때는 학습한 모든 노드를 사용해야겠죠? 그렇기 때문에 train시 p 확률만큼 활성화시켰던 노드를 보정해 주기 위해 p로 나눠줍니다.  

train_step에서 기댓값이 감소하였던 것을 test_step에서 고려해 줘서 보정해줘야 한다는 것입니다.

 

지금까지 Pytorch 또는 tensor flow를 이용하여 모델을 만들어서 이런 작업이 자동으로 되고 있었던 것입니다.

이런 기저동작을 이해하시고 dropout을 이용하면 좀 더 이해도도 높은 상태에서 작업을 할 수 있지 않을까 합니다ㅎㅎ

 

Dropout: Inference time vs train time


 

Dropout은 언제 쓰고 언제 꺼야 할까요??

 

설명 전에 Inference time, train time, train time에 대해 알아보고 설명하겠습니다.

 

학습(training): 모델이 데이터를 기반으로 패턴을 학습하는 과정.

추론(inference): 학습된 모델이 새로운 데이터에 대해 예측을 수행하는 과정.

 

구분 Inference (추론) Test (테스트)
목적 새로운 데이터를 이용해 예측 결과를 생성하기 위해 사용 모델의 성능을 평가하기 위해 사용
결과 예측값(출력)만 생성 예측값과 **정답(라벨)**을 비교하여 정확도, F1-score 등을 계산
사용 시점 모델 배포 후, 실시간 또는 배치 처리 시 사용 모델 학습 후, 검증/테스트 데이터셋을 이용한 평가 단계에서 사용
데이터 일반적으로 레이블이 없는 새로운 데이터 레이블이 있는 테스트 데이터셋
성능 지표 추론 속도, latency, throughput 정확도, 손실(loss), 정밀도, 재현율 등 다양한 평가 지표

 

이 셋의 차이를 정확하게 이해하고 있으면 앞으로 좋을 것 같아요ㅎㅎ

 

이제 본론으로 들어와서 dropout은 언제 키고 꺼야 할까요?

답은 학습과정에서는 키고 테스트와 추론과정에서는 꺼야 합니다. 학습 시 오버피팅을 방지하기 위해 사용하는 것이기 때문에 학습 시에 드롭아웃을 이용합니다. 이후 테스트 또는 추론을 할 때는 모든 노드를 이용해야 하기 때문에 노드를 전부 활용해야죠!!

 

간단한 예시 코드를 같이 살펴보고 마무리하겠습니다.

import torch
import torch.nn as nn

class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc1 = nn.Linear(10, 50)
        self.dropout = nn.Dropout(p=0.5)
        self.fc2 = nn.Linear(50, 1)
    
    def forward(self, x):
        x = self.fc1(x)
        x = self.dropout(x)  # 학습 시에만 Dropout 적용
        x = self.fc2(x)
        return x

model = SimpleModel()

# 학습 모드 (Dropout 활성화)
model.train()
output_train = model(torch.randn(5, 10))

# 평가/추론 모드 (Dropout 비활성화)
model.eval()
output_eval = model(torch.randn(5, 10))

 

여기서 보시면 pytorch를 이용하면 자동적으로 위에서 설명했던 내용이 적용되는 건데요. model.train()을 하면 알아서 dropout이 활성화되고 model.eval()을 하면 알아서 dropout이 비활성 되는 것을 알 수 있습니다.

 

이번 포스팅을 통해 dropout에 대해 이해할 수 있는 시간이 되었으면 좋겠습니다.