일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- dfs
- 인접리스트
- CROSS JOIN
- 백준
- depthwise convolution
- 그래프
- get_dummies()
- 인접행렬
- 데이터모델링
- Depthwise Separable Convolution
- SQLD
- 정규화
- BFS
- skip connection
- Two Pointer
- dp
- bottleneck
- feature map
- mobilenet
- numpy
- SQLD 후기
- 엔터티
- Inductive Bias
- 1x1 Convolution
- 연산량 감소
- resnet
- outer join
- SQL
- 식별자
- pytorch
- Today
- Total
SJ_Koding
Bottleneck 구조(resnet)의 설명 및 Pytorch 예시 본문
부제: - ConvNeXt 이해하기 2편 -
Bottleneck이란 용어 자체는 병목현상을 의미한다. 정말 많은 분야에서 쓰이는 말이다.
시스템 분야에서의 병목현상은 다음과 같이 정의된다.
- 시스템 내에서 전체적인 처리 속도를 떨어뜨리게 되는 특정한 부분을 가리키는 용어
- 시스템의 CPU나 메모리, 디스크 등의 자원 중 하나가 다른 자원들에 비해 처리 속도가 느려서, 전체적인 성능을 제한하는 경우를 말함
그렇다면 Deep leaning network에서 말하는 병목현상 즉, bottleneck layer는 무엇을 의미할까?
Bottleneck은 구조는 2015년 ResNet에 의해 널리 알려지고 사용되었으며, 대표적으로 아래의 사진으로 나타낸다
1 x 1 convolution을 사용하여 채널을 줄인 후 3x3으로 피처를 추출한 뒤, 다시 1x1 convolution으로 원래차원으로 늘려 skip connection을 진행하는 구조이다. 1x1 convolution의 설명은 아래 포스팅을 참고하자.
연산량
IC : Input Channel
OC: Output Channel
H: height of feature map
W: width of feature map
K: kernel size
Bottelneck을 사용하지 않고 일반적인 convolution 블럭을 사용한다고 가정하고, IC와 OC가 256, H와 W가 224, K가 3 이라고 가정해보자.
즉, 모델 구조는 아래의 코드와 같다.
import torch
import torch.nn as nn
import torch.nn.functional as F
class BasicConvBlock(nn.Module):
def __init__(self, in_channels, out_channels):
super(BasicConvBlock, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
self.bn = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
x = self.conv(x)
x = self.bn(x)
x = self.relu(x)
return x
# 입력 채널 수와 출력 채널 수가 모두 256인 일반 컨볼루션 블록의 예시
basic_block = BasicConvBlock(256, 256)
이 경우 연산량은
H*W*K*K*IC*OC == 224*224*3*3*256*256 --> 29,595,009,024 ( 약 29.5B ) 가 된다.
반면 Bottleneck구조를 사용하여 IC를 1x1 convolution으로 256 --> 64채널 로 줄인 후 3x3 Convolution을 적용한 후 다시 1x1 convolution으로 64 --> 256채널로 확장하는 경우를 생각해보자. 즉 모델 구조는 아래의 코드와 같다.
class Bottleneck(nn.Module):
def __init__(self, channels, internal_channels):
super(BottleneckNoExpansion, self).__init__()
self.conv1 = nn.Conv2d(channels, internal_channels, kernel_size=1)
self.bn1 = nn.BatchNorm2d(internal_channels)
self.conv2 = nn.Conv2d(internal_channels, internal_channels, kernel_size=3, padding=1)
self.bn2 = nn.BatchNorm2d(internal_channels)
self.conv3 = nn.Conv2d(internal_channels, channels, kernel_size=1)
self.bn3 = nn.BatchNorm2d(channels)
self.relu = nn.ReLU()
def forward(self, x):
identity = x
out = self.relu(self.bn1(self.conv1(x)))
out = self.relu(self.bn2(self.conv2(out)))
out = self.bn3(self.conv3(out))
out += identity
out = self.relu(out)
return out
bottleneck_model = Bottleneck(256, 64)
이 경우 연산량은 3단계로 나뉘어서 더해진다.
(1) IC * OC * H * W * K * K == 256 * 64 * 224 * 224 * 1 * 1 ( 1x1convolution으로 256 --> 64채널로 줄이는 연산량)
(2) IC * OC * H * W * K * K == 64 * 64 * 224 * 224 * 3 * 3 (줄여진 채널(64)에서 3x3 convolution연산 수행)
(3) IC * OC * H * W * K * K == 64* 256 * 224 * 224 * 1 * 1 ( 1x1convolution으로 64--> 256채널로 늘리는 연산량)
(1) + (2) + (3) == 822,083,584 + 1,849,688,064 + 822,083,584 = 3,493,855,232 (약 3.5B)
따라서 위 상황에서 Bottleneck을 사용할 시 연산량은 29.5B에서 3.5B로 대폭 작아진다. 또한 layer마다 activation함수를 추가했기 때문에 비선형성이 더욱 가중된다.
'Deep Learning' 카테고리의 다른 글
ConvNeXt (A ConvNet for the 2020s, facebook) 논문 리뷰 (0) | 2024.04.04 |
---|---|
manifold와 Inverted Bottleneck의 설명 (1) | 2024.04.04 |
Grouped convolution의 설명 및 PyTorch 예시 (1) | 2024.04.03 |
Depthwise (Separable) Convolution의 설명 및 Pytorch 예시 (0) | 2024.04.03 |
1x1 convolution의 설명 및 Pytorch 예시 (0) | 2024.04.03 |