Inception Net V1 (2014)
Abstract
Inception을 이용한 deep CNN
- 네트워크 내의 컴퓨팅 자원을 효율적으로 사용하였다.
- 수행 시간은 유지하면서 네트워크의 너비, 높이는 늘렸다.
- Hebbian, multi-scale processing을 이용해 구조적으로 최적화를 시도함
- 총 22 layer의 딥러닝 네트워크
Introduction
- Object Detection에 있어서 큰 발전은 큰 모델을 쓰는 것이 아닌, 고전적인 기법과 deep 한 구조를 결합해 만들어진 것이다.
- 객체 인식에 쓰이는 시간을 단축해 학문 분야만이 아닌 실제 세상에서 활용할 수 있는 알고리즘을 제작
- Inception(처음) = We need to go deeper 이라는 밈의 반대 의미로 사용, 반어법.
- “Deep”하다의 의미
Related Work
- LeNet-5 : CNN이 주목받던 초창기에 CNN의 구조를 확립시킨 모델 → Fully Connected model, normalization, max-pooling
- Gabor filter : 사인파와 가우스 함수를 곱한 필터 → 이전 연구들에서는 고정된 크기의 필터를 여러 번 사용하였으나, Inception 네트워크에서는 데이터에 따른 제일 좋은 경우를 알 수 없기 때문에 모든 종류의 필터를 사용한다.(후술)
- Network-in-Network : ReLU activation function을 적용한 이후 추가로 1 x 1 의 필터를 한번 더 적용한다. neural network의 표현력을 올리기 위해 사용
- R-CNN(Regions with CNN) : 전체적인 detection 문제를 2개의 작은 문제로 분할 가능
Motivation and High Level Considerations
- 가장 딥러닝 성능을 쉽게 올리는 방법은 deeeeep하게 만드는 것이다. = Layer 수를 늘린다.
- 하지만 이는 하드웨어 자원 상 한계가 있으며, overfitting의 문제도 존재
- 데이터셋의 확률 분포가 느슨하고 깊은 네트워크에 들어가면 가장 정확한 구조가 완성된다.
- 여러 번의 시행 착오(노가다) 결과 만들어진 것이 Inception!
Architectural Details
최종 목표 : 느슨하면서도 깊은 모델을 만들기
적절한 local construction을 찾고 이것을 반복
- 필터 사이즈는 뭐가 좋을지 알 수 없다 → 여러가지 사이즈를 가진 conv layer를 병렬로 통과시켜 보자
- 그렇게 얻은 ferature map들을 depth 방향으로 concat 시킨다. → concat을 하려면 각 결과들의 size가 같아야 한다.

- 1 x 1 : padding = 0, stride = 1
- 3 x 3 : padding = 1, stride = 1
- 5 x 5 : padding = 2, stride = 1
- 3 x 3 max pooling : padding = 1, stride = 1 → 사이즈를 유지하기 위한 조치들
- 5 x 5만 가더라도 지나치게 연산이 많이 들게 된다. → 채널 수를 조절하기 위해 1 x 1 convolution을 이용한다.

- 192 → 128로 변할 때 3 x 3 을 바로 통과 vs 192 →96 →128로 사이에 1 x 1 을 거쳐서 통과
- 필터 크기가 커지면 연산량이 많아지니 먼저 1 x 1로 채널 수를 줄여준다
GoogleNet
- 저자가 google 출신 + LeNet-5에서 아이디어를 얻음
- 기존 deep한 네트워크보다 성능은 떨어지지만 ensemble을 통해 성능이 개선되었음 + 하드웨어 자원에서 엄청 큰 이득을 얻음


- inception module 안쪽의 모든 convolution들은 ReLU Activation function을 사용한다.
- 이 네트워크는 매개변수를 갖는 계층(layers with parameters) 만 계산할 경우 22층 깊이(depth) 를 가지며, 풀링(pooling) 계층까지 포함하면 총 27층 깊이를 가진다. 하지만, 네트워크를 구성하는 전체 독립적인 빌딩 블록(building blocks) 수는 약 100개에 달한다.
- S : 사이즈를 Same 혹은 반으로 떨어지게 적절히 한다는 뜻
- LRN(Local Response Normalization)
- Auxilary Classifier
- 정리하면 다음과 같다.
성능 비교

- 7개의 모델(앞서 제시된 모델과 동일한 사이즈 6개 + 1개 좀 더 큰 모델)을 Ensemble
- 여러가지 resize, crop 방법으로 이미지 하나를 144개의 이미지로 변형을 거친 다음 통과시켜 총 144 * 7 = 1008 개의 출력을 평균 내서 최종 분류 수행 - 일종의 Test Time Augmentation

코드
- Inception 모듈
Copy
class Inception(nn.Module):
def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):
super().__init__()
self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
self.branch2 = nn.Sequential(BasicConv2d(in_channels, ch3x3red, kernel_size=1),
BasicConv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)) # red는 reduce를 줄인 것
self.branch3 = nn.Sequential(BasicConv2d(in_channels, ch5x5red, kernel_size=1),
BasicConv2d(ch5x5red, ch5x5, kernel_size=5, padding=2))
# Here, kernel_size=3 instead of kernel_size=5 is a known bug. (버그 fix: kernel_size 3=>5, padding 1=>2 로 변경)
# Please see https://github.com/pytorch/vision/issues/906 for details.
self.branch4 = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
BasicConv2d(in_channels, pool_proj, kernel_size=1))
def forward(self, x):
branch1 = self.branch1(x)
branch2 = self.branch2(x)
branch3 = self.branch3(x)
branch4 = self.branch4(x)
outputs = [branch1, branch2, branch3, branch4]
return torch.cat(outputs,1)
- Auxilary classifier
Copy
class InceptionAux(nn.Module):
def __init__(self, in_channels, num_classes, drop_p = 0.7):
super().__init__()
self.avgpool = nn.AvgPool2d(kernel_size=5, stride=3)
self.conv = BasicConv2d(in_channels, 128, kernel_size=1)
self.fc1 = nn.Linear(2048, 1024)
self.act = nn.ReLU()
self.dropout = nn.Dropout(p=drop_p)
self.fc2 = nn.Linear(1024, num_classes)
def forward(self, x):
# aux1: N x 512 x 14 x 14, aux2: N x 528 x 14 x 14
x = self.avgpool(x)
# aux1: N x 512 x 4 x 4, aux2: N x 528 x 4 x 4
x = self.conv(x)
# N x 128 x 4 x 4
x = torch.flatten(x, 1)
# N x 2048
x = self.fc1(x)
x = self.act(x)
x = self.dropout(x)
# N x 1024
x = self.fc2(x)
# N x 1000 (num_classes)
return x
- GoogleNet
Copy
class Inception_V1(nn.Module):
def __init__(self, num_classes = 1000, use_aux = True, init_weights = None, drop_p = 0.4, drop_p_aux = 0.7):
super().__init__()
self.use_aux = use_aux
self.conv1 = BasicConv2d(3, 64, kernel_size=7, stride=2, padding=3)
self.maxpool1 = nn.MaxPool2d(3, stride=2, padding=1)
self.conv2a = BasicConv2d(64, 64, kernel_size=1)
self.conv2b = BasicConv2d(64, 192, kernel_size=3, padding=1)
self.maxpool2 = nn.MaxPool2d(3, stride=2, padding=1)
self.inception3a = Inception(192, 64, 96, 128, 16, 32, 32)
self.inception3b = Inception(256, 128, 128, 192, 32, 96, 64)
self.maxpool3 = nn.MaxPool2d(3, stride=2, padding=1)
self.inception4a = Inception(480, 192, 96, 208, 16, 48, 64)
self.inception4b = Inception(512, 160, 112, 224, 24, 64, 64)
self.inception4c = Inception(512, 128, 128, 256, 24, 64, 64)
self.inception4d = Inception(512, 112, 144, 288, 32, 64, 64)
self.inception4e = Inception(528, 256, 160, 320, 32, 128, 128)
self.maxpool4 = nn.MaxPool2d(3, stride=2, padding=1)
self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)
self.inception5b = Inception(832, 384, 192, 384, 48, 128, 128)
if use_aux:
self.aux1 = InceptionAux(512, num_classes, drop_p=drop_p_aux)
self.aux2 = InceptionAux(528, num_classes, drop_p=drop_p_aux)
else:
self.aux1 = None
self.aux2 = None
self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) # GAP
self.dropout = nn.Dropout(p=drop_p)
self.fc = nn.Linear(1024, num_classes)
if init_weights:
for m in self.modules():
if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear):
torch.nn.init.trunc_normal_(m.weight, mean=0.0, std=0.01, a=-2, b=2)
elif isinstance(m, nn.BatchNorm2d):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
def forward(self, x):
# N x 3 x 224 x 224
x = self.conv1(x)
# N x 64 x 112 x 112
x = self.maxpool1(x)
# N x 64 x 56 x 56
x = self.conv2a(x)
# N x 64 x 56 x 56
x = self.conv2b(x)
# N x 192 x 56 x 56
x = self.maxpool2(x)
# N x 192 x 28 x 28
x = self.inception3a(x)
# N x 256 x 28 x 28
x = self.inception3b(x)
# N x 480 x 28 x 28
x = self.maxpool3(x)
# N x 480 x 14 x 14
x = self.inception4a(x)
# N x 512 x 14 x 14
if self.aux1 is not None and self.training:
aux1 = self.aux1(x)
else:
aux1 = None # 뭐라도 넣어놔야 not defined error 안 뜸
x = self.inception4b(x)
# N x 512 x 14 x 14
x = self.inception4c(x)
# N x 512 x 14 x 14
x = self.inception4d(x)
# N x 528 x 14 x 14
if self.aux2 is not None and self.training:
aux2 = self.aux2(x)
else:
aux2 = None
x = self.inception4e(x)
# N x 832 x 14 x 14
x = self.maxpool4(x)
# N x 832 x 7 x 7
x = self.inception5a(x)
# N x 832 x 7 x 7
x = self.inception5b(x)
# N x 1024 x 7 x 7
x = self.avgpool(x)
# N x 1024 x 1 x 1
x = torch.flatten(x, 1)
# N x 1024
x = self.dropout(x)
x = self.fc(x)
# N x 1000 (num_classes)
return x, aux2, aux1
InceptionNet V2 (2015)
Abstract
- 계산의 효율성(Computational Efficiency)과 적은 파라미터 개수(Low Parameter Count)등은 빅데이터 처리나 모바일 비전 등에서 여전히 중요한 요소이다.
- 이 버전의 모델에서는 분해된 컨볼루션(factorized convolutions), bottleneck 방지를 위한 regularization 등을 이용해 이전의 모델에서 더욱 효율적인 계산을 이끌어 내었다.
Introduction
우리는 CNN을 통해서 분류의 성능을 높여왔다.
이 논문은 이전 모델에서의 분류 성능 향상을 위해 제작된 모델이다. 성능 향상을 통해 기존 모델보다 다양한 분야에도 응용될 수 있다.
- VGG의 경우 모델 자체는 간단하지만 연산량이 많아 성능은 떨어진다는 단점이 존재하였다. V1의 경우에는 연산량을 줄이기 위한 다양한 노력이 있다. 3배나 적은 파라미터가 사용되었다.
- 그럼에도 Inception의 경우 모델 자체에 연산이 있기 때문에 이상적인 결과를 내기에는 여전히 연산량이 많았으며, 특히 네트워크의 구조가 깊어질수록 이점이 낮아지는 단점이 있었다.
- V2는 깊이가 깊어짐에도 연산량을 효과적으로 줄일 수 있는 더 많은 방법들을 제시하였다. Inception 네트워크에만 적용되는 기법이 아니라 살펴볼 부분이 있는 논문.
- V1의 차원을 줄이는 방식, Inception 모듈의 병렬적인 연산 방식을 가져와 만든 구조
General Design Principles
- Representational BottleNeck 의 방지
- 더 높은 차원의 표현은 네트워크 내에서 지역적으로 처리하기 더 쉽다. 컨볼루션 신경망에서 타일당 활성화 수를 증가시키면 더 잘 분리된 특징을 얻을 수 있다. 그 결과, 이러한 네트워크는 더 빠르게 학습될 것이다.
- 그러나 인접된 픽셀과의 상관관계로 인해 채널이 축소되더라도 공간 정보가 크게 손상되지는 않는다. (3 x 3 필터 등)
- 네트워크의 적절한 깊이, 너비를 설정한다.
Factorizing Convolutions with Large Filter Size
- Inception 네트워크는 Fully Convolutional이므로, 각각의 weight가 모두 한번씩은 곱해지는데 사용된다.
- VGG 네트워크의 deep 네트워크를 통해 파라미터 수를 줄이는 아이디어를 발전시킴


- VGG : 3 x 3 두번으로 5 x 5의 receptive field를 얻기
- VGG Net에서 나아가 1 x 3, 3 x 1 두 번으로 3 x 3의 receptive field를 얻기 : Parameter 수가 감소


→ 기존의 5 x 5 필터를 3 x 3 두번으로 바꾸었다.
- 3 x 3 을 1 x 3 + 3 x 1 로 쪼개는 것도 반영 → 논문에서는 7 x 7 → 1 x 7 + 7 x 1을 제안


Auxiliary Classifier의 사용

- V1 과는 달리 하나만 사용(입력 쪽에 가까운 모듈을 없애 보았는데 큰 차이 없었다)
- aux classifer는 loss에 aux loss를 추가함으로써 regularizer 역할을 하는 것 같다.
- GAP 사용 시 정보량이 급격히 줄어드는 문제 → 채널 수를 늘리고 GAP를 수행한다.
'Computer Vision' 카테고리의 다른 글
[2025-1] 전연주 - NeuralRecon: Real-Time Coherent 3D Reconstruction from Monocular Video (0) | 2025.03.22 |
---|---|
[2025-1] 임수연 - PIFuHD (0) | 2025.03.19 |
[2025-1] 전연주 - Multi‑modal transformer architecture for medical image analysis and automated report generation (0) | 2025.03.15 |
[2025-1] 임수연 - MobileUNETR (0) | 2025.03.14 |
[2025-1] 유경석 - XprospeCT: CT Volume Generation from Paired X-Rays (0) | 2025.03.14 |