본문 바로가기
CV/Coding

GoogLeNet

by BaekDaBang 2024. 4. 22.

1. Information

인셉션은 구글에서 연구 논문을 통해 2014년에 발표했음
인셉션의 구조의 특징은 신경망 내부적으로 계산 자원의 효율을 높였음
인셉션 신경망 구조를 구현한 GoogLeNet은 22개 층으로 구성(VGGNet보다 층수가 많음)되었으나 파라미터 수는 VGGNet의 1/12에 불가함

→ VGGNet: 1억 3800만개, GoogLeNet: 1300만개
GoogLeNet은 적은 파라미터 수로 향상된 성능을 보임
인셉션 신경망 구조는 AlexNet이나 VGGNet에서 따온 고전적인 CNN 구조를 따르지만 인셉션 모듈(inception module)이라는 새로운 요소를 도입하였음


합성곱층의 커널 크기
- 앞서 살펴본 신경망 구조는 커널 크기가 제각각으로, 1x1, 3x3, 5x5, 큰 것은 11x11 (AlexNet)까지 있었음
- 합성곱층을 설계하다 보면 데이터셋에 맞는 커널 크기를 선택하게 됨
- 크기가 작은 커널은 이미지의 세세한 특징을 포착할 수 있고, 큰 커널은 세세한 특징을 놓치기 쉬움


풀링층의 배치
- AlexNet구조에서는 1개 또는 2개 합성곱층마다 풀링층을 배치해 특징을 다운샘플링
- VGGNet은 2, 3, 4개 합성곱층마다 풀링층을 매치했는데 신경망의 얕은 쪽에 풀링층을 더 자주 배치했음 (2개 합성곱층마다 풀링층 배치)


인셉션에서는 합성곱의 필터 크기나 풀링층의 배치를 직접 결정하는 대신 블록 전체에 똑같은 설정(인셉션 모듈)을 적용
GoogLeNet은 기존의 방식대로 층을 쌓는 대신 커널 크기가 서로 다른 합성곱층으로 구성된 인셉션 모듈을 쌓는 방식으로 신경망을 구성함

 

LeNet, AlexNet, VGGNet 등의 기존 방식에서는 합성곱층과 풀링층을 번갈아 쌓아 올리는 방식으로 특징 추출기를 구성함
인셉션 구조에서는 인셉션 모듈과 풀링층을 쌓아 특징 추출기를 구성함

 

인셉션 모듈의 구성

- 1x1 합성곱층, 3x3 합성곱층, 5x5 합성곱층, 3x3 최대풀링층
- 각 층의 출력은 연접처리(concatenation)를 통해 하나의 출력으로 합쳐져 다음 단계의 입력이 됨

 

차원 축소가 적용된 인셉션 모듈

단순 인셉션 모듈은 5x5 합성곱층과 같은 크기가 큰 필터를 포함하기 때문에 계산비용이 큼
- 32x32x200 크기의 입력이 5x5 크기의 합성곱 필터 32개를 갖춘 합성곱층에 입력
- 필요한 곱셈의 수는(32x32x200)x(5x5x32) = 약 1억6300만회
이때 연산수를 줄이기 위해 차원 축소층의 도입이 필요

 

차원 축소층 (1x1 합성곱층)

1x1 합성곱층을 도입하면 1억 6300만회의 곱셈을 약 1/10으로 줄일 수 있음
3x3 또는 5x5 처럼 크기가 큰 필터를 포함하는 합성곱층 앞에 1x1 합성곱층을 배치해서 입력의 깊이를 축소하고 필요한 연수 횟수를 줄임

 

연산이 줄어드는 과정
계산비용 = 1x1 합성곱층의 연산 횟수 + 5x5 합성곱층의 연산 횟수
              = (32x32x200)x(1x1x16)+(32x32x16)x(5x5x32) 
              = 3276800 + 13107200 
              = 약 1630만

1x1 합성곱층을 이용한 차원 축소는 이 합성곱층이 이미지 크기는 대로 유지한  필터수를 해 출력의 널수(이)를 자유로이  다는 을 이용한 

1x1 합성곱층 병목층(bottleneck layer)라고 하는데, 신경망 구조 내에서 차원을 축소하는 이 층의 역할이 마치 병에서 가장 좁은 병목을 연상케하기 때문

 

인셉션

 

GoogLeNet

 

 

하이퍼파라미터 설정

학습률 스케줄러: 8 에포크 마다 학습률 learning rate 4%씩 감소

최적화 알고리즘: 경사하강법
모멘텀: 0.9

 

2. Code

Inception Module

class inception_module(nn.Module):
    def __init__(self,in_channels: int, filters_1x1: int, filters_3x3_reduce: int, filters_3x3: int,
                 filters_5x5_reduce: int,filters_5x5: int,filters_pool_proj: int):
        super().__init__()
        
        self.branch1 = nn.Sequential(
            nn.Conv2d(in_channels, filters_1x1, kernel_size=1, padding="same"),
            nn.ReLU())

        self.branch2 = nn.Sequential(
            nn.Conv2d(in_channels, filters_3x3_reduce, kernel_size=1),
            nn.ReLU(),
            nn.Conv2d(filters_3x3_reduce, filters_3x3, kernel_size=3, padding="same"),
            nn.ReLU())

        self.branch3 = nn.Sequential(
            nn.Conv2d(in_channels, filters_5x5_reduce, kernel_size=1),
            nn.ReLU(),
            nn.Conv2d(filters_5x5_reduce, filters_5x5, kernel_size=5, padding="same"),
            nn.ReLU())

        self.branch4 = nn.Sequential(
            nn.MaxPool2d(kernel_size=3, stride=1, padding=1, ceil_mode=True),
            nn.Conv2d(in_channels, filters_pool_proj,kernel_size=1, padding="same"),
            nn.ReLU())

    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)

 

GoogLeNet architecture

class GoogLeNet(nn.Module):
    def __init__(self, 
                 num_classes: int = 1000, 
                 aux_logits: bool = False,
                 init_weights: Optional[bool] = None,
                 dropout: float = 0.5,
                 dropout_aux: float = 0.7):
        super().__init__()
        
        inception_block = inception_module

        self.aux_logits = aux_logits
        
        self.partA = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(3, stride=2, ceil_mode=True),

            nn.Conv2d(64, 64, kernel_size=1, stride=1),
            nn.ReLU(),

            nn.Conv2d(64, 192, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(192),
            nn.ReLU(),
            nn.MaxPool2d(3, stride=2, ceil_mode=True),
        )
        
        self.relu = nn.ReLU()
        
        self.inception_3a = inception_block(in_channels=192, filters_1x1=64, filters_3x3_reduce=96,
                                            filters_3x3=128, filters_5x5_reduce=16, filters_5x5=32,
                                            filters_pool_proj=32)
        
        self.inception_3b = inception_block(in_channels=256, filters_1x1=128, filters_3x3_reduce=128,
                                            filters_3x3=192, filters_5x5_reduce=32, filters_5x5=96,
                                            filters_pool_proj=64)
        
        self.maxpool3 = nn.MaxPool2d(3, stride=2, ceil_mode=True)
        
        self.inception_4a = inception_block(in_channels=480, filters_1x1=192, filters_3x3_reduce=96,
                                            filters_3x3=208, filters_5x5_reduce=16, filters_5x5=48,
                                            filters_pool_proj=64)
        
        self.inception_4b = inception_block(in_channels=512, filters_1x1=160, filters_3x3_reduce=112, 
                                            filters_3x3=224, filters_5x5_reduce=24, filters_5x5=64,
                                            filters_pool_proj=64)
        
        self.inception_4c = inception_block(in_channels=512, filters_1x1=128, filters_3x3_reduce=128,
                                            filters_3x3=256, filters_5x5_reduce=24, filters_5x5=64,
                                            filters_pool_proj=64)
        
        self.inception_4d = inception_block(in_channels=512, filters_1x1=112, filters_3x3_reduce=144,
                                            filters_3x3=288, filters_5x5_reduce=32, filters_5x5=64,
                                            filters_pool_proj=64)
            
        self.inception_4e = inception_block(in_channels=528, filters_1x1=256, filters_3x3_reduce=160,
                                            filters_3x3=320, filters_5x5_reduce=32, filters_5x5=128,
                                            filters_pool_proj=128)
        
        self.maxpool4 = nn.MaxPool2d(3, stride=2, ceil_mode=True)
        
        ## classifier_1
        if aux_logits:
            self.auxilliary_output_1 = nn.Sequential(nn.AvgPool2d(5, stride=3),
                                              nn.Conv2d(512,128, kernel_size=1, padding="same"),
                                              nn.ReLU(),
                                              nn.Flatten(),
                                              nn.Linear(2048,1024),
                                              nn.ReLU(),
                                              nn.Dropout(p=0.7),
                                              nn.Linear(1024, num_classes)
                                             )
        else:
            self.auxilliary_output_1 = None
        
        
        
        
        
        if aux_logits:
            self.auxilliary_output_2 = nn.Sequential(nn.AvgPool2d(5, stride=3),
                                              nn.Conv2d(528,128, kernel_size=1, padding="same"),
                                              nn.ReLU(),
                                              nn.Flatten(),
                                              nn.Linear(2048,1024),
                                              nn.ReLU(),
                                              nn.Dropout(p=0.7),
                                              nn.Linear(1024, num_classes)
                                             )
        else:
            self.auxilliary_output_2 = None
            
        ## classifier_2
        self.inception_5a = inception_block(in_channels=832, filters_1x1=256, filters_3x3_reduce=160,
                                            filters_3x3=320, filters_5x5_reduce=32, filters_5x5=128, 
                                            filters_pool_proj=128)
        
        self.inception_5b = inception_block(in_channels=832, filters_1x1=384, filters_3x3_reduce=192,
                                             filters_3x3=384, filters_5x5_reduce=48, filters_5x5=128,
                                             filters_pool_proj=128)
    

        self.avgpool = nn.AvgPool2d((7,7),stride=1)
        self.dropout = nn.Dropout(p=0.4)
        self.fc = nn.Linear(1024, num_classes)
        self.softmax = nn.Softmax(dim=-1)
                    
    def forward(self, x: Tensor):
        
        x = self.partA(x)
        
        # N x 192 x 28 x 28
        x = self.inception_3a(x)
        # N x 256 x 28 x 28
        x = self.inception_3b(x)
        # N x 480 x 28 x 28
        x = self.maxpool3(x)
        
        x = self.inception_4a(x)
        # N x 512 x 14 x 14
        aux1: Optional[Tensor] = None
        if self.auxilliary_output_1 is not None:
            aux1 = self.auxilliary_output_1(x)

        x = self.inception_4b(x)
        # N x 512 x 14 x 14
        x = self.inception_4c(x)
        # N x 512 x 14 x 14
        x = self.inception_4d(x)
        # N x 528 x 14 x 14
        aux2: Optional[Tensor] = None
        if self.auxilliary_output_2 is not None:
            aux2 = self.auxilliary_output_2(x)

        x = self.inception_4e(x)
        # N x 832 x 14 x 14
        x = self.maxpool4(x)
        # N x 832 x 7 x 7
        x = self.inception_5a(x)
        # N x 832 x 7 x 7
        x = self.inception_5b(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, aux1, aux2

 

'CV > Coding' 카테고리의 다른 글

ResNet  (0) 2024.04.22
VGG  (0) 2024.04.22
AlexNet  (0) 2024.04.22
LeNet  (0) 2024.04.17