AI 개발 공부 공간

AI, 머신러닝, 딥러닝, Python & PyTorch, 실전 프로젝트

딥러닝/딥러닝: 자연어

AlexNet (2012)

qordnswnd123 2025. 2. 25. 11:43

1. AlexNet 

1.1 AlexNet 이란?

AlexNet은 2012년 ImageNet 대규모 시각 인식 챌린지에서 우승한 합성곱 신경망(CNN) 아키텍처입니다. 이 챌린지는 방대한 이미지 데이터셋인 ImageNet을 사용하여 알고리즘을 평가하고 다양한 시각 인식 작업에서 높은 정확도를 달성하기 위해 경쟁하는 대회입니다.
AlexNet의 주요 혁신은 다중 합성곱 층, 풀링 층, 완전 연결 층으로 구성된 깊은 구조에 있습니다. 이러한 설계를 통해 네트워크는 ImageNet과 같은 대규모 이미지 데이터셋 에서 복잡한 특징과 패턴을 학습할 수 있습니다.

 

1.2 dateset

 

ImageNet은 1000개의 카테고리로 라벨이 지정된 약 1400만 개의 고해상도 이미지로 구성된 이미지 데이터베이스입니다. 대부분의 사전 학습 모델들은 바로 이 ImageNet 데이터셋을 사용하여 학습되었습니다. 이 데이터셋은 다양한 객체와 장면을 포함하고 있어, 모델이 넓은 범위의 시각적 패턴을 학습할 수 있도록 돕습니다.
AlexNet의 입력은 크기 227x227의 RGB 이미지입니다. 이는 훈련 세트의 모든 이미지와 테스트 이미지가 227x227 크기로 변환되어야 함을 의미합니다.
이 대회는 ImageNet의 이미지를 사용하여 연구자들이 가장 낮은 top-1 및 top-5 오류율을 달성하도록 도전합니다.
Top-1 오류율은 모델이 이미지를 보고 가장 가능성이 높은 하나의 클래스를 예측했을 때, 그 예측이 실제 정답과 일치하지 않는 비율입니다. 예를 들어, 모델이 한 이미지를 보고 '고양이"라고 예측했지만 실제 정답은 "개인 경우, 이는 top-1 오류로 간주됩니다.
Top-5 오류율은 모델이 이미지를 보고 가능성이 높은 다섯 개의 클래스를 예측했을 때, 그 중 어느 하나도 실제 정답과 일치하지 않는 비율입니다. 예를 들어, 모델이 한 이미지를 보고 '고양이", "호랑이", "사자", "표범", "재규어"라고 예측했지만 실제 정답은 개인 경우, 이는 top-5 오류로 간주됩니다. 하지만 만약 이 다섯 개의 예측 중 하나라도 개를 포함하고 있다면, 이 예측은 올바른 것으로 간주됩니다.


2. AlexNet 아키텍처의 주요 특징

2.1. ReLU 활성화 함수

AlexNet 아키텍처가 개발되기 전에는 딥러닝 컨볼루션 신경망에서 시그모이드와 tanh 함수를 사용했기 때문에 사라지는 그래디언트(vanishing gradient) 문제에 직면했습니다. 이 함수들은 값이 너무 커지거나 작아지면 출력을 일정하게 만들어, 역전파 중에 그래디언트가 거의 0이 되게 합 니다.
AlexNet 네트워크는 ReLU 활성화 함수를 사용하여 이 문제를 상당히 완화했습니다. ReLU는 포화되지 않아 그래디언트가 네트워크를 통해 자유롭게 흐를 수 있게 합니다. 이 덕분에 사라지는 그래디언트(vanishing gradient) 문제를 극복할 수 있었고, 딥 CNN이 더 빠르고 정확하게 계산 될 수 있었습니다.
그러나 ReLU가 사라지는 그래디언트 문제를 완전히 제거하지는 않습니 다. 이 문제를 피하면서 효율적이고 정확한 딥러닝 모델을 개발하기 위해 서는 ReLU 외에도 다른 기술이 필요할 때가 많습니다.
ReLU 함수는 다음과 같이 정의됩니다. [f(x) = max(0,z)]

 

2.2. 과적합 문제 해결 방법

AlexNet에서는 과적합 문제가 주요 이슈였습니다. 이를 줄이기 위해 두가지 방법을 사용했습니다.


1) 데이터 증강 (Data Augmentation)
제한된 데이터 세트로 딥러닝 컨볼루션 네트워크를 훈련하는 것은 과적합 때문에 어려울 수 있습니다. 이를 해결하기 위해 AlexNet은 데이터 증강 방식을 사용했습니다. 데이터 증강은 원래 이미지를 무작위로 변경하여 새로운 이미지를 만드는 방법입니다. 여기에는 자르기, 뒤집기, 회전, 노이즈 추가, 색상 변경 등이 포함됩니다.
이 방법을 사용하면 훈련 데이터 세트의 크기와 다양성이 크게 늘어나게 됩니다. 그 결과, 모델의 일반화 능력이 향상되고, 학습 속도와 정확도가 높아지며, 과적합 문제를 줄일 수 있습니다.

 

2) 드롭아웃

 

드롭아웃은 훈련 과정에서 각 계층의 일부 뉴런을 무작위로 비활성화합니다. 즉, 신경망이 각 반복에서 다른 뉴런 조합에 의존하도록 강제하여 훈련 데이터의 특정 기능에 대한 의존을 억제합니다. 결과적으로 과적합을 피하고 모델의 일반화 능력을 높이는 데 도움이 됩니다.
AlexNet 아키텍처에서 드롭아웃은 처음 두 개의 완전 연결 레이어에 적용됩니다. 두 개의 fully connected layer는 매우 많은 수의 뉴런(각각 4096개)을 사용하기 때문에 과적합에 취약합니다.
AlexNet에서는 50% 의 드롭아웃 비율을 사용하는데, 이는 각 계층의 뉴 런의 절반이 훈련 중에 무작위로 드롭아웃된다는 것을 의미합니다. 이 높은 비율은 이러한 큰 계층에서 과적합을 방지하는 것의 중요성을 강조합니다.


2.3. GPU 도입

AlexNet 이전에는 연구자들이 주로 CPU를 사용하여 모델을 훈련했는데, GPU 처리에 직접 액세스할 수 없었기 때문입니다. 이는 Nvidia가 CUDA API를 출시하면서 바뀌어 AI 소프트웨어가 GPU를 사용하여 병렬 처리에 액세스할 수 있게 되었습니다.
GPU는 병렬 처리 능력이 뛰어나 많은 양의 데이터를 동시에 처리할 수 있습니다. AlexNet은 GPU를 사용하여 대규모 데이터셋을 효율적으로 처리하고 훈련 속도를 크게 향상시켰습니다. 이를 통해 깊은 신경망 모델 의 훈련이 가능해졌습니다.
아래 이미지는 CPU와 GPU의 작업 흐름을 비교한 것입니다. CUDA 라이 브러리와 런타임 환경을 통해 GPU의 글로벌 메모리와 공유 메모리에 접근할 수 있게 되어 신경망의 병렬 연산이 가능해졌습니다.


3. AlexNet 아키텍처

AlexNet은 학습 가능한 매개변수를 가진 8개의 층으로 구성되어 있습니다.

5개의 합성곱 층
3개의 완전 연결 층

 

 

코드의 구조는 특징 추출기 (feature extractor) 와 분류기 (classifier)로 나뉩니다. 
특징 추출기는 이미지를 입력 받아 연속된 합성곱 및 풀링 층을 거쳐 고차원 특징을 추출하는 역할을 합니다.

반면, 분류기는 특징 추출기에서 추출 된 특징을 바탕으로 최종 클래스를 예측하는 역할을 합니다.

 

 

3.1. 특징 추출기 (feature extractions)

AlexNet의 전반부는 특징 추출기 부분으로, 주로 합성곱 층과 풀링 층으 로 구성되어 있습니다. 이 부분은 입력 이미지에서 유용한 특징을 추출하는 역할을 합니다.


1) 첫 번째 합성곱 층 (Conv1)
첫 번째 합성곱 층은 11x11 크기의 필터 96개를 사용하여 스트라이드 4 로 입력 이미지에 적용됩니다. 이 층에서는 ReLU 활성화 함수가 사용됩 니다. 스트라이드 4는 필터가 한 번에 4픽셀씩 이동하며 이미지의 특징을 추출함을 의미합니다. 이 과정은 이미지의 공간적 특성을 추출하고, 큰 필터 크기와 스트라이드를 통해 입력 이미지의 크기를 크게 줄입니다. 결과 적으로 출력 특징 맵의 크기는 55x55x96이 됩니다.

 

 

2) 첫 번째 맥스 풀링 층 (Max Pooling)
AlexNet 네트워크는 합성곱 계층에서 생성된 피처 맵의 크기와 복잡성을 줄이기 위해 최대 풀링을 사용합니다. 최대 풀링은 2×2 또는 3×3과 같은 작은 영역에서 가장 큰 값을 선택하여 출력하는 방식입니다. 이 방법은 불필요한 중복이나 노이즈를 제거하면서 중요한 특징을 유지하는 데 도움이 됩니다.


AlexNet 아키텍처를 보면 첫 번째, 두 번째, 다섯 번째 합성곱 층 뒤에 최 대 풀링 층이 있습니다. 이러한 최대 풀링 층은 피처 맵의 겹치는 영역을 함께 처리합니다. 이는 겹치지 않는 최대 풀링보다 더 많은 중요한 정보를 유지하고 오류를 줄이는 데 효과적입니다.
첫 번째 합성곱 층(Conv1) 다음으로, 첫 번째 맥스 풀링 층이 옵니다. 이 층에서는 크기 3x3, 스트라이드2를 가진 풀링이 적용됩니다. 맥스 풀링 은 특징 맵의 공간적 크기를 줄이고, 주요 특징을 유지하면서 계산 복잡성 을 낮추는 역할을 합니다. 결과적으로 출력 특징 맵의 크기는 27x27x96 이 됩니다.

 

import torch
import torch.nn as nn
import torch.nn.functional as F
# 0️⃣ 임의의 입력 데이터 생성 (1채널, 32x32 이미지)
x = torch.randn(1, 3, 227, 227)
print(f'Input shape: {x.shape}')
Input shape: torch.Size([1, 3, 227, 227])

 

# 1️⃣ 첫 번째 합성곱 층 (Conv1)
conv1 = nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2)
x = F.relu(conv1(x))
print(f'After Conv1: {x.shape}')

# 2️⃣ 첫 번째 맥스 풀링 층 (MaxPool1)
pool1 = nn.MaxPool2d(kernel_size=3, stride=2)
x = pool1(x)
print(f'After Pool1: {x.shape}')
After Conv1: torch.Size([1, 96, 56, 56])
After Pool1: torch.Size([1, 96, 27, 27])

 

3.2. 두 번째 합성곱 및 맥스 풀링 층 적용

1) 두 번째 합성곱 층 (Conv2)
그 후, 두 번째 합성곱 층에서는 필터 크기 5x5, 256개의 필터, 스트라이드 1, 패딩 2를 사용합니다. 이 층에서도 ReLU 활성화 함수가 사용됩니다. 출력 특징 맵의 크기는 27x27x2560이 됩니다.

 

2) 두 번째 맥스풀링 층(Max Pooling)

 

# 3️⃣ 두 번째 합성곱 층 (Conv2) & 4️⃣ 두 번째 맥스 풀링 층 (MaxPool2)
conv2 = nn.Conv2d(96, 256, kernel_size=5, stride=1, padding=2)
x = F.relu(conv2(x)) # 활성화 함수 적용
x = pool1(x)         # 맥스 풀링 적용

print(f'After Pool2: {x.shape}')
After Pool2: torch.Size([1, 256, 13, 13])

 

3.3. 세 번째, 네 번째, 다섯 번째 합성곱 층 및 세 번째 맥스 풀링 층 적용

1) 세 번째 합성곱 층 (Conv2)

 

2) 네 번째 합성곱 층 (Conv2)

 

3) 다섯 번째 합성곱 층 (Conv2)

4) 세 번째 맥스풀링 층(Max Pooling)

 

# 5️⃣ 6️⃣ 7️⃣ 세 번째, 네 번째, 다섯 번째 합성곱 층 (Conv3)
conv3 = nn.Conv2d(256, 384, kernel_size=3, stride=1, padding=1)
x = F.relu(conv3(x))

conv4 = nn.Conv2d(384, 384, kernel_size=3, stride=1, padding=1)
x = F.relu(conv4(x))

conv5 = nn.Conv2d(384, 256, kernel_size=3, stride=1, padding=1)
x = F.relu(conv5(x))

# 8️⃣ 세 번째 맥스 풀링 층 (MaxPool3)
pool3 = nn.MaxPool2d(kernel_size=3, stride=2)
x = pool3(x)

print(f'After Pool3: {x.shape}')
After Pool3: torch.Size([1, 256, 6, 6])

4. 분류기(Classifier)

분류기 부분은 특징 추출기에서 추출한 특징들을 바탕으로 최종 클래스를 예측하는 역할을 합니다. 주로 완전 연결 층과 소프트맥스 활성화 함수로 구성되어 있습니다.

4.1. 평탄화, 드롭아웃 및 완전 연결 층을 통한 최종 출력 과정

1) 첫 번째 드롭아웃 층(Dropout 1)

 

2) 첫 번째 완전 연결 층(FC 1)

 

3) 두 번째 드롭아웃 층(Dropout 2)

 

4) 출력층

 

# Flatten
x = x.view(x.size(0), -1)

# 9️⃣ 첫 번째 드롭아웃 층 (Dropout1)
dropout1 = nn.Dropout(p=0.5)
x = dropout1(x)

# 🔟 첫 번째 완전 연결 층 (FC1)
fc1 = nn.Linear(256 * 6 * 6, 4096)
x = F.relu(fc1(x))
print(f'After FC1: {x.shape}')

# 1️⃣1️⃣ 두 번째 드롭아웃 층 (Dropout2)
dropout2 = nn.Dropout(p=0.5)
x = dropout2(x)

# 1️⃣2️⃣ 두 번째 완전 연결 층 (FC2)
fc2 = nn.Linear(4096, 4096)
x = F.relu(fc2(x))
print(f'After FC2: {x.shape}')

# 1️⃣3️⃣ 출력 층 (Output)
fc3 = nn.Linear(4096, 1000)
x = fc3(x)
print(f'Output shape: {x.shape}')
After FC1: torch.Size([1, 4096])
After FC2: torch.Size([1, 4096])
Output shape: torch.Size([1, 1000])

5. 클래스로 구현한 AlexNet 모델

1) AlexNet 모델 클래스 정의

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()

        # 특징 추출 (feature extraction) 부분을 위한 레이어 정의
        self.conv1 = nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2)
        self.conv2 = nn.Conv2d(96, 256, kernel_size=5, stride=1, padding=2)
        self.conv3 = nn.Conv2d(256, 384, kernel_size=3, stride=1, padding=1)
        self.conv4 = nn.Conv2d(384, 384, kernel_size=3, stride=1, padding=1)
        self.conv5 = nn.Conv2d(384, 256, kernel_size=3, stride=1, padding=1)

        self.pool = nn.MaxPool2d(kernel_size=3, stride=2)

        # 분류기(Classifier) 부분을 위한 레이어 정의
        self.fc1 = nn.Linear(256 * 6 * 6, 4096)
        self.fc2 = nn.Linear(4096, 4096)
        self.fc3 = nn.Linear(4096, 1000)

        self.dropout = nn.Dropout()

    def forward(self, x):
        # 특징 추출 (feature extraction) 부분
        x = F.relu(self.conv1(x))
        x = self.pool(x)
        x = F.relu(self.conv2(x))
        x = self.pool(x)
        x = F.relu(self.conv3(x))
        x = F.relu(self.conv4(x))
        x = F.relu(self.conv5(x))
        x = self.pool(x)

        # 완전 연결 계층을 위한 텐서 평탄화
        x = x.view(x.size(0), -1)

        # 분류기(Classifier) 부분
        x = self.dropout(x)
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x

 

2) AlexNet 모델 초기화 및 요약 출력

from torchsummary import summary

model = AlexNet()
summary(model, (3, 227, 227))
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1           [-1, 96, 56, 56]          34,944
         MaxPool2d-2           [-1, 96, 27, 27]               0
            Conv2d-3          [-1, 256, 27, 27]         614,656
         MaxPool2d-4          [-1, 256, 13, 13]               0
            Conv2d-5          [-1, 384, 13, 13]         885,120
            Conv2d-6          [-1, 384, 13, 13]       1,327,488
            Conv2d-7          [-1, 256, 13, 13]         884,992
         MaxPool2d-8            [-1, 256, 6, 6]               0
           Dropout-9                 [-1, 9216]               0
           Linear-10                 [-1, 4096]      37,752,832
          Dropout-11                 [-1, 4096]               0
           Linear-12                 [-1, 4096]      16,781,312
           Linear-13                 [-1, 1000]       4,097,000
================================================================
Total params: 62,378,344
Trainable params: 62,378,344
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.59
Forward/backward pass size (MB): 6.15
Params size (MB): 237.95
Estimated Total Size (MB): 244.69
-----------

 

5.1. AlexNet 아키텍처 요약

이것이 AlexNet 모델의 전체 아키텍처입니다. 총 6천 230만 개의 학습 가능한 매개변수를 가지고 있으며, 깊은 합성곱 네트워크와 완전 연결 층을 통해 이미지 분류 작업에서 뛰어난 성능을 발휘합니다.

 

 

5.2. AlexNet이 중요한 이유

획기적인 성능: 2012년에 이미지 분류 정확도에서 큰 향상을 이루어 머신 러닝 알고리즘의 강력함을 보여주었습니다.
깊은 아키텍처: 8개의 층으로 이루어진 깊은 네트워크를 활용하여 CNN 아키텍처의 발전에 기여했습니다.
GPU 사용: GPU를 활용하여 훈련 속도를 높이고, 대규모 데이터셋 처리 의 성능과 효율성을 크게 향상시켰습니다.

 

혁신적인 기술
ReLU 활성화 함수: 빠른 훈련을 위한 ReLU 활성화 함수 사용.
드롭아웃: 과적합 방지를 위해 훈련 중 뉴런을 무작위로 드롭.
데이터 증강: 이미지 변환 및 반사를 통한 데이터 증강으로 모델 일반화 향상.
대규모 데이터: 수백만 개의 이미지가 포함된 대규모 ImageNet 데이터 셋에서 훈련되어 머신 러닝에서 다양한 데이터셋의 중요성을 강조


5.3. 결론

AlexNet은 2012년 대회에서 top-5 오류율 15.3%로 우승하였으며, 이는 2위의 top-5 오류율 26.2%에 비해 우수한 성적이었습니다. AlexNet의 성공은 주로 훈련을 위해 GPU를 활용하고 이 많은 매개변수를 훈련할 수 있었기 때문입니다. 이후의 계층에서는 AlexNet을 넘어서는 개선이 여러 번 이루어져 VGG, GoogLeNet, ResNet과 같은 모델이 탄생했습니다.


6. Torchvision으로 불러온 AlexNet 사전 학습 모델

from torchvision import models

AlexNet_model = models.alexnet(pretrained=True)
print(AlexNet_model)
AlexNet(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (4): ReLU(inplace=True)
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace=True)
    (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU(inplace=True)
    (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(6, 6))
  (classifier): Sequential(
    (0): Dropout(p=0.5, inplace=False)
    (1): Linear(in_features=9216, out_features=4096, bias=True)
    (2): ReLU(inplace=True)
    (3): Dropout(p=0.5, inplace=False)
    (4): Linear(in_features=4096, out_features=4096, bias=True)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)

 

# 입력 데이터 생성
x = torch.randn(1, 3, 227, 227)

# 순전파
logits = AlexNet_model(x)
print(logits.shape)  # (1, 1000)

# 손실 함수 정의 및 사용
criterion = nn.CrossEntropyLoss()
target = torch.tensor([1])  # 예시 정답 레이블
loss = criterion(logits, target)
print(loss)
torch.Size([1, 1000])
tensor(9.9485, grad_fn=<NllLossBackward0>)

 

※ 사전 훈련된 모델과의 차이점 

 

학습시간
사전 훈련된 모델: 이미 ImageNet과 같은 대규모 데이터셋에서 학습된 가중치를 사용하기 때문에 추가 학습 시간이 절약됩니다. 필요한 경우 사전 훈련된 가중치를 기반으로 추가 학습(파인 튜닝)을 진행하면 됩니 다.
사전 훈련되지 않은 모델: 모델의 가중치가 무작위로 초기화되어 있기 때문에, 처음부터 모든 가중치를 학습시켜야 합니다. 이는 더 긴 학습 시간이 필요함을 의미합니다.


성능
사전 훈련된 모델: 일반적으로 좋은 초기 성능을 가지며, 학습된 가중치가 이미지를 잘 분류하는 데 도움이 됩니다. 추가 학습을 통해 성능을 더 향상시킬 수 있습니다.
사전 훈련되지 않은 모델: 초기 성능이 낮을 가능성이 높으며, 충분한 양 질의 데이터를 사용하여 학습시키지 않으면 성능이 좋지 않을 수 있습니다.


데이터 요구사항
사전 훈련된 모델: 특정 작업을 위해 적은 양의 데이터만 추가로 사용하여도 좋은 성능을 낼 수 있습니다.
사전 훈련되지 않은 모델: 일반적으로 더 많은 데이터와 더 긴 학습시간이 필요합니다. 특히, 대규모 데이터셋이 없으면 모델이 과적합될 가능성이 높습니다.


결론
pretrained=False로 설정하여 사전 훈련되지 않은 AlexNet 모델을 사용 할때는 더 긴 학습 시간과 더 많은 데이터가 필요할 수 있습니다. 반면, 사전 훈련된 모델을 사용하면 학습 시간을 절약하고, 초기 성능이 좋기 때문에 특정 작업에 빠르게 적용할 수 있습니다. 따라서, 작업의 성격과 데이터 가용성에 따라 사전 훈련된 모델을 사용할지, 사전 훈련되지 않은 모델을 사용할지 결정해야 합니다.

'딥러닝 > 딥러닝: 자연어' 카테고리의 다른 글

자연어 처리 모델  (0) 2025.02.26
임베딩(Embedding)  (0) 2025.02.25
LeNet-5 (1998)  (0) 2025.02.24
토크나이저  (0) 2025.02.19
자연어 데이터 전처리  (0) 2025.02.13