데이터 분석/딥러닝

[MobileNet] 논문 리뷰 & 구현 (Pytorch)

개발자 소신 2020. 12. 19. 22:33
반응형

안녕하세요 ! 소신입니다.

 

 

성능을 최대한 보전하면서, 모델의 용량과 연산량을 가볍게 만드는 방법을 제시한 MobileNet입니다.

개인적으로 앞으로의 연구방향으로 제일 중요한 모델이라고 생각합니다.

성능을 보전하면서 가볍고, 빠르게 만드는것은 Real-Time world에서 굉장히 중요하기 때문이죠


# MobileNet, 미래

모바일과 임베디드 플랫폼에서 딥러닝 모델이 돌아갈 수 있다면

Real Time 처리가 필요한 시대에 정말 유용할 것입니다.

그런면에서 MobileNet은 이러한 현실에 집중한 모델이 아닐 수 없습니다.

 

MobileNet은 기존의 Conv. Filter를 분리해 Depthwise, Pointwise로 네트워크를 구성했습니다.

이것은 큰 변화인데, 기존의 이미지, IN-OUT 채널, Filter Size를 모두 한번에 계산하는 경우에는 아무래도 파라미터 수도 많고, 이는 곧 연산량이 많다는 것을 의미하기 때문입니다.

 

이를 분리함으로써, 약 1%의 정확도를 포기하면서, Cost는 8~9배 가량 감소시키는 결과를 가져왔습니다.

Trade-Off 연금술을 잘 해낸것이죠

 


# Additional Smaller & Faster method

또한, channel수를 줄이는 방법과, input image의 size를 줄이는 방법을 사용했습니다.

 

모델링 또한 굉장히 간단하다는 생각이 들었습니다. (우측)

VGGNet 이후 Template기반 Simple한 모델링이 대세가 되면서, MobileNet도 비슷한 형식을 취하려고 한 것 같습니다.

 

BatchNorm과 ReLU, Downsampling도 ResNet에 이어서 가져오게 되고,

Optimizer를 RMSprop으로 바꿨습니다.

RMSprop은 가중이동평균을 사용해 최근 계산한 기울기를 과거에 계산한 기울기보다 더 많이 반영합니다.

이러한 Optimizer에 따라 방향의 강도를 제약하는 weight decay를 줄이게 되었습니다.

 


# Pytorch 구현

import torch.nn as nn

def mobile_block(in_dim, out_dim, stride=1):
    return nn.Sequential(
        nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=3, stride=stride, padding=1, groups=in_dim),
        nn.BatchNorm2d(in_dim),
        nn.ReLU(inplace=True),
        nn.Conv2d(in_channels=in_dim, out_channels=out_dim, kernel_size=1, stride=1, padding=0),
        nn.BatchNorm2d(out_dim),
        nn.ReLU(inplace=True),
    )

class MobileNet(nn.Module):
    def __init__(self, num_classes=1000):
        super(MobileNet, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True),

            mobile_block(32, 64),
            mobile_block(64, 128, 2),
            mobile_block(128, 128),
            mobile_block(128, 256, 2),
            mobile_block(256, 256),
            mobile_block(256, 512, 2),
            *[mobile_block(512, 512) for _ in range(5)],
            mobile_block(512, 1024, 2),
            mobile_block(1024, 1024),

            nn.AvgPool2d(7),
        )
        self.classifier = nn.Linear(1024, num_classes)

    def forward(self, x):
        x = self.model(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        return x

MobileNet은 depthwise separable convolution을 반복해서 사용해주는 모델이기 때문에,

이를 mobile_block이라는 함수에 묶어주었습니다.

 

depthwise conv filter는 3x3 size에 in, out channel, groups를 input channel로 맞춰주면,

논문에서 설명하는 그림이 나오게 되는 것이죠.

 

논문상에선 위와같이 표현했기 때문에, input channel이 1이고 Output채널이 M인건가? 하고 헷갈릴 수 있는데

사실 MatMul 연산조차 안되기 때문에 자연스럽게 세로로 잘라냈다는 것을 알 수 있습니다.

 

 


# 결론

성능을 보존하면서, 복잡도를 줄이기 위한 방법으로 여러가지를 연구했지만, 위의 경우 외에는 효율적으로 줄일 수 있는 방법이 딱히 없어보인다.

 

한가지 중요한 사실은, channel수를 줄여도 깊게 쌓는 것이, 얕게 쌓고 channel수를 늘린 것 보다 정확도가 더 높다는 것

이미지의 크기와 정확도는 비례하는 경향을 보임

 

ResNeXt의 소요시간은 절반정도, 정확도는 같은 Epoch 대비 3.3% 낮은 결과가 나왔습니다.

확실히 시간이 많이 줄어드는것을 확인할 수 있었습니다

근데 이론상 8~9배 (Input Channel N은 충분히 작은 숫자가 되므로)까지 시간이 줄어들어야하는데..

데이터 로드하는 시간이나 validating 할때 시간이 오래 걸리는 건지 확인 해봐야될것같습니다.


ref.

MobileNet Article

MobileNet Pytorch 구현 코드

 

반응형