✍ 해당 시리즈 포스팅은 스탠포드 대학의 cs231n 강의 내용을 정리한 글입니다.
포스팅을 작성하는 2024년 말 기준에서는 이미지 처리에서도 CNN 대신 Transformer-based 모델들이 다양하게 연구되고 있지만, 다양한 모델들의 backbone으로 CNN 아키텍쳐들, 그리고 이와 관련된 아이디어가 많이 들어가기 때문에 여전히 CNN 아키텍쳐들을 공부하는 것은 의미가 있다고 생각한다.
2012년 등장한 최초의 large scale CNN으로 ConvNet 연구의 부흥을 일으킨 구조이다. 두 개의 conv-pooling-norm layers 뒤에 conv가 3번 더 붙고, 한 번의 pooling 이 후 fully connected layer 3개가 결합된 구조이다.
Q1. 227x227x3 크기의 이미지를 첫 번째 96개의 11x11 필터로 stride 4로 convolution을 진행하는 Conv layer에 통과시킨다면 그 결과의 크기는 얼마일까?
→ 힌트를 참고하면 한 필터로 첫 번째 행 방향으로 convolution을 진행하게 되면 출력은 길이 55의 한 행이 나오게 된다. 그렇다면 전체 열까지 모두 convolution을 진행하면 길이 55인 행이 55개가 나오므로 55x55인 feature map이 하나 나오게 되고, 필터 개수가 총 96개라고 했기 때문에 이런 feature map이 총 96장개가 나오게 되므로 출력 크기는 55x55x96이 된다.
Q2. 그렇다면 이 layer의 전체 파라미터 개수는?
→ 학습되는 11x11 크기의 필터는 각각 channel이 3이고 96개이므로 11x11x3x96 이 된다.
5강에서 배운 대로라면 각 필터 당 bias term 하나가 추가되어서 (11x11x3 + 1)x96 이라고 생각했는데, 이번 강의에서는 bias term을 따로 언급하진 않는다.
Q3. 그럼 다음으로, conv layer1을 지나서 결과로 나온 값에 3x3 필터로 stride 2로 pooling을 진행하면 결과 크기는 얼마?
→ 마찬가지로 힌트를 따라 pooling을 하면 width는 27, height는 27이 나오고 depth는 96을 그대로 유지하므로 27x27x96이 된다.
Q4. 그렇다면 이 pooling layer의 파라미터 수는?
→ Pooling layer에는 학습 시킬 파라미터가 없음! 단순히 입력 값에서 max를 취해줌
AlexNet의 전체 구조와 기본 세팅이니 필요하다면 참고하자.
그림만 볼 때 왜 첫 번째 conv layer에서 output이 두 개로 나뉘어 나오나 궁금할 수 있는데, AlexNet을 학습할 당시 사용한 GTX850에는 VRAM 용량이 3GB밖에 되지 않아서 두 개의 GPU에 모델의 뉴런과 feature map을 반반씩 나눠서 그렇다고 한다.
그래서 각 출력의 depth는 96에서 2를 나눈 48이다.
그리고 이렇게 나뉜 feature map들은 뒤 convolution까지도 분리된 상태로 넘어가서 conv 1,2,4,5 에서는 전체(96개의) feature map을 볼 수 없다.
대신 conv3, fc 7,8,9 에서는 GPU 간 통신을 하기 때문에 이전 계층의 전체 feature map과 연결될 수 있다.
AlexNet은 2012년도의 ILSVRC 우승 모델이고, 이후 등장하는 유명한 CNN 아키텍쳐들의 조상 격이 된다.
AlexNet의 8개 layer보다 더 깊은 16, 19개의 layer들을 갖고, 3x3으로 필터의 크기가 확연히 줄어들었고, 주기적인 pooling을 수행하며 전체 네트워크를 구성한다.
Q1. 왜 기존보다 훨씬 작은 크기의 필터들을 사용했을까?
→ 우선 필터의 크기가 작으면 파라미터의 수도 그만큼 줄어들고, 이에 따라 큰 필터에 비해서 layer를 조금 더 쌓아서 더 깊은 network를 만들 수 있다. 3x3 필터를 여러 개 쌓은 것은 결국 7x7 필터를 사용하는 것과 실질적으로 동일한 receptive filter를 가지게 된다.
Q2. 그렇다면 stride가 1인 3x3 필터 세 개를 쌓게 되면 실질적인 receptive field는 어떻게 될까?
→ 우선 첫 번째 layer의 receptive field는 3x3이 되고, 두 번째 layer는 각 뉴런이 첫 번째 layer 출력의 3x3 만큼을 보게 되면 실질적으로 각 사이드를 학 픽셀 씩 더 볼 수 있어서 5x5만큼의 receptive field를 갖는다. 같은 방식으로 세 번째 layer까지 지나게 되면 7x7만큼의 receptive field를 갖게 된다.
따라서 3x3 필터 세 개를 사용하는 것은 7x7 필터 하나를 사용하는 것과 같은 크기의 receptive field 를 가지면서도, network를 더 깊게 쌓을 수 있기 때문에 non-linearity를 추가할 수도 있고, 파라미터 수도 더 적다는 장점을 가지게 된다.
채널이 3인 경우 파라미터 수를 비교해보면 3x3 세 개는 3 x(3x3x3x3) 면 243개이고, 7x7 한 개는 (7x7x3x3) 으로 441개로 확연한 차이가 난다.
VGG16의 전체 구조와 파라미터 수 이니 필요하다면 참고.
Inception Module을 여러 개 쌓아서 만든 구조. FC Layers가 없어서 파라미터 수가 AlexNet에 비해서 훨씬 적으면서도 깊다.
네트워크 속 네트워크(Network within a network) 개념으로 Local Network를 여러 개 쌓아 올리는 구조이고, 이 Local Network를 Inception Module이라고 한다.
Inception Module 내부에는 동일한 입력을 받는 서로 다른 다양한 필터들이 병렬로 존재한다. Input에 대한 다양한 Conv 연산을 수행한 후 그 결과들을 모두 depth 방향으로 합친다. 이 하나의 tensor가 다음 layer로 전달된다. 이 때 각 출력들의 spatial dimension을 맞춰줄 땐(아래 그림의 예시는 28x28) stride를 조절하거나 zero padding을 활용한다.
하지만 위 네 가지 layer들의 출력들을 모두 depth 방향으로 합치게 되면 input은 28x28x256이었던 데 반해, output은 28x28x672로 depth가 매우 불어나게 된다.
이렇게 되면 연산량이 너무 많아지고, Pooling layer에서는 입력의 depth를 유지해서 하나의 inception module을 거칠 때마다 depth가 불어날 수 밖에 없는 구조가 된다.
이를 해결하기 위해 bottleneck layer를 이용한다.
1x1 convolution을 다시 한 번 살펴보자. 이는 각 spatial location에서만 내적을 수행하면서 depth를 줄일 수 있다. 위 슬라이드의 예시는 32개의 필터를 사용하여 64였던 depth를 32로 줄였다. 이는 depth를 더 낮은 차원으로 projection하는 것으로 볼 수도 있다. Input feature map들 간의 선형결합으로 볼 수도 있다.
이런 아이디어를 활용하여, 각 3x3, 5x5 convolution 마다 차원을 줄여주는 1x1 convolution layer을 추가한다. 그리고 pooling 후에도 1x1 conv를 추가하여 bottleneck layers의 역할을 해준다.
그 후 연산량을 보면 이전의 naive한 방식보다 두 배 이상 줄었고, output의 depth도 훨씬 작아지게 되었다.
다시 GoogLeNet 구조를 전체적으로 살펴보면(왼→오) 초반엔 conv pooling을 반복해주고, 이 후 Inception module을 여러 개 달고 마지막엔 classifier 출력 부분이 있다.
계산량이 많았던 마지막의 FC Layer를 대부분 없앤 점을 확인 가능하다. 총 22개의 가중치 layer가 있다.
그리고 Inception module 사이를 보면 중간에 줄기들이 뻗어있는데, 이는 보조 분류기(auxiliary classifier) 역할을 한다. 이 곳에서도 loss를 계산하여 전체 네트워크 학습 시 각 보조 분류기의 loss를 모두 합친 평균을 계산한다. 이는 추가적인 gradient를 얻을 수 있고, 중간 layer의 학습을 도울 수 있다.
2015년도 ILSVRC 대회 우승 아키텍처로, 바로 한 해 전의 우승 아키텍처인 GoogLeNet이 22개의 layer를 쌓았던 데 비해 layer를 152개로 대폭 증가시킨 아키텍처이다.
ResNet의 motiavation은 “과연 기존 평범한 CNN 구조에서 layer를 깊게 쌓으면 쌓을수록 무조건적으로 성능 향상이 이루어질까?” 에서 시작한다.
→ 이에 대한 답은, No 였다. 위 슬라이드의 loss 그래프는 20-layer, 56-layer 구조 모두 평범한 CNN인데, layer가 더 많다(깊다)고 해서, 무조건 적으로 test loss가 작은 건 아니었다.
test 그래프만 보면 56-layer가 20-layer보다 파라미터 수가 많으니 overfitting이 발생했다고 생각할 수도 있지만, training 에서도 56-layer가 더 loss가 컸기 때문에, overfitting에 의한 결과는 아니었다.
그래서 처음 저자들이 세운 가설은 “모델이 깊을 수록 최적화가 어렵다” 였다. 그렇다면 깊은 모델이 얕은 모델보다는 적어도 같거나 좋은 성능이 나와야 한다.
우선 더 얕은 모델의 가중치를 깊은 모델의 일부 layer에 복사하고, 나머지 layer는 identity mapping으로 input을 output으로 그냥 내보내는 방식을 활용하고자 하였다. 이렇게 한다면 깊은 모델의 학습이 제대로 안 되더라도, 얕은 모델 만큼의 성능은 보장이 될 것이다.
이러한 motivation을 모델에 녹이기 위해, direct mapping 대신 residual mapping을 하도록 블럭을 쌓았다. layer가 직접 를 학습하기 보다, (residual)를 학습할 수 있도록 만든 것이다. 이러한 skip connection에는 weight가 없고, 그저 input을 identity mapping으로 그대로 출력으로 내보낸다.
그럼 실제 layer는 input 에 대한 잔차(residual)만 학습하면 된다. layer가 full mapping을 학습하기보다는, 조금의 변화( 자체가 아니라, 입력 받은 에서 얼마나 더하고 빼야 하는지..) 에 대해서 만 학습한다.
ResNet의 전체 구조인데, 그림과 같이 residual block을 깊게 쌓는다. 이 때 한 residual block의 구조는 input 를 받아서 conv → relu → conv → + → relu
로 이루어져 있다. residual block을 쌓으면서 주기적으로 필터를 두 배 증가시키고, 이 때 stride는 2로 설정하여 downsampling을 수행한다.
시작 부분엔 Conv layer가 추가적으로 붙고, 마지막에는 GoogLeNet과 마찬가지로 소프트맥스를 위해 필요한 FC를 제외하고는 추가적인 FC Layer들이 없다.
대신 GAP(Global Average Pooling)으로 한 feature map 전체를 average pooling한다.
ResNet layer는 논문에서는 34, 50, 101, 152 까지 증가 시켰는데, 50 이상일 경우엔 GoogLeNet처럼 bottleneck layer(1x1 convolution)를 추가해야 한다.
input을 받으면 처음엔 64개의 1x1 필터를 적용해서 depth를 64로 만든 후 64개의 3x3 필터를 적용해주고, 이에 다시 256개의 1x1 필터를 적용해서 28x28x256의 결과가 나오도록 한다. 덕분에 3x3 convolution의 계산량이 줄어들 수 있다.
ResNet에서는 모든 Conv layer 다음에 Batch Normalization을 사용하였고, 초기 가중치는 Xavier initialization에서 2를 나누어 사용하였다. 그 외 세팅은 슬라이드 참고.
위와 같은 방법으로 ImageNet에서 성공적인 분류 결과를 보였다. 또한 앞서 언급했던, 깊은 모델에서 training error가 얕은 모델보다 높게 나오던 일도 없었다고 한다.
네트워크 안에 작은 네트워크를 넣는 아이디어. 각 Conv layer 안에 Multi layer Perceptron(FC layer, 1x1 conv)을 쌓아서 조금 더 복잡한 방식으로 activation map을 얻도록 한다. GoogLeNet보다도 먼저 bottleneck 개념을 정립하였다.
ResNet 저자들이 기존 ResNet block에서 direct path를 늘려 정보들이 더 잘 전달될 수 있도록 개선한 방식이다.
네트워크의 depth보다는 residual에 더 집중하여 conv layer의 필터 수 k개 만큼 증가시킨 방법.
각 Residual block 블럭 내에 multiple parallel pathways를 추가하여 residual block의 width를 늘린 방식이다. Pathways의 총 합을 cardinality라고 한다. 구조 자체는 ResNet과 유사하면서도, 한 residual block 내부에서 여러 layer들을 병렬로 묶어준다는 점에서 Inception Module이 떠오르기도 한다.
이번엔 ResNet 구조에서 depth에 집중하여, 네트워크가 깊어질수록 발생하는 vanishing gradients 문제를 해결하고자 학습 시 일부 layer를 제거한다. (identity connection으로 대체. Dropout 아이디어와 유사하다.) test 시에는 모든 layer를 다 사용한다.
Residual 학습보다는 깊고 얕은 네트워크의 정보 모두를 잘 전달하는 것이 중요하다는 생각에서 나온 아키텍쳐. 구조가 fractal하다.
깊고 얕은 부분의 경로를 모두 출력에 연결한다. 학습 시에는 dropout처럼 일부 경로만으로 학습 후 테스트 시에는 full network를 사용한다.
한 layer가 그 layer의 하위 모든 layer들과 연결된 Dense block을 사용한다. Input 이미지가 네트워크의 모든 layer의 입력으로 들어가게 된다, 이 출력들은 모두 concat된다. 해당 방식이 gradient vanishing 문제를 해결할 수 있다고 한다.
Fire module로 구성된 네트워크인데, 이 안에는 1x1 필터로 구성된 squeeze layer 뒤에 1x1/3x3 필터들로 구성되는 expand layer 가 존재한다. ImageNet에서 AlexNet과 유사한 정확도를 보이면서도 파라미터는 50배나 적었다고 한다. 효율성 면에서 좋다.