컴퓨터 비전

2. Classification

인공지능파이썬 2025. 2. 28. 15:55

1. 분류(Classification)
* 분류(Classification)는 이미지나 비디오에서 객체나 패턴을 식별하고, 이를 미리 정의된 카테고리 중 하나로 분류하는 작업입니다.
  * 예를 들어, 이미지에 나타난 고양이와 개를 구별하거나, 특정 물체가 무엇인지를 분류하는 것입니다.
* 이 과정은 이미지 데이터를 입력으로 받아, 딥러닝 모델이나 머신러닝 알고리즘을 통해 각 이미지가 어떤 클래스에 속하는지 예측하는 방식으로 진행됩니다.
* 이때 사용되는 대표적인 모델로는 Convolutional Neural Network(CNN)가 있으며, 학습된 모델은 새로운 이미지에 대해서도 빠르고 정확하게 분류할 수 있습니다.
* 분류는 크게 두 가지로 나눌 수 있습니다.
  * 이진 분류와 다중 클래스 분류입니다.
* 이진 분류는 두 개의 클래스 중 하나로 데이터를 분류하는 작업으로, 예를 들어 이메일을 '스팸'과 '비스팸'으로 구분하는 경우입니다.
* 반면, 다중 클래스 분류는 세 개 이상의 클래스로 데이터를 분류하는 작업으로, 예를 들어 이미지를 '고양이', '개', '새'와 같은 여러 카테고리로 분류하는 경우입니다.
* 또한, 다중 라벨 분류라는 유형도 존재하는데, 이는 하나의 입력에 대해 여러 개의 클래스를 동시에 예측하는 작업으로, 예를 들어 하나의 이미지에 여러 개의 물체가 있을 때 각 물체를 개별적으로 분류하는 경우에 해당합니다.



2. Surface Crack Detection 데이터셋
* Surface Crack Detection 데이터셋은 콘크리트 표면에서 균열을 자동으로 탐지하기 위한 학습 데이터를 제공합니다.
* 이 데이터셋은 주로 다양한 콘크리트 표면 이미지를 포함하고 있으며, 각 이미지는 균열이 포함된 부분과 그렇지 않은 부분으로 구분됩니다.
* 이러한 데이터셋은 컴퓨터 비전 모델, 특히 Convolutional Neural Network(CNN) 등의 딥러닝 모델을 훈련시키는 데 사용되며, 균열 탐지 및 구조물의 상태 평가에 중요한 역할을 합니다.
* 다양한 환경과 조건을 반영한 이미지를 제공하여, 실제 적용에서 발생할 수 있는 다양한 상황에 대한 모델의 일반화 능력을 높이는 데 도움을 줍니다

링크 주소 : https://www.kaggle.com/datasets/arunrk7/surface-crack-detection

 

Surface Crack Detection

Concrete surface sample images for Surface Crack Detection

www.kaggle.com

 

예시 1)

# kaggle 에서 가져오기
!kaggle datasets download arunrk7/surface-crack-detection

 

예시 2)

# 압축 풀기
!unzip -q /content/surface-crack-detection.zip

 

예시 3)

import os
import shutil
import random
import torch
import glob
import numpy as np
from torch.utils.data import Subset
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from torchvision.datasets import ImageFolder
from torchvision.models import vgg19, VGG19_Weights
from torchvision import datasets, models, transforms
from torch.utils.data import DataLoader
from PIL import Image
from torch.utils.data import SubsetRandomSampler

 

예시 4)

# device 사용 여부
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)

 

예시 5)

# train, val, test 폴더 및 하위 폴더 생성
dataset_structure = ['train/negative', 'train/positive',
                          'val/negative', 'val/positive',
                          'test/negative', 'test/positive']

 

예시 6)

##folder 생성
for folder in dataset_structure:
  os.makedirs(folder, exist_ok=True)

 

예시 7)

# 데이터 분할 및 복사
categories = ['Negative', 'Positive']

for category in categories:
    files = os.listdir(category)
    random.shuffle(files)
    num_files = len(files)
    train_split = int(num_files * 0.6)
    val_split = int(num_files * 0.2)

    train_files = files[:train_split]
    val_files = files[train_split:train_split + val_split]
    test_files = files[train_split + val_split:]

    target_category = category.lower()

    for file in train_files:
        shutil.copy(os.path.join(category, file), f'train/{target_category}/')
    for file in val_files:
        shutil.copy(os.path.join(category, file), f'val/{target_category}/')
    for file in test_files:
        shutil.copy(os.path.join(category, file), f'test/{target_category}/')

print("데이터 분할 및 복사 완료!")

 

예시 8)

# 폴더 경로 설정
train_positive_dir = "train/positive"
train_negative_dir = "train/negative"


# 각 폴더에서 4개씩 샘플링
positive_files = random.sample(os.listdir(train_positive_dir), 4)
negative_files = random.sample(os.listdir(train_negative_dir), 4)

print(positive_files)
print(negative_files)
-->
['03108.jpg', '09198.jpg', '00932.jpg', '12690_1.jpg']
['11177.jpg', '02028.jpg', '06301.jpg', '02204.jpg']

 

예시 9)

# 파일 경로 리스트 생성
positive_paths = [os.path.join(train_positive_dir, file) for file in positive_files]
negative_paths = [os.path.join(train_negative_dir, file) for file in negative_files]
print(positive_paths)
print(negative_paths)
-->
['train/positive/03108.jpg', 'train/positive/09198.jpg', 'train/positive/00932.jpg', 'train/positive/12690_1.jpg']
['train/negative/11177.jpg', 'train/negative/02028.jpg', 'train/negative/06301.jpg', 'train/negative/02204.jpg']

 

예시 10)

# 이미지 시각화를 위한 서브플롯 생성
fig, axes = plt.subplots(2, 4, figsize=(12, 6))  # 2x4 형태의 플롯을 생성하고, 전체 크기를 (12,6)으로 설정
fig.suptitle("Train Dataset Samples", fontsize=16)  # 전체 제목 설정

# 긍정(Positive) 샘플 이미지 표시
for i, file_path in enumerate(positive_paths):  # positive_paths 리스트에서 이미지 경로를 하나씩 가져옴
    image = Image.open(file_path)  # 이미지 파일을 열기
    axes[0, i].imshow(image)  # 첫 번째 행(0행)에 이미지를 표시
    axes[0, i].axis("off")  # 축(좌표) 숨기기
    axes[0, i].set_title("Positive")  # 타이틀(Positive) 설정

# 부정(Negative) 샘플 이미지 표시
for i, file_path in enumerate(negative_paths):  # negative_paths 리스트에서 이미지 경로를 하나씩 가져옴
    image = Image.open(file_path)  # 이미지 파일을 열기
    axes[1, i].imshow(image)  # 두 번째 행(1행)에 이미지를 표시
    axes[1, i].axis("off")  # 축(좌표) 숨기기
    axes[1, i].set_title("Negative")  # 타이틀(Negative) 설정

# 그래프 출력
plt.show()  # 플롯(이미지 시각화) 표시

--->

 

예시 11)

# 데이터 전처리 정의
transform = transforms.Compose([
    transforms.Resize((224, 224)),  # 이미지 크기 조정
    transforms.ToTensor(),  # 이미지를 텐서로 변환
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 정규화
])

 

예시 12)

# negative 폴더의 데이터 0으로 라벨링, positive 폴더의 데이터를 1로 라벨링
train_dataset = ImageFolder('/content/train', transform=transform)
val_dataset = ImageFolder('/content/val', transform=transform)
# test_dataset = ImageFolder('/content/test', transform=transform)

print(len(train_dataset))
print(len(val_dataset))
# print(len(test_dataset))
--->
24000
8000

 

예시 13)

# 사용할 데이터셋의 비율 (예: 10%만 사용)
subset_ratio = 0.1  

# 전체 데이터셋 크기 확인
total_train_size = len(train_dataset)
total_val_size = len(val_dataset)

# 선택할 샘플 수 계산
train_subset_size = int(total_train_size * subset_ratio)
val_subset_size = int(total_val_size * subset_ratio)

# 랜덤하게 샘플 선택
train_indices = np.random.choice(total_train_size, train_subset_size, replace=False)
val_indices = np.random.choice(total_val_size, val_subset_size, replace=False)

 

예시 14)

# Subset을 사용하여 데이터셋 크기 줄이기
train_dataset = Subset(train_dataset, train_indices)
val_dataset = Subset(val_dataset, val_indices)

# 데이터셋 크기 출력
print(f"Train dataset size after reduction: {len(train_dataset)}")
print(f"Validation dataset size after reduction: {len(val_dataset)}")
--->
Train dataset size after reduction: 2400
Validation dataset size after reduction: 800

 

예시 15)

# DataLoader 생성
from torch.utils.data import DataLoader

# 훈련 데이터셋을 위한 DataLoader 생성
train_loader = DataLoader(
    train_dataset,  # 훈련 데이터셋
    batch_size=32,  # 한 번에 가져올 데이터 샘플 개수 (미니배치 크기)
    shuffle=True,   # 매 epoch마다 데이터 섞기 (훈련 성능 향상을 위함)
    num_workers=4,  # 데이터를 불러올 때 사용할 병렬 작업(worker) 수 (CPU 코어 수에 맞춰 설정 가능)
    pin_memory=True # GPU 사용 시 데이터를 고정된 메모리 영역(pin memory)으로 할당하여 속도 향상
)

# 검증 데이터셋을 위한 DataLoader 생성
val_loader = DataLoader(
    val_dataset,    # 검증 데이터셋
    batch_size=32,  # 한 번에 가져올 데이터 샘플 개수 (미니배치 크기)
    shuffle=False,  # 검증 데이터는 순서대로 사용 (모델 성능 평가의 일관성을 위해 섞지 않음)
    num_workers=4,  # 데이터를 불러올 때 사용할 병렬 작업(worker) 수
    pin_memory=True # GPU 사용 시 속도 향상을 위해 고정된 메모리 영역에 할당
)

 

3. vgg19
* VGG19는 2014년 Visual Geometry Group(VGG)에서 개발한 합성곱 신경망(CNN) 모델로, ImageNet 대회(ILSVRC-2014)에서 우수한 성능을 보이며 널리 알려졌습니다. 
* 총 19개 층(16개의 합성곱 층 + 3개의 완전연결 층)으로 구성되었으며, 모든 합성곱 층에서 3x3 필터를 사용하고, 최대 풀링을 통한 다운샘플링을 적용하여 깊은 계층에서도 효과적으로 특징을 학습할 수 있도록 설계되었습니다. 
* VGG19는 깊은 구조를 통해 고해상도 이미지의 복잡한 패턴을 학습하는 데 강점이 있으며, 이미지 분류, 객체 검출, 스타일 트랜스퍼 등 다양한 컴퓨터 비전 작업에서 널리 활용됩니다.

 

 

예시 1)

# VGG19 모델을 사전 훈련된 가중치(IMAGENET1K_V1)로 로드
net = vgg19(weights=VGG19_Weights.IMAGENET1K_V1)

# 모델 구조 출력
net
-->
VGG(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace=True)
    (16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (17): ReLU(inplace=True)
    (18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace=True)
    (23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (24): ReLU(inplace=True)
    (25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (26): ReLU(inplace=True)
    (27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (29): ReLU(inplace=True)
    (30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (31): ReLU(inplace=True)
    (32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (33): ReLU(inplace=True)
    (34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (35): ReLU(inplace=True)
    (36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
  (classifier): Sequential(
    (0): Linear(in_features=25088, out_features=4096, bias=True)
    (1): ReLU(inplace=True)
    (2): Dropout(p=0.5, inplace=False)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU(inplace=True)
    (5): Dropout(p=0.5, inplace=False)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)

 

예시 2)

# 모델의 모든 파라미터를 고정
for param in net.parameters():
    param.requires_grad = False

 

예시 3)

# classifier의 마지막 레이어를 Binary Classification Task에 맞게 교체하고, 
# 이 레이어의 파라미터는 학습 가능하도록 설정
net.classifier[6] = nn.Linear(4096, 2)
net.classifier[6].requires_grad = True

 

예시 4)

# 손실 함수
criterion = nn.CrossEntropyLoss()

# GPU로 이동
def train_model(optimizer_name, net, train_loader, val_loader, criterion, num_epochs=20):
    # GPU가 사용 가능하면 GPU로, 그렇지 않으면 CPU를 사용
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    net.to(device)  # 모델을 지정된 장치로 이동

    # 옵티마이저 설정
    if optimizer_name == 'SGD':
        optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)  # SGD 옵티마이저
    elif optimizer_name == 'Adam':
        optimizer = optim.Adam(net.parameters(), lr=0.001, betas=(0.9, 0.999))  # Adam 옵티마이저
    elif optimizer_name == 'RAdam':
        optimizer = optim.RAdam(net.parameters(), lr=0.001, betas=(0.9, 0.999))  # RAdam 옵티마이저
    else:
        raise ValueError(f"Unsupported optimizer: {optimizer_name}")  # 지원되지 않는 옵티마이저 처리

    # 학습 및 검증 과정에서 손실(loss)과 정확도 저장을 위한 리스트
    train_losses = []
    val_losses = []
    val_accuracies = []

    # 전체 에포크 반복
    for epoch in range(num_epochs):
        net.train()  # 모델을 학습 모드로 설정
        running_loss = 0.0  # 한 에포크 동안의 누적 손실 초기화

        # 미니배치 단위 학습
        for i, data in enumerate(train_loader):
            inputs, labels = data  # 배치 데이터 분리
            inputs, labels = inputs.to(device), labels.to(device)  # 입력 및 라벨을 GPU로 이동

            optimizer.zero_grad()  # 옵티마이저의 기울기 초기화
            outputs = net(inputs)  # 모델을 사용하여 예측 수행
            loss = criterion(outputs, labels)  # 손실 계산
            loss.backward()  # 역전파 수행
            optimizer.step()  # 가중치 업데이트

            running_loss += loss.item()  # 현재 배치의 손실을 누적

        # 에포크별 평균 학습 손실 저장
        train_loss = running_loss / len(train_loader)
        train_losses.append(train_loss)

        # 검증 과정 (모델 평가)
        val_loss = 0.0
        net.eval()  # 모델을 평가 모드로 변경
        correct = 0
        total = 0
        with torch.no_grad():  # 검증 과정에서는 그래디언트 계산 비활성화
            for inputs, labels in val_loader:
                inputs, labels = inputs.to(device), labels.to(device)  # 입력 및 라벨을 GPU로 이동
                outputs = net(inputs)  # 모델을 사용하여 예측 수행

                # 가장 높은 확률을 가진 클래스 예측
                _, predicted = torch.max(outputs.data, 1)

                # 총 샘플 수와 맞춘 개수 계산
                total += labels.size(0)
                correct += (predicted == labels).sum().item()

                # 손실 계산 및 누적
                loss = criterion(outputs, labels)
                val_loss += loss.item()

        # 평균 검증 손실 저장
        val_loss /= len(val_loader)
        val_losses.append(val_loss)

        # 검증 정확도 계산 및 저장
        val_accuracy = 100 * correct / total
        val_accuracies.append(val_accuracy)

        # 학습 진행 상황 출력
        print(f'[{optimizer_name}] Epoch {epoch + 1}, Train Loss: {train_loss:.6f}, Val Loss: {val_loss:.6f}, Validation Accuracy: {val_accuracy:.2f}%', flush=True)

    return train_losses, val_losses, val_accuracies  # 학습 손실, 검증 손실, 검증 정확도 반환

 

예시 5)

# 'SGD' 옵티마이저를 사용하여 모델 학습 진행
# 학습 손실, 검증 손실, 검증 정확도를 저장하는 변수로 결과를 반환
train_losses_SGD, val_losses_SGD, val_accuracies_SGD = train_model(
    'SGD',        # 사용할 옵티마이저: Stochastic Gradient Descent (SGD)
    net,          # 학습할 신경망 모델 (예: VGG19)
    train_loader, # 학습 데이터셋을 제공하는 DataLoader
    val_loader,   # 검증 데이터셋을 제공하는 DataLoader
    criterion     # 손실 함수 (예: CrossEntropyLoss)
)
-->
[SGD] Epoch 1, Train Loss: 0.257922, Val Loss: 0.125437, Validation Accuracy: 97.25%
[SGD] Epoch 2, Train Loss: 0.120991, Val Loss: 0.096535, Validation Accuracy: 96.75%
[SGD] Epoch 3, Train Loss: 0.100337, Val Loss: 0.081366, Validation Accuracy: 97.00%
[SGD] Epoch 4, Train Loss: 0.085789, Val Loss: 0.075284, Validation Accuracy: 97.00%
[SGD] Epoch 5, Train Loss: 0.082679, Val Loss: 0.067386, Validation Accuracy: 97.62%
[SGD] Epoch 6, Train Loss: 0.072852, Val Loss: 0.064919, Validation Accuracy: 97.50%
[SGD] Epoch 7, Train Loss: 0.073927, Val Loss: 0.059331, Validation Accuracy: 97.88%
[SGD] Epoch 8, Train Loss: 0.068004, Val Loss: 0.055193, Validation Accuracy: 98.25%
[SGD] Epoch 9, Train Loss: 0.065957, Val Loss: 0.054776, Validation Accuracy: 98.12%
[SGD] Epoch 10, Train Loss: 0.061886, Val Loss: 0.051242, Validation Accuracy: 98.38%
[SGD] Epoch 11, Train Loss: 0.065479, Val Loss: 0.051524, Validation Accuracy: 98.25%
[SGD] Epoch 12, Train Loss: 0.069186, Val Loss: 0.048044, Validation Accuracy: 98.25%
[SGD] Epoch 13, Train Loss: 0.066781, Val Loss: 0.046765, Validation Accuracy: 98.38%
[SGD] Epoch 14, Train Loss: 0.061556, Val Loss: 0.045849, Validation Accuracy: 98.38%
[SGD] Epoch 15, Train Loss: 0.059411, Val Loss: 0.047036, Validation Accuracy: 98.38%
[SGD] Epoch 16, Train Loss: 0.060726, Val Loss: 0.042838, Validation Accuracy: 98.50%
[SGD] Epoch 17, Train Loss: 0.055241, Val Loss: 0.042139, Validation Accuracy: 98.50%
[SGD] Epoch 18, Train Loss: 0.056984, Val Loss: 0.042828, Validation Accuracy: 98.38%
[SGD] Epoch 19, Train Loss: 0.060816, Val Loss: 0.039293, Validation Accuracy: 98.75%
[SGD] Epoch 20, Train Loss: 0.058406, Val Loss: 0.039788, Validation Accuracy: 98.62%

 

예시 6)

# 사전 훈련된(pretrained) VGG19 모델 로드
net = models.vgg19(pretrained=True)  # ImageNet 데이터셋으로 학습된 가중치를 사용

# 모델의 모든 파라미터를 업데이트하지 않도록 설정 (특징 추출 용도)
for param in net.parameters():
    param.requires_grad = False  # 기존 가중치를 고정 (학습되지 않도록 설정)

# VGG19의 분류기(classifier) 마지막 출력층 변경 (기존 1000개 클래스 → 2개 클래스)
net.classifier[6] = nn.Linear(4096, 2)  # 마지막 Fully Connected Layer를 (4096 -> 2)로 수정

# 새로운 출력층의 가중치는 학습할 수 있도록 설정
net.classifier[6].requires_grad = True  # 마지막 레이어만 학습 가능하도록 변경

 

예시 7)

# 'Adam' 옵티마이저를 사용하여 모델 학습 진행
# 학습 손실, 검증 손실, 검증 정확도를 저장하는 변수로 결과를 반환
train_losses_Adam, val_losses_Adam, val_accuracies_Adam = train_model(
    'Adam',       # 사용할 옵티마이저: Adam (Adaptive Moment Estimation)
    net,          # 학습할 신경망 모델 (예: VGG19)
    train_loader, # 학습 데이터셋을 제공하는 DataLoader
    val_loader,   # 검증 데이터셋을 제공하는 DataLoader
    criterion     # 손실 함수 (예: CrossEntropyLoss)
)
-->
[Adam] Epoch 1, Train Loss: 0.129376, Val Loss: 0.069436, Validation Accuracy: 97.90%
[Adam] Epoch 2, Train Loss: 0.064884, Val Loss: 0.055811, Validation Accuracy: 98.26%
[Adam] Epoch 3, Train Loss: 0.051403, Val Loss: 0.050155, Validation Accuracy: 98.11%
[Adam] Epoch 4, Train Loss: 0.043205, Val Loss: 0.043721, Validation Accuracy: 98.52%
[Adam] Epoch 5, Train Loss: 0.041816, Val Loss: 0.039672, Validation Accuracy: 98.52%
[Adam] Epoch 6, Train Loss: 0.037835, Val Loss: 0.037981, Validation Accuracy: 98.72%
[Adam] Epoch 7, Train Loss: 0.040333, Val Loss: 0.036974, Validation Accuracy: 98.82%
[Adam] Epoch 8, Train Loss: 0.037169, Val Loss: 0.043310, Validation Accuracy: 98.21%
[Adam] Epoch 9, Train Loss: 0.036397, Val Loss: 0.033819, Validation Accuracy: 98.92%
[Adam] Epoch 10, Train Loss: 0.034391, Val Loss: 0.033907, Validation Accuracy: 98.82%
[Adam] Epoch 11, Train Loss: 0.031498, Val Loss: 0.032480, Validation Accuracy: 98.98%
[Adam] Epoch 12, Train Loss: 0.030011, Val Loss: 0.033339, Validation Accuracy: 98.98%
[Adam] Epoch 13, Train Loss: 0.028217, Val Loss: 0.032059, Validation Accuracy: 99.13%
[Adam] Epoch 14, Train Loss: 0.029901, Val Loss: 0.032653, Validation Accuracy: 98.98%
[Adam] Epoch 15, Train Loss: 0.031889, Val Loss: 0.033636, Validation Accuracy: 98.82%
[Adam] Epoch 16, Train Loss: 0.028364, Val Loss: 0.032907, Validation Accuracy: 99.03%
[Adam] Epoch 17, Train Loss: 0.027806, Val Loss: 0.031888, Validation Accuracy: 99.08%
[Adam] Epoch 18, Train Loss: 0.031321, Val Loss: 0.032784, Validation Accuracy: 99.03%
[Adam] Epoch 19, Train Loss: 0.029025, Val Loss: 0.032557, Validation Accuracy: 99.08%
[Adam] Epoch 20, Train Loss: 0.030647, Val Loss: 0.031684, Validation Accuracy: 99.08%

 

예시 9)

# 초기화
net = models.vgg19(pretrained=True)
for param in net.parameters():
    param.requires_grad = False

net.classifier[6] = nn.Linear(4096, 2)
net.classifier[6].requires_grad = True

 

예시 10)

# 'RAdam' 옵티마이저를 사용하여 모델을 훈련하고 손실 및 정확도 기록
train_losses_RAdam, val_losses_RAdam, val_accuracies_RAdam = train_model(
    'RAdam',   # 옵티마이저로 RAdam 사용
    net,       # 훈련할 신경망 모델
    train_loader,  # 훈련 데이터셋을 제공하는 DataLoader
    val_loader,    # 검증 데이터셋을 제공하는 DataLoader
    criterion  # 손실 함수 (예: CrossEntropyLoss)
)
--->
[RAdam] Epoch 1, Train Loss: 0.384638, Val Loss: 0.196749, Validation Accuracy: 96.31%
[RAdam] Epoch 2, Train Loss: 0.142593, Val Loss: 0.112970, Validation Accuracy: 97.08%
[RAdam] Epoch 3, Train Loss: 0.091390, Val Loss: 0.084922, Validation Accuracy: 97.49%
[RAdam] Epoch 4, Train Loss: 0.074442, Val Loss: 0.069415, Validation Accuracy: 97.95%
[RAdam] Epoch 5, Train Loss: 0.066210, Val Loss: 0.061247, Validation Accuracy: 98.36%
[RAdam] Epoch 6, Train Loss: 0.057135, Val Loss: 0.056342, Validation Accuracy: 98.41%
[RAdam] Epoch 7, Train Loss: 0.050938, Val Loss: 0.051804, Validation Accuracy: 98.62%
[RAdam] Epoch 8, Train Loss: 0.049155, Val Loss: 0.048864, Validation Accuracy: 98.46%
[RAdam] Epoch 9, Train Loss: 0.045520, Val Loss: 0.046273, Validation Accuracy: 98.36%
[RAdam] Epoch 10, Train Loss: 0.041155, Val Loss: 0.042144, Validation Accuracy: 98.67%
[RAdam] Epoch 11, Train Loss: 0.039683, Val Loss: 0.040386, Validation Accuracy: 98.82%
[RAdam] Epoch 12, Train Loss: 0.040976, Val Loss: 0.039006, Validation Accuracy: 98.82%
[RAdam] Epoch 13, Train Loss: 0.036574, Val Loss: 0.037595, Validation Accuracy: 98.82%
[RAdam] Epoch 14, Train Loss: 0.040283, Val Loss: 0.038725, Validation Accuracy: 98.57%
[RAdam] Epoch 15, Train Loss: 0.034644, Val Loss: 0.036295, Validation Accuracy: 98.82%
[RAdam] Epoch 16, Train Loss: 0.031640, Val Loss: 0.036839, Validation Accuracy: 98.67%
[RAdam] Epoch 17, Train Loss: 0.031739, Val Loss: 0.034802, Validation Accuracy: 98.87%
[RAdam] Epoch 18, Train Loss: 0.033256, Val Loss: 0.032365, Validation Accuracy: 98.77%
[RAdam] Epoch 19, Train Loss: 0.031009, Val Loss: 0.033959, Validation Accuracy: 98.77%
[RAdam] Epoch 20, Train Loss: 0.028169, Val Loss: 0.033739, Validation Accuracy: 98.72%

 

 

언제 Adam과 RAdam을 사용할까?
* Adam: 기본적으로 가장 많이 사용되는 최적화 알고리즘이며, 다양한 모델에서 잘 동작함.
* RAdam: 학습 초반에 불안정한 동작을 보이는 경우 (예: 작은 배치 크기, 불안정한 손실 함수)에는 Adam보다 RAdam이 더 좋은 선택.
  --> 즉, Adam을 먼저 사용하고, 학습이 불안정하면 RAdam을 고려하는 것이 일반적인 전략입니다.

 

예시 11)

import matplotlib.pyplot as plt

# 학습 손실과 검증 정확도 그래프 그리기
plt.figure(figsize=(15, 10))  # 전체 그림 크기 설정 (가로 15, 세로 10)

# 학습 손실 그래프
plt.subplot(3, 1, 1)  # 3행 1열의 첫 번째 위치
plt.plot(train_losses_SGD, label='SGD')      # SGD 옵티마이저의 학습 손실
plt.plot(train_losses_Adam, label='Adam')    # Adam 옵티마이저의 학습 손실
plt.plot(train_losses_RAdam, label='RAdam')  # RAdam 옵티마이저의 학습 손실
plt.xlabel('Epoch')  # x축: Epoch(훈련 반복 횟수)
plt.ylabel('Loss')   # y축: Loss(손실 값)
plt.title('Training Loss Over Epochs')  # 그래프 제목
plt.legend()  # 범례 추가

# 검증 손실 그래프
plt.subplot(3, 1, 2)  # 3행 1열의 두 번째 위치
plt.plot(val_losses_SGD, label='SGD')      # SGD 옵티마이저의 검증 손실
plt.plot(val_losses_Adam, label='Adam')    # Adam 옵티마이저의 검증 손실
plt.plot(val_losses_RAdam, label='RAdam')  # RAdam 옵티마이저의 검증 손실
plt.xlabel('Epoch')  # x축: Epoch(훈련 반복 횟수)
plt.ylabel('Loss')   # y축: Loss(손실 값)
plt.title('Validation Loss Over Epochs')  # 그래프 제목
plt.legend()  # 범례 추가

# 검증 정확도 그래프
plt.subplot(3, 1, 3)  # 3행 1열의 세 번째 위치
plt.plot(val_accuracies_SGD, label='SGD', color='blue')      # SGD 옵티마이저의 검증 정확도
plt.plot(val_accuracies_Adam, label='Adam', color='green')   # Adam 옵티마이저의 검증 정확도
plt.plot(val_accuracies_RAdam, label='RAdam', color='orange')# RAdam 옵티마이저의 검증 정확도
plt.xlabel('Epoch')   # x축: Epoch(훈련 반복 횟수)
plt.ylabel('Accuracy (%)')  # y축: Accuracy(정확도 %)
plt.title('Validation Accuracy Over Epochs')  # 그래프 제목
plt.legend()  # 범례 추가

plt.tight_layout()  # 그래프 간 간격 자동 조정
plt.show()  # 그래프 출력

--->

 

예시 12)

# Image load 및 tensor로 변환
def load_and_transform_image(image_path, transform):
    image = Image.open(image_path).convert('RGB')
    return transform(image).unsqueeze(0)  # 이미지를 모델에 맞게 변환하고 배치 차원 추가

 

예시 13)

# 클래스별 폴더 경로
class_folders = {
    'crack': '/content/test/positive',
    'normal': '/content/test/negative'
}

 

예시 14)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

 

예시 15)

plt.figure(figsize=(20, 8))

# subplot 인덱스를 위한 카운터
counter = 1


# 각 클래스별로 5장의 이미지 추론 및 시각화
for class_name, folder_path in class_folders.items():
    # 해당 클래스의 이미지 경로 가져오기
    image_paths = glob.glob(os.path.join(folder_path, '*'))
    selected_paths = image_paths[:5]  # 첫 5장 선택

    for image_path in selected_paths:
        image = load_and_transform_image(image_path, transform)

        # ✅ 입력 데이터도 GPU로 이동
        image = image.to(device)

        net.eval()  # 모델을 평가 모드로 설정
        # 모델을 사용한 추론
        with torch.no_grad():
            outputs = net(image)
            _, predicted = torch.max(outputs, 1)

        prediction = 'normal' if predicted.item() == 0 else 'crack'

        # 결과 시각화
        plt.subplot(2, 5, counter)
        plt.imshow(Image.open(image_path))
        plt.title(f'True: {class_name}, Pred: {prediction}')
        plt.axis('off')

        counter += 1  # subplot 인덱스 업데이트

plt.tight_layout()
plt.show()

--->

 

728x90
LIST

'컴퓨터 비전' 카테고리의 다른 글

컴퓨터 비전(Computer Vision)  (2) 2025.02.28