주관적인리뷰 이므로 틀린내용이 무조건 존재

https://arxiv.org/abs/1909.13719

 

RandAugment: Practical automated data augmentation with a reduced search space

Recent work has shown that data augmentation has the potential to significantly improve the generalization of deep learning models. Recently, automated augmentation strategies have led to state-of-the-art results in image classification and object detectio

arxiv.org

RandAugment Paper Review

논문 링크 : https://arxiv.org/abs/1909.13719

Abstract, Introduction

data augmentation은 model의 **generalization(일반화)**을 크게 개선한다. 특히 image classification(분류), object detection(객체탐지) 등 다양한 분야에서 모델 성능 개선에 큰 도움이 된다는 것이 밝혀졌다.

하지만 이러한 Data augmentation은 어려움이 존재한다.

  1. data augmentation을 적용할려는 domain마다 가지고 있는 데이터셋의 특성이 다름.
  2. 그러므로 domain에 **prior knowledge(사전지식)**을 알고 augmentation policy(증강정책) 선택.
  3. 하지만 이러한 prior knowledge를 찾는 것은 어렵고 별도의 Search space가 필요.
  4. 그리고 만약 prior knowledge를 찾더라도 다른 domain으로 확대하는 것은 매우 어려움.

이러한 문제를 해결하기 위해 최근 data augmentation policy를 딥러닝을 통해 찾기 시작하였다.

  1. NAS에서 최적의 Network 아키텍처를 찾는 것 처럼 data augmentation에서도 최적의 policy를 찾을려고 노력 하는 것.
  2. train된 data augmentation policy로 ML model을 학습하는 것은 정확도를 올려주는 경향이 존재.
  3. 하지만 data augmentation policy와 ML model 각각 training 하는 것은 계산량이 많음.
  4. 특히 두개의 분리된 최적화 절차를 수행하는 것은 어려움.

최근에는 PBA, Fast autoaugment에서 효율적인 방식을 제시 하였지만 여전히 문제가 존재한다.

  1. 기존에 존재하던 문제와 마찬가지로 여전히 분리된 최적화 절차가 필요함.
  2. 그리고 작은 데이터셋 학습한 data augmentation policy가 큰 경우에도 적용된다고 가정.
    • 하지만 작은 데이터셋에서 학습한 것을 큰 데이터셋에 그대로 적용하는 것은 문제가 존재.
    • 문제가 발생한 다는 것은 본 논문에서 실험을 통해 보여줌.
    • augmentation을 적용하는 정도는 모델, 데이터셋 사이즈에 의존한다는 것을 확인 가능.

그러므로 본 논문에서는 위에 결과물들을 참고하여 RandAugment를 고안하였고 대략적인 특징은 다음과 같다.

  1. Search space를 낮추기 위해 별도의 Proxy task를 제거, 아주작은 연산량으로 적용이 가능.
  2. Proxy task를 없애고 Augmentation 을 적용 하여도 성능이 좋거나 비슷함.

위 Table을 확인하면 개략적인 성능을 알 수 있다.

  • CIFAR-10, SVHN, ImageNet 데이터셋.
  • PyramidNet, Wide-ResNet-28-10, ResNet-50, EfficientNet-B7 모델.
  • AutoAugment, Fast AutoAugment, Population Base Augmentation, RandAugment 사용.
  • Search Space가 10^2 이지만, 4개의 Case에서 동등하거나 좋은 성능을 보임.

2. Related Works

Data augmentation은 deep vision model을 train할때 자주 사용되었다.

  1. natural image에서 horizontal flip, random cropping, translation 등 은 일반적으로 자주사용.
    • horizontal flip은 이미지를 좌우반전 시키는 것.
    • random cropping은 이미지의 일부분을 취득하는 것.
    • translation은 이미지를 이동시키는 것.
    • 등등 다양한 이미지 처리 연산이 존재한다. 너무 많은 연산이 존재하므로 일부만 소개.
  2. MNIST 에서는 scale, position에 elastic distortions 적용하여 인상적인 결과를 얻었다.
  • Elastic distortions은 Scale과 Position에 왜곡을 주는 것.

                                                            MNIST Elastic Distortion을 적용 한 것.
  1. 이전의 예시에서는 트레이닝 데이터셋의 분포를 유지한 채로 증가 시켰다. 그러므로 수행하는 연산은 일반화를 늘리는데 효과적이다. 일부 방법들은 validation accuracy, robustness 또는 둘다 향상을 시키기 위해서 무작위로 영상
    에서 patch를 지우거나, noise를 추가하였다.
  2. Mixup은 CIFAR-10과 ImageNet에서 특히 효과적인 augmentation방법이다.
  • 여기서 network는 이미지와 그에 대응되는 label의 조합에 대해 훈련을 진행.
  •  
                       MixUp 방식으로 다음과 같이 두개의 이미지를 조합하는 annotation 방법

  1. Object-centric cropping은 일반적으로 object detection tasks에서 사용. cut-and-paste로 train image에 새로운 object image를 추가한다.
                                     Cut and Paste를 이용하여 기존 Real Image에 학습 한 것.

위의 data augmentation 방식들을 제외하고도 data를 확장하는 작업은 다른 것과 결합하기 위한 최적의 전략을 찾는데 초점을 맞추고 있다.

  • 예를 들면 Smart Augmentation의 경우에는 동일한 class의 두개의 sample을 병합하여 새로운 data를 생성하는 network를 train
  • Tran이라는 연구자는 train 세트에서 학습한 distribution을 바탕으로 베이지안 접근방식으로 data augmentation을 수행.
  • DeVries는 data를 증가시키기 위해 **noise, interpolation(보간), extrapolations(외삽)**를 수행.
  • GAN을 이용하여 data augmentation을 수행.

data로 부터 data augmentation 전략을 학습하는 또 다른 접근방식은 AutoAugment로 강화학습 을 이용하여 sequence of operation과 적용 확률 및 규모를 선택함. 위 그림은 sub-policy가 적용될 확률 및 크기

  • AutoAugment policy 적용에는 여러가지 확률 적용. 다음과 같은 절차를 거쳐서 적용한다.
    1. 모든 minibatch의 모든 이미지에 대해 uniform probability로 sub-policy가 선택.
    2. 각 sub-policy에서의 동작에는 확률이 있음.
    3. 일부 연산은 방향에 대한 확률을 가진다.
      • 예를 들면 이미지를 시계방향이나 시계반대 방향으로 회전
  • 확률을 이용하여 network훈련되는 다양성을 증가 시키고, 이는 많은 데이터셋에서 generalization을 크게 개선

PBAFast Autoaugmentautoaugment에서 더 좋은 방법을 찾기 위해 노력한 결과물이다.

  • 시간은 줄어들었지만 별도의 search phase가 있어서 문제.
  • 이 논문에서는 별도의 proxy task에서 search phase를 제거하는 것을 목표로함

3. Methods

RandAugment의 목표는 proxy task에서 별도의 search phase가 필요하지 않도록 하는것.

  • proxy task란 본래의 목적을 달성하기 위한 부가적인 task를 말함.
  • Search phase를 없앨려는 이유는 별도의 search phase가 training을 복잡하게됨.
  • 그리고 계산량이 많아지는 안좋은 현상이 존재.
  • 그리고 proxy task가 꼭 최선의 결과를 얻는것도 아님!!.

이전에 augmentation 방법들은 30개 이상의 하이퍼파라미터를 포함 해야했음.

  • 저자들은 parameter space을 크게 줄이는데 초점을 맞춤.

                                                          변환 적용 확률을 열거한 것.
  •  
  • 이전 연구에서는 다음과 같이 변환중에 변환을 선택하고 각 변환을 적용할 확률을 열거함.

그러면 RandAugment에서는 어떤 parameter만을 사용하느냐?

  1. 첫번째 parameter로는 augmentation을 적용할 변환의 개수(N), 논문에서는 14개 선택.
  • parameter space를 줄이면서 이미지의 다양성을 유지하기 위해 각 변환을 적용하는 확률은 균일한 확률인 1/K.

       저자들이 적용한 변환의 종류 총 14개
  • Training image에 N개이 변환이 주어지면 RandAugment의 경우에는 K^N개의 정책을 선택할 수 있음.
  1. 그리고 마지막 Parameter는 distortion(왜곡)의 크기(M)
  • 왜곡의 크기란 그림으로 이해하는게 더 쉬움

                Figure1. Example RandAugment
  • 위 의 그림은 보면 N = 2 이고, M은 한줄씩 9,17,28를 적용한 예 값이 커질수록 그림의 왜곡이 심해지는 것을 알 수 있다. 논문에서는 0~10 사이로 M을 정한다고 합니다.
  • 저자들은 M을 선택하는 방식을 여러개로 구분하여 Test Random, Constant, Linear Increasing, Random Magnitude로 Test 성능이 0.1% 정도 거의 차이가 나지 않는 다는 것을 알 수 있다.

  1. 알고리즘은 다음과 같이 아주 간단한 파이썬 코드로 구현가능하다.

                       Python Based Numpy 구현
  • 코드가 매우 간단하며 인간이 해석하기 편하고 N,M이 커질수록 regularization strength이 커짐 ( Data가 더욱더 다양해 지므로)
  • N,M을 선택하기 위해 다른방법도 선택 할 수 있지만 저자들이 개발한 것은 매우 작은 search space를 고려할 때 naive grid search가 효과적이라고 함. Grid search (격자 탐색) 은 모델 하이퍼 파라미터에 넣을 수 있는 값들을 순차적으로 입력한뒤에 가장 높은 성능을 보이는 하이퍼 파라미터들을 찾는 탐색 방법이다.

4. Results

본 논문에서는 small proxy task에서 data augmentation policy를 찾는것이 문제라고함 모델 사이즈와 data set 사이즈가 두가지 측면에서 이를 분석함

  • 그림을 보면 왼쪽위를 보면 distortion magnitude에 따른 성능을 확인 할 수 있음.
    • 사각형이 표시 된 것이 최적의 Magnitude인것을 암시함.
    • network size가 클수록 큰 distortion Magnitude에서 좋은 성능을 보임.
    • 위의 결과로 알 수 있는 것은 small proxy task에서 distortion Magnitude 찾는것은 부적절함
  • 왼쪽 밑에 그림은 widening, 네트워크 사이즈에 따른 결과임.
    • Parameter가 커질 수록 distortion 이 커져야 성능이 좋아지는 것을 알 수 있음.
  • 오른쪽은 training data set 사이즈 에 대한 결과임.
    • 확인하면 **1k인 파란색에서는 3%**정도. 4k인 것은 2%, **10k인 것은 약 1.5%**만 성능이 좋아짐.
  • 오른쪽 아래를 보면 data set의 사이즈가 클수록 optimal distortion magnitude가 커짐.
    • 이는 작은 data set에서 더 큰 Regularization이 필요할거 같다는 예상과는 일치안함
    • 이 결과는 중요한 점이 있음. 더 큰 data set에서는 더 강한 augmentation이 필요함. 일부만으로 파악하는 proxy task에는 문제가 있음. proxy task에서 한 policy는 전체 training data에는 적용하기 안좋은 것을 알 수 있음.

CIFAR와 SVHN에서 결과

  • CIFAR , SVHN에서 결과는 다음과 같다.
  • RA는 PBA, FAST AA, AA에 비해 성능이 꿀리지 않고, 몇몇은 제일 좋은 것을 알 수 있음.
  • CIFAR와 SVHN은 아예다른 이미지를 가지고 있음. Fast AA나 ,AA에서의 Policy는 많이 다른 결과가 나왔다고 한다.
    • 즉 data augmentation policy 가 많이 달라도 RandAugment는 동일 또는 더 좋은 성능이 나오게 된다는 것을 알 수 있음.

IMAGENET에서 결과

  • 모델에서 성능을 개선하는 data augmentation이 항상 imagenet과 같은 데이터셋에서 성능을 좋게 하는 것은 아님.
  • 항상 성능을 향상시키는게 아니거나 거의 변화가 없었다.

COCO에서 결과

  • object detection은 다음과 같은 결과가 나온 것을 알 수 있다.
  • Auto augment에서는 randAugment에서 사용하지 않은 변환도 사용하도록 하였다.
  • 그리고 굉장히 큰 Search space, GPU연산량이 들어도 6개의 value의 하이퍼 파라미터 튜닝한 RandAugment와 비슷한 결과가 나온 것을 알 수 있다.
  • 이 실험에서는 RandAugment가 bbox에서도 적용가능한 transformation이 제한되어 있어 더 다양한 변환이 필요하다고 함.

변환 개수에 따른 결과

모든 결과는 CIFAR-10 기준이다.

  • (A)
    • 그래프 A를 보면 변환이 많으면 성능이 높아짐.
  • (B)
    • 그래프 B를 보면 rotate가 성능에 큰 영향을 미친 다는 것을 알 수 있음.
  • (C)
    • 그래프 C를 보면 translate는 생각보다 큰 영향을 미치지 않는 것을 알 수 있음.
  • (D)
    • 그래프 D를 보면 poseterize는 성능이 안좋아지는 것을 알 수 있음. (이미지 음영을 조절하는것,아래 그림은 poseterize의 결과)
     

다른 결과

  • 위의 결과는 확률을 학습하면 성능이 좋아진다고 생각했으며, 작은 data set에서 테스트를 한 것.성능이 향상된것을 확인할 수 있었으며, 큰 data set에 대해선 차후 과제로 남겨두었습니다.

5. Discussion

  • data augmentation은 최고의 성능을 위해 필수
  • 학습된 data augmentation 전략을 자동화 하여 성능을 높임
  • 별도의 search 없이 기존연구와 비슷하거나 좋은 성능을 얻음
  • 기존의 연구는 큰 data set에서는 적용이 힘들지만 두개의 hyperparameter를 이용하여 좋은 성능을 얻음

 

Using RandAugment

Unofficial Pytorch Reimplementation of RandAugment 카카오 브레인 김일두

GitHub - ildoonet/pytorch-randaugment: Unofficial PyTorch Reimplementation of RandAugment.

 

GitHub - ildoonet/pytorch-randaugment: Unofficial PyTorch Reimplementation of RandAugment.

Unofficial PyTorch Reimplementation of RandAugment. - GitHub - ildoonet/pytorch-randaugment: Unofficial PyTorch Reimplementation of RandAugment.

github.com

RandAugment가 구현된 부분은 다음과 같다.

pytorch-randaugment/augmentations.py at master · ildoonet/pytorch-randaugment

 

GitHub - ildoonet/pytorch-randaugment: Unofficial PyTorch Reimplementation of RandAugment.

Unofficial PyTorch Reimplementation of RandAugment. - GitHub - ildoonet/pytorch-randaugment: Unofficial PyTorch Reimplementation of RandAugment.

github.com

Python Imaging Library를 이용하여 구현

pip install git+https://github.com/ildoonet/pytorch-randaugment

명령어를 입력하여 설치 가능.

from torchvision.transforms import transforms
from RandAugment import RandAugment

transform_train = transforms.Compose([
    transforms.RandomCrop(32, padding=4),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(_CIFAR_MEAN, _CIFAR_STD),
])

# Add RandAugment with N, M(hyperparameter)
transform_train.transforms.insert(0, RandAugment(N, M))

다음과 같이 transform에 N,M Hyperparameter를 조절하여 insert한다.

Google Colaboratory

 

RandAugment.ipynb

Colaboratory notebook

colab.research.google.com

 

https://inha-kim.tistory.com/47

 

[논문 리뷰] ResNet (2015) 논문리뷰 (Deep Residual Learning for Image Recognition)

https://arxiv.org/pdf/1512.03385.pdf 논문 링크 입니다. 이제 4개째 CNN논문 리뷰네요. 다음에는 좀 다른 유형의 논문을 리뷰 할 계획입니다. 감사합니다 _-_ 2015년에 압도적인 성능개선으로 ILSVRC를 우승 한

inha-kim.tistory.com

이 그림을 참고하여 구현 하였습니다.
https://github.com/weiaicunzai/pytorch-cifar100/blob/master/models/resnet.py

 

GitHub - weiaicunzai/pytorch-cifar100: Practice on cifar100(ResNet, DenseNet, VGG, GoogleNet, InceptionV3, InceptionV4, Inceptio

Practice on cifar100(ResNet, DenseNet, VGG, GoogleNet, InceptionV3, InceptionV4, Inception-ResNetv2, Xception, Resnet In Resnet, ResNext,ShuffleNet, ShuffleNetv2, MobileNet, MobileNetv2, SqueezeNet...

github.com

이 코드 구현을 참고

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import torch
import torch.nn as nn
from torchsummary import summary
 
class BasicBlock(nn.Module):
    # ResNet Basic Block으로 18, 34 layer에 들어가는 것들이다.
    # dimension 이 달라지는 경우
    dimension_expansion = 1  
    # size 축소시에 stride=2로 전달받음
    def __init__(self,in_channels,out_channels,stride=1):
        super().__init__()
        # stride = 1인 경우 size 유지, stride가 2 인 경우 size 2로 나눠짐
        self.residual_function = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=3,stride=stride,padding=1,bias=False),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels * BasicBlock.dimension_expansion, kernel_size=3,stride=1,padding=1,bias=False),
            nn.BatchNorm2d(out_channels * BasicBlock.dimension_expansion),
        )
        # Shortcut 
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels * BasicBlock.dimension_expansion:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels * BasicBlock.dimension_expansion, kernel_size = 1,stride = stride, bias=False),
                nn.BatchNorm2d(out_channels * BasicBlock.dimension_expansion),
            )
        # input, output 결합
        self.relu = nn.ReLU(inplace=True)
    
    def forward(self,x):
        out = self.residual_function(x) + self.shortcut(x)
        out = self.relu(out)
        return out
 
class BottleNeck(nn.Module):
  ㄱ # ResNet BottleNeck Block으로 50,101,152 layer에 들어가는 것들이다.
    # dimension 이 달라지는 경우가 존재, 4배로 커지는 경향이 있음
    dimension_expansion = 4
    # size 축소시에 stride=2로 전달받음
    def __init__(self,in_channels,out_channels,stride=1):
        super().__init__()
        self.residual_function = nn.Sequential(
            nn.Conv2d(in_channels,out_channels,kernel_size=1,stride=1,bias=False),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels,out_channels,kernel_size=3,stride=stride,padding=1,bias=False),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels,out_channels*BottleNeck.dimension_expansion,kernel_size=1,stride=1,bias=False),
            nn.BatchNorm2d(out_channels*BottleNeck.dimension_expansion),
        )
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels * BottleNeck.dimension_expansion:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels * BottleNeck.dimension_expansion, kernel_size = 1,stride = stride, bias=False),
                nn.BatchNorm2d(out_channels * BottleNeck.dimension_expansion),
            ) 
        self.relu = nn.ReLU(inplace=True)
    
    def forward(self,x):
        out = self.residual_function(x) + self.shortcut(x)
        out = self.relu(out)
        return out
 
class ResNet(nn.Module):
    # ResNet class
    def __init__(self,block_type,num_blocks,num_classes=10):
        super().__init__()
        self.in_channels = 64
        
        self.conv1 = nn.Sequential(
            nn.Conv2d(3,64,kernel_size = 7,stride = 2,padding = 3,bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3,stride=2,padding=1)       
        )
        # maxpool2d가 사실 conv2_x에 속해서 size를 반으로 줄임,그러므로 stride=1로 전달
        self.conv2_x = self.make_layer(block_type,64,num_blocks[0],1)
        self.conv3_x = self.make_layer(block_type,128,num_blocks[1],2)
        self.conv4_x = self.make_layer(block_type,256,num_blocks[2],2)
        self.conv5_x = self.make_layer(block_type,512,num_blocks[3],2)
        self.avg_pool = nn.AdaptiveAvgPool2d((1,1))
        self.fc = nn.Linear(512 * block_type.dimension_expansion ,num_classes)
 
    def make_layer(self,block_type,out_channels,num_block,stride):
        # stride가 2 일 경우 list 맨 앞만 2, 나머진 1
        strides = [stride] + [1* (num_block-1)
        layers = []
        for stride in strides:
            layers.append(block_type(self.in_channels,out_channels,stride))
            self.in_channels = out_channels * block_type.dimension_expansion
        return nn.Sequential(*layers)
    
    def forward(self,x):
        out = self.conv1(x)
        out = self.conv2_x(out)
        out = self.conv3_x(out)
        out = self.conv4_x(out)
        out = self.conv5_x(out)
        out = self.avg_pool(out)
        out = out.view(out.size(0),-1)
        out = self.fc(out)
        return out
 
def resnet18():
    """ return a ResNet 18 object
    """
    return ResNet(BasicBlock, [2222])
 
def resnet34():
    """ return a ResNet 34 object
    """
    return ResNet(BasicBlock, [3463])
 
def resnet50():
    """ return a ResNet 50 object
    """
    return ResNet(BottleNeck, [3463])
 
def resnet101():
    """ return a ResNet 101 object
    """
    return ResNet(BottleNeck, [34233])
 
def resnet152():
    """ return a ResNet 152 object
    """
    return ResNet(BottleNeck, [38363])
 
 
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
model = resnet50().to(device)
summary(model, (3224224), device=device.type)
cs

https://arxiv.org/pdf/1512.03385.pdf

논문 링크 입니다. 이제 4개째 CNN논문 리뷰네요.

다음에는 좀 다른 유형의 논문을 리뷰 할 계획입니다. 감사합니다 _-_

2015년에 압도적인 성능개선으로 ILSVRC를 우승 한 작품입니다.

Abstract

neural networks가 깊을 수록 train 하기에는 매우 어렵습니다.
여기서 저자들은 이전에 사용된 network보다 아주 deep한 network를 train하기 위한 기법인 residual learning  Framework를 제안합니다.

여기 learning unreferenced function대신에 저자들은 layer 의 input을 참조하여, residual functions learning 하는 것으로 layer을 재구성 합니다.
이러한 residual network는 optimize하기 더 쉽고, 늘어난 depth에 따라서 더 높은 정확도를 얻을 수 있습니다.
ImageNet dataset에서 VGG보다 약 8배 더 깊은 최대 152개의 layer로 evaluate하는데, complexity는 낮습니다.
약 3.57% error을 달성하는데, classification분야에서 1등 하였으며, 100 layer와 1000 layer에서의 CIFAR-10의 대한 분석을 제시합니다.
Depth of representation은 visual recognition tasks에서 가장 중요 합니다.
COCO object detection dataset에 대해서는 28%의 relative improvement를 얻었습니다.
residual network는 ImageNet detection, ImageNet localization, COCO detection, and COCO segmentation 에서 1등을 차지 하였습니다. 

1. Introduction

Deep convolutional neural network는 image classification에서 아주 좋은 기법입니다.
Deep network는 low/mid/high level의 feature와 classifiers in an end-to-end multilayer 방식으로 자연스러운 통합,
'level' of the feature은 stacked layer의 깊이에 의해서 풍부하게 될 수 있습니다. 
다양한 논문을 보면 network의 depth는 중요하며, ImageNet dataset에 대해서 모두 depth가 높은 것을 선택 했습니다.
다른 nontrivial visual recognition task에서도 deep model의 benefits을 받았습니다.

그림 1

근데 계속해서 연구를 하다보니 저자들은 depth에 중요성에 대해서 의문을 가지게 되었습니다.
더 좋은 network를 만드는 것이 layer를 더 쌓는 것이 중요한가?

이 질문에 대답하기 위해서는 저자들은 수렴을 방해하는 요소들인 vanishing/exploding gradient문제 였습니다.
하지만 이러한 문제들은 normalized initialization과 intermediate normalization layer로 해결 하였습니다.
이 layer들은 수십개의 layer가 있는 network가 backpropagation을 통해 SGD에 대한 수렴을 할 수 있게 합니다.
깊은 Network가 수렴을 시작 할때 성능저하 문제가 노출 되었습니다.
network의 깊이가 증가에 따라서 정확도가 빠르게 낮아지는 것을 알 수 있습니다.
그림1을 보면 알 수 있습니다. Training, Test error가 둘다 깊은 layer가 낮아서 overfitting문제가 아닌 것을 알 수 있다.

training accuracy가 낮아지는 현상은 모든 system이 optimize되는 것은 쉽지 않은 것을 알려줍니다.
더 shallower 한 architecture와 더 많은 layer를 추가하는 architecture를 고려합니다.
이렇게 deeper model에 대한 해결 솔루션은 존재 합니다. 
추가 된 것은 identity mapping이고, 다른 layer들은 학습된 shallower model에서 복사 됩니다.
이 솔루션은 깊은 모델들이 얕은 모델보다 더 높은 training error을 생성하면 안됩니다.
하지만 직접 해본 결과 해결책을 찾을 수 없었습니다. 

그림 2

이 논문에서는 deep residual learning framework를 도입하여 degradation 문제를 해결 합니다.
쌓여있는 몇개의 layer가 directly fit되기를 바라는 것을 원하기 보다는, 다음과 같이 layer가 residual mapping이 되도록
명시적으로 지정합니다.
공식적으로 보면 다음과 같습니다.
기존의 neural net의 경우 underlying mapping이 H(x)라고 한다면, 이 H(x)를 최소화 하는 것이 목표 였습니다.
이 논문에서는 F(x) := H(x) - x 가 되도록 합니다.그러면 original mapping을 F(x) + x 로 cast됩니다.
unreferenced mapping을 최적화 하는 것은 어렵고, residual mapping이 더 최적화 하기 쉽다고 가정합니다.
극단적으로 identity mapping의 optimal인 경우, nonlinear layer의 stack에 의한 identity mapping을 맞추는 것 보다는
residual은 0으로 맞추는 것이 더 쉽습니다.
F(x) + x 의 경우 shortcut connection이 있는 feedforward neural networks에 의해서 실현이 가능합니다.
shortcut connection의 경우 하나 이상의 layer를 건너 뛰게 됩니다.
이 경우 shortcut connections은 단순희 identity mapping을 수행하고, stacked layer에 output 에 추가됩니다.
identity shortcut connections은 추가 parameter나 computational complexity를 추가 하지 않습니다.
전체 network또한 backpropagation에 의해서 SGD를 통해 end-to-end train이 가능 합니다.
어떠한 개념인지 알고는 있지만 이렇게 영어로 직역할려니 힘드네요.

그냥 간단하게 설명하자면 다음과 같습니다.

1. H(x) = x 가 되도록 train합니다.

2. network의 output인 F(x)는 0이 되도록 train 합니다.
3. 그러면 H(x) = F(x) + x = x 입니다. 그러면 미분 시 F(x) + x의 경우 적어도 미분값이 1 이상입니다.
4. 이렇게 해서 모든 계층에서 gradient vanishing 현상을 해결 하였습니다.


논문의 저자들은 degradation problem을 보여주고, 방법을 평가 하기 위해서 ImageNet에서 test를 하였습니다.
1. 저자들의 extremely deep residual nets은 최적화 하기는 쉽다, 하지만 다른 일반적인 network들은 depth가
증가하면 높은 training error가 나오게 됩니다.

2. residual network는 쉽게 정확도가 향상되며 다른 network보다 좋은 결과를 얻을 수 있습니다.

CIFAR 10 Set에서도 유사한 현상이 있었으며, 이는 optimization의 어려움과 이 방법의 효과가 특정 데이터셋에
만 적용되는 것이 아닌 것을 알려줍니다.
저자들은 100개 이상의 layer를 가진 dataset에 대해 성공적으로 훈련된 model을 제시하고, 1000개 이상의 layer를 
가지 model들을 탐색 합니다.
ImageNet에서 우수한 결과, VGG NET보다 복잡성이 낮고, 앙상블을 통해서 3.57% 의 Error, coco 에서도 다양한 부분
에서도 우승 하였습니다.

여기는 직역하기에는 뭔가 너무 어렵네요. 아래에서 추가적으로 설명 하겠습니다.

2. Related Work

여기는 다른 관련된 연구에 대해서 설명하는데, 다른 논문을 참고하면서 해야 이해할거 같아서 SKIP하겠습니다.

3. Deep Residual Learning

3.1. Residual Learning

H(x)를 몇개의 stack layer에 의해 underlying mapping으로 간주하고, x를 이러한 layer에서 첫번째 layer에 대한 입력이라고 가정합니다.
만약 multiple nonlinear layers들이 asymptotically 하게 복잡한 함수에 근사가 가능하다면 , H(x) - x 같은 residual function 또한 asymptotically 하게 근사 가능 하다는 가설과 같습니다. 
(이때 input, output dimensions는 같아야 한다.)
그래서 저자들은 stacked layer들이 H(x) 근접하기를 기대하기 보다는, 명시적으로 residual function F(x) := H(x) - x에 
근접하도록 합니다. 
따라서 original function은 F(x) + x 입니다.
비록 두 형태 모두 원하는 functions에 따라서 점근적으로 근사 할 수 있어야 하지만, learning의 용이성을 다를 수 있습니다.

이러한 reformulation은 degradation problem에 대한 counterinituitive phenomena에 대해 동기부여가 됩니다.
introduction에서 말 했던것 처럼, 추가된 layer이 identity mapping으로 구성 될 경우에 더 깊은 모델이 얕은 model보다
크지 않은 training error를 가져야 합니다.
이러한 degradation problem의 해결하기 위해서 여러 solver들은 여러 nonlinear layer에 의한 identity mapping을 근사
하는게 어려움이 있을 수 있습니다. 
residual learning reformulation을 통해 , identity mapping이 optimal인 경우, solver들은 단순하게 identity mapping에 
접근 하기 위해서 multiple nonlinear layers의 weight를 0으로 유도 할 수도 있습니다.

real cases의 경우 identity mapping이 optimal일 확률을 낮습니다.
하지만 저자들의 reformulation은 문제를 precondition 화 하는데 도움이 될 수 있씁니다.
만약 optimal function이 zero mapping보다 identity mapping에 가까울 경우에, solver는 새로운 function으로 학습하는 것 보다, identity mapping을 reference 하여 perturbations을 찾는 것이 더 쉬워야 합니다.


여기서 실험을 통해서 학습된 residual functions은 일반적으로 small response를 가지고 있다는 것을 보여주며 이는 
identity mapping이 합리적인 prevcondition을 제공합니다.

3.2. Identity Mapping by Shortcuts

저자들은 모든 stacked layer에 residual learning을 적용 합니다.
building block은 그림2와 같으며, 본 논문에서 저자들은 (1)와 같이 정의된 building block을 고려 합니다.
여기서 x,y,는 layer의 input과 output 입니다.
F(x, {Wi})는 학습해야 할 residual mapping을 나타 냅니다.
그림 2의 예를 보면, 두개의 layer를 가지고 있으며, F = W2 σ(W1x) , 여기서 σ는 ReLU 입니다.
F + x operation은 shortcut- connection 및 element-wise addition에 의해 수행 됩니다.
추가 후 두번째 nonlinearity 을 채택합니다. (다시 relu)
shortcut connection은 extra parameter나 추가적인 compuation complextiy는 없습니다.(element wise는 너무 적음)
이러한 것은 매력적이고, 일반 network와 residual network를 비교하는데에도 중요합니다.
parameter의 수, depth, width, computational cost 등이 동일한 plain,residual network를 적절하게 비교가 가능합니다.
(element-wise는 연산량이 적어서 무시 가능할 수준)
x, F는 dimension이 같아야 합니다. 
그렇지 않을 경우에는 linear projection Ws를 이용하여 shortcut connection에서 dimension 맞출 수 있습니다.

저자들은 square matrix Ws를 사용 할 수도 있습니다.
그러나 여러 실험을 통해서 저자들은 identity mapping이 degradation 문제를 해결 기에 충분하고, 경제적이므로
Ws는 그저 dimension을 일치 시킬때만 사용 하기로 하였습니다.


residual function F는 flexible합니다
이 논문에서는 F는 2개 또는 3개의 layer를 가지게 됩니다. 더 많은 layer도 가능 합니다. (그림 5 참고)
그러나 만약 F가 오직 한개의 layer만 가지게 된다면,  Eqn(1)은 linear layer에 비슷하게 될것입니다.
다음과 같은 형태를 가지는데 y = W1x + x, 이러면 저자들은 advantages를 얻지 못한다고 합니다.|
우리는 또한 위의 notations이 단순성을 위해 fully connected layer를 대한 것 이지만, convolution layer에도 적용 할 수 있다는 것에 주목 해야 합니다.
F(x, {Wi}) 는 multiple convolution layer로도 표현 될 수 있습니다.

elements wise additions은 두개의 feature map에 적용 되는데, channel by channel로 됩니다.

3.3. Network Architectures

우리는 다양한 Plain/Residual nets을 test하였습니다. 여기서 consistent phenomena를 관찰 할 수 있었습니다.
여기서 저자들은 두개의 모델에 대해서 설명 합니다.

Plain Network.

저자들의 Plain baseline은 Fig3의 가운데 인데, VGGnet에서 영감을 받은 것 입니다.
convolution layer은 대부분 3x3 filter 그리고 두가지의 simple design rule를 따르게 됩니다.
(i) same output feature map size, the layers have the same number of filter
(ii) feature map의 크기가 반으로 줄면 filter의 수가 두배로 증가하여 complexity per layer를 보존합니다.
그리고 저자들은 stride가 2인 convolution layer에 의해 직접 downsampling을 수행 합니다.
network는 global average pooling layer와 1000-way fully-connected with softmax로 끝나게 됩니다.
fig 3의 가운데는 weighted layer의 수는 34입니다.
저자들이 모델은 VGG net보다 fewer filters and low complexity입니다.
34-layer baseline은 3.6 billion Flops이고, VGG의 18%에 해당합니다.(19.6 billion Flops)

Residual Network.

plain network를 base로 하며, 여기다가 shortcut connection을 넣었습니다.
residual version (오른쪽)
identity shortcuts(Eqn (1))의 input, output의 dimension이 같으면 직접 사용이 가능합니다.(Solid line)
dimension이 증가하면(dotted line shortcuts) 여기서는 두가지 옵션을 선택합니다.
(A)는 Shortcut 여전히 identity mapping으로 작동합니다. 나머지 증가된 dimension은 zero로 padding합니다.
(B)는 Projection shortcut을 이용합니다.(Eqn (2)) 이것은 dimension을 맞추기 위한 것으로 1x1 convolution을 이용 
합니다. 두가지 option은 모두 shortcut이 두개의 크기의 feature map을 통과할때 stride가 2로 작동 합니다.

3.4. Implementation

저자들의 구현은 기존에 ImageNet에서 사용하던 것을 이용 하였습니다.
image resize shorter side randomly sampled in [256,480] for scale augmentation.
224x224 crop is randomly sampled from an image, horiziontal flip, per-pixel mean substracted, 
standard color augmentation, 그리고 batch normalization을 after each convolution and before activation.
그리고 weight의 initialize는 기존에 있던 논문과 같은 방식으로 하고, plain, residual net을 모두 train합니다.
SGD를 이용하였으며 mini-batch size는 256, lr 은 0.1로 시작하여 error plateaus 마다 10씩 나누었습니다.
그리고 weight decay는 0.0001, momentum은 0.9를 이용 하였습니다.
그리고 dropout은 사용 안했고, test에서 비교 연구를 위해서 standard 10-crop test를 이용 하였습니다.

그리고 좋은 결과를 위해서 fullcyconvolutional form 형태를 채택하고, multiple scale에서 점수를 평균 합니다.
짧은쪽이 224,256,384,480,640이 되도록 합니다

 

4. Experiments

4.1. ImageNet Classification

논문의 저자들은 1000개의 class를 가지는 ImageNet 2012 Classification dataset을 이용하여 평가 하였습니다.
model은 1.28 million 개의 training image, evaluate는 50k의 validation image입니다.
그리고 저자들은 100k의 test image로 final result 를 얻었습니다.
TOP-1, TOP-5 의 error rate를 evaluate 하였습니다.

Plain Networks

우선 처음으로 18, 34 layer의 plain net을 evaluate 하였습니다.
Table 1을 보면 상세한 network architectures를 알 수 있습니다.

그리고 결과는 Table 2에 볼 수 있습니다. 
여기서 알 수 있는 것은 깊은 34-layer가 18-layer보다 error rate가 높은 것을 알 수 있습니다.
그리고 Fig4를 봐도 training, validation모두 34-layer가 높다는 것을 알 수 있습니다.
여기서 저자들은 degradation problem을 알 수 있었습니다.
34 layer가 모든 training구간에서 error가 더 높습니다.
저자들은 이렇게 optimization이 어려운 이유가 vanishing gradient때문이라고 설명합니다.

Plain network에서 BN을 이용하여 Train하여 forward propagated signal이 0이 아닌 분산을 가지도록 한다.
그리고 backward propagate에서도 gradient가 BN으로 인해 healthy norms이 보이도록 하였습니다.
그러므로 forward nor backward signal은 사라지지 않습니다.

실제로 34 plain network도 꽤나 경쟁력 있는 정확도를 달성 합니다.
Table3을 보면 어느정도 작동함을 시사합니다.
여기서 저자들은  deep plain network의 경우 기하급수적으로 낮은 수렴확률을 가진다고 합니다.
이는 training error의 감소에 영향을 미칩니다.
이러한 optimization의 어려움을 나중에 연구 될 것이라고 합니다.

 

Residual Networks

다음으로는 저자들의 18-layer and 34-layer를 가지는 residual net을 평가 합니다.(Resnet)
baseline architecture은 plain net과 같습니다.
shortcut connection을 3x3 filter pair에 추가 합니다.
첫 비교는 Table2, Fig 4의 오른쪽을 보면 됩니다.
identity mapping for all shortcut, 그리고 dimension을 맞추기 위한 것은 zero padding으로 하였습니다.
그러므로 no extra parameter가 없습니다.
저자들은 Table2, Fig4 에서 3개의 관찰결과를 얻을 수 있었습니다.


첫째, residual learning 으로 Plain network에서 생긴 상황이 반전 되었습니다.
34 Layer를 가지는 Resnet은 18 layer를 가지는 것 보다 성능이 더 좋습니다.
중요한 것은 34 layer가 더 낮은 training error를 가지며, validation data에 더 generalizable하다는 것 입니다.
degrading problem을 잘 다뤄서 depth를 증가 시키고, 더 좋은 정확도를 얻을 수 있었습니다.

둘째, plain 과 비교하면 34 layer Resnet은 top-1 error가 3.5이고, 성공적으로 training error도 내렸습니다.
이것으로 extremely deep systems에는 residual learning이 좋다는 것을 알 수 있습니다.

 

마지막으로 18-layer plain/residual net의 정확도는 Table2, 그리고 18 Resnet이 더 빨리 수렴합니다.
net가 지나치게 깊지 않은 18 layer일때 , 현재의 SGD solver는 Plain net에는 좋은 해결책 일 수도 있습니다.
이경우 Resnet은 더 빠른 수렴을 제공하여 최적화를 쉽게 합니다.

 

Identity vs. Projection Shortcuts

저자들은 parameter free, identity shortcut이 training에 도움이 된다는 것을 알 수 있었다고 하였습니다.
그리고 projection shortcut (Eqn (2))에 대해서 조사 하였습니다.
Table 3의 세가지 option을 주었습니다.
(A) zero padding shortcut, increasing dimension, all shortcut parameter free
(B) projection shortcut, increasing dimension, other shortcut identity
(C) all shortcut projection shortcut
Table 3의 결과를 보면 B가 A보다 약간 좋습니다.
이유로는 A는 zero-padded dimensions에 residual learning이 없기 때문이라고 생각한다고 합니다.
C는 또 B보다 약간 좋네요.
Extra parameter들이 증가 하면서 그렇게 된 것 같습니다.
3개의 차이가 너무 미미해서 안하는게 좋다고 합니다.
그러므로 C를 사용 안합니다. 모델이 너무 커서 Memory와 complexity가 너무 많이 사용 됩니다.
identity shortcut은 부분적으로 complexitiy를 증가 시키지 않는 것을 좋습니다. 
아래쪽의 Deeper Bottleneck architecture를 확인하세요.

 

Deeper Bottleneck Architectures

저자들은 ImageNet을 위한 deeper net을 소개 합니다.
training time에 대한 우려로 인해서 building block을 bottleneck design으로 수정합니다.
각 residual function F에 대해 2개가 아닌 3개의 Layer stack을 사용합니다.(Fig 5)
1x1, 3x3, 1x1 convolution이며, 1x1은 크기를 줄이고, 증가시켜 input output dimension을 유지 합니다.
fig 5가 두가지 설계가 유사한 시간 복잡성을 가진 다는 것을 알 수 있다.
parameter free identity shortcut은 bottlenect architecture가 중요 합니다.
만약 fig 5의 오른쪽이 projection을 대신하면 , 그 shortcut이 두개의 high-dimensonal 의 끝에 연결돼
시간 복잡도, 모델의 크기가 두배가 커지게 됩니다.
그래서 identity shortcut은 bottleneck designs보다 효율적이 모델로 이어지게 됩니다.

 

50-layer ResNet

저자들은 2-layer block이 3-layer bottleneck block으로 교체하여서 50layer의 Resnet 1을 생성 합니다.(Table1)
그리고 dimension 을 늘리기 위해서 option B를 이용하였고, 3.8 billion Flops입니다.

 

101-layer and 152-layer ResNets

저자들은 101,152 layer Resnet을 구축 하였습니다. 3-layer block을 더 사용 합니다.
depth를 늘려도 152-layer ResNet은 11.3 billion FLOPs, VGG-16/19 net은 15.3/19.6 billion FLOPs 계산량이 적습니다.
50/101/152 layer ResNet은 34 layer보다 훨씬 정확 합니다.
degradation proble은 관찰 할 수 없었고, 깊이를 늘릴 수록 좋은 정확도가 나왔씁니다.

 

Comparisons with State-of-the-art Methods

Table 4에서는 비교 하는데, 이전의 single-model result와 비교해서 매우 좋습니다.
single model의 경우 top-5 에서 4.49, 앙상블 result인 table5에서도 1등, 그러므로 ILSVRC 2015에서 우승 하였습니다.

4.2. CIFAR-10 and Analysis

저자들은 CIFAR10 dataset에서도 연구를 진행 하였습니다.
50k의 train image,10k 의 test image, 10개의 class를 가집니다.
의도적으로 간단한 아키텍처로 실험을 하였습니다. plain/residual architecture은 Fig 3의 form을 따르게 됩니다.
network input은 32x32 image입니다. pixel에서 mean을 뻇습니다.
first layer에서는 3x3 convolution, 6n layer stack을 사용 하고, feature map size는 {32,16,8} 입니다.
각 feature map size에 대해 2n layer를 이용 합니다. subsampling의 stride는 2로 convolution 를 수행 합니다.
network의 end은 global average pooling, a 10-way fully-connected layer, and softmax를 합니다.
그러면 총 6n+2 stacked weighted  layer가 됩니다.
요약하면 다음과 같습니다.

shortcut connection은 pairs of 3x3 layers에 이용 됩니다. (총 3n shortcut)
이 dataset에는 모두 option A를 이용 하였습니다.

그리고 저자들의 residual model을 plain model과 완벽히 같은 depth,width,parameter를 가집니다.
weight decay 0.0001, momentum 0.9, weight initialization은 Reference 논문 13과 같은 방식, BN, no dropout
두개의 GPU로 Batch size가 128 train 하였습니다.
learning rate는 0.1로 시작하여 32k, 48k iteration일때 10으로 나누어 주었습니다.
그리고 64k iteration 일때 종료 하였습니다 . 45k/5k train/val split.
simple data augmentation in for training: 4 pixels are padded on each side,
32x32 crop randomly sample from the padded image or horizontal flip
test에서는 32x32 single image를 이용 하였습니다.


n이 3,5,7,9 일때 즉 20,32,44,56 layer에 대해서 비교 하였습니다.
Fig 6의 왼쪽 에서는 plain net, deep plain net에서는 깊어질수록 error가 높아지는 것을 알 수 있습니다.
MNIST나 ImageNet에서 동일한 결과가 나왔습니다.
Fig 6의 가운데는 ResNet입니다. ImageNet case와 비슷 합니다.  
Resnet이 좋게 나오고 110일때는 조금 다르게 training 했다고 합니다. 주저리 주저리 말이 많네요.

Analysis of Layer Responses.

Fig 7은 layer response의 std를 보여줍니다.
response output of 3x3 layer after BN 를 그래프로 보여줍니다.
ResNet은 분석을 통해서 residual function을 확일 할 수 있습니다.
Fig 7은 generally smaller response를 가지고 있습니다. (plain과 비교하면)
이 결과는 residual function은 일반적으로 non residual function보다 0에 가까울 수 있다는 저자들의 말을 뒷받침한다.
깊은 Resnet은 깊을수록 작은 response 를 가지는 것을 알 수 있습니다.

 

Exploring Over 1000 layers

여기서 저자들은 1000 layer를 넘게 가지고 이쓴 model도 확인 하였습니다.

n = 200, 1202 layer를 가지게 됩니다. 
저자들의 방법은 no optimization difficulty 이므로 아주 낮은 training error를 가지는 것을 알 수 있습니다.
test error도 나쁘지는 않습니다.
그러나 deep model에는 문제가 있습니다. 1202 layer의 test error가 110 layer보다 안좋은 것 입니다.
overfitting 문제입니다. 너무 커서 19.4M이니 dataset이 적은 것이 문제 입니다.
strong regularzation maxout, dropout 적용하면 이 데이터셋에 더 좋은결과가 나옵니다.

4.3. Object Detection on PASCAL and MS COCO

마지막으로 object detection에도 아주좋은 결과나 나왔다는 것을 알 수 있습니다.

https://inha-kim.tistory.com/45

 

[논문 리뷰] inception v1, GoogLeNet(2014) 논문리뷰 (Going Deeper with Convolutions)

저는 cs231n을 base로 들어서 자세한 내용까지 설명하지 않았습니다. https://arxiv.org/abs/1409.4842 Going Deeper with Convolutions We propose a deep convolutional neural network architecture codenamed..

inha-kim.tistory.com

pytorch 구현 생각보다 복잡하네요..

https://www.youtube.com/watch?v=uQc4Fs7yx5I&t=39s&ab_channel=AladdinPersson

유튜브의 도움을 받았습니다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# import package
import torch
import torch.nn as nn
from torchsummary import summary
# https://www.youtube.com/watch?v=uQc4Fs7yx5I&t=39s&ab_channel=AladdinPersson
class Conv_block(nn.Module):
    def __init__(self,in_channels, out_channels,**kwargs):
        super(Conv_block,self).__init__()
        self.conv_layer = nn.Sequential(
            nn.Conv2d(in_channels, out_channels,**kwargs),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(),
        )
    def forward(self,x):
        return self.conv_layer(x)
 
class Inception_block(nn.Module):
    def __init__(self,in_channels,out_1x1,red_3x3,out_3x3,red_5x5,out_5x5,out_1x1pool):
        super(Inception_block,self).__init__()
        self.branch_1 = Conv_block(in_channels,out_1x1,kernel_size=1)
        self.branch_2 = nn.Sequential(
            Conv_block(in_channels,red_3x3,kernel_size=1),
            Conv_block(red_3x3,out_3x3,kernel_size=3,padding=1),
        )
        self.branch_3 = nn.Sequential(
            Conv_block(in_channels,red_5x5,kernel_size = 1),
            Conv_block(red_5x5,out_5x5,kernel_size=5,padding = 2),
        )
        self.branch_4 = nn.Sequential(
            nn.MaxPool2d(kernel_size=3,stride=1,padding =1),
            Conv_block(in_channels,out_1x1pool,kernel_size=1),
        )
    def forward(self,x):
        out = torch.cat([self.branch_1(x),self.branch_2(x),self.branch_3(x),self.branch_4(x)],dim=1)
        return out
 
# loss에 0.3곱해짐
class inception_Auxiliary_classifier(nn.Module):
    def __init__(self,in_channels,num_classes):
        super(inception_Auxiliary_classifier,self).__init__()
 
        self.conv = nn.Sequential(
            nn.AvgPool2d(kernel_size=5,stride=3),
            Conv_block(in_channels,128,kernel_size=1),
        )
        self.fc = nn.Sequential(
            nn.Linear(20481024),
            nn.ReLU(),
            nn.Dropout(),
            nn.Linear(1024, num_classes),
        )
    def forward(self,x):
        out = self.conv(x)
        out = out.view(out.shape[0],-1)
        out = self.fc(out)
        return out
 
class GoogLeNet(nn.Module):
    def __init__(self, auxiliary_classifier = True, num_classes = 10):
        super(GoogLeNet,self).__init__()
        # True or False 가 아니면 assert error 발생
        assert auxiliary_classifier == True or auxiliary_classifier == False
        self.auxiliary_classifier = auxiliary_classifier
        self.conv1 = Conv_block(in_channels=3,out_channels=64, kernel_size=7,stride=2,padding=3)
        self.maxpool1 = nn.MaxPool2d(kernel_size=3,stride=2,padding=1)
        self.conv2 = Conv_block(in_channels=64,out_channels=192,kernel_size=3,stride=1,padding=1)
        self.maxpool2 = nn.MaxPool2d(kernel_size=3,stride=2,padding=1)
        self.inception3a = Inception_block(192,64,96,128,16,32,32)
        self.inception3b = Inception_block(256,128,128,192,32,96,64)
        self.maxpool3 = nn.MaxPool2d(kernel_size=3,stride=2,padding=1)
        self.inception4a = Inception_block(48019296208164864)
        # auxiliary classifier
        self.inception4b = Inception_block(512160112224246464)
        self.inception4c = Inception_block(512128128256246464)
        self.inception4d = Inception_block(512112144288326464)
        # auxiliary classifier
        self.inception4e = Inception_block(528,256,160,320,32,128,128)
        self.maxpool4 = nn.MaxPool2d(kernel_size=3,stride=2,padding=1)
        self.inception5a = Inception_block(832,256,160,320,32,128,128)
        self.inception5b = Inception_block(832,384,192,384,48,128,128)
        self.avgpool = nn.AvgPool2d(kernel_size=7,stride=1)
        self.dropout = nn.Dropout(p=0.4)
        self.fc1 = nn.Linear(1024,num_classes)
        if self.auxiliary_classifier:
            self.aux1 = inception_Auxiliary_classifier(512,num_classes)
            self.aux2 = inception_Auxiliary_classifier(528,num_classes)
        else:
            self.aux1 = self.aux2 = None
 
    def forward(self,x):
        out = self.conv1(x)
        out = self.maxpool2(out)
        out = self.conv2(out)
        out = self.maxpool2(out)
        out = self.inception3a(out)
        out = self.inception3b(out)
        out = self.maxpool3(out)
        out = self.inception4a(out)
        if self.auxiliary_classifier and self.training:
            aux1 = self.aux1(out)
        out = self.inception4b(out)
        out = self.inception4c(out)
        out = self.inception4d(out)
        if self.auxiliary_classifier and self.training:
            aux2 = self.aux2(out)
        out = self.inception4e(out)
        out = self.maxpool4(out)
        out = self.inception5a(out)
        out = self.inception5b(out)
        out = self.avgpool(out)
 
        out = out.view(out.shape[0],-1)
        out = self.dropout(out)
        out = self.fc1(out)
 
        if self.auxiliary_classifier and self.training:
            return out,aux1,aux2
        else:
            return out
 
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = GoogLeNet(auxiliary_classifier=True, num_classes=10).to(device)
 
summary(model, input_size=(3,224,224), device=device.type)
cs

저는 cs231n을 base로 들어서 자세한 내용까지 설명하지 않았습니다.

https://arxiv.org/abs/1409.4842

 

Going Deeper with Convolutions

We propose a deep convolutional neural network architecture codenamed "Inception", which was responsible for setting the new state of the art for classification and detection in the ImageNet Large-Scale Visual Recognition Challenge 2014 (ILSVRC 2014). The

arxiv.org

역대 우승자

2014년에 GoogleNet은 ILSVRC 에서 우승 하였습니다.

Abstract

우리는 ImageNet Large-Scale Visual Recognition Challenge 2014 (ILSVRC14) 에서 detection 과 classification 분야에서 새로운 deep convolutional neural network architecture를 제안 하는데 이름은 Incep-tion 입니다.

이 Architecture는network 내부의 Computing resources를 개선 합니다.
이는 네트워크의 depth와 width를 계산량을 유지하면서 늘리는 것이 목표 이며, 구조는 multi-scale processing과 
Hebbian principle에 기초로 하였습니다.
GoogLeNet은 22개의 layer이다.

1 Introduction

지난 3년간 딥러닝보다는 Convolution network의 발전으로 인해서 image recognition과 object detection은 극적인 
속도로 발전 하였습니다. 한가지 고무적인 것은 이러한 발전이 강력한 하드웨어와 큰 데이터셋, 그리고 큰 model 덕분이
아니라 새로운 아이디어, 그리고 개선된 알고리즘과 network architecture의 결과라는 것 입니다.
ILSVRC 2014에 제출한 GoogleNet은 2년전의 AlexNet보다 12배 적은 parameter를 사용하여 훨씬 정확한 결과를 얻을 수 있었습니다.
그리고 object detection의 큰 이점은 deep network와 아주 큰 model에서 오는 것이 아니라 R-CNN 같이
deep architecture와 고전적인 컴퓨터 비전의 시너지에서 오게 됩니다.
그리고 mobile및 embedded 컴퓨팅이 지속적으로 발전하여 알고리즘의 효율성, 그리고 메모리 사용의 중요성이 커지고
있으며, 주목할만한 것은 이 논문에서는 deep architecture의 설계에서 고려된 사항이 정확도 숫자에 집착 보다는 효율적인 계산, 메모리 사용량에 대한 것이 포함됩니다.

실제로 이거는 추론시간에 1.5billion 이하의 연산만을 수행하도록 설계 되었다고 합니다.
이 모델이 순수한 학문적 호기심이 아니라 대규모 데이터셋에서도 잘 사용되었으면 한다고 합니다.
이 논문에서는 컴퓨터 비전 분야에서 효율적인 deep CNN architecture인 inception에 focus를 맞춥니다.
이 아키텍처는 유명한 “we need to go deeper” 라는 인터넷 밈과 관련하여서 연구진이 네트워크 이름을 정했습니다.

2 Related Work

LeNet-5 를 시작으로 CNN은 일반적으로 하나이상의 Fully-connected layer이 뒤에 오는 Stacked convolutional layer를 가지게 됩니다.
이 기본적인 설계의 변형은 image-classification 분야에 넓게 퍼짐, MNIST에서 최고의 결과가 나왔습니다. 

CIFAR, 특히 ImageNet classification같은 것은 대규모 데이터셋이므로 최근 추세는 layer 수와 layer의 size를 늘리고 
있으며, overfitting 문제를 해결하기 위해서 dropout을 사용 하였습니다.

그리고 maxpooling layer가 spatial information의 손상을 초래 한다는 우려에도 불구하고, 동일한 CNN 이 localization,
object detection, human pose estimation 분야에서 성공적으로 채택 되었습니다.
Inception model이 여러번 반복되는 GoogLeNet model의 경우 22-layer의 deep model입니다.

object detecion은 이 당시에 가장 좋은 접근 방식은 R-CNN으로 R-CNN의 경우 Detecion을 위해서 두가지 하위 문제로 
분해하는데, 먼저 color와 subpixel의 일관성과 같은 low-level의 단서를 이용하여 object proposal를 하고, CNN을 이용
하여서 해당 위치의 object의 category를 정하게 됩니다. 이러한 접근 방식은 low-level의 단서로 bbox를 분할의 정확성,
그리고 CNN의 매우 강력한 object classification 성능을 결합하는 것 입니다. 

3 Motivation and High Level Considerations

deep neural networks는 성능을 향상시키는 것은  크기를 늘리는 것이라고 합니다.
여기서 network의 depth와 width의 증가도 포함됩니다.
특히 아주 많은 양의 lable된 train data를 사용 할 수 있다는 점 덕분에 higher quality model를 쉽고, 안전하게 훈련 
가능 합니다. 하지만 여기서는 두개의 단점이 존재합니다.

그림 1

크기가 클수록 일반적으로 parameter의 수가 많아서 특히 train set의 labeled된 예제 수가 제한 된 경우에는 network가
overfitting되기 쉽습니다.
그리고 high-quality의 training set을 만드는것 상당히 까다롭고, 비쌉니다.
그리고 ImageNet과 같이 세분화된 영역에서는 이러한 것이 문제가 될 수 있습니다.

그리고 크기가 uniformly 하게 증가된 network는 computational resource가 엄청나게 증가합니다.
예를들면 deep vision network에서 만약 두개의 convolutional layer가 결합하면 filter 수가 균일하게 증가하여 계산량이 2배가 증가 합니다.
만약 추가된 capacity가 ( 가중치가 0에 가까운 경우) 많은 계산량이 낭비 됩니다.
실제로 할 수 있는 계산량을 유한하여, 주요 목적이 결과의 quality를 좋게 하기 위해선 크기보다는 계산 resources를 
효율적으로 분배하는 것이 좋습니다.

Spare, Dense차이


이러한 문제를 해결하는 방법은 fully connected된 것에서 sparsely connected architecutre로 바꾸는 것 입니다.
심지어 convolution 내부에서도 이렇게 바꿉니다.
생물학적 시스템을 보고 따라한것 이외에도, 획기적인 연구로 인해서 단단한 이론적 토대가 될 수 있습니다.
어떤 연구에서는 주요 dataset의  probability distribution이 크고 spared deep neural network에 표현 될 수 있는 경우,

last later의 activation correlation statics를 분석하고, 상관관계가 높은 출력을 가진 neuron을 clustering 하여 최적의
network toplogy를 얻을 수 있다고 합니다. 수학적 증명이 필요합니다.
이 아이디어는 less strict한 조건에서도 적용이 가능합니다.

단점으로는, 오늘날의 Computing infrastructure는 non-uniform sparse data structure의 numerical calculation에 매우 비효율적 입니다.
arithmetic operations 100배 감소 하더라도, lookup와  cache miss는 매우 우세하여, sparse matrics로 전환하면 좋은 
성과를 얻기는 힘들어집니다.
기본적인 CPU또는 GPU Hardware 의 아주 작은 detatil을 활용하여서 매우 빠른 dense matrix multiplication을 허용하고
개선된 라이브러를 활용함으로써 계속에서 격차가 벌어지게 됩니다.
또한 non-uniform sparse model은 정교한 engineering괴 computing infrastrucutre가 필요합니다.
대부분의 vision oriented machine learning systems은 단지 convolution layer를 이용하는 것 만으로 spatial space을 
활용합니다.
Convolution은 이전 layer의 patches의 dense connection으로 구성 됩니다.
ConvNet은 보통 대칭성를 깨고, train을 개선하기 위해서 기능 차원에서 무작위 및 spare 연결 table을 이용 하였지만,
optimize parallel computing를 개선하기 위해서 fully connected로 변경 되었습니다.
structure의 uniformity와 많은 수의 filter, 더 큰 batch크기를 이용하여서 효율적으로 dense computation을 이용 할 수 있습니다.

 

Spares matrix 연산을 다루는 문제는 Sparse matrix를 클러스터링 하여 Dense한 Submatrix를 만드는 것을 제한 했고 
괜찮다고 하였습니다.
GoogleNet의 저자들은 Inception 구조는 Sparse구조를 test하기 위해 시작했는데, hyperparameter를 조정하고 한 결과
꽤 좋은 성과가 나왔습니다.

4 Architectural Details

 

inception module

Inception architecture의 주요 idea는 convolution vision network의 optimal local sparse structure를 찾는 쉽게 구할 수 
있는 dense가 높은 components로 근사하고 커버가 가능한 방법을 찾는것을 base로 합니다.
translation invariance를 가정 한 뒤에 network의 convolution building block을 구축 하다는 것을 의미합니다.
여기서 필요 한 것은 optimal local construction을 찾아서 spatially으로 반복 하는 것 입니다.
Arora는 마지막 계층에서 correlation 를 분석하여 correlation 가 높은 단위 group으로 cluster를해야 하는 layer-by-layer 를 제안 합니다. .. 주저리 주저리 말이 많은데 별로 안 중요한거 같네요.

이러한 inception module은 서로 stacked되는데, output의 correlation staristics는 달라질 수 밖에 없습니다.
즉 이러한 higher abstraction의 features이 higher layer의 captured됨에 따라서 spatial concentration이 감소 할 것으로
예상이 되어 3x3 및 5x5 convolution의 비율이 높아져야 합니다.

이러한 형태의 module은 큰 문제가 있는데, filter수가 많은 convolution layer 위에서 5x5 convolution layer을 사용하면
엄청나게 계산량이 많아 집니다. 이 문제는 pooling unit이 mix에 추가 되면 더욱더 심해집니다.
output fliter의 수는 previous stage의  filter수와 같습니다.
pooling layer의 output과 convolution layer의 output이 병합하면 stage 간 output의 수가 매우 증가합니다.
이러한 구조는 계산량이 폭발하게 됩니다.

이는 두번째 아이디어로 이어집니다.
즉 계산 요구사항이 지나치게 증가 하는 것을 막기 위해서 dimension reductions and projection을 적용합니다.
이는 embeddings의 성공에 기반하며, 저차원 embedding에도 상대적으로 큰 image patch에 대한 많은 정보가 포함
가능합니다. 그러나 embedding은 information 밀도가 높고 압축된 것은 모델링하기 어렵습니다.
그러므로 1x1 convolution은 계산량이 많은 3x3 , 5x5 convolution 을 계산하기 위해서 사용합니다.
이는 reductions효과 뿐만 아니라 Rectified linear activation의 사용을 포함하므로 dual-purpose입니다.
최종 결과는 b입니다.

일반적으로 inception network는 위와 같은 module들이 stack이 된 형태이며, grid resolution을 줄이기 위해서 stride가
2인 max pooling layer가 가끔 존재합니다.
train 중에 메모리 효율성으로 인해, 낮은 layer들은 기존의 convolution 벙식을 유지, 높은 layer들은 inception moduel을 사용 하였습니다.
이 디자인은 실질적으로 유용한 측명이 있는데 다양한 시각정보를 다양한 규모로 처리 한 뒤에 통합하여야 한다는 직관
과 일치합니다.
이 디자인은 계산량이 상당히 조절되어 어려움 없이 width와 depth 를 늘릴 수 있습니다.
inception을 활용하는 다른 방안은 안좋지만 계산적으로 더 저렴한 것을 만드는 것 입니다.

5 GoogLeNet

이 사람들은 ILSVRC14 대회에서 GoogLeNet이라는 팀 이름을 선택, 이것은 LeNet5 네트워크를 개척한 LeKun에게 경의
를 표하는 것 이라고 하네요. 앙상블 하여서 제출 하였습니다.
inception modules 내부를 포함한 모든 Convolution layer은 ReLU를 사용합니다.
Network의 receptive field는 224x224로 RGB channel의 평균으로 subtraction합니다.
3x3 reduce와 5x5 reduce는 3x3 및 5x5 convolution 이전에 사용 된 reduction layer의 filter 수를 나타냅니다.
maxpooling 후 projection layer에서 1x1 filter 수를 볼 수 있습니다.
layer를 변경된 rectified linear activation도 사용 합니다.

network는 계산의 효율성, 그리고 실용성을 염두하고 설계 하였으며, 메모리 공간의 적은 계산 자원을 이용하여 
inference가 되도록 하였습니다.
parameter거 있는 layer만 셀 경우 depth는 22, pooling까지 세면 27개 입니다.
network에 사용되는 전체 layer는 100개 입니다.

network가 depth가 깊어지면 gradient를 효과적으로 모든 layer에 전파 할 수 있는 능력이 중요합니다.
이것은 중간 layer에 보조 분류기를 추가 하여, 하위 단계에서 gradient signal를 증가시키며, 추가적인 regularzation을
증가 시킵니다. 
inference시간에는 보조 network 없어집니다.

보조 분류기는 다음과 같습니다.
5x5 filter 크기에 stride 3인 average pooling layer로 , 출력은 4x4x512 입니다. (4a)의 경우, (4d)의 경우 4x4x528입니다.
dimension reduction 및 ReLU를 위한 128 개의 1x1 convolution filter
1024개의 unit과 ReLU 로 연결된 FC layer.
dropout layer, 70%
classifier은 softmas 입니다.(1000개의 class inference시간에는 사라짐)

Conclusions

Inception 구조는 Spares structure을 Dense Structure로 근사 성능을 개선.

기존에 cs231n으로 이미 본 model이였는데, 대충 몇개 이해안되는 부분이 있었지만 , 1x1 conv, 보조 분류기를
이용하여 계산량을 낮추고, graident 가 사라지는 현상을 방지하여 deep 하고 wide한 모델을 만든거 같음.
아이디어가 매우좋다.
논문보면서 직감대로 해석한거라 틀린부분도 있습니다.

https://inha-kim.tistory.com/43?category=963044 

 

[논문 리뷰] VGG Net(2014) 논문리뷰 (Very Deep Convolutional Networks for Large-Scale Image Recognition)

https://arxiv.org/abs/1409.1556 Very Deep Convolutional Networks for Large-Scale Image Recognition In this work we investigate the effect of the convolutional network depth on its accuracy in the la..

inha-kim.tistory.com

논문 리뷰는 다음과 같이 하였습니다.

 

구현

 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# VGG-11, VGG-13, VGG-16, VGG-19 총 4개의 Model이 존재
# https://www.youtube.com/watch?v=ACmuBbuXn20&t=4s&ab_channel=AladdinPersson
VGG_Network ={
    'VGG11' : [64'M'128'M'256256'M'512,512'M',512,512,'M'],
    'VGG13' : [64,64'M'128128'M'256256'M'512,512'M'512,512,'M'],
    'VGG16' : [64,64'M'128128'M'256256,256'M'512,512,512'M',512,512,512,'M'],
    'VGG19' : [64,64'M'128128'M'256256,256,256'M'512,512,512,512'M',512,512,512,512,'M']
}
 
# VGG
class VGGnet(nn.Module):
    def __init__(self,model,in_channels = 3, num_classes = 10,init_weights = True):
        super(VGGnet,self).__init__()
        self.in_channels = in_channels
 
        # create conv layer , VGG Type
        self.conv_layers = self.create_conv_layer(VGG_Network[model])
 
        self.fcs = nn.Sequential(
            nn.Linear(in_features  = 512*7*7,out_features=4096),
            nn.ReLU(),
            nn.Dropout(),
            nn.Linear(in_features = 4096,out_features=4096),
            nn.ReLU(),
            nn.Dropout(),
            nn.Linear(4096,num_classes),
        )
        if init_weights:
            self._initialize_weights()
            
    def forward(self,x):
        out = self.conv_layers(x)
        out = out.view(-1,512*7*7)
        out = self.fcs(out)
        return out
 
    def create_conv_layer(self,Network):
        layers = []
        in_channels = self.in_channels
 
        for x in Network:
            if type(x) == int# conv layer
                out_channels = x
                layers += [nn.Conv2d(in_channels=in_channels,
                                    out_channels=out_channels,
                                    kernel_size =(3,3),
                                    stride = (1,1),
                                    padding = (1,1)),
                        nn.BatchNorm2d(x),
                        nn.ReLU()]
                in_channels = x
            elif x == 'M'# maxpooling
                layers += [nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))]
        return nn.Sequential(*layers)
 
    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m,nn.Conv2d):
                nn.init.kaiming_normal_(m.weight,mode='fan_out',nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias,0)
            elif isinstance(m,nn.BatchNorm2d):
                nn.init.constant_(m.weight,1)
                nn.init.constant_(m.bias,0)
            elif isinstance(m,nn.Linear):
                nn.init.normal_(m.weight,mean = 0,std=0.01)
                nn.init.constant_(m.bias,0)
 
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
model = VGGnet('VGG11', in_channels=3, num_classes=10, init_weights=True).to(device)
 
cs

https://arxiv.org/abs/1409.1556

 

Very Deep Convolutional Networks for Large-Scale Image Recognition

In this work we investigate the effect of the convolutional network depth on its accuracy in the large-scale image recognition setting. Our main contribution is a thorough evaluation of networks of increasing depth using an architecture with very small (3x

arxiv.org

논문 링크 입니다.

역대 우승자

VGG-16은 ILSVRC에서 2014년에 TOP-5 error rate가 7.3%가 나온 아주 우수한 model로 대표적인 연구 입니다.

ABSTRACT

이 논문에서는 Convolution netwokr 의 Depth가 Large-Scale image recognition 설정에서 미치는 영향을 조사 합니다.
그리고 이 논문에서는 3*3 convolution filter를 가진 netwrok architecture을 이용하여 depth를 증가시켜 평가합니다.

그리고 network의 깊이를 16-19 weight layer로 하면서 이전의 기술보다 더 좋아졌습니다.
ImageNet Challange 2014에 출품 하였는데, localisation and classification tracks에서 각각 1위와 2위를 하였습니다.
그리고 컴퓨터 비전에 추가 연구에 용이하게 하기 위해 두가지 ConvNet 모델을 공개 하였습니다.

INTRODUCTION

ConvNets은 최근 large-scale and video recognition에서 큰 성공을 거두고 있습니다.
이는 2009년 ImageNet과 대규모 공공 이미지 덕분에 가능해 졌고, GPU와 large-scale distribute cluster같은 것들이 있어서 성공적으로 가능 하였습니다.
그리고 deep visual recognition architectures의 발전에 중요한 역활은 ILSVRC에 의해서 수행이 되었습니다.
이미지 분류 시스템의 Testbed 같은 곳 입니다.

ConvNets는 컴퓨터 비전 분야에서 더욱 상품화 됨에 따라 AlexNet의 연구를 더욱 개선 할려고 하였습니다.
그 결과 13년에 우승한 작품은 AlexNet에서 조금만 변경 하였습니다.(파라미터나 층 구조)
또 다른 쪽에서는 전체 이미지와 Multiple scales의 걸쳐 network를 조밀하게 훈련하고 테스트 하였습니다.
이 논문에서는 ConvNet architecture 설계에서 중요한 depth문제를 다루는데, 이를 위해서  architecture 의 다른 
parameters를 수정하고 모든 layer에 매우 작은(3x3) convolutional layer를 추가하여 network의 depth를 높였습니다.

결과적으로 ILSVRC classification and localisation 높은 정확도, 그리고 단순한 Pipeline의 일부를 사용하더라도 우수한 성능을 달성하는 다른 이미지 인식 데이터셋에도 적용 가능합니다. (예를 들면 fine-tuning 없이 liear SVM으로 분류된 
Deep feature)그리고 성능좋은 모델 두개를 공개 하였습니다.(VGG16,VGG19)

나머지 부분에 잘 정리 되어 있으며 , 2장은 ConvNet의 구성에 대해 설명, image classification training and evaluation 은 3장, 4장에는 ILSVRC Classification , 5장에서는 논문을 끝냅니다.
부록 A에서는 ILSVRC-2014 object localisation system를 설명, 부록 B는 dataset에 대한 generalisation읜 Discuss,
그리고 부록C에는 주요 논문 목록을 담고 있습니다.

2 CONVNET CONFIGURATIONS

2.1 에서는 ConvNet의 일반적인 Configurations
2.2 에서는 ConvNet의 평가에 사용되는 특정 Configurations
2.3 에서는 자기들의 설계에 대해서 설명하고, 앞에 기술과 비교 합니다.

2.1 ARCHITECTURE

train 중에는 ConvNet의 대한 INPUT은 224*224 RGB Image로 고정 됩니다.
여기서 하는 data pre-processing은 오직 train set에서 계산한 mean RGB값을 빼는 것 뿐입니다.
Image는 Convolution layer를 통과 하며, 여기서 저자들은 아주 작은 Receptive filed를 사용 합니다.

(CNN에서 Receptive field는 각 단계의 입력 이미지에 대해 하나의 필터가 커버할 수 있는 이미지 영역의 일부를 뜻)
3 x 3을 이용하는데 좌우아래위 중앙을 capture하는 작은 크기 입니다.
그 중에는 input channel을 linear transformation 으로 볼 수 있는 1x1 convolution filter도 사용 합니다.
비선형은 뒤에서 처리합니다. Convolution stride는 1 pixel로 고정됩니다.
그리고 Conv layer에서 Spatial padding은 Convolution 이후에도 spatial resolution이 유지 됩니다.
즉 3x3 Convolution layer에 대해 padding을 1 입니다.
왜냐하면 (이미지 width/height - filter_size + padding*2) / stride + 1) 이기 때문입니다.
Spatial padding은 Max Pooling layer에 의해서 수행됩니다. 그리고 이 layer는 일부는 Convolution layer이후에 수행,
이때 Max pooling 은 stride는 2, 2x2 로 수행됩니다.
Convolution layer stack에는 그 이후에 3개의 Fully connected layer가 옵니다.
처음 두개는 4096개의 Channel, 세번째는 ILSVRC를 위해서 1000개의 Channel입니다.

VGGNET의 간단한 구조

Final layer는 softmax layer이며, Fully connected layer의 Configuration은 모두 동일합니다.
모든 Hidden layer는 ReLU가 non-linearity가 있습니다.
LRN , 저번에 AlexNet에서 사용한 방식은 사용하지 않습니다. 왜냐하면 Local Response Normalisation는
ILSVRC Dataset 의 성능을 향상 시키지는 않지만 Memory와 계산 시간을 증가 시킵니다.

2.2 CONFIGURATIONS

ConvNet configurations

A-E 까지 이름을 정합니다.

모든 Configuration은 2.1에서 말한것에 의해 일반적인 설계를 가지게 됩니다. 깊이만 다릅니다.

11 weight layers in the network A (8 conv. and 3 FC layers)
19 weight layers in the network E (16 conv. and 3 FC layers)
Convolution layer의 Channel width는 작은 편으로, 첫 layer에서는 64, maxPooling layer마다 2배씩 증가하여 512.
표2에서는 각 Configuration 마다 Parameter수가 나옵니다. 원래는 엄청 많지만, 다른 것보다는 적네요.

2.3 DISCUSSION

Receptive field 3x3 filter

VGG의 ConvNet 의 Configuration은 2012년 AlexNet과 2013년 우슨자의 Sermanet과는 다르게 되어 있습니다.
첫 Convolution layer는 large Receptive field, AlexNet의 경우 Stride 4, Stride를 사용하는 것에 비해 여기서는 모든
Network에 걸쳐서 매우 작은 3x3 Receptive filed를 사용합니다. 

 

두개의 3x3 Convolution layer로 이루어진 Stack은 5x5 의 Receptive filed를 가지고 있습니다.
따라서 생각해보면 3x3 Convolution layer는 7x7 의 Receptive filed를 가지게 됩니다.
그러므로 하나의 7x7 layer를 사용하는 대신에 3x3 layer stack 을 사용하면 얻게 되는 장점은 무엇일까요?
첫째 3개의 Non linear rectification layer을 이용하여 decision function이 더욱 차별적으로 만듭니다.(좋게한다)
그리고 parameters의 수를 줄일 수 있습니다.
간단하게 3x3 Convolution stack 은 모두 C개의 채널로 구성되어 있다고 가정합니다.
3x3 Convolution layer stack 의 weight는 3 * (3*3*C*C) , 27*C^2 입니다.
7x7 Convolution layer의 경우 weight는 7*7*C^2, 49*C^2 입니다.
이로인해 약 3x3 Convolution filter를 이용하면 약 81%의 parameter를 줄일 수 있씁니다.
이것은 7x7 Convolution filter를 정규화 하는 것으로 볼 수 있으며 3x3 으로 분해합니다.

1x1 Convolution layer는 Convolution layer의 Receptive  fields에 영향을 끼치지 않고 decision function의 non-linearlity
를 증가 시키는 방법입니다. 비록 1x1읜 입출력 채널의 수는 동일한 liear projection 이지만, 추가적으로 non-linearlity는 
rectification 함수가 추가됩니다. 1x1은 Network in Network 아키텍처에서 사용 되었습니다.

 

Small size convolution filter는 이전에도 몇번 사용 되었습니다. 그러나 less deep 하고 ILSVRC Dataset에서 평가 하지 않았습니다. GoodFellow는 11 weight layer로 Street Number recongition 을 적용하였고, network의 depth가 깊어질수록 성능이 좋아지는 것을 알 수 있었습니다.
ILSVRC-2014 Classification에서 일등을 한 GoogLeNet에서는 VGG와 독립적으로 개발 하였지만, 매우 깊은 ConvNet(22weight layter)와 small convolution filter(3x3 과는 별도로 1x1, 5x5도 사용합니다.)를 기반으로 합니다.
Network topology는 VGG보다 복잡 하지만, 계산량을 줄이기 위해 첫 Layer에서는 Feature map의 resolution이 더
공격적으로 감소합니다.  single-network classification accuracy에서 Szegedy보다 우수 합니다.

3 CLASSIFICATION FRAMEWORK

앞에서는 Network configuration에 대해서 설명 하였고, 이제 ConvNet Training 그리고 Evaluation에 대해 설명합니다.

3.1 TRAINING

ConvNet의 training procedure을 일반적으로 AlexNet을 다르게 됩니다.

(input crops from multi-scale training images 을 제외)
즉 여기서 training은 mini-batch gradient descent를 (역전파 기반)을 사용하며 mometum도 사용, multinomial logistic regression을 목표로 optimising 합니다.
batch size는 256, momemtum은 0.9입니다.
training regularised의 weight decay는 L2 penalty 5*10^(-4)와 , 첫 두 layer에 대한 drop out regularsation의 비율을 0.5
learning rate는 처음에는 1e-2 이지만 validation set의 accuracy가 좋아지지 않자 10배 감소 하도록 하였고, 총 train동안
3번 감소 하였습니다. 그리고 370K의 iteration후에 멈추었으며, 74epochs가 돌았습니다.
여기서 AlexNet 에 비해 더 많은 parameter와 , 더 큰 depth에도 불구하고, 더 큰 깊이, 그리고 더 작은 Convolution 크기에 의해서 암묵적으로 regularisation됩니다. 그리고 특정 layer의 pre-initialisation 덕분에 금방 수렴합니다. 

 

네트워크의 weight의 initialisation은 중요합니다. 초기화가 잘못되면 deep network의 gradient 불안정성으로 인해 
학습이 굉장히 오래 걸릴 수 있습니다.
이 문제를 피하기 위해서는 표1의 A를 random initialisation 할 수 있을 정도로 얕은 train부터 시작 하였고,그 다음
더 깊은 architecutres를 train 할때는 처음 4개의 Conv layer와 마지막 3개의 FC Later를 A Layer와 함께 초기화 .
(중간 layer는 무작위로 초기화) 여기서 미리 initialised된 layer는 learning rate를 줄이지 않고, train 중에 바꿀수 있도록 하였습니다.
random initalisation은 평균 0, 분산이 1e-2인 정규 분포에서 표본을 추출 하였고, bias는 0으로 하였습니다.
그리고 논문을 제출 한 다음에 Glorot & Bengjo의 random initialisation procedure을 통해 pre-train없이 초기화 가능 한
것을 찾았다고 합니다.

training image size는 isotropically rescaled을 하는데 이것의 의미는 training image의 넓이, 높이 중에 더 작은 width, height를 해당 사이즈로 줄이고, 이때 aspect ratio를 유지하여 rescale 합니다.
즉 해당 사이즈가 256이면, H = 1024, W= 512 이면 작은 길이를 가지는 W가 256으로 바뀌고, H는 512가 됩니다.
이때의 Scale하는 S값은 우리가 정해줍니다. 그리고 이 이미지에서 224x224만큼 Crop 합니다.
Crop의 크기가 224x224로 고정된 동안에는 원칙적으로는 s는 224이상의 값을 가져야 합니다.

여기서 Training Scale S를 설정하기 위해 두가지 방법으로 접근합니다.

single Scale training 이 방법은 S를 256 그리고 384로 고정시켜서 학습합니다. S를 256으로 학습 한 뒤에 그 다음으로 S를 384로 학습합니다. S=256으로 pre-train되어 있으므로 S=384로 할때는 Learning rate을 1e-3으로 낮춰서 학습합니다.

Second approach는 S를 multi-scale training 하는 것 입니다.
각 훈련 이미지는 [Smin, Smax]에서 random 하게 sampling 하여 scale을 조정합니다.(Smin = 256, Sma =512)
영상의 object size는 다를 수 있기 때문에 Train 중에는 이것을 고려 하는 것이 좋습니다.
이는 single model 이 크기가 다양한 범위의 object를 인식하도록 훈련하는 Scale jiittering 에 의한data augmentation 효과를 볼 수 있습니다. 속도상의 이유로 동일한 Configuration으로 single-scale model의 layer를 미세 조정 하여서 multi-scale model을 train 하였는데, S= 384로 Pre-train 하였습니다.
이것을 보통 scale jittering이라고 합니다.

Scale jittering

 

3.2 TESTING

test에서는 ConvNet과 입력 이미지가 주어지면 다음과 같은 방식으로 합니다.
다양하게 Recale하여 입력으로 들어갔습니다. 다양하게 하는 덕분에 성능이 개선되었고, 또 Horizontal flipping를 하여 test set을 증가 시키고, 최종 점수를 얻기 위해서는 원본과 data augmentation 된 이미지들의 평균 점수를 이용합니다.
test image에서도 crop을 하였지만 비효율적 이라고 합니다.

3.3 IMPLEMENTATION DETAILS

여기서 구현은 Caffe을 이용 하였다고 합니다. 
NVIDIA Titan Black GPU 4개를 이용하여 2~3주 걸렸습니다.
4개 사용해서 3.75배 빨라졌다고 합니다.

4 CLASSIFICATION EXPERIMENTS

dataset은 ILSCRC-2012 dataset을 이용합니다.
이거는 Train image는 130M, valid 는 50K, test는 100K를 사용합니다.
평가 기준은 top-1, top-5 두가치 척도를 이용하는데, top-1의 경우 예측이 잘못 된 경우, top-5는 predicte category에 없는 경우 입니다.

4.1 SINGLE SCALE EVALUATION

결과

ConvNet model의 성능은 Single Scale로 평가 합니다.
test image size는 Q = S , jitter [Smin, Smax]의 경우 Q = 0.5(Smin + Smax) 로 설정합니다,
첫째는 LRN을 사용하는 모델 A에는 좋아지는 모습이 없었습니다. 그러므로 B ~ E에는 사용하지 않았습니다.
둘째는 Classification 오류는 ConvNet이 depth가 증가 할 수록 감소합니다.
A는 11개, E는 19개 Layer로 이루어 집니다. 
특히 같은 depth에도 불구하고, C는 3개의 1x1 conv layer를 사용하는 것은, 네트워크 전체에 3x3 convv layer를 사용
하는 D보다 성능이 안좋습니다. 
이는 추가적인 Non- linearity 에는 도움이 되긴 하지만,( C가 B보다 좋기 때문에) receptive field가 있는 것을 사용하는 것이 (D가 더 좋은거) 공간적인 맥락을 이해하는데 더 좋은거 같습니다.
아키텍처 Error rate는 depth가 19 layer에 도달하면 saturate됩니다. 더 깊은 model도, 더 큰 dataset도 도움이 될 수도 있습니다.
여기서 B와 5x5 conv layer을 가진 shallow network와 비교 하였는데, 이는 B에서 3x3 conv를 쓰는 것 보다 top-1 error rate가 7% 높다고 합니다.
마지막으로 single scale test 시간에 사용되더라도 train scale jittering 이 fix 된 것 보다 (S ≤ [256; 512]) 으로 하는게 더 좋은 결과가 나온 것 입니다. 한마디로 data augmentation이 잘 되었으므로 실제로 큰 도움이 된 것 입니다.

4.2 MULTI-SCALE EVALUATION

이제 Multi-scale 을 평가 하여 봅니다. scale jitter 효과를 평가 하는 것 이지요.
test 이미지의 여려 scale된 버전으러 model을 실행 하고 나서 class 의 posterior를 평균으로 구합니다.
train scale과 test scale의 큰 차이가 성능저하가 되는 것을 고려하여, 고정 S로 Train 한 model을 train image 크기에 
가까운 test image size에 대해 평가 하였습니다.
Q = {S − 32, S, S + 32}
그리고 동시에 train 시에 scale jittering을 통해 된 것은  S s [Smin; Smax], Q = {Smin, 0.5(Smin + Smax), Smax} 에서 
평가 하였습니다.
표 4에 결과를 보면 single-scale보다 multi scale도 좋은 결과가 나오는 것을 알 수 있습니다.
S를 고정하는 것 보다는 Scale jitter가 더 좋다는 것 입니다. 검증 세트에서 제일 좋은 것은24.8%/7.5% top-1/top-5.
그리고 Test set에서 TOP-5 error가 7.3% 입니다.

4.3 MULTI-CROP EVALUATION

이 표는 dense가 높은 ConvNet 과 Multi crop 을 평가 및 비교 합니다.
softmax 출력은 두 평가 기법의 상호보완성을 평가하는데, 두가지 동시에 접근하는 방식이 상호보완적이라 좋습니다.
위에서 말한거와 같이 convolution boundary condition의 처리 때문 이라고 생각한다고 합니다.

4.4 CONVNET FUSION

지금까지는 개별 ConvNet에 model의 성능에 대해서 평가 하였습니다.
이 실험에서는 여러 모델의 softmax posteriors를 결합하여 평균화 합니다. 
ILSVRC 제출 후에는 여기서는 dense eval을 통해여 7.0%를 ,dense multi-crop을 통하여 6.8%로 줄이는데 이때 두개의
최고성능 multi scale mode d,e만 앙상블을 하였습니다.
최고성능은 model E 입니다.

4.5 COMPARISON WITH THE STATE OF THE ART

table 7은 다른 결과와 비교합니다.
VGG는 7개의 model과 앙상블 하여 7.3%로 2위를 하였습니다.
그리ㅗ 제출 한 뒤에 2개의 모델로 앙상블 하여 6.8%로 줄였습니다.
GoogLeNet와 비교해도 상당히 경쟁력이 있습니다.
그리고 흥미로운 것은 ILSVRC 에 제출한것과 달리 2개를 앙상블 한것 이 더 우수하다는 것 입니다.
단일 아키텍처 기준으로 자기들것이 0.9% 좋다고 합니다.

5 CONCLUSION

이 연구에서는 대규모 이미지 Classification을 위해서 deep convolutional network(19 weight layer)를 사용 하였습니다.

representation depth가 classification accuracy에 큰 도움이 되며, ImageNet 챌린지 데이터셋에 대한 좋은 성능 뿐만 아니라 ConvNet 아키텍처를 이용하여 달성 할 수 있다는 것이 입증되었습니다.

부록에서는 model이 광범위한 작업 및 dataset에 잘 일반화되어 deep image representation을 중심으로 구축된 복잡한 recognition pipeline과 거의 일치하거나 그 이상의 성능을 보여줬습니다.
여기서 visual representation은 depth의 중요성을 확인 해 줍니다.
GPU 빌려준 NVIDIA 감사합니다. 라고 하네여.

너무 기네요 논문 ㅜ

틀린 점 있으면 댓글 부탁 드립니다.
다음에는 논문을 구현하여 올리겠습니다.

https://inha-kim.tistory.com/41

 

[논문 리뷰] AlexNet(2012) 논문리뷰 (ImageNet Classification with Deep ConvolutionalNeural Networks)

https://proceedings.neurips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf 오늘 review할 논문은 딥러닝의 시대를 열었다고 해도 되는 AlexNet입니다. AlexNet은 2012년  ILSVRC(ImageNet La..

inha-kim.tistory.com

논문 리뷰는 다음과 같이 하였습니다.

 

구현

 

 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class AlexNet(nn.Module):
    def __init__(self, num_classes = 1000):
        super().__init__()
        # INPUT 227*227*3
        self.conv_layer = nn.Sequential(
            nn.Conv2d(in_channels=3,out_channels=96,kernel_size = 11, padding = 0, stride=4),
            nn.ReLU(inplace=True),
            nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2),
            nn.MaxPool2d(kernel_size=3,stride = 2),
 
            nn.Conv2d(in_channels=96,out_channels=256,kernel_size = 5, padding = 2, stride=1),
            nn.ReLU(inplace=True),
            nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2),
            nn.MaxPool2d(kernel_size=3,stride = 2),
 
            nn.Conv2d(in_channels=256,out_channels=384,kernel_size = 3, padding = 1, stride=1),
            nn.ReLU(inplace=True),
                      
            nn.Conv2d(in_channels=384,out_channels=384,kernel_size = 3, padding = 1, stride=1),
            nn.ReLU(inplace=True),
            
            nn.Conv2d(in_channels=384,out_channels=256,kernel_size = 3, padding = 1, stride=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3,stride = 2)
        )
        self.fc_layer = nn.Sequential(
            nn.Dropout(p=0.5,inplace=True),
            nn.Linear(in_features=(256*6*6), out_features=4096),
            nn.ReLU(inplace=True),
 
            nn.Dropout(p=0.5,inplace=True),
            nn.Linear(in_features=4096, out_features=4096),
            nn.ReLU(inplace=True),
            nn.Linear(in_features=4096,out_features=num_classes)
        )
        self.init_weight_bias()
    def init_weight_bias(self):
        for layer in self.conv_layer:
            # Conv2D Layer check 
            if isinstance(layer, nn.Conv2d):
                nn.init.normal_(layer.weight, mean = 0, std = 0.01)
                nn.init.constant_(layer.bias,0)
        nn.init.constant_(self.conv_layer[4].bias, 1)
        nn.init.constant_(self.conv_layer[10].bias, 1)
        nn.init.constant_(self.conv_layer[12].bias, 1)
    
    def forward(self,x):
        x = self.conv_layer(x)
        x = x.view(-1,256*6*6)
        return self.fc_layer(x)
cs

+ Recent posts