DNN 성능 향상의 가장 직관적인 방법은 레이어 수와 레이어 당 유닛 수를 늘리는 것인데, 이는 네트워크 크기가 커질수록 파라미터 수가 급격히 증가하고, 네트워크 크기가 균일하게 증가할 경우 연산량이 급격히 늘어난다는 단점이 존재함.
- 완전 연결 대신 희소 연결 구조를 사용하면, 근본적 해결 가능하고, 이는 Hebbian 이론과도 일맥상통하나, 현재의 컴퓨팅 인프라에선 비효율적이며, CPU, GPU 등도 밀집 행렬에 최적화되어서 연산량이 많더라도 밀집 행렬 곱셈이 희소 행렬 곱셈보다 빠를 수 있음.
- 공간적 도메인에서 희소성을 어느 정도 활용 중임 (ex) 컨볼루션
- 현재 하드웨어의 밀집 행렬 연산 이점을 살리면서도 필터 수준에서의 희소성을 일부 활용할 수 있는 중간 단계의 아키텍처가 가능한가? ⇒ 희소 행렬을 상대적으로 밀집한 submatrix로 클러스터링하면 우수한 성능을 얻을 수 있음.
- 이러한 아이디어를 기반으로 시작해 희소 구조를 실제로 구현하되, 밀집된 기존 컴포넌트로 이를 대체한 것이 Inception 아키텍처이며(즉, 희소 연결처럼 작동하는 컨볼루션 블록들을 dense하게 만듦(여러 개 컨볼루션 결과를 합치는 형태)), 이는 local optimality를 지님.
** Contrast Normalization : 이미지 밝기/대비 균일하게 맞추는 것
Inception의 주요 아이디어는 컨볼루션 비전 네트워크에서 최적의 local sparse structure를 어떻게 쉽게 이용 가능한 dense 컴포넌트로 근사하고 덮을 수 있을까를 찾는 데 있으며, 이는 translation invariance를 가정하기에 컨볼루션 블록들로 구성되므로 최적의 국소 구조를 찾아내 이를 공간적으로 반복해야 함.



Polyak averaging : 모델 파라미터들의 이동 평균(지금까지 지나온 파라미터 평균)을 계산하는 방법
- 일부 구현에선 5x5 대신 3x3을 두 번 포함해 5x5 컨볼루션의 효과를 냄
- 이후 버전들에선 연산량 절감을 위해 3x3 연산을 1x3, 3x1 커널로 나누어 연산하기도 함.
GoogLeNet(
# 앞쪽 -> local한 특징 추출 + 계산량 줄임
(conv1): BasicConv2d(
(conv): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn): BatchNorm2d(64, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
(maxpool1): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=True)
(conv2): BasicConv2d(
(conv): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(64, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
(conv3): BasicConv2d(
(conv): Conv2d(64, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn): BatchNorm2d(192, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
(maxpool2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=True)
# Global한 특징 통합
# 희소 구조를 밀집하게 근사하기 위해 브랜치를 나누고, 여러 스케일 정보를 뽑기 위해
# 다양한 종류의 필터 사용
(inception3a): Inception(
(branch1): BasicConv2d(
(conv): Conv2d(192, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(64, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
(branch2): Sequential(
(0): BasicConv2d(
(conv): Conv2d(192, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(96, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
(1): BasicConv2d(
(conv): Conv2d(96, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
)
(branch3): Sequential(
(0): BasicConv2d(
(conv): Conv2d(192, 16, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(16, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
(1): BasicConv2d(
(conv): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn): BatchNorm2d(32, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
)
(branch4): Sequential(
(0): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=True)
(1): BasicConv2d(
(conv): Conv2d(192, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(32, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
)
)