CIFAR-10 ResNet13

Posted on Dec 16, 2023
tl;dr: PyTorch, ResNet13, epoch 30, accuracy 74%

요약

Model

  • CIFAR-10-2x2 모델은 CIFAR-10 이미지 4개를 2x2 그리드로 이어붙인 사진을 분류하는 Multilabel classifier 이다.
  • Convoltion 레이어는 총 13개이다.

모델

Max Pooling

ImageNet을 분류하는 ResNet은 맨 처음 7x7 conv (stride=2)을 하고 바로 Max Pooling을 한다. 이것은 ImageNet 데이터셋 해상도가 224x224이기 때문이다. (실제로는 더 크지만 resize한 것이다.) 반면에 CIFAR-10 데이터셋 해상도는 32x32밖에 안된다. 따라서 어딘가에서 일어나는 Downsample을 없애야 한다. 나는 처음에 실행하는 Max Pooling을 없앴다.

CIFAR-10-2x2에서는 정확히 해상도가 두 배가 되기 때문에 (64x64) Max Pooling을 그대로 뒀다.

사실 Max Pooling을 하는 이유를 잘 모르겠다. 오리지널 ResNet에서 맨 처음에 실행하는 7x7 convolution은 필터 크기가 크다. High level knowledge를 사용하겠다는 의미다. 또한 채널의 너비는 전체 모델 중에서 제일 작은 단계다. 이렇게 중요한 특징 맵을 deterministic한 Max Pooling에 맡겨도 되는 것일까?

Block

Model ResNet에서 제일 성가신 부분은 Downsample이다. Residual Learning 자체는 아름다운 기법이지만 Residual block에서 Downsample이 일어난다면 Skip connection의 출력은 원래 해상도를 유지하기 때문에 원래 네트워크로 바로 합칠 수 없다. 그래서 Skip connection에서도 똑같이 Downsample을 해줘야 한다.

이 Downsample도 곰곰히 생각해보면 깔끔하지 않다. 오리지널 ResNet에서는 1x1 stride=2 convolution 으로 처리한다. 그런데 1x1 stride=2는 사실상 모든 두번째 행·열을 그냥 버리겠다는 의미다. 그럼 3x3 필터를 써야 하나? 그렇게 되면 Skip connection의 위력이 떨어진다. Max Pooling? Adaptive Average Pooling? Squeeze-and-Excitation? … 결국 최선은 1x1 stride=2 convolution이다.

최적화 함수

오리지널 ResNet은 SVG를 사용한다. 나는 처음에 Adam을 써봤는데 학습이 어느정도 되었는데도 값이 수렴하지 않고 왔다갔다 했다. SVG를 쓰긴 싫어서 찾아보니 AdamW라는 게 있었다. 써보니 낮은 오류값으로 잘 수렴했다.

학습

Param CIFAR-10 CIFAR-10-2x2
Batch size 256 64
Learning rate 0.001 0.001
Epoch 30 30

내 데스크탑을 집에 놔두고 왔기 때문에 어쩔 수 없이 epoch를 작게 했다.

코드

cifar-10 ipynb 파일 (53 KB)

원래 ResNet 코드를 보면 Downsample 부분을 아주 꼬아놨다. 이 문제의 원인은 ResNet 클래스에서 Downsample 레이어를 미리 결정해주기 때문이다. 하지만 실제 실행하는 부분은 Block 클래스에 있기 때문이다. 나는 Downsample 레이어를 생성하는 코드를 Block 클래스로 옮겨주었다. 나머지는 크게 다른 부분이 없다.

성능

Metric CIFAR-10 CIFAR-10-2x2
Precision - 53.16%
Recall - 72.12%
Accuracy 74.19% 68.23%
Exact - 1.64%

내 모델이 다른 모델에 비해 특별히 다른 부분은 없다… 성능이 낮은 원인은 레이어가 13개 밖에 안되는 점, 그리고 epoch가 낮은 이유일 것이다.

결론

데이터 사이언티스트가 얼마나 힘든 일인지 알게됐다. 나는 원래 개발자 지망이었지만, 어쨌든 좋은 경험이었다.

참고