4. Alexnet 구현하기

2025. 1. 20. 14:17LLM(Large Language Model)의 기초/딥러닝

1. Alexnet
* AlexNet은 2012년 ILSVRC(ImageNet Large Scale Visual Recognition Challenge)에서 우승한 딥러닝 모델로, 딥러닝의 대중화를 이끈 중요한 합성곱 신경망(CNN)입니다. 
* 이 모델은 8개의 레이어(5개의 합성곱 레이어와 3개의 완전 연결 레이어)로 구성되어 있으며, ReLU 활성화 함수, 드롭아웃(dropout), 데이터 증강(data augmentation) 등을 사용해 과적합을 방지하고 학습 성능을 향상시켰습니다. 
* AlexNet은 대규모 데이터셋과 GPU 병렬 연산을 활용해 1,000개의 클래스 분류 문제에서 top-1, top-5 error rates가 각각 37.5%, 17.5%로 뛰어난 성능을 보여, 컴퓨터 비전에서 딥러닝이 표준 기법으로 자리 잡는 데 기여했습니다. 
* 이 성과는 당시 기준으로 매우 뛰어난 결과였습니다. 
* 특히 AlexNet은 이전에 사용된 전통적인 머신러닝 방법론보다 훨씬 큰 차이로 성능을 끌어올리며, 딥러닝의 가능성을 보여주었습니다

논문 링크 : https://papers.nips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf
참고 링크 : https://pytorch.org/vision/stable/generated/torchvision.datasets.CIFAR10.html#torchvision.datasets.CIFAR10


 

 
※ ImageNet LSVRC

* ImageNet LSVRC는 Large Scale Visual Recognition Challenge의 약자로, 이미지 인식 및 분류 기술을 겨루는 대회입니다. 
* 2010년부터 매년 개최되었으며, ImageNet이라는 대규모 이미지 데이터셋을 기반으로 참가자들이 다양한 모델을 설계하고 경쟁했습니다.

* ImageNet 데이터셋: 약 1400만 장의 이미지를 포함하며, 1000개의 클래스(예: 고양이, 강아지, 자동차 등)로 분류된 대규모 이미지 데이터셋입니다.
* 목적: 컴퓨터 비전 및 딥러닝 기술의 발전을 촉진하고, 이미지 인식 분야에서 혁신적인 기술을 발견하는 것이 목표였습니다.
* LSVRC-2010: 이 대회에서 AlexNet이 2012년에 처음으로 딥러닝 기반 접근법을 사용해 뛰어난 성능을 보여줌으로써 딥러닝의 새로운 시대를 열었습니다.
 
### Error Rate
* 이미지 분류 모델의 성능을 평가하는 지표로, 모델이 이미지를 얼마나 정확히 분류했는지를 나타냅니다.

1. Top-1 Error Rate
* 모델이 예측한 가장 높은 확률의 클래스(Top-1)가 정답이 아닐 확률입니다.
예를 들어, 이미지에 "고양이"가 있고, 모델이 가장 높은 확률로 "강아지"라고 예측했다면, 이건 Top-1 에러입니다.

2. Top-5 Error Rate
* 모델이 예측한 상위 5개의 클래스 중 하나라도 정답에 포함되지 않았을 확률입니다.
* 예를 들어, 이미지가 "고양이"인데 모델이 "강아지", "토끼", "고양이", "호랑이", "여우"를 상위 5개로 예측했다면, 이건 정답으로 간주됩니다.
    * Top-5를 사용하는 이유: 사람이 보기에 유사한 클래스(예: 치타와 표범)를 분류하는 것은 어렵기 때문에, 상위 5개 중에 정답이 있는지를 확인하는 방식으로 보다 실용적인 성능을 평가합니다.
 
2. CIFAR 데이터셋
* CIFAR 데이터셋은 torchvision 라이브러리에서 제공하는 이미지 데이터셋으로, 주로 딥러닝 모델의 학습 및 평가에 사용됩니다. 
* CIFAR-10과 CIFAR-100 두 종류가 있으며, 각각 10개와 100개의 클래스에 대해 32x32 크기의 컬러 이미지로 구성됩니다. 
* CIFAR-10은 클래스당 6,000개(총 60,000개)의 이미지로 이루어져 있으며, CIFAR-100은 클래스당 600개(총 60,000개)로 구성됩니다. 
* PyTorch는 torchvision.datasets 모듈을 통해 이 데이터셋을 쉽게 불러올 수 있으며, 학습/테스트 데이터셋 분리, 데이터 증강(transforms), 정규화 등의 전처리를 지원합니다. 
* 이 데이터셋은 이미지 분류 알고리즘을 실험하고 비교하는 데 널리 사용됩니다.
 
 
3. Alexnet 직접 구현(CIFAR 데이터셋 사용)
링크 주소: https://pytorch.org/vision/stable/datasets.html

 

Datasets — Torchvision 0.20 documentation

Shortcuts

pytorch.org

 
예시 1)

import numpy as np
import matplotlib.pyplot as plt

# PyTorch 라이브러리 import
import torch
from torch.utils.data import DataLoader
from torch import nn

# torchvision 라이브러리에서 데이터셋과 변환(transform)을 import
from torchvision import datasets
from torchvision.transforms import transforms
from torchvision.transforms.functional import to_pil_image

# CIFAR-10 데이터셋 로드 (학습용 데이터셋)
train_img = datasets.CIFAR10(
    root='data',  # 데이터를 저장할 경로
    train=True,  # 학습용 데이터셋을 다운로드
    download=True,  # 데이터셋이 없으면 다운로드
    transform=transforms.ToTensor()  # 이미지를 텐서(Tensor) 형태로 변환
)

# CIFAR-10 데이터셋 로드 (테스트용 데이터셋)
test_img = datasets.CIFAR10(
    root='data',  # 데이터를 저장할 경로
    train=False,  # 학습용 데이터셋을 다운로드
    download=True,  # 데이터셋이 없으면 다운로드
    transform=transforms.ToTensor()  # 이미지를 텐서(Tensor) 형태로 변환
)

 
예시 2)

# CIFAR-10 데이터셋의 채널별 평균과 표준편차 계산
mean = train_img.data.mean(axis=(0,1,2)) / 255  # 픽셀 값의 평균 계산 (0~255 범위를 0~1로 정규화)
std = train_img.data.std(axis=(0,1,2)) / 255  # 픽셀 값의 표준편차 계산 (0~255 범위를 0~1로 정규화)
print(f'평균:{mean}, 표준편차:{std}')  # 계산된 평균과 표준편차 출력
--->
평균:[0.49139968 0.48215841 0.44653091], 표준편차:[0.24703223 0.24348513 0.26158784]

 
예시 3)

# 학습 데이터에 사용할 변환(transform) 정의
transform_train = transforms.Compose([
    transforms.ToTensor(),  # 이미지를 텐서(Tensor)로 변환
    transforms.RandomCrop(size=train_img.data.shape[1], padding=4),  # 이미지를 랜덤하게 자르고(padding 포함) 크기 유지
    transforms.RandomHorizontalFlip(),  # 이미지를 좌우로 랜덤하게 뒤집기
    transforms.Normalize(mean, std)  # 데이터 정규화 (평균과 표준편차를 이용해 스케일링)
])

# 테스트 데이터에 사용할 변환(transform) 정의
transform_test = transforms.Compose([
    transforms.ToTensor(),  # 이미지를 텐서(Tensor)로 변환
    transforms.Normalize(mean, std)  # 데이터 정규화 (평균과 표준편차를 이용해 스케일링)
])

 
예시 4)

# CIFAR-10 학습용 데이터셋 로드 (transform_train 적용)
train_img = datasets.CIFAR10(
    root='data',  # 데이터를 저장할 경로
    train=True,  # 학습용 데이터셋을 다운로드
    download=True,  # 데이터셋이 없으면 다운로드
    transform=transform_train  # 학습 데이터에 정의한 변환 적용
)

# CIFAR-10 테스트용 데이터셋 로드 (transform_test 적용)
test_img = datasets.CIFAR10(
    root='data',  # 데이터를 저장할 경로
    train=False,  # 학습용 데이터셋을 다운로드
    download=True,  # 데이터셋이 없으면 다운로드
    transform=transform_test  # 테스트 데이터에 정의한 변환 적용
)

 
예시 5)

# 학습 관련 설정
EPOCH = 10  # 전체 학습 반복(epoch) 수
BATCH_SIZE = 128  # 한 번의 학습에 사용할 배치 크기
LEARNING_RATE = 1e-3  # 학습률(learning rate)

# 학습에 사용할 디바이스 설정 (GPU가 사용 가능하면 GPU 사용, 아니면 CPU 사용)
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # CUDA 사용 가능 여부 확인
print("Using Device:", DEVICE)  # 선택된 디바이스 출력

 
예시 6)

# DataLoader를 사용하여 학습 데이터와 테스트 데이터를 배치 단위로 로드
train_loader = DataLoader(
    train_img,  # 학습용 데이터셋
    batch_size=BATCH_SIZE,  # 배치 크기 설정
    shuffle=True  # 데이터를 섞어서 로드 (학습에 유리)
)

test_loader = DataLoader(
    test_img,  # 테스트용 데이터셋
    batch_size=BATCH_SIZE,  # 배치 크기 설정
    shuffle=False  # 데이터를 섞지 않고 로드 (평가 시 순서 유지)
)

# 학습 데이터셋과 테스트 데이터셋 정보를 출력
print(train_img, '\n------------------\n', test_img)
--->
Dataset CIFAR10
    Number of datapoints: 50000
    Root location: data
    Split: Train
    StandardTransform
Transform: Compose(
               ToTensor()
               RandomCrop(size=(32, 32), padding=4)
               RandomHorizontalFlip(p=0.5)
               Normalize(mean=[0.49139968 0.48215841 0.44653091], std=[0.24703223 0.24348513 0.26158784])
           ) 
------------------
 Dataset CIFAR10
    Number of datapoints: 50000
    Root location: data
    Split: Train
    StandardTransform
Transform: Compose(
               ToTensor()
               Normalize(mean=[0.49139968 0.48215841 0.44653091], std=[0.24703223 0.24348513 0.26158784])
           )

 
 
예시 7)

# 학습 데이터셋의 첫 번째 샘플 가져오기
# train_img[0]은 CIFAR-10 데이터셋의 첫 번째 샘플을 반환
# 반환값은 (이미지, 레이블)의 튜플로 구성됨
first_sample = train_img[0]  # 첫 번째 샘플 가져오기
# first_sample의 구조: (이미지 텐서, 정수형 레이블)
# 예: CIFAR-10의 경우, 이미지 텐서는 (채널, 높이, 너비)의 형태를 가지며 레이블은 해당 이미지의 클래스 정보
-->
(tensor([[[-1.9892e+00,  3.6025e-01,  4.2375e-01,  ..., -9.0973e-01,
           -1.1955e+00, -1.3066e+00],
          [-1.9892e+00, -5.2496e-02, -1.0012e-01,  ..., -1.1796e+00,
           -1.7035e+00, -1.9892e+00],
          [-1.9892e+00, -2.5887e-01, -8.4246e-02,  ..., -6.7161e-01,
           -1.2114e+00, -1.7352e+00],
          ...,
          [-1.9892e+00, -1.1479e+00, -1.1002e+00,  ...,  1.0429e+00,
            1.1540e+00,  1.2016e+00],
          [-1.9892e+00, -6.7161e-01, -4.4936e-01,  ...,  1.0905e+00,
            9.6349e-01,  7.5711e-01],
          [-1.9892e+00, -3.6622e-02,  4.0787e-01,  ...,  9.9524e-01,
            8.5236e-01,  6.7774e-01]],
 
         [[-1.9802e+00,  1.6905e-02,  3.3011e-02,  ..., -1.1105e+00,
           -1.2072e+00, -1.2394e+00],
          [-1.9802e+00, -5.7902e-01, -6.4344e-01,  ..., -1.5454e+00,
           -1.8514e+00, -1.9802e+00],
          [-1.9802e+00, -8.0450e-01, -6.2733e-01,  ..., -1.1749e+00,
           -1.5454e+00, -1.8675e+00],
          ...,
          [-1.9802e+00, -1.4326e+00, -1.4810e+00,  ...,  5.4840e-01,
            6.1283e-01,  4.8398e-01],
          [-1.9802e+00, -1.1266e+00, -9.8167e-01,  ...,  4.8398e-01,
            3.3902e-01,  7.9890e-04],
          [-1.9802e+00, -4.9849e-01, -7.9731e-02,  ...,  4.1955e-01,
            3.0681e-01,  9.7435e-02]],
 
         [[-1.7070e+00, -1.6289e-01, -1.7788e-01,  ..., -1.0774e+00,
           -1.0624e+00, -1.0324e+00],
          [-1.7070e+00, -8.5249e-01, -9.5743e-01,  ..., -1.5871e+00,
           -1.7070e+00, -1.7070e+00],
          [-1.7070e+00, -1.0774e+00, -9.5743e-01,  ..., -1.3622e+00,
           -1.5871e+00, -1.7070e+00],
          ...,
          [-1.7070e+00, -1.4072e+00, -1.6021e+00,  ..., -1.3022e+00,
           -1.3172e+00, -1.1973e+00],
          [-1.7070e+00, -1.1973e+00, -1.1973e+00,  ..., -1.3322e+00,
           -1.2573e+00, -1.0774e+00],
          [-1.7070e+00, -6.2762e-01, -4.4772e-01,  ..., -7.0258e-01,
           -4.0275e-01, -2.9781e-01]]]),
 6)

 
예시 8)

# 학습 데이터에서 첫 번째 배치 가져오기
# DataLoader를 통해 배치 단위로 데이터를 로드하고, 첫 번째 배치를 가져옴
train_features, train_labels = next(iter(train_loader))
# train_features: 배치에 포함된 이미지 데이터 (배치 크기, 채널, 높이, 너비)
# train_labels: 배치에 포함된 레이블 데이터 (배치 크기)

# 배치의 크기 및 구조 출력
print(f'Feature batch shape: {train_features.size()}')  # 이미지 텐서의 크기 출력
print(f"Labels batch shape: {train_labels.size()}")  # 레이블 텐서의 크기 출력
--->
eature batch shape: torch.Size([128, 3, 32, 32])
Labels batch shape: torch.Size([128])

 
예시 9)

# CIFAR-10 데이터셋의 레이블과 클래스 이름을 매핑하는 딕셔너리 정의
labels_map = {
    0: "plane",  # 클래스 0: 비행기
    1: "car",    # 클래스 1: 자동차
    2: "bird",   # 클래스 2: 새
    3: "cat",    # 클래스 3: 고양이
    4: "deer",   # 클래스 4: 사슴
    5: "dog",    # 클래스 5: 개
    6: "frog",   # 클래스 6: 개구리
    7: "horse",  # 클래스 7: 말
    8: "ship",   # 클래스 8: 배
    9: "truck",  # 클래스 9: 트럭
}

 
예시 10)

# 정규화된 이미지를 원래 픽셀 값으로 되돌리는 함수 정의
def denormalize(img, mean, std):
    # mean과 std를 텐서 형태로 변환하고 이미지와 동일한 차원으로 맞춤
    mean = torch.tensor(mean).view(3, 1, 1)  # 3: 이미지 채널, 1: 공간 차원(높이와 너비)
    std = torch.tensor(std).view(3, 1, 1)  # 3: 이미지 채널, 1: 공간 차원(높이와 너비)
    
    # 정규화된 이미지에 표준편차를 곱하고 평균을 더해 원래 값으로 복원
    return img * std + mean

 
예시 11)

import torch
import matplotlib.pyplot as plt
from torchvision.transforms.functional import to_pil_image

# PyTorch에서 사용할 데이터셋과 관련된 설정 (가정: train_img, mean, std, labels_map이 이미 정의되어 있음)

figure = plt.figure(figsize=(8, 8))  # 그림 크기를 8x8로 설정
cols, rows = 5, 5  # 5x5 격자에 이미지를 표시하기 위한 열과 행의 수

for i in range(1, cols * rows + 1):  # 총 25개의 이미지를 표시하기 위해 반복문 실행
    # 데이터셋에서 랜덤한 인덱스 선택
    sample_idx = torch.randint(len(train_img), size=(1,)).item()
    
    # 선택한 인덱스의 이미지와 라벨 가져오기
    img, label = train_img[sample_idx]
    
    # denormalize: 이미지를 복원 (normalize 과정을 역으로 수행)
    img = denormalize(img, mean, std)  # denormalize 함수는 사용자 정의 함수라고 가정

    # 행렬에 subplot 추가 (5x5 격자의 i번째 위치)
    figure.add_subplot(rows, cols, i)
    
    # subplot에 라벨(title) 추가 (라벨을 labels_map에서 매핑)
    plt.title(labels_map[label])
    
    # 축 숨김
    plt.axis('off')

    # 텐서를 PIL 이미지로 변환 후 subplot에 표시
    # to_pil_image: 텐서를 PIL 이미지로 변환하는 함수
    # 텐서 이미지는 0~1 또는 0~255 범위를 가져야 함
    plt.imshow(to_pil_image(img))

# 모든 subplot을 화면에 표시
plt.show()

--->

 
예시 12)

import torch
import torch.nn as nn

# AlexNet 모델 정의
class AlexNet(nn.Module):
    def __init__(self, num_classes=10):
        super(AlexNet, self).__init__()
        
        # 특징 추출 부분 (Feature Extractor)
        self.features = nn.Sequential(
            # 첫 번째 합성곱 계층 (Conv1)
            nn.Conv2d(3, 96, kernel_size=3, stride=1, padding=1),  # 입력 채널: 3, 출력 채널: 96, 커널 크기: 3x3, 스트라이드: 1, 패딩: 1
            nn.ReLU(inplace=True),                                # 활성화 함수 ReLU
            nn.MaxPool2d(kernel_size=2, stride=2),               # 첫 번째 최대 풀링 계층 (2x2 커널, 스트라이드 2)

            # 두 번째 합성곱 계층 (Conv2)
            nn.Conv2d(96, 256, kernel_size=3, padding=1),        # 입력 채널: 96, 출력 채널: 256, 커널 크기: 3x3, 패딩: 1
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),               # 두 번째 최대 풀링 계층

            # 세 번째 합성곱 계층 (Conv3)
            nn.Conv2d(256, 384, kernel_size=3, padding=1),       # 입력 채널: 256, 출력 채널: 384, 커널 크기: 3x3, 패딩: 1
            nn.ReLU(inplace=True),

            # 네 번째 합성곱 계층 (Conv4)
            nn.Conv2d(384, 384, kernel_size=3, padding=1),       # 입력 채널: 384, 출력 채널: 384, 커널 크기: 3x3, 패딩: 1
            nn.ReLU(inplace=True),

            # 다섯 번째 합성곱 계층 (Conv5)
            nn.Conv2d(384, 256, kernel_size=3, padding=1),       # 입력 채널: 384, 출력 채널: 256, 커널 크기: 3x3, 패딩: 1
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),               # 세 번째 최대 풀링 계층
        )

        # 분류기 부분 (Classifier)
        self.classifier = nn.Sequential(
            nn.Linear(256 * 4 * 4, 4096),  # 첫 번째 완전 연결 계층 (Flatten 크기: 256*4*4 -> 4096)
            nn.Dropout(0.5),               # 드롭아웃 계층 (50% 확률로 뉴런 비활성화)
            nn.ReLU(inplace=True),         # 활성화 함수 ReLU

            nn.Linear(4096, 4096),         # 두 번째 완전 연결 계층
            nn.Dropout(0.5),               # 드롭아웃 계층
            nn.ReLU(inplace=True),

            nn.Linear(4096, num_classes),  # 세 번째 완전 연결 계층 (출력: 클래스 수)
        )

    # 순전파(Forward) 정의
    def forward(self, x):
        x = self.features(x)               # 특징 추출
        x = x.view(x.size(0), -1)          # Flatten (다차원 텐서를 1차원으로 펼침)
        x = self.classifier(x)             # 분류 수행
        return x

 
예시 13)

# Model instance 생성 및 Device로 이동
model = AlexNet().to(DEVICE)  # AlexNet 인스턴스를 생성하고, DEVICE로 이동 (GPU 또는 CPU)
print(model)  # 모델의 구조 출력
--->
AlexNet(
  (features): Sequential(
    (0): Conv2d(3, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(96, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (4): ReLU(inplace=True)
    (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(256, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace=True)
    (8): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU(inplace=True)
    (10): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (classifier): Sequential(
    (0): Linear(in_features=4096, out_features=4096, bias=True)
    (1): Dropout(p=0.5, inplace=False)
    (2): ReLU(inplace=True)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): Dropout(p=0.5, inplace=False)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=4096, out_features=10, bias=True)
  )
)

 
예시 14)

# 손실 함수 설정
loss = nn.CrossEntropyLoss()  # 교차 엔트로피 손실 함수, 분류 문제에서 주로 사용

# 최적화 알고리즘 설정
optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)  # Adam 최적화 알고리즘, 학습률은 LEARNING_RATE로 설정

 
예시 15)

# 모델 학습 함수 정의
def train(train_loader, model, loss_fn, optimizer):
    model.train()  # 모델을 학습 모드로 설정
    
    size = len(train_loader.dataset)  # 전체 학습 데이터 크기
    
    for batch, (X, y) in enumerate(train_loader):  # 배치 단위로 데이터 로드
        X, y = X.to(DEVICE), y.to(DEVICE)  # 입력 데이터(X)와 라벨(y)를 DEVICE로 이동
        pred = model(X)  # 모델을 통해 예측 수행

        # 손실 계산
        loss = loss_fn(pred, y)

        # 역전파 단계
        optimizer.zero_grad()  # 이전 단계에서의 그래디언트 초기화
        loss.backward()        # 그래디언트 계산
        optimizer.step()       # 파라미터 업데이트

        # 100번째 배치마다 손실 정보 출력
        if batch % 100 == 0:
            loss, current = loss.item(), batch * len(X)
            print(f'loss: {loss:>7f}  [{current:>5d}]/{size:5d}')

 
예시 16)

# 모델 테스트 함수 정의
def test(test_loader, model, loss_fn):
    model.eval()  # 모델을 평가 모드로 설정

    size = len(test_loader.dataset)  # 전체 테스트 데이터 크기
    num_batches = len(test_loader)  # 배치 개수
    test_loss, correct = 0, 0  # 초기화

    with torch.no_grad():  # 그래디언트 계산 비활성화 (평가 시 필요 없음)
        for X, y in test_loader:  # 배치 단위로 데이터 로드
            X, y = X.to(DEVICE), y.to(DEVICE)  # 입력 데이터(X)와 라벨(y)를 DEVICE로 이동
            pred = model(X)  # 모델을 통해 예측 수행
            test_loss += loss_fn(pred, y).item()  # 배치 손실 계산 및 누적
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # 올바른 예측 개수 누적

    test_loss /= num_batches  # 평균 손실 계산
    correct /= size           # 정확도 계산
    print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:8f}\n")  # 결과 출력

 
예시 17)

# 모델 학습 및 평가 루프
for i in range(EPOCH):  # 전체 학습 epoch 반복
    print(f"Epoch {i+1} \n------------------------")  # 현재 epoch 출력
    train(train_loader, model, loss, optimizer)  # 학습 단계 실행
    test(test_loader, model, loss)               # 평가 단계 실행
print("Done!")  # 학습 완료 메시지 출력
-->
Epoch 10 
------------------------
loss: 0.652419  [    0]/50000
loss: 0.723971  [12800]/50000
loss: 0.659195  [25600]/50000
loss: 0.767987  [38400]/50000
Test Error: 
 Accuracy: 78.6%, Avg loss: 0.616753

Done!

 
### itertools
* 파이썬 표준 라이브러리 모듈로 반복과 관련된 효율적이고 고성능의 도구를 제공합니다.
다양한 반복 가능한 객체나 순열, 조합을 생성하거나 조작하는 함수들을 포함하고 있습니다. 
 
예시 1)

from itertools import product, permutations, combinations, islice

#데카르트 곱
# 데카르트 곱 계산 예제
color = ['red', 'blue']  # 색상 리스트
size = ['S', 'M', 'L']   # 사이즈 리스트

# itertools.product: 두 리스트의 모든 조합(데카르트 곱)을 생성
result = list(product(color, size))  # 색상과 사이즈의 가능한 모든 조합 생성
print(result)  # 결과 출력
-->
[('red', 'S'), ('red', 'M'), ('red', 'L'), ('blue', 'S'), ('blue', 'M'), ('blue', 'L')]

 
 
예시 2)

# 순열
# 순열 계산 예제
number = [1, 2, 3]  # 숫자 리스트
perm = list(permutations(number, 2))  # 길이가 2인 순열 생성
print(perm)  # 결과 출력

--->
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]

 
예제 3)

# 조합
# 조합 계산 예제
letter = ['A', 'B', 'C']  # 문자 리스트
comb = list(combinations(letter, 2))  # 길이가 2인 조합 생성
print(comb)  # 결과 출력
-->
[('A', 'B'), ('A', 'C'), ('B', 'C')]

 
예제 4)

# 슬라이싱
number = range(10)

#2부터 7까지, 간격을 2로 설정
sliced = list(islice(number, 2, 8, 2))
print(sliced)
--->
[2, 4, 6]

 
예제 5)

import itertools
# 혼동 행렬 시각화 함수 정의
def plot_confusion_matrix(cm, target_names=None, cmap=None, 
                          normalize=True, labels=True, title='Confusion matrix'):
    # np.trace: 혼돈 행렬의 대각선 요소 합을 계산하여 정확도 추출
    accuracy = np.trace(cm) / float(np.sum(cm))  # 정확도 계산
    misclass = 1 - accuracy  # 오분류율 계산

    # 색상 맵 설정
    if cmap is None:
        cmap = plt.get_cmap('Blues')

    # 정규화 옵션이 활성화된 경우 행별로 값을 정규화
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]  # 각 행의 합으로 나눔

    # 그래프 생성
    plt.figure(figsize=(8, 6))
    plt.imshow(cm, interpolation='nearest', cmap=cmap)  # 픽셀 간 간격 최소화
    plt.title(title)
    plt.colorbar()  # 범례 추가

    # 기준 임계값 설정
    thresh = cm.max() / 1.5 if normalize else cm.max() / 2

    # 클래스 이름이 주어진 경우 축 레이블 추가
    if target_names is not None:
        tick_marks = np.arange(len(target_names))
        plt.xticks(tick_marks, target_names)
        plt.yticks(tick_marks, target_names)

    # 각 셀에 레이블 표시 (정규화 여부에 따라 다르게 표시)
    if labels:
        for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
            if normalize:
                plt.text(j, i, "{:0.4f}".format(cm[i, j]),
                         horizontalalignment="center",
                         color="white" if cm[i, j] > thresh else "black")
            else:
                plt.text(j, i, "{:,}".format(cm[i, j]),
                         horizontalalignment="center",
                         color="white" if cm[i, j] > thresh else "black")

    # 레이아웃 정렬 및 축 레이블 설정
    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label\naccuracy={:0.4f}; misclass={:0.4f}'.format(accuracy, misclass))
    plt.show()

 
예제 6)

from sklearn.metrics import confusion_matrix

# 혼동 행렬 계산 및 모델 평가 코드
model.eval()  # 모델을 평가 모드로 설정
ylabel = []  # 실제 라벨을 저장할 리스트
ypred_label = []  # 예측된 라벨을 저장할 리스트

# 테스트 데이터 로더를 순회하며 예측 수행
for batch_idx, (inputs, targets) in enumerate(test_loader):
    inputs, targets = inputs.to(DEVICE), targets.to(DEVICE)  # 입력과 타겟 데이터를 DEVICE로 이동
    outputs = model(inputs)  # 모델을 통해 예측 수행
    _, predicted = outputs.max(1)  # 예측값에서 가장 높은 확률의 클래스 선택

    # 실제 타겟과 예측된 값을 리스트에 추가 (CPU로 이동하여 numpy 배열로 변환)
    ylabel = np.concatenate((ylabel, targets.cpu().numpy()))
    ypred_label = np.concatenate((ypred_label, predicted.cpu().numpy()))

# 혼동 행렬 계산
cnf_matrix = confusion_matrix(ylabel, ypred_label)  # 실제 값과 예측 값을 기반으로 혼동 행렬 생성

 
예제 7)

ylabel
-->
array([6., 9., 9., ..., 9., 1., 1.])

 
예제 8)

ypred_label
-->
array([5., 9., 9., ..., 9., 1., 8.])

 
예제 9)

# 혼동 행렬 계산
cnf_matrix = confusion_matrix(ylabel, ypred_label)  # 실제 값과 예측 값을 기반으로 혼동 행렬 생성
cnf_matrix
-->
array([[4234,   91,  199,   44,   48,   14,    7,   37,  237,   89],
       [  54, 4607,   13,   10,    5,   10,    6,    6,   86,  203],
       [ 297,   33, 3739,  142,  334,  179,  130,   90,   37,   19],
       [ 137,   27,  322, 2484,  338, 1206,  124,  221,   86,   55],
       [ 116,    7,  276,   91, 4150,  125,   72,  131,   22,   10],
       [  54,   10,  280,  410,  287, 3620,   28,  279,   16,   16],
       [  53,   83,  317,  210,  336,  167, 3742,   38,   27,   27],
       [  92,   11,  147,   88,  498,  188,    8, 3912,   11,   45],
       [ 233,   95,   45,   21,   25,   14,   10,    8, 4504,   45],
       [ 105,  330,   20,   35,   19,   19,    7,   39,  131, 4295]])

 
예제 10)

plot_confusion_matrix(cnf_matrix, 
                      target_names=labels_map.values(), 
                      title='Confusion matrix, trained by AlexNet')

---->

 

728x90
LIST