1. AlexNet 이란?
AlexNet은 인공지능의 ILSVRC에서 2012년에 당시 오차율 16.4%로 다른 모델보다 압도적으로 우승한 모델입니다. 현재 시점에서 수치를 보면 그렇게 좋은 정확도가 아니지만, 대회 당시에는 굉장한 정확도였다고 합니다. 2011년에 우승했던 모델의 오차율이 25.8%였으니, 오차율 성능이 40% 만큼 좋아졌습니다.
AlexNet의 'Alex'는 모델 논문의 저자인 Alex Khrizevsky의 이름 입니다.
2. AlexNet 구조
AlexNet은 위의 그림과 같은 구조입니다.
순서대로 나열하면 아래와 같습니다.
Input layer
Conv1 - MaxPool1 - Norm1
Conv2 - MaxPool2 - Norm2
Conv3 - Conv4 - Conv5 - Maxpooling
FC1- FC2
Output layer
Input layer
224x224x3 크기의 이미지
Conv_1
11x11(stride=4, padding=0)의 Kernel (filter) 96개
Input : 224x224x3
Output : 55x55x96
MaxPooling_1
3x3(stride=2, padding=0) Kernel (filter)
Input : 55x55x96
Output: 27x27x96
Norm_1
LRN을 사용한 Normalization layer 이며, 자세한 내용은 아래에 있습니다.
Input : 27x27x96
Output : 27x27x96
Conv_2
5x5(Stride=1, Padding=2) Kernel(filter) 256개
Input : 27x27x96
Output : 27x27x256
MaxPooling_2
3x3(stride=2, padding=0) Kernel
input : 27x27x256
output : 13x13x256
Norm_2
LRN을 사용한 Normalization layer
Input : 13x13x256
Output : 13x13x256
Conv_3
3x3(Stride=1, Padding=1) Kernel(filter) 384개
Input : 13x13x256
Output : 13x13x384
Conv_4
3x3(Stride=1, Padding=1) Kernel(filter) 384개
Input : 13x13x384
Output : 13x13x256
Conv_5
3x3(Stride=1, Padding=1) Kernel(filter) 256개
Input : 13x13x384
Output : 13x13x256
MaxPooling_3
3x3(stride=2, padding=0) Kernel
Input : 13x13x256
Output : 6x6x256
FC_1
FCL 4096개
Input : 6x6x256
Output : 4096
FC_2
FCL 4096개
Input : 4096
Output : 4096
Output layer
FCL 1000 Softmax
Input : 4096
Output : 1000
3. AlexNet 특징
1. Relu 함수
활성화 함수로 Relu 함수를 사용 했습니다.
이전까지는 Tanh 함수를 사용했는데, 두 함수의 차이점은 어떤 것이 있을까요?
우선 두 함수의 생김새는 아래와 같습니다.
가장 큰 차이점은 tanh함수는 [-1, 1] 범위에서 존재하지만,
ReLU함수는 [0, ∞] 범위에 존재한다는 점입니다.
이러한 범위는 논문의 'Saturating(포화상태)' 개념과 관련이 있습니다.
tanh 함수가 saturating function이기 때문에 non saturating 한 ReLU보다 훨씬 느리다는 것이
Alex net 논문의 주장입니다. 그러면 Saturating function이란 무엇일까요?
쉽게 생각하자면 -∞ 또는 +∞ 범위로 국한되지 않고 발산하는 함수를 non-saturating 함수라고 정의합니다.
ReLU함수는 +∞ 범위로 계속 무한대로 나아가고 있기에 non-saturating 함수이고,
반면 tanh함수는 [-1, 1]의 범위로 되어있기 때문에 saturating 함수입니다.
이러한 saturating 함수의 완만한 기울기는 Gradient의 Update를 느리게 만든다고 알려져 있습니다.
실제로 논문에서 제시한 위 그래프를 보시면,
실선인 ReLU 함수가 적은 epoch에도 빠른 Error rate 감소를 보이고 있습니다.
실제로 6배 정도 더 빠른 성능을 보였다고 합니다.
따라서 Alexnet 에서는 Relu 활성화 함수를 채택했습니다.
2. Local Responce Normalization(LRN) 의 사용
Batch normalization으로 잘 알려진 정규화 계열의 방법입니다.
이 방법은 인체의 현상 중 lateral inhibition(측면 억제)에서 영감을 받아 만들어졌습니다.
LRN은 일반화(generalizaion) 목적으로 사용합니다.
위의 설명과 같이 ReLU는 non-saturating 함수이기 때문에 saturating을 예방하기 위한 입력 normalizaion이 필요로 하지 않는 성질을 갖고 있습니다. ReLU는 양수 값을 받으면 그 값을 그대로 neuron에 전달하기 때문에 너무 큰 값이 전달되어 주변의 낮은 값이 neuron에 전달되는 것을 막을 수 있습니다. 이것을 예방하기 위한 normalization이 LRN 입니다.
위 그림은 측면 억제의 유명한 그림인 헤르만 격자입니다. 검은 사각 형안에 흰색의 선이 지나가고 있습니다. 신기한 것은 흰색의 선에 집중하지 않을 때 회색 점이 보이는데 이러한 현상이 측면 억제에 의해 발생하는 것입니다. 이는 흰색으로 둘러싸인 측면에서 억제를 발생시키기 때문에 흰색이 더 반감되어 보입니다.
AlexNet에서 LRN을 구현한 수식을 살펴보겠습니다.
a는 x, y 위치에 적용된 i번째 Kernel의 Output을 의미하고
a를 normalization 하여 큰 값이 주변의 약한 값에 영향을 주는 것을 최소화했다고 합니다.
이러한 기법으로 top-1와 top-5 error를 각각 1.4%, 1.2% 감소시켰다고 합니다.
하지만 AlexNet 이후 현재 CNN에서는 LPR 대신 Batch normalization 기법이 많이 쓰입니다.
3. Overlapping Pooling
Pooling을 'Overlap(중첩)' 하여 사용한 것입니다.
아래 그림은 기존 방식과 중첩 방식을 보여줍니다.
기존에는 위 그림의 상단처럼 Overlap 하지 않은 pooling을 사용했습니다.
하단 그림은 stride를 조절하여 Overlappling pooling을 사용했습니다.
이는 기존의 방법보다 약간 더 overfitting의 해결에 효과적이라는 점을 Error rates를 통해 알 수 있습니다.
3. Overfiting 해결
AlexNet에는 6천만 개의 parameters가 있습니다. 이미지 1000개 classes로 분류하기 위해서는 상당한 overfitting 없이 수많은 parameters를 학습시키는 것은 어렵다고 말합니다.
AlexNet 논문에서는 overfitting을 해결하기 위해 적용한 두 가지 기법을 사용합니다.
첫 번째는 Augmentation 이고, 두 번째는 Dropout입니다.
1. Data Augmentation
Augmentation은 CNN 모델에서 데이터를 다양하게 증대시키는 방법입니다.
데이터 증대는 두 가지 방법을 사용하는데,
첫 번째는 단순 '수평반전'
두 번째는 RGB 픽셀 값을 변화
쉽게 설명하면 1개의 이미지를 수평으로 뒤집고,
이를 랜덤으로 crop 해서 이미지를 증대시키는 방법입니다.
이렇게 전환한다면 더 많은 학습 이미지를 형성하고 다양한 학습이 가능합니다.
2. Drop out
Dropout이란 말 그대로 네트워크의 일부를 생략하는 것입니다.
아래 그림처럼 네트워크의 일부를 생략하고 학습을 진행하게 되면,
생략한 네트워크는 학습에 영향을 끼치기 않게 됩니다.
4. AlexNet 간단한 코드
맨 처음 소개드렸던 AlexNet 구조입니다.
아래 그림 구조에 따라서 구현되는 간단한 class 코드입니다.
import torch import torch.nn as nn import torchvision from torchsummary import summary class AlexNet(nn.Module): def __init__(self,num_classes=1000): super(AlexNet,self).__init__() self.feature_extraction = nn.Sequential( nn.Conv2d(in_channels=3,out_channels=96,kernel_size=11,stride=4,padding=2,bias=False), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3,stride=2,padding=0), nn.Conv2d(in_channels=96,out_channels=192,kernel_size=5,stride=1,padding=2,bias=False), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3,stride=2,padding=0), nn.Conv2d(in_channels=192,out_channels=384,kernel_size=3,stride=1,padding=1,bias=False), nn.ReLU(inplace=True), nn.Conv2d(in_channels=384,out_channels=256,kernel_size=3,stride=1,padding=1,bias=False), nn.ReLU(inplace=True), nn.Conv2d(in_channels=256,out_channels=256,kernel_size=3,stride=1,padding=1,bias=False), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2, padding=0), ) self.classifier = nn.Sequential( nn.Dropout(p=0.5), nn.Linear(in_features=256*6*6,out_features=4096), nn.ReLU(inplace=True), nn.Dropout(p=0.5), nn.Linear(in_features=4096, out_features=4096), nn.ReLU(inplace=True), nn.Linear(in_features=4096, out_features=num_classes), ) def forward(self, x): x = self.feature_extraction(x) x = x.view(x.size(0),256*6*6) # 8, 9216 x = self.classifier(x) return x if __name__ =='__main__': model = AlexNet() alex = model.cuda() summary(alex, (3,224,224))
아래는 위의 코드 summary 출력 결과입니다.
이상으로 AlexNet 리뷰를 마치겠습니다.
AlexNet 으로 학습하는 코드는 추후 업데이트하겠습니다.
감사합니다.
Comments