딥러닝 이야기 / Convolutional Neural Network (CNN) & Residual Network (ResNet) / 3. Residual Network (ResNet)

Residual Network (ResNet)

작성자: 여행 초짜
작성일: 2022.07.28

시작하기 앞서 틀린 부분이 있을 수 있으니, 틀린 부분이 있다면 지적해주시면 감사하겠습니다.

이전글에서는 convolutional neural network (CNN)에 대해 설명하였습니다. 이번글에서는 CNN 모델을 기반으로 하는 residual network (ResNet)에 대해 알아보겠습니다. ResNet은 당시 CNN 기반 학습에 있어서 큰 혁명을 가져온 모델입니다. 그 당시 최초로 사람보다 더 좋은 결과를 낳은 모델이기도 했습니다. 이 글에서는 ResNet의 원리, 목표 등 ResNet의 전반에 대해 살펴보겠습니다. 그리고 CNN에 대한 설명은 이전글을 참고하시기 바랍니다.

오늘의 컨텐츠입니다.

  1. ResNet의 등장 배경
  2. ResNet의 원리
  3. ResNet의 구조
  4. ResNet 결과

Residual Network (ResNet)

ResNet의 등장 배경

컴퓨터 비전과 이미지 처리에 있어서 convolutional neural network (CNN)는 필수적인 모델입니다. 꽤 예전에 transformer가 등장하고 나서 요즘 이미지도 transformer로 처리하는 vision transformer (ViT)가 많이 사용되긴 하지만 여전히 CNN의 입지는 강건합니다. 그중 residual network (ResNet)는 한창 CNN으로 ImageNet 대회를 할 때 신선한 충격을 안겨준 그런 모델이었습니다. 현재 글 작성 시점에서 ResNet 논문의 인용수는 무려 10만회가 넘어가며, 계속해서 증가하고 있는 추세입니다. 그리고 ResNet의 영향 때문에 transformer등 다양한 모델에서 residual connection을 기본으로 사용하고 있기도 합니다.

먼저 ResNet의 등장배경부터 살펴보겠습니다. 당시 한창 ImageNet 대회를 통해 top-5 error가 어떻니부터 SOTA (State of the Art) 모델이 어쩌구할 때 등장한 모델이 바로 ResNet입니다. ResNet 등장 이전에 다양한 ImageNet 모델이 있었습니다. 그 대표적인 예가 VGGNet이 었습니다. 이때부터 이미지 분류를 위해 아주 깊은 모델이 만들어지고 있었죠. 그리고 대부분의 경향이 깊은 모델일수록 그 성능은 얕은 모델보다 뛰어났습니다. 어찌 생각해보면 깊은 모델일수록 feature representation을 잘 할 것이니 당연한 결과이기도 했습니다. 하지만 모델이 너무 깊어져서 10개 이상의 layer, 즉 수십개의 레이어를 가진 모델의 성능이 오히려 낮아지는 현상이 발생하였습니다. 이 현상이 바로 degradation 현상입니다.

여러 연구자들은 위에 대한 문제의 원인을 처음에 아래와 같이 생각했습니다.

  • 레이어가 너무 깊어져서 training set에 overfitting이 되어 성능이 안 좋아진 것일까?
모델이 깊어져서 overfitting이 일어났다면, 깊은 모델의 training loss가 얕은 모델에서 더 낮아야할 것입니다. 하지만 아래 그림을 보면 알겠지만 test loss에서도 물론이고, training loss에서까지 얕은 모델보다 깊은 모델이 성능이 안 좋은 것을 볼 수 있습니다.

따라서 연구자들은 아래와같은 결론을 내립니다.
  • 모델이 깊어질수록 성능이 안 좋아지는 이유가 overfitting 때문이 아니라, 모델 최적화(optimization)가 어려웠기 때문이다.
  • 모델이 깊어질수록 gradient vanishing, gradient exploding 현상이 발생하기 때문이다.

깊은 모델과 얕은 모델의 성능, 출처: ResNet paper


그럼 위에서 언급한 두 가지의 문제점을 해결할 수 있는 방법은 무엇이 있을까요? 바로 아래와 같은 간단한 방법이 있을 수 있습니다.

  • 성능이 가장 좋을 때 까지의 얕은 레이어는 이미지에서 특징을 추출하고, 그 이후에 더 깊은 레이어는 얕은 레이어에서 추출된 특징을 그대로 유지하면서 output을 내는 방법.
  • 얕은 레벨에 있는 레이어는 이미지에서 좋은 특징 추출이 가능해야함.
좀 더 간단하게 20개의 레이어의 성능이 가장 좋고 20개보다 깊은 모델의 성능이 안 좋아지기 시작한다고 가정을 해봅시다. 그렇다면 20개 이상의 레이어를 가진 깊은 모델에서 상위 20개의 레이어는 특징 추출을, 그 이후의 레이어는 20개의 레이어에서 나온 특징을 그대로 유지하면서 output을 낸다면 성능이 좋아질 것이라 생각한 것입니다. 사실 상위 20개의 레이어에서 이보다 더 좋을 수 없는 특징을 추출했다고 가정하고, 그 이후의 레이어서 성능을 더 끌어올리기 위해 20개의 레이어의 결과를 크게 바꾸지 않는 선에서 학습을 한다면 저자들은 무조건 얕은 모델보다 성능이 더 좋아야할 것이라고 생각했습니다.

위의 해결 방법 아이디어에서부터 ResNet이 시작됩니다.

ResNet의 원리

ResNet의 등장 배경을 살펴보았으니, ResNet의 저자들이 어떻게 해결했는지 살펴보겠습니다. ResNet의 원리는 정말 간단합니다. 아래 그림을 봐서 알겠지만, 레이어를 거치기 전 \(x\)를 거친 후의 결과에 더해주는 것이 다입니다. 그리고 이렇게 레이어를 거치기 전 \(x\)를 더해주는 과정을 shortcut 혹은 skip connection이라고 부릅니다.

CNN과 ResNet


그럼 좀 더 수식적인 측면에서 접근 해보겠습니다. 레이어가 있는 모델을 \(f(\cdot)\)이라고 가정하고, 우리가 이미지를 통해 최종적으로 예측해야하는 label을 잘 나타낼 수 있는 mapping의 결과를 \(H(x)\)라고 가정해보겠습니다.

\[model\,=\,f(\cdot)\] \[mapping\,=\,H(x)\]


그렇다면 CNN과 ResNet을 나타내는 mapping의 결과는 아래와 같이 쓸 수 있습니다.

\[CNN:\,H(x)\,=\,f(x)\] \[ResNet:\,H(x)\,=\,f(x)+x\]


그리고 위의 ResNet 식을 다시 모델 \(f(\cdot)\)에 대해 다시 쓰면 아래와 같이 쓸 수 있습니다.

\[ResNet:\,f(x)\,=\,H(x)-x\]


위의 식에서 결국 모델 \(f(\cdot)\)이 의미하는 것은 \(H(x)-x\)인 잔차(Residual)를 의미합니다. 즉 모델은 잔차를 학습하는 것이며, 따라서 이름이 ResNet이라고 붙게 된 것입니다.

여기서 우리는 등장 배경에서 언급했던 기존 깊은 모델들이 가지는 문제점에 대한 해결 방법을 상기해야 합니다. 분명 위에서 얕은 레이어 레벨에서 나온 특징을 깊은 레이어를 통과했을 때도 결과가 크게 변하지 않고 그대로 유지해야한다고 했습니다. 이것을 저자들은 identity mapping이라고 부릅니다. 즉 identity mapping을 위해서 ResNet의 식은 아래와 같이 해석할 수 있습니다.

\[ResNet:\,H(x)\,=\,f(x)+x\,=x\] \[\therefore f(x)=0\]


여기서 아주 중요한 결론이 나옵니다. 결국 깊은 모델이 가지던 문제점을 해결하기 위해서는 identity mapping이 필요합니다. 이를 위해서 ResNet \(f(x)\)는 0이 되도록 학습이 진행되고, \(H(x)=x\)가 되도록 학습이 되어야 합니다. 그리고 이렇게 잔차를 학습함으로써 얻는 장점은 이렇습니다.

  • 기존 모델들은 처음부터 \(y\)에 잘 mapping 가능한 \(H(x)\)를 다이렉트로 찾아야했지만, ResNet 같은 경우 \(H(x)\)의 목표인 \(x\)가 더해주는 과정으로써 제공되어 모델이 참조가 가능하기 때문에 학습이 더 수월함. 왜냐하면 x를 기반으로 아주 적은 정보만 학습하면 되기 때문. 이를 pre-conditioning이라고 부름.
  • 기존 모델에 비해 더해주는 과정만 추가되어 모델의 파라미터 수는 동일하며, 연산량도 증가되지 않음.
  • \(H(x)=f(x)+x\)이므로 이를 미분한 값인 \(H'(x)=f'(x)+1\)이 되며, 최소 gradient가 1이 보장되기 때문에 모델이 깊어졌을 때 문제점의 원이이 되었던 gradient vanishing 현상이 해소됨.
  • Gradient가 최소 1이 보장되므로 0으로 수렴할 일이 없어 항상 모든 정보가 통과하며, 지속적인 residual learning이 가능하여 깊게 레이어를 쌓을 수 있음.

그리고 첫 번째 장점에 사족을 더 붙이자면, 실제로 \(H(x)\)의 최적 mapping이 identity mapping이 될 확률은 매우 낮습니다. 하지만 실제 mapping이 identity mapping과 비슷하다면 pre-conditioning을 통해 \(x\)를 보여줌으로써 모델이 이를 통해 작은 변화를 학습하기가 더 쉽습니다. 이는 ResNet 등장 배경에서 설명했던 깊은 모델의 문제점 해결 방법 중 하나인, 얕은 레벨에서 나온 특징을 그대로 유지하면서 아주 조금의 변화만 캐치해야한다는 방법과 일맥상 통합니다. 그리고 identity mapping이 최적일 확률은 실제로 낮지만, identity mapping이라고 가정하고 ResNet을 학습한 결과를 보여줌으로써 identity mapping이 합리적이다는 것을 저자들은 증명합니다. 이후에 나오겠지만 실제로 identity mapping이라고 가정한 ResNet의 성능이 기존 CNN보다 상당히 뛰어난 것을 확인할 수 있습니다.


ResNet과 다이렉트로 \(x\)가 나오도록 학습하는 방법의 차이는?
그럼 이쯤에서 의문이 하나 듭니다. "어짜피 ResNet은 잔차를 학습함으로써 \(H(x)=x\)가 되도록 하는 것이 목표인데, 기존 모델을 통해 바로 \(x\)가 나오도록 학습하는 것과 다른점이 무엇일까?"라는 의문이 듭니다. 실제로 \(H(x)=x\)가 되도록 학습하는 모델은 autoencoder라는 비슷한 모델이 있죠(Autoencoder에 대한 글은 이전글 참고).

바로 x를 학습하는 것과 ResNet의 차이


차이는 간단합니다. 바로 \(x\)를 학습하는 모델은 말 그대로 \(x\)라는 똑같은 값이 나오도록 모델을 학습해야하는 것이고, ResNet은 \(x\)를 더해줌으로써 0이 되도록 학습하는 것에 차이가 있습니다. 즉 ResNet은 \(x\)를 다이렉트로 학습하는 것이 아니라, x는 그대로 둔채 미세한 정보만 학습하면 되기 때문에 바로 \(x\)를 학습하는 모델보다 더 간단한 것이죠.

ResNet의 구조

위에서는 깊은 모델이 가지는 문제점과 원인, 이를 해결하기 위한 ResNet의 가설을 살펴보았습니다. 그리고 이러한 해결 방법을 구현하기 위한 ResNet의 원리 및 이러한 방법을 채택함으로써 얻게 되는 ResNet의 장점을 살펴보았습니다. 그럼 이제 ResNet의 좀 더 세세한 구조를 살펴보도록 하겠습니다.

아래 구조를 살펴보겠습니다. 왼쪽은 shortcut이 없는 일반적인 CNN의 구조이고, 오른쪽은 shortcut이 있는 ResNet의 구조입니다. 그리고 그림에는 각 레이어의 kernel 크기와 개수(out channel size)가 나타나있습니다. ResNet의 구조는 특정 규칙이 있는데 아래 그림과 함께 보면 이해가 잘 될 것입니다. 그리고 구조를 이해하기 위해서는 CNN의 input, output 크기의 계산 방법과 CNN 연산에 대한 이해가 필요하므로 잘 모르시는 분들은 이전글을 참고하시기 바랍니다.

  • 기본적으로 kernel: 3*3, stride: 1, padding: 1을 사용하여 input과 ouptut의 크기 변화가 없음.
  • 레이어에 '/2'라고 적혀있는 부분은 down-sampling이 일어난 것이며, 이는 kernel: 3*3, stride: 2, padding: 1를 사용하여 output 크기를 input에 비해 절반으로 줄임.
  • 위에서 down-sampling을 할 때 stride가 2이므로 1인 레이어에 비해 time complexity가 절반이 되므로, 이를 같게 맞춰주기 위해서 kernel 개수를 2배로 늘려 ouptut channel이 2배가 되게 함.

CNN과 ResNet 구조, 출처: ResNet paper




차원과 크기가 다른 데이터는 서로 어떻게 더하나?
그럼 여기서 하나 의문이 듭니다. 아래 그림에서 보라색 레이어의 실선으로 더해주는 부분은 레이어를 거치기 전 더해주는 값과 레이어를 거친 후 더해주는 크기와 차원(channel)이 서로 같습니다. 즉 실선은 두 값의 크기와 차원이 같은 identity shortcut입니다.

하지만 점선을 보면 보라색에서 나온 결과를 초록색에서 나온 결과와 더하는데 둘 사이의 크기와 차원이 서로 다릅니다. 예를 들어 보라색의 레이어를 거쳐서 나온 데이터의 크기를 (batch * 64 * 28 * 28)이라고 하면, 초록색을 거쳐서 나온 데이터의 크기는 (batch * 128 * 14 * 14)가 됩니다. 즉 위에서 ResNet 구조를 설명할 때 두 번째에서 언급했던 down-sampling이 일어난 것이지요. ResNet의 전체적인 구조를 보면 점선으로 그려진 shortcut이 많은데 이 부분이 모두 down-sampling 때문에 야기된 두 데이터간의 크기가 다른 부분입니다. 이러한 문제를 해결하기 위해 저자들은 세 가지 방법을 소개합니다.

크기가 서로 다른 데이터의 덧셈, 출처: ResNet paper

  1. Zero padding을 이용.
  2. 위 방법은 2배로 늘어난 channel에 대해서는 zero padding을, 절반으로 줄어든 가로, 세로의 크기에 대해서는 stride 2의 pooling을 이용해서 크기를 맞춰준 후 더해주는 방법입니다.

  3. 크기가 달라지는 점선 shortcut에만 1*1 convolutional layer 사용.
  4. 크기가 같은 실선의 identity shortcut 같은 경우는 그냥 더하면 되고, 크기가 달라지는 점선 shortcut에 대해 stride가 2인 (1*1) convolutional layer를 거쳐 크기를 맞춰주는 방법입니다.

  5. 점선, 실선 상관 없이 모든 shortcut에 1*1 convolutional layer 사용.
  6. 모든 shortcut에 대해 크기가 같은 실선 부분은 stride가 1, 크기가 달라지는 점선 부분은 stride 2인 (1*1) convolutional layer를 거쳐 크기를 맞춰주는 방법입니다.
성능은 3 > 2 > 1 순서로 좋게 나왔지만 그 차이가 미비하다고 합니다. 그리고 2, 3번 방법의 경우 convolution 연산이 추가되었기 때문에 1번에 비해 parameter 수가 커진다는 단점이 존재합니다. 따라서 현재 ResNet이 구현된 PyTorch 등에서의 코드에서는 2번의 방법을 통해 shortcut을 계산합니다.

지금까지 ResNet의 기본 구조와 shortcut을 계산하는 방법을 알아보았습니다. 이러한 방법을 기반으로 레이어를 쌓게 되며, 그 레이어의 깊이에 따라 여러 종류의 ResNet이 있습니다.

ResNet의 종류


Bottleneck 구조
여기서 주목해야하는 점이 하나 더 있습니다. 위 표에서 18, 34 레이어 깊이의 모델까지는 하나의 residual block에 2개의 레이어가 존재합니다. 하지만 50 레이어 깊이의 모델부터는 하나의 residual block에 3개의 레이어가 존재하는 것을 볼 수 있습니다. 깊은 모델에 대해서 residual block에 3개의 레이어를 쌓은 이유는 학습할 때 시간과 자원을 줄이기 위함입니다. 깊은 모델일수록 당연히 학습 시간이 오래걸리기 망정인데, ImageNet 학습 시간을 단축 시키기 위해서 깊은 모델에 대해 이러한 해결 방법을 둔 것입니다.

아래 그림은 bottleneck 구조와 아닌 구조의 비교 그림입니다. Bottleneck 구조는 residual block을 이루는 모델의 형태가 bottleneck처럼 보여 이름을 이렇게 지은 것입니다. 그런데 레이어가 3개가 되었는데 왜 더 빨라지는 것일까요? 그 이유는 레이어가 3개더라도 파라미터 수가 현저히 적기 때문입니다.

좌: 일반적인 구조의 ResNet, 우: Bottleneck 구조의 ResNet, 출처: ResNet paper


아래는 각각의 경우에 대해 파라미터 수를 계산한 결과입니다. Bottleneck 구조의 파라미터 수가 레이어는 더 많아도 약 22 % 정도 감소된 것을 확인할 수 있습니다.

\[기존\,ResNet: (3*3*64)*2=1152\] \[Bottleneck\,ResNet: (3*3*64) + (1*1*64) + (1*1*256)=896\]


추가로 위의 bottleneck 구조의 그림에 input이 256-d로 적혀있습니다. 이 부분은 원래 ResNet 종류 표대로라면 64-d가 맞지만 실제로는 shortcut을 더해줄 때 64-d의 데이터를 (1*1) convolutional layer를 거치는 과정에서 kernel 수를 늘려 차원을 늘린 후 더해주기 때문에 저렇게 적혀있는 것입니다. 많은 리뷰 글에서 이 부분이 zero-padding을 한 후 더해주었다고 하는데 그 말은 틀린 말이며, convolutional layer를 거치면서 변한 부분입니다.

ResNet 결과

그럼 실제로 ResNet의 성능이 어떤지 확인해봐야겠죠. 아래 결과는 일반 CNN과 ResNet의 ImageNet 분류 결과입니다. 일반 CNN 구조는 그 깊이가 더 깊어질수록 성능이 저하되는 degradation이 발생하였지만, ResNet같은 경우는 degradation이 발생하지 않고 깊은 모델의 성능이 더 좋은 것을 확인할 수 있습니다.

일반 CNN과 ResNet의 ImageNet 분류 결과, 출처: ResNet paper


ResNet은 당시 최초로 사람보다 좋은 성능을 낸 모델이었으며, 지금에 들어서 shortcut 기반으로 모델을 구성하는 것이 기본이 된 만큼 AI 필드에 있어서 많은 영향을 끼친 연구입니다. 아래는 ResNet의 논문 링크입니다.




다음에는 원래의 ResNet이 너무 깊기 때문에 직접 custom ResNet을 구현해보고 CIFAR-10 데이터를 분류해보도록 하겠습니다.

태그 #CNN #ResNet
⟨ 이전글
CNN을 이용한 MNIST 분류
다음글 ⟩
ResNet 구현 및 CIFAR-10 분류