카테고리 없음

MNIST Lab 9편 - Dropout forward/backward 직접 구현하기

cedis 2026. 5. 29. 00:23

MNIST Lab 기본 구현 9편

Dropout은 학습 중 일부 뉴런을 무작위로 끄는 계층이다. 핵심은 학습 모드에서는 mask를 만들고, backward에서는 같은 mask로 gradient도 막는 것이다.

1. Dropout이 막는 문제

모델이 특정 뉴런 몇 개에만 과하게 의존하면 훈련 데이터에는 잘 맞지만 새로운 데이터에는 약해질 수 있다. Dropout은 학습 때 일부 뉴런을 랜덤하게 꺼서 이런 의존을 줄인다.

1
학습 모드

랜덤 mask를 만들고 일부 뉴런 출력을 0으로 만든다.

2
역전파

꺼졌던 뉴런 위치는 gradient도 흐르지 않게 한다.

3
평가 모드

랜덤하게 끄지 않고 평균적인 출력 크기만 맞춘다.

2. 최종 구현 코드

class Dropout:
    def __init__(self, drop_ratio=0.5):
        self.drop_ratio = drop_ratio

    def forward(self, x, train=True):
        if train:
            self.mask = np.random.rand(*x.shape) > self.drop_ratio
            return x * self.mask
        return x * (1 - self.drop_ratio)

    def backward(self, dout):
        return dout * self.mask

3. train과 inference의 차이

모드 동작 이유
train=True 무작위 mask로 일부 값을 0으로 만든다. 특정 뉴런 의존을 줄이기 위해서다.
train=False 랜덤으로 끄지 않고 1 - drop_ratio를 곱한다. 학습 때 평균적으로 살아남던 비율과 출력 크기를 맞춘다.
backward mask를 곱해 꺼진 위치 gradient를 막는다. forward 때 계산에 참여하지 않은 뉴런은 갱신 신호도 받으면 안 된다.

4. 테스트가 묻는 것

테스트 확인 조건
test_dropout_forward_train_shape 학습 모드 출력 shape가 입력과 같은가
test_dropout_forward_inference_scale 평가 모드에서 출력에 살아남는 비율이 곱해지는가
주의할 점

Dropout은 랜덤성이 있으므로 값 자체를 고정해서 테스트하기 어렵다. 그래서 학습 모드는 shape를 보고, 평가 모드는 deterministic한 scale 결과를 본다.

이번 글에서 기억할 것

Dropout은 학습 때 일부 뉴런과 그 gradient를 함께 막고, 평가 때는 평균적인 출력 크기를 맞추는 계층이다.

스스로 점검

  1. Dropout이 학습 모드와 평가 모드에서 다르게 동작해야 하는 이유는 무엇인가?
  2. forward에서 꺼진 뉴런은 backward에서 어떻게 처리되는가?
  3. 이 구현은 inverted dropout 방식인가, 기본 dropout 방식인가?

다음 글 예고

다음 글에서는 train/evaluate를 구현한다. 지금까지 만든 부품을 한 epoch 학습 루프로 연결한다.

한 줄 정리

Dropout은 학습 때 일부 뉴런과 그 gradient를 함께 막고, 평가 때는 평균적인 출력 크기를 맞추는 계층이다.