Notice
Recent Posts
Recent Comments
Link
12-20 19:48
«   2024/12   »
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
Archives
Today
Total
관리 메뉴

AI 전문가가 되고싶은 사람

(구현) ImageNet Classification with Deep Convolutional Neural Networks (PyTorch) 본문

논문

(구현) ImageNet Classification with Deep Convolutional Neural Networks (PyTorch)

Kimseungwoo0407 2024. 9. 4. 15:47

https://seungwoo0407.tistory.com/48

 

(공부용) ImageNet Classification with Deep Convolutional Neural Networks

https://kmhana.tistory.com/3 딥러닝을 위한 논문 가이드☆딥러닝 공부를 위해서 꼭 읽어야 할 논문(사이트)들의 리스트를 정리해보고자한다. 순수히 개인적인 의견으로, 사용자의 관점에서 평가했다.

seungwoo0407.tistory.com

 

[1] ImageNet Classification with Deep Convolutional Neural Networks(AlexNet)

https://proceedings.neurips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf

[2] Github alexnet-pytorch

https://github.com/dansuh17/alexnet-pytorch

 

GitHub - dansuh17/alexnet-pytorch: Pytorch Implementation of AlexNet

Pytorch Implementation of AlexNet. Contribute to dansuh17/alexnet-pytorch development by creating an account on GitHub.

github.com

이 자료들을 참고하여 AlexNet을 구현하는 데 필요한 개념과 기술을 이해하고, 구현 방법을 배웠다.

# 텐서(tensor) 연산, 신경망 구성, GPU 연산 등을 위한 다양한 기능을 제공
import torch
# 신경망을 구성하기 위한 모듈
import torch.nn as nn
# torch.nn의 기능을 좀 더 유연하게 사용할 수 있도록 함수형 인터페이스를 제공
import torch.nn.functional as F

class AlexNet(nn.Module):
	"""
    AlexNet 논문에서 제안한 레이어로 구성된 신경망 모델
	"""
    
    def __init__(self, num_classes=1000):
        """
        이 신경망에 대한 레이어를 정의하고 할당
        Args: num_classes : 이 모델로 예측할 클래스 수 (기본값:1000, ImageNet 데이터셋에 맞춰짐)
        """
        super().__init__()
        
        # input size : b x 3 x 227 x 227
        # 원본 논문에서는 너비와 높이가 224px라고 명시되어 있지만, 
        # 첫 컨볼루션 레이어를 통과한 후 크기가 55 x 55가 되지 않는다.
        # 따라서, 227 x 227 크기의 입력을 사용하여 55 x 55 출력을 만들어준다.
        
        # 구성
        self.net = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=96, kernel_size=11, stride=4), # (b x 96 x 55 x 55)
            nn.ReLU(),
            nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2),
            nn.MaxPool2d(kernel_size=3, stride=2), # (b x 96 x 27 x 27)
            nn.Conv2d(96, 256, 5, padding=2), # (b x 256 x 27 x 27)
            nn.ReLU(),
            nn.LocalResponseNorm(size=5, alpha=0.0001, beta=0.75, k=2),
            nn.MaxPool2d(kernel_size=3, stride=2), # (b x 256 x 13 x 13)
            nn.Conv2d(256, 384, 3, padding=1), # (b x 384 x 13 x 13)
            nn.ReLU(),
            nn.Conv2d(256, 384, 3, padding=1), # (b x 384 x 13 x 13)
            nn.ReLU(),
            nn.Conv2d(256, 256, 3, padding=1), # (b x 384 x 13 x 13)
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2), # (b x 256 x 6 x 6)
        )

        # classifier는 선형 레이어의 이름일 뿐이다.
        # 처음 두 레이어에만 Dropout 적용
        self.classifier = nn.Sequential(
            nn.Dropout(p=0.5, inplace=True),
            nn.Linear(in_features=(256 * 6 * 6), out_features=4096),
            nn.ReLU(),
            nn.Dropout(p=0.5, inplace=True),
            nn.Linear(in_features=4096, out_features=4096),
            nn.ReLU(),
            nn.Linear(in_features=4096, out_features=num_classes),
        )
        self.init_bias()
    
    # Alexnet 모델에서 각 레이어의 가중치와 편향을 초기화하는 역할
    # 초기화로 신경망이 더 빠르고 안정적으로 학습 가능
    def init_bias(self):
        for layer in self.net:
            # 해당 레이어가 nn.Conv2d인지 확인 후 True라면 가중치와 편향 초기화
            if isinstance(layer, nn.Conv2d):
                # 평균이 0이고 표준편차가 0.01인 정규분포에서 샘플링된 값들로 초기화
                nn.init.normal_(layer.weight, mean=0, std=0.01)
                # 0으로 초기화
                nn.init.constant_(layer.bias, 0)
        # 논문에서 Conv2d layers의 2,4,5 번째 conv layer의 편향을 1로 설정한다
        nn.init.constant_(self.net[4].bias,1)
        nn.init.constant_(self.net[10].bias,1)
        nn.init.constant_(self.net[12].bias,1)
    
    def forward(self, x):
        """
        입력 데이터 x를 네트워크(self.net)를 통해 통과시킨다.
        이 과정에서 네트워크의 각 레이어를 차례로 통과하면서 데이터를 변형하고 최종적으로 예측 결과 생성
        Args : x (Tensor) : input tensor
        Returns : output(Tensor) : output tensor
        """
        x = self.net(x) # 통과한 후 (b, 256, 6, 6) -> 4D 텐서
        x = x.view(-1, 256 * 6 * 6) # 데이터의 차원을 줄여 전결합 레이어에 입력으로 제공 4D 텐서 -> 2D 텐서
        return self.classifier(x)

 

입력이 (b, 3, 227, 227)로 주어졌을 때 첫 번째 컨볼루션 연산 후 출력 크기를 아래 공식을 사용하여 계산해보았다.

 

 

출력 채널 수가 96으로 바뀌고 커널 크기와 스트라이드를 대입해서 계산하면 코드 내용대로 (b,96,55,55)가 나오게된다.

첫 번째 maxpool 또한 계산해보았을 때, (b,96,27,27)로 코드 내용과 일치하게 된다.