- 1. Basic Vision Model
- [12′ NIPS] ImageNet Classification with Deep Convolutional Neural Networks (AlexNet) 핵심 리뷰
- [15′ CVPR] Going deeper with convolutions (GoogleNet, inception) 핵심 리뷰
- [15′ ICLR] VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION (VGGNet)
- [15′ ICML] Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
- [16′ CVPR] Deep Residual Learning for Image Recognition (ResNet)
- 2. Vision Model 응용 버전
- [16′ BMVC] Wide ResNet : Wide Residual Networks
- [17′ CVPR] Xception: Deep Learning with Depthwise Separable Convolutions
- [17′ ICLR] FRACTALNET: ULTRA-DEEP NEURAL NETWORKS WITHOUT RESIDUALS
- [17′ CVPR] Densely Connected Convolutional Networks (DenseNet)
- [17′ CVPR] Deep Pyramidal Residual Networks (PyramidNet)
- [17′ CVPR] Active Convolution: Learning the Shape of Convolution for Image Classification
- [17′ CVPR] Residual Attention Network for Image Classification
- [18′ CVPR] SENet : Squeeze and excitation networks
- [18′ BMVC] BAM: Bottleneck Attention Module
- [18′ ECCV] CBAM : convolutional block attention module
- [19′ CVPR] Selective Kernel Networks (SKNet)
- [19′ ICML] EfficientNet : Rethinking Model Scaling for Convolutional Neural Networks
- [21′ ICLR] Vision Transformer : AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE
- [21′ NIPS] MLP-Mixer: An all-MLP Architecture for Vision
- [논문 리뷰] KAN: Kolmogorov–Arnold Networks
1. 들어가며
이번 글에서는 2018년 BMVC에 발표된 BAM: Bottleneck Attention Module 논문을 리뷰합니다.
이 논문은 BAM이라는 별칭으로 불리며, 이번 글에서는 BAM으로 지칭하겠습니다.
먼저 제목의 의미를 한번 생각해 볼까요? Bottleneck Attention Module이라는 이름을 하고 있는데요. 제목으로부터 크게 세 가지 정보를 얻을 수 있습니다.
첫 번째로 BAM은 Attention 기능을 수행할 것이라는 점입니다.
두 번째로 BAM의 Attention 기능은 Bottleneck 구조를 하고 있을 것이라는 점입니다.
세 번째로 BAM의 Attention 기능은 Module로 구성되어 CNN 중간에 삽입할 수 있을 것이라는 점입니다.
위의 세 가지 포인트에 집중하여 이번 글에서는 다음 순서로 BAM 논문을 살펴보겠습니다.
먼저 BAM에서 해결하고자 했던 문제를 살펴보겠습니다. 다음으로 문제를 해결하기 위한 BAM의 큰 그림을 살펴보고 BAM의 구성을 하나씩 자세히 살펴보겠습니다. 이어서 파이썬을 사용하여 직접 BAM을 구현해 보겠습니다. 마지막으로 실험 결과를 살펴보며 실제로 BAM은 어떤 효과가 있는지 살펴보고 의의를 정리해보겠습니다..
2. 기존 방법의 문제점
이전 글에서는 Squeeze and Excitation Network (SENet)에 대해 리뷰해 보았습니다. 기존의 CNN에는 중요한 부분에 더 큰 가중치를 부여하는 Attention 기능이 없음을 문제로 지적하였죠. SENet에서는 이 문제를 해결하기 위해 Squeeze와 Excitation 연산을 사용해 Attention 기능을 추가했습니다. 그런데 Attention에도 다양한 종류가 있는데요. 어떤 부분에 집중할 것인지에 따라 Channel Attention, Spatial Attention, Pixel Attention 등 다양한 방법이 있죠. 엄밀히 말하면 SENet에서 사용한 Attention은 Channel Attention입니다. 말 그대로 채널별 가중치를 다르게 주는 방법을 말하죠. 이는 Feature Map에서 중요한 채널을 선택하겠다는 것이고, 이는 ‘무엇’에 집중할 것인지를 선택하겠다는 의미입니다. Feature Map에서 채널별 정보는 보통 ‘무엇’에 해당하니까요.
그런데 ‘무엇’에만 집중하는 것보다 더 좋은 방법은 없을까요? 아래 그림은 CNN으로부터 추출된 Feature Map에 Attention을 적용하는 과정을 도식화한 그림입니다.
입력 이미지는 강아지 그림이었다고 가정하겠습니다. 강아지 그림으로부터 추출된 Feature Map에 Attention을 적용할 건데요. 기존 SENet에서는 ‘무엇’, 즉 강아지 정보가 들어있는 채널에 집중하기 위해 Channel Attention 방법을 사용했습니다. 위 그림에서는 채널별로 분리한 Feature에 각기 다른 Attention Score를 적용하는 Channel Attention을 표현하고 있습니다.
그런데 말이죠, 이렇게 찾아낸 ‘강아지 정보를 포함하고 있는 채널’ 정보에서도 걸러낼 정보가 있지 않을까요? 생각해 보면 Channel Attention이 적용된 각각의 채널 정보는 (WxHx1) 사이즈를 같잖아요. 그렇다면 Spatial 정보는 모두 보전되어 있다는 것이고, 그럼 분명 배경과 물체 정보를 모두 가지고 있을 텐데요. 여기서 배경 정보는 없애고 물체에만 Attention을 적용해 주면 더 좋지 않을까요?
이러한 기능을 Spatial Attention이라고 합니다. Channel Attention은 Channel별로 가중치를 적용해 ‘무엇’에 집중했었죠. 반면 Spatial Attention은 이미지상의 위치별로 가중치를 적용합니다. 이는 ‘무엇(What)’이 아닌 ‘어디(Where)’에 집중하는 Attention이라고 표현할 수 있겠네요. 위 그림에서는 Channel Attention이 적용된 Feature에 Spatial Attention을 적용하여 물체(강아지) 부분은 강조하고 배경 부분은 가중치를 줄이는 모습을 표현하고 있습니다.
BAM은 SENet의 철학을 계승하면서 한계를 개선한 모델입니다. 따라서 SENet의 내용을 알고 있어야 BAM의 내용을 정확히 이해할 수 있습니다. SENet의 자세한 내용은 해당글을 참고해 주세요.
3. 제안 방법
지금까지 SENet의 방법인 Channel Attention만 적용하는 방법의 한계를 살펴봤습니다. Channel Attention과 Spatial Attention을 동시에 적용하면 더 성능이 좋을 것임을 알 수 있었죠. 이 아이디어에 착안하여 BAM은 Channel Attention과 Spatial Attention을 동시에 적용하는 방법을 모색합니다. 이번 챕터에서는 BAM의 큰 그림에서부터 시작하여 구성 모듈을 하나씩 자세히 살펴보겠습니다.
3-1. BAM의 큰 그림
먼저 BAM의 큰 그림을 생각해 보겠습니다. BAM의 핵심은 Channel Attention과 Spatial Attention을 동시에 적용하는 것이라고 했습니다. 그럼 아래와 같은 큰 그림이 그려지겠네요.
위 그림을 보면 입력 Feature Map에 대해 Channel Attention 모듈과 Spatial Attention 모듈이 병렬로 연결된 모습을 볼 수 있습니다. 이렇게 나온 결과물은 채널별 가중치와 위치에 대한 가중치가 모두 적용된 모습이죠. 즉 최종 Feature Map은 ‘무엇’과 ‘어디’에 집중할지가 모두 반영된 결과라고 할 수 있습니다.
이제 BAM의 Channel Attention과 Spatial Attention 기능을 하나씩 살펴보겠습니다.
3-2. BAM의 Channel Attention Branch
먼저 BAM의 Channel Attention 기능을 살펴보겠습니다.
BAM 보다 앞선 연구인 SENet에서는 Channel Attention 기능을 적용하여 CNN 구조의 성능을 개선하는 데 성공했습니다. BAM도 SENet의 Channel Attention 모듈의 구성을 거의 그대로 차용합니다. 그림으로 표현하면 다음과 같습니다.
위 그림을 보면 입력 Feature Map에 대하여 정보 압축과 중요도 계산 단계를 순차적으로 거치는 모습을 볼 수 있습니다. 이때 정보 압축은 Global Average Pooling을 사용합니다. 이는 SENet과 완전히 동일한 구성이죠. 중요도 계산 방법에서는 살짝 차이가 있긴 하지만 큰 틀에서는 동일합니다.
먼저 Fully Connected 연산들로 이어준 뒤 마지막에 Batch Normalization을 수행합니다. 이는 Spatial Attention 결과와 scale을 맞춰주기 위함인데요. 큰 그림에서 보았듯 Channel Attention 결과는 병렬로 수행된 Spatial Attention 결과와 합쳐줄 겁니다.
이때 두 Attention 결과의 scale이 같아야 의미가 있는데요. 이를 고려해 Channel Attention과 Spatial Attention 모두 마지막에 Batch Normalization을 적용하여 scale을 맞춰주는 작업을 수행합니다. 지금까지의 내용을 수식으로 표현하면 다음과 같습니다.
- Mc : Channel Attention Module
- MLP : Multi Layer Perceptron
- AvgPool : Average Pooling
지금까지의 내용을 깔끔하게 수식으로 정리한 모습을 볼 수 있습니다.
3-3. BAM의 Spatial Attention Branch
다음은 SENet과 BAM의 가장 큰 차이인 Spatial Attention 기능을 살펴보겠습니다.
Spatial Attention 기능은 ‘어디’에 집중하기 위한 기능이라고 말씀드렸습니다. 이는 입력 정보로 (WxHxC) 사이즈의 텐서를 받아 (WxHx1) 사이즈의 Attention Score Map을 결과로 내야 함을 의미합니다. 따라서 Spatial Attention 연산의 핵심은 Spatial Size (WxH)는 유지한 채 Channel Size (C)를 줄이는 것입니다.
이를 위해 딱 떠오르는 연산이 무엇인가요? 이때 가장 대표적인 연산이 1×1 Convolution이죠. 1×1 Convolution을 사용하면 Spatial Size는 유지한 채 채널수만 줄이거나 늘릴 수 있습니다.
하지만 1×1 Convolution만 사용하면 서로 다른 위치에 있는 정보들을 연산할 수가 없습니다. 왜냐하면 1×1 Convolution은 말 그대로 Receptive Field Size가 1×1이기에 주변 정보를 동시에 연산할 수 없기 때문이죠. 따라서 1×1 Convolution 외에도 주변 정보를 동시에 연산할 수 있는, 이왕이면 Receptive Field Size가 큰 연산이 필요합니다.
이를 위해 딱 떠오르는 연산은 무엇인가요? 이때 사용하기 적절한 연산 중 하나로 Dilated Convolution을 들 수 있을 겁니다. Dilated Convolution은 기존 Convolution 연산보다 넓은 Receptive Field Size를 갖고 있죠.
지금까지의 생각을 그대로 구현해 보면 다음과 같이 Spatial Attention 모듈을 구성할 수 있습니다.
먼저 입력 Feature Map에 대해 1×1 Convolution을 사용해서 채널수를 줄여줍니다. 일단 연산량을 줄여주는 거죠. 그리고 두 번의 Dilated Convolution 연산을 사용하여 주변 정보에 대한 연산을 수행해 줍니다. 마지막으로 1×1 Convolution을 사용해서 채널수를 1로 압축해 줄 겁니다. 그 결과 (WxHx1) 사이즈의 Spatial Attention Score Map이 나오게 되겠죠. 이를 Channel Size의 관점에서 보면 다음과 같습니다.
먼저 입력 Feature Map의 채널수는 C라고 가정할게요. 첫 번째 1×1 Convolution 연산을 통해 채널수가 C/r로 압축되었다고 하겠습니다. 이후 두 번의 Dilated Convolution을 거치고요. 마지막 1×1 Convolution을 통해 채널수가 1로 최종 압축될 겁니다. 이는 ResNet에서 제안한 Bottleneck 구조와 유사한데요. 물론 ResNet에서는 병목현상처럼 채널수가 줄었다가 다시 커지는 구조였습니다. 다만 1×1 Convolution으로 채널수를 줄여 병목현상이 생긴다는 점에서는 동일하죠. BAM이라는 이름의 Bottleneck은 바로 이 점에서 나온 단어입니다.
지금까지의 Spatial Attention 모듈을 수식으로 표현하면 다음과 같습니다.
- Ms : Spatial Attention Module
- f1×1 : 1×1 Convolution
- f3×3 : 3×3 Convolution
- BN : Batch Normalization
지금까지의 긴 이야기를 깔끔하게 수식으로 정리한 모습을 볼 수 있습니다.
3-4. Attention Branch 합쳐주기
지금까지 Channel Attention 모듈과 Spatial Attention 모듈을 각각 살펴봤습니다.
이제 이 두 결과물을 합쳐서 하나의 최종 Attention Score Map으로 구성해주어야 합니다. 하지만 이 두 결과물을 바로 합쳐주기에는 문제가 있는데요. 두 결과물인 각각의 Attention Score Map은 서로 사이즈가 다릅니다. Channel Attention 결과물은 채널에 대한 Attention Score만 갖기에 (1x1xC) 사이즈의 텐서일 겁니다. 반면 Spatail Attention 결과물은 위치에 대한 Attention Score이기에 (WxHx1) 사이즈의 텐서이죠. 이 둘을 합쳐주기 위해서는 사이즈를 통일해줘야 합니다. 최종 사이즈는 (WxHxC)로 맞춰줄 겁니다.
이를 위해 Channel Attention 결과인 (1x1xC) 사이즈의 텐서는 width와 height 방향으로 복사 붙여 넣기 하여 (WxHxC) 사이즈로 만들어줍니다. 반대로 Spatial Attention 결과인 (WxHx1) 사이즈의 텐서는 채널 방향으로 복사 붙여 넣기 하여 (WxHxC) 사이즈로 만들어줍니다. 이제 이 둘의 사이즈가 통일되었으니 동일 위치값끼리 더해주는 element wise summation 방법을 사용하여 합쳐줄 겁니다.
위의 내용을 그림으로 표현하면 다음과 같습니다.
입력 Feature Map에 대해 Channel Attention과 Spatial Attention 결과가 각각 (1x1xC)와 (WxHx1)로 나온 모습을 볼 수 있습니다. 이제 각각을 서로 부족한 방향으로 복사 붙여 넣기 방법으로 채운다음 element wise summation 방법으로 합쳐줍니다. 이렇게 나온 최종 결과물은 Attention Score Map인데요. 따라서 결괏값이 0~1 사이값으로 나와야 합니다. 이를 위해 가장 마지막 연산으로 Sigmoid를 붙여줍니다. 이제 최종적으로 (WxHxC) 사이즈의 0~1 사이값을 갖는 Attention Score Map을 구하게 되었습니다.
3-5. BAM 전체 구성
지금까지 BAM을 구성하는 핵심 기능인 Channel Attention과 Spatial Attention, 그리고 이 둘의 결과물을 합치는 과정을 자세히 살펴봤습니다. 이제 BAM의 전체 구성을 살펴보겠습니다.
위 그림은 BAM의 구성 전체를 도식화한 그림입니다. BAM Attention Map을 구하는 과정은 위에서 살펴봤습니다. 이렇게 나온 BAM Attention Map은 입력 Feature Map과 동일하게 (WxHxC) 사이즈의 0~1 사이값을 갖습니다. 따라서 입력 Feature Map에 BAM Attention Map을 동일 위치값끼리 곱하면, 즉 element wise multiplication 연산을 통해 BAM Attention이 적용된 Feature Map을 최종적으로 구할 수 있습니다. 이렇게 나온 BAM Attention이 적용된 Feature Map은 채널과 위치 모두에 Attention이 적용된 결과이므로 ‘무엇’과 ‘어디’에 대한 가중치가 모두 적용된 결과라고 할 수 있습니다.
BAM 전체 구성에 대한 논문의 그림은 다음과 같습니다.
표현 방법이 조금 다를 뿐 동일한 내용임을 알 수 있습니다. 이 모든 과정을 수식으로 표현하면 더 간단하게 표현할 수 있는데요.
- F : Input Feature Map
- B : BAM
BAM은 아래와 같이 간단하게 표현할 수 있죠.
- Mc : Channel Attention Module
- Ms : Spatial Attention Module
- 𝜎 : Sigmoid
BAM의 가장 큰 장점 중 하나는 SE 모듈과 마찬가지로 CNN의 중간에 삽입할 수 있다는 것입니다. 이를테면 아래와 같이 구성할 수 있죠.
CNN의 중간중간에 BAM이 삽입된 모습을 볼 수 있습니다.
재미있는 건 BAM의 Attention 효과입니다. 그림 아래 부분에서 Intermediate feature maps를 표현하고 있습니다. 이는 BAM이 적용되기 전과 후를 비교할 수 있는데요. 어떤가요? 확실히 BAM이 적용되고 나면 Attention 효과가 명확한 모습을 볼 수 있습니다. 특히 얕은 Layer에서는 BAM이 배경을 지워주는 Denoising 효과가 있어 보입니다. 반면 깊은 Layer에서는 BAM이 Semantic Feature에 집중하게 만들어주는 효과를 볼 수 있습니다.
4. 파이썬 구현
이번 챕터에서는 파이썬을 사용하여 직접 BAM을 구현해봅니다. 이 과정을 통해 위에서 살펴본 내용을 확실하게 이해해보겠습니다.
4-1. Import Module
먼저 필요한 Module들을 Import 해줍니다.
import torch
import torch.nn as nn
import torch.nn.functional as F
4-2. BAM Class 정의하기
다음으로 BAM Class를 정의해주겠습니다. BAM의 핵심은 Spatial Attention과 Channel Attention을 병렬로 연결해주는 것인데요. __init__ 함수에서는 Spatial Attention과 Channel Attention 기능을 각각 정의해주고 있습니다. 이어서 forward 함수에서는 입력 x에 대해 Spatial Attention과 Channel Attention을 병렬로 연산한 뒤 결과물을 합쳐주는 모습을 볼 수 있습니다.
class BAM(nn.Module):
def __init__(self, channel, reduction=16):
super(BAM, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
# Channel Attention
self.channel_fc = nn.Sequential(
nn.Linear(channel, channel // reduction, bias=False),
nn.ReLU(inplace=True),
nn.Linear(channel // reduction, channel, bias=False),
nn.Sigmoid()
)
# Spatial Attention
self.spatial_conv = nn.Sequential(
nn.Conv2d(2, 1, kernel_size=7, padding=3, stride=1, bias=False),
nn.Sigmoid()
)
def forward(self, x):
b, c, _, _ = x.size()
# Channel Attention
channel_att = self.avg_pool(x).view(b, c)
channel_att = self.channel_fc(channel_att).view(b, c, 1, 1)
# Spatial Attention
spatial_att = torch.cat([x.mean(1, keepdim=True), x.std(1, keepdim=True)], 1)
spatial_att = self.spatial_conv(spatial_att)
# Combine attentions
att = 1 + channel_att * spatial_att
return x * att
4-3. 사용하기
이렇게 정의한 BAM Class는 이렇게 사용할 수 있습니다.
# Create the BAM module
bam_module = BAM(256)
5. 효과
지금까지 BAM의 동작 방법에 대한 모든 내용을 살펴봤습니다. 이번 챕터에서는 실험 결과를 살펴보며 BAM의 효과에 대해 정리해 보겠습니다.
먼저 Image Classification 실험 결과를 살펴보겠습니다.
위 표를 보면 CIFAR100과 ImageNet 데이터셋에 대한 실험 결과를 보여주고 있는데요. 기존 CNN 모델과 여기에 BAM을 적용했을 때의 성능을 비교하고 있습니다. 거의 모든 데이터셋과 모델에서 BAM을 적용한 뒤 성능이 개선된 모습을 보이고 있습니다. 반면 연산량은 아주 조금 증가했을 뿐이죠.
다음은 Object Detection 실험 결과입니다.
위 표는 COCO 데이터셋과 VOC 데이터셋에 대한 실험 결과입니다. 마찬가지로 기존 CNN과 여기에 BAM을 추가했을 때의 성능을 비교하고 있는데요. Image Classification 결과와 마찬가지로 BAM을 추가했을 때 모두 성능이 개선되는 모습을 볼 수 있습니다.
다음은 SE 모듈과의 성능 비교입니다.
위 표는 CIFAR100 데이터셋에 대해 기존 CNN과 여기에 SE를 추가한 모델, BAM을 추가한 모델의 성능을 비교한 표입니다. 우선 BAM은 SE보다 파라미터는 더 적고, 연산량은 조금 더 많은 모습을 볼 수 있습니다. 하지만 거의 대부분 SE를 추가했을 때 보다 더 큰 성능 향상을 보이는 모습입니다.
위의 세 가지 실험결과를 통해 다음과 같은 결론을 내릴 수 있습니다.
첫 번째로 BAM은 CNN의 중간에 삽입되어 Image Classification과 Object Detection에서의 성능 개선 효과가 있습니다.
두 번째로 BAM은 SE보다 적은 파라미터를 사용하여 더 큰 성능 개선 효과를 낼 수 있습니다.
6. 의의
다음은 BAM 논문의 의의를 살펴보겠습니다.
첫 번째 의의는 중요한 특성에 집중하는 방법, 즉 Attention 방법을 제안했다는 것입니다. BAM은 주목할만한 특성에 집중하여 네트워크의 성능을 향상시킵니다. 이는 채널과 공간 정보를 동시에 고려하여 어떤 특성이 중요한지 판단합니다. 이로 인해 모델은 더 정확한 예측을 할 수 있게 되며, 특히 복잡한 문제나 데이터셋에서 더 높은 성능을 보입니다.
두 번째 의의는 기존 아키텍쳐와 호환 가능한 방법을 제안했다는 점입니다. BAM은 기존의 CNN 아키텍처, 예를 들어 ResNet이나 DenseNet,에 쉽게 적용할 수 있습니다. 이는 BAM을 기존의 네트워크에 추가하기만 하면 성능 향상을 볼 수 있다는 것을 의미합니다. 따라서 별도의 복잡한 튜닝 없이도 기존 모델을 향상시킬 수 있는 강력한 도구입니다.
이 두 가지 의의는 BAM이 단순히 성능을 향상시키는 것을 넘어, 기존의 딥러닝 모델을 더욱 효율적이고 정확하게 만드는 중요한 기술적 발전이라고 할 수 있습니다.
7. 결론
지금까지 2018년 BMVC에 발표된 BAM: Bottleneck Attention Module의 내용을 자세히 살펴봤습니다. BAM은 SENet의 한계를 지적하며 이를 개선한 방법입니다. SENet은 기존 CNN에 추가할 수 있는 Channel Attention 모듈이었습니다. 좋은 아이디어이고 성능 개선을 이루었지만 Channel Attention만 적용했다는 한계가 있었죠. 이에 BAM은 Channel Attention 뿐만 아니라 Spatial Attention 기능도 추가해 줍니다. 이 둘을 병렬로 연결해 주었죠. 그 결과 BAM의 Attention Score Map은 각 채널별 가중치뿐만 아니라 위치별로도 가중치를 갖게 되었습니다. 즉 ‘무엇’과 ‘어디’에 따라 다른 가중치를 주는 Attention Module이라고 할 수 있습니다. BAM은 Image Classification과 Object Detection 실험 결과를 통해 다양한 문제에서 CNN의 성능 개선 효과가 있음을 입증했습니다. 뿐만 아니라 SE 모듈보다 성능 개선폭이 더 큼을 보였습니다.